diff --git a/arch/arm/configs/htcleo_defconfig b/arch/arm/configs/htcleo_defconfig index 5f799b34..830ca0a3 100644 --- a/arch/arm/configs/htcleo_defconfig +++ b/arch/arm/configs/htcleo_defconfig @@ -404,6 +404,7 @@ CONFIG_HAVE_MLOCKED_PAGE_BIT=y CONFIG_KSM=y CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 CONFIG_ALIGNMENT_TRAP=y +CONFIG_ALLOW_CPU_ALIGNMENT=y # CONFIG_UACCESS_WITH_MEMCPY is not set # diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 2c1db77d..a6c66f59 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -382,11 +382,13 @@ ENDPROC(sys_clone_wrapper) sys_sigreturn_wrapper: add r0, sp, #S_OFF + mov why, #0 @ prevent syscall restart handling b sys_sigreturn ENDPROC(sys_sigreturn_wrapper) sys_rt_sigreturn_wrapper: add r0, sp, #S_OFF + mov why, #0 @ prevent syscall restart handling b sys_rt_sigreturn ENDPROC(sys_rt_sigreturn_wrapper) diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 4946c727..772c3c5b 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -158,10 +158,10 @@ __secondary_data: * registers. */ __enable_mmu: -#ifdef CONFIG_ALIGNMENT_TRAP - orr r0, r0, #CR_A -#else +#ifdef CONFIG_ALLOW_CPU_ALIGNMENT bic r0, r0, #CR_A +#else + orr r0, r0, #CR_A #endif #ifdef CONFIG_CPU_DCACHE_DISABLE bic r0, r0, #CR_C diff --git a/arch/arm/mach-msm/acpuclock-scorpion.c b/arch/arm/mach-msm/acpuclock-scorpion.c index 7aab81e8..e84cbee6 100644 --- a/arch/arm/mach-msm/acpuclock-scorpion.c +++ b/arch/arm/mach-msm/acpuclock-scorpion.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,19 @@ struct clkctl_acpu_speed { unsigned axiclk_khz; }; +static unsigned long max_axi_rate; + +struct regulator { + struct device *dev; + struct list_head list; + int uA_load; + int min_uV; + int max_uV; + char *supply_name; + struct device_attribute dev_attr; + struct regulator_dev *rdev; +}; + /* clock sources */ #define CLK_TCXO 0 /* 19.2 MHz */ #define CLK_GLOBAL_PLL 1 /* 768 MHz */ @@ -76,135 +90,46 @@ struct clkctl_acpu_speed { #define SRC_PLL1 3 /* 768 MHz */ struct clkctl_acpu_speed acpu_freq_tbl[] = { -#ifdef CONFIG_HTCLEO_UNDERVOLT_1000 - { 19200, CCTL(CLK_TCXO, 1), SRC_RAW, 0, 0, 1000, 14000 }, + { 19200, CCTL(CLK_TCXO, 1), SRC_RAW, 0, 0, 1000, 14000}, + { 96000, CCTL(CLK_TCXO, 1), SRC_AXI, 0, 0, 1000, 14000 }, { 128000, CCTL(CLK_TCXO, 1), SRC_AXI, 0, 0, 1000, 14000 }, { 245000, CCTL(CLK_MODEM_PLL, 1), SRC_RAW, 0, 0, 1000, 29000 }, - //{ 256000, CCTL(CLK_GLOBAL_PLL, 3), SRC_RAW, 0, 0, 1000, 29000 }, - { 384000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0A, 0, 1000, 58000 }, - { 422400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0B, 0, 1000, 117000 }, - { 460800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0C, 0, 1000, 117000 }, - { 499200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0D, 0, 1025, 117000 }, - { 537600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0E, 0, 1050, 117000 }, - { 576000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0F, 0, 1050, 117000 }, - { 614400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x10, 0, 1075, 117000 }, - { 652800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x11, 0, 1100, 117000 }, - { 691200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x12, 0, 1125, 117000 }, - { 729600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x13, 0, 1150, 117000 }, - { 768000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x14, 0, 1150, 128000 }, - { 806400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x15, 0, 1175, 128000 }, - { 844800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x16, 0, 1200, 128000 }, - { 883200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x17, 0, 1200, 128000 }, - { 921600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x18, 0, 1225, 128000 }, - { 960000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x19, 0, 1225, 128000 }, - { 998400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1A, 0, 1225, 128000 }, -#elif CONFIG_HTCLEO_UNDERVOLT_925 - // should work with most of HD2s - { 19200, CCTL(CLK_TCXO, 1), SRC_RAW, 0, 0, 925, 14000 }, - { 128000, CCTL(CLK_TCXO, 1), SRC_AXI, 0, 0, 925, 14000 }, - { 245000, CCTL(CLK_MODEM_PLL, 1), SRC_RAW, 0, 0, 925, 29000 }, - //{ 256000, CCTL(CLK_GLOBAL_PLL, 3), SRC_RAW, 0, 0, 925, 29000 }, - { 384000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0A, 0, 950, 58000 }, - { 422400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0B, 0, 975, 117000 }, - { 460800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0C, 0, 1000, 117000 }, - { 499200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0D, 0, 1025, 117000 }, - { 537600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0E, 0, 1050, 117000 }, - { 576000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0F, 0, 1050, 117000 }, - { 614400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x10, 0, 1075, 117000 }, - { 652800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x11, 0, 1100, 117000 }, - { 691200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x12, 0, 1125, 117000 }, - { 729600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x13, 0, 1150, 117000 }, - { 768000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x14, 0, 1150, 128000 }, - { 806400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x15, 0, 1175, 128000 }, - { 844800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x16, 0, 1200, 128000 }, - { 883200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x17, 0, 1200, 128000 }, - { 921600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x18, 0, 1225, 128000 }, - { 960000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x19, 0, 1225, 128000 }, - { 998400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1A, 0, 1225, 128000 }, -#elif CONFIG_HTCLEO_UNDERVOLT_800 - // not working yet - { 19200, CCTL(CLK_TCXO, 1), SRC_RAW, 0, 0, 850, 14000 }, - { 128000, CCTL(CLK_TCXO, 1), SRC_AXI, 0, 0, 850, 14000 }, - { 245000, CCTL(CLK_MODEM_PLL, 1), SRC_RAW, 0, 0, 850, 29000 }, - //{ 256000, CCTL(CLK_GLOBAL_PLL, 3), SRC_RAW, 0, 0, 850, 29000 }, - { 384000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0A, 0, 850, 58000 }, - { 422400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0B, 0, 875, 117000 }, - { 460800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0C, 0, 900, 117000 }, - { 499200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0D, 0, 925, 117000 }, - { 537600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0E, 0, 950, 117000 }, - { 576000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0F, 0, 950, 117000 }, - { 614400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x10, 0, 975, 117000 }, - { 652800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x11, 0, 1000, 117000 }, - { 691200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x12, 0, 1025, 117000 }, - { 729600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x13, 0, 1050, 117000 }, - { 768000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x14, 0, 1125, 128000 }, - { 806400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x15, 0, 1125, 128000 }, - { 844800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x16, 0, 1150, 128000 }, - { 883200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x17, 0, 1150, 128000 }, - { 921600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x18, 0, 1175, 128000 }, - { 960000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x19, 0, 1175, 128000 }, - { 998400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1A, 0, 1200, 128000 }, -#else - { 19200, CCTL(CLK_TCXO, 1), SRC_RAW, 0, 0, 1050, 14000}, - { 128000, CCTL(CLK_TCXO, 1), SRC_AXI, 0, 0, 1050, 14000 }, - { 245000, CCTL(CLK_MODEM_PLL, 1), SRC_RAW, 0, 0, 1050, 29000 }, - /* Work arround for acpu resume hung, GPLL is turn off by arm9 */ - /*{ 256000, CCTL(CLK_GLOBAL_PLL, 3), SRC_RAW, 0, 0, 1050, 29000 },*/ - { 384000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0A, 0, 1050, 58000 }, - { 422400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0B, 0, 1050, 117000 }, - { 460800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0C, 0, 1050, 117000 }, - { 499200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0D, 0, 1075, 117000 }, - { 537600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0E, 0, 1100, 117000 }, - { 576000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0F, 0, 1100, 117000 }, - { 614400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x10, 0, 1125, 117000 }, - { 652800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x11, 0, 1150, 117000 }, - { 691200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x12, 0, 1175, 117000 }, - { 729600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x13, 0, 1200, 117000 }, - { 768000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x14, 0, 1200, 128000 }, - { 806400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x15, 0, 1225, 128000 }, - { 844800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x16, 0, 1250, 128000 }, - { 883200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x17, 0, 1275, 128000 }, - { 921600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x18, 0, 1300, 128000 }, - { 960000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x19, 0, 1300, 128000 }, - { 998400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1A, 0, 1300, 128000 }, -#endif -#ifdef CONFIG_HTCLEO_OVERCLOCK -#ifdef CONFIG_HTCLEO_UNDERVOLT_1000 - { 1036800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1B, 0, 1225, 128000 }, - { 1075200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1C, 0, 1250, 128000 }, - { 1113600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1D, 0, 1275, 128000 }, - { 1152000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1E, 0, 1300, 128000 }, - { 1190400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1F, 0, 1325, 128000 }, -#elif CONFIG_HTCLEO_UNDERVOLT_925 - { 1036800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1B, 0, 1225, 128000 }, - { 1075200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1C, 0, 1250, 128000 }, - { 1113600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1D, 0, 1275, 128000 }, - { 1152000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1E, 0, 1300, 128000 }, - { 1190400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1F, 0, 1325, 128000 }, -#elif CONFIG_HTCLEO_UNDERVOLT_800 - { 1036800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1B, 0, 1225, 128000 }, - { 1075200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1C, 0, 1250, 128000 }, - { 1113600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1D, 0, 1275, 128000 }, - { 1152000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1E, 0, 1300, 128000 }, - { 1190400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1F, 0, 1325, 128000 }, -#else - { 1036800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1B, 0, 1300, 128000 }, - { 1075200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1C, 0, 1300, 128000 }, - { 1113600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1D, 0, 1300, 128000 }, - { 1152000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1E, 0, 1325, 128000 }, - { 1190400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1F, 0, 1325, 128000 }, -#endif + /* Work arround for acpu resume hung, GPLL is turn off by arm9 */ + /*{ 256000, CCTL(CLK_GLOBAL_PLL, 3), SRC_RAW, 0, 0, 1050, 29000 },*/ + { 384000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0A, 0, 1000, 58000 }, + { 422400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0B, 0, 1000, 117000 }, + { 460800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0C, 0, 1000, 117000 }, + { 499200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0D, 0, 1050, 117000 }, + { 537600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0E, 0, 1050, 117000 }, + { 576000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0F, 0, 1050, 117000 }, + { 614400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x10, 0, 1075, 117000 }, + { 652800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x11, 0, 1100, 117000 }, + { 691200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x12, 0, 1125, 117000 }, + { 729600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x13, 0, 1150, 117000 }, + { 768000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x14, 0, 1150, 128000 }, + { 806400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x15, 0, 1175, 128000 }, + { 844800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x16, 0, 1225, 128000 }, + { 883200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x17, 0, 1250, 128000 }, + { 921600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x18, 0, 1300, 128000 }, + { 960000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x19, 0, 1300, 128000 }, + { 998400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1A, 0, 1300, 128000 }, +#ifdef CONFIG_HTCLEO_OVERCLOCK + { 1036800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1B, 0, 1300, 128000 }, + { 1075200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1C, 0, 1300, 128000 }, + { 1113600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1D, 0, 1300, 128000 }, + { 1152000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1E, 0, 1300, 128000 }, + { 1190400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x1F, 0, 1325, 128000 }, #endif #ifdef CONFIG_HTCLEO_EXOVERCLOCK - { 1228800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x20, 0, 1325, 128000 }, - { 1267200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x21, 0, 1350, 128000 }, - { 1305600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x22, 0, 1350, 128000 }, - { 1344000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x23, 0, 1350, 128000 }, - { 1382400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x24, 0, 1350, 128000 }, - { 1420800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x25, 0, 1350, 128000 }, - { 1459200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x26, 0, 1350, 128000 }, - { 1497600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x27, 0, 1350, 128000 }, - { 1536000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x28, 0, 1350, 128000 }, + { 1228800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x20, 0, 1325, 128000 }, + { 1267200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x21, 0, 1350, 128000 }, + { 1305600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x22, 0, 1350, 128000 }, + { 1344000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x23, 0, 1350, 128000 }, + { 1382400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x24, 0, 1350, 128000 }, + { 1420800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x25, 0, 1350, 128000 }, + { 1459200, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x26, 0, 1350, 128000 }, + { 1497600, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x27, 0, 1350, 128000 }, + { 1536000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x28, 0, 1350, 128000 }, #endif { 0 }, }; @@ -231,11 +156,10 @@ static void __init acpuclk_init_cpufreq_table(void) freq_table[i].index = i; freq_table[i].frequency = CPUFREQ_ENTRY_INVALID; - /* Skip speeds we don't want */ - if ( acpu_freq_tbl[i].acpu_khz == 19200 || - //acpu_freq_tbl[i].acpu_khz == 128000 || - acpu_freq_tbl[i].acpu_khz == 256000) - continue; + /* Skip speeds using the global pll */ + if (acpu_freq_tbl[i].acpu_khz == 256000 || + acpu_freq_tbl[i].acpu_khz == 19200) + continue; vdd = acpu_freq_tbl[i].vdd; /* Allow mpll and the first scpll speeds */ @@ -269,6 +193,7 @@ struct clock_state { unsigned long wait_for_irq_khz; struct clk* clk_ebi1; struct regulator *regulator; + int (*acpu_set_vdd) (int mvolts); }; static struct clock_state drv_state = { 0 }; @@ -345,11 +270,10 @@ static void scpll_set_freq(uint32_t lval) dmb(); /* wait for frequency switch to finish */ - while (readl(SCPLL_STATUS_ADDR) & 0x1) - ; + while (readl(SCPLL_STATUS_ADDR) & 0x1); /* completion bit is not reliable for SHOT switch */ - udelay(25); + udelay(15); } /* write the new L val and switch mode */ @@ -363,8 +287,7 @@ static void scpll_set_freq(uint32_t lval) dmb(); /* wait for frequency switch to finish */ - while (readl(SCPLL_STATUS_ADDR) & 0x1) - ; + while (readl(SCPLL_STATUS_ADDR) & 0x1); } /* this is still a bit weird... */ @@ -625,13 +548,20 @@ static void __init acpuclk_init(void) } drv_state.current_speed = speed; - for (speed = acpu_freq_tbl; speed->acpu_khz; speed++) + for (speed = acpu_freq_tbl; speed->acpu_khz; speed++) { speed->lpj = cpufreq_scale(loops_per_jiffy, init_khz, speed->acpu_khz); + max_axi_rate = speed->axiclk_khz * 1000; + } loops_per_jiffy = drv_state.current_speed->lpj; } +unsigned long acpuclk_get_max_axi_rate(void) +{ + return max_axi_rate; +} + unsigned long acpuclk_get_rate(void) { return drv_state.current_speed->acpu_khz; @@ -674,6 +604,7 @@ void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us; drv_state.power_collapse_khz = clkdata->power_collapse_khz; drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz; + drv_state.acpu_set_vdd = acpuclk_set_vdd_level; if (clkdata->mpll_khz) acpu_mpll->acpu_khz = clkdata->mpll_khz; @@ -708,7 +639,7 @@ ssize_t acpuclk_get_vdd_levels_str(char *buf) void acpuclk_set_vdd(unsigned acpu_khz, int vdd) { int i; - vdd = vdd / 25 * 25; //! regulator only accepts multiples of 25 (mV) + vdd = (vdd / HTCLEO_TPS65023_UV_STEP_MV) * HTCLEO_TPS65023_UV_STEP_MV; mutex_lock(&drv_state.lock); for (i = 0; acpu_freq_tbl[i].acpu_khz; i++) { @@ -722,5 +653,16 @@ void acpuclk_set_vdd(unsigned acpu_khz, int vdd) } mutex_unlock(&drv_state.lock); } - +unsigned int acpuclk_get_vdd_min(void) +{ + return HTCLEO_TPS65023_MIN_UV_MV; +} +unsigned int acpuclk_get_vdd_max(void) +{ + return HTCLEO_TPS65023_MAX_UV_MV; +} +unsigned int acpuclk_get_vdd_step(void) +{ + return HTCLEO_TPS65023_UV_STEP_MV; +} #endif diff --git a/arch/arm/mach-msm/board-htcleo-audio.c b/arch/arm/mach-msm/board-htcleo-audio.c index 3b2e66c7..1ee46c6d 100644 --- a/arch/arm/mach-msm/board-htcleo-audio.c +++ b/arch/arm/mach-msm/board-htcleo-audio.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "board-htcleo.h" #include "devices.h" diff --git a/arch/arm/mach-msm/board-htcleo-bl-led.c b/arch/arm/mach-msm/board-htcleo-bl-led.c index 38ec9940..299a8bfa 100644 --- a/arch/arm/mach-msm/board-htcleo-bl-led.c +++ b/arch/arm/mach-msm/board-htcleo-bl-led.c @@ -39,7 +39,6 @@ #define HTCLEO_DEFAULT_BACKLIGHT_BRIGHTNESS 255 - static struct led_trigger *htcleo_lcd_backlight; static int auto_bl_state=0; static DEFINE_MUTEX(htcleo_backlight_lock); diff --git a/arch/arm/mach-msm/board-htcleo-ls.c b/arch/arm/mach-msm/board-htcleo-ls.c index 6583b2ee..8e00c0ef 100644 --- a/arch/arm/mach-msm/board-htcleo-ls.c +++ b/arch/arm/mach-msm/board-htcleo-ls.c @@ -118,7 +118,7 @@ int lightsensor_read_value(uint32_t *val) } *val = data[1] | (data[0] << 8); - D("lsensor adc = %d\n", *val); + D("lsensor adc = %u\n", *val); /* val is unsigned */ return 0; } diff --git a/arch/arm/mach-msm/board-htcleo-mmc.c b/arch/arm/mach-msm/board-htcleo-mmc.c index a4f78f0c..e144e491 100644 --- a/arch/arm/mach-msm/board-htcleo-mmc.c +++ b/arch/arm/mach-msm/board-htcleo-mmc.c @@ -30,6 +30,7 @@ #include #include +#include #include "board-htcleo.h" #include "devices.h" @@ -391,7 +392,7 @@ static int __init htcleommc_dbg_init(void) { struct dentry *dent; - if (!machine_is_htcleo() && !machine_is_htcleo()) + if (!machine_is_htcleo()) return 0; dent = debugfs_create_dir("htcleo_mmc_dbg", 0); diff --git a/arch/arm/mach-msm/board-htcleo.c b/arch/arm/mach-msm/board-htcleo.c index 8b5f90be..01d66fac 100644 --- a/arch/arm/mach-msm/board-htcleo.c +++ b/arch/arm/mach-msm/board-htcleo.c @@ -55,7 +55,9 @@ #ifdef CONFIG_SERIAL_BCM_BT_LPM #include #endif +#ifdef CONFIG_PERFLOCK #include +#endif #include #include @@ -395,10 +397,9 @@ static uint32_t flashlight_gpio_table[] = PCOM_GPIO_CFG(HTCLEO_GPIO_FLASHLIGHT_FLASH, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), }; -static int config_htcleo_flashlight_gpios(void) +static void config_htcleo_flashlight_gpios(void) { config_gpio_table(flashlight_gpio_table, ARRAY_SIZE(flashlight_gpio_table)); - return 0; } static struct flashlight_platform_data htcleo_flashlight_data = @@ -748,28 +749,6 @@ static struct platform_device qsd_device_spi = { /////////////////////////////////////////////////////////////////////// // KGSL (HW3D support)#include /////////////////////////////////////////////////////////////////////// - -static struct resource msm_kgsl_resources[] = -{ - { - .name = "kgsl_reg_memory", - .start = MSM_GPU_REG_PHYS, - .end = MSM_GPU_REG_PHYS + MSM_GPU_REG_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .name = "kgsl_phys_memory", - .start = MSM_GPU_PHYS_BASE, - .end = MSM_GPU_PHYS_BASE + MSM_GPU_PHYS_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_GRAPHICS, - .end = INT_GRAPHICS, - .flags = IORESOURCE_IRQ, - }, -}; - static int htcleo_kgsl_power_rail_mode(int follow_clk) { int mode = follow_clk ? 0 : 1; @@ -786,16 +765,7 @@ static int htcleo_kgsl_power(bool on) return msm_proc_comm(cmd, &rail_id, 0); } -static struct platform_device msm_kgsl_device = -{ - .name = "kgsl", - .id = -1, - .resource = msm_kgsl_resources, - .num_resources = ARRAY_SIZE(msm_kgsl_resources), -}; - -#ifdef CONFIG_MSM_KGSL -/* start kgsl */ +/* start kgsl-3d0 */ static struct resource kgsl_3d0_resources[] = { { .name = KGSL_3D0_REG_MEMORY, @@ -843,9 +813,7 @@ struct platform_device msm_kgsl_3d0 = { .platform_data = &kgsl_3d0_pdata, }, }; -/* end kgsl */ -#endif - +/* end kgsl-3d0 */ /////////////////////////////////////////////////////////////////////// // Memory /////////////////////////////////////////////////////////////////////// @@ -897,7 +865,7 @@ static struct platform_device android_pmem_mdp_device = { static struct platform_device android_pmem_adsp_device = { .name = "android_pmem", - .id = 4, + .id = 1, /* 4 */ .dev = { .platform_data = &android_pmem_adsp_pdata, }, @@ -905,7 +873,7 @@ static struct platform_device android_pmem_adsp_device = { static struct platform_device android_pmem_venc_device = { .name = "android_pmem", - .id = 5, + .id = 3, /* 5 */ .dev = { .platform_data = &android_pmem_venc_pdata, }, @@ -1083,6 +1051,7 @@ static struct msm_acpu_clock_platform_data htcleo_clock_data = { // .wait_for_irq_khz = 19200, // TCXO }; +#ifdef CONFIG_PERFLOCK static unsigned htcleo_perf_acpu_table[] = { 245000000, 576000000, @@ -1093,6 +1062,8 @@ static struct perflock_platform_data htcleo_perflock_data = { .perf_acpu_table = htcleo_perf_acpu_table, .table_size = ARRAY_SIZE(htcleo_perf_acpu_table), }; +#endif + /////////////////////////////////////////////////////////////////////// // Reset /////////////////////////////////////////////////////////////////////// @@ -1139,7 +1110,9 @@ static void __init htcleo_init(void) msm_acpu_clock_init(&htcleo_clock_data); +#ifdef CONFIG_PERFLOCK perflock_init(&htcleo_perflock_data); +#endif #if defined(CONFIG_MSM_SERIAL_DEBUGGER) msm_serial_debug_init(MSM_UART1_PHYS, INT_UART1, diff --git a/arch/arm/mach-msm/board-htcleo.h b/arch/arm/mach-msm/board-htcleo.h index d3777317..fcab3fe5 100644 --- a/arch/arm/mach-msm/board-htcleo.h +++ b/arch/arm/mach-msm/board-htcleo.h @@ -178,7 +178,8 @@ /* Voltage driver */ #define HTCLEO_TPS65023_MIN_UV_MV (800) -#define HTCLEO_TPS65023_MAX_UV_MV (1350) +#define HTCLEO_TPS65023_MAX_UV_MV (1375) +#define HTCLEO_TPS65023_UV_STEP_MV (25) /* LEDS */ #define LED_RGB (1 << 0) @@ -196,11 +197,12 @@ struct microp_led_platform_data { int num_leds; }; - - - int htcleo_pm_set_vreg(int enable, unsigned id); int __init htcleo_init_panel(void); int htcleo_is_nand_boot(void); +unsigned htcleo_get_vbus_state(void); +void config_camera_on_gpios(void); +void config_camera_off_gpios(void); +int is_valid_mac_address(char *mac); #endif /* __ARCH_ARM_MACH_MSM_BOARD_HTCLEO_H */ diff --git a/arch/arm/mach-msm/clock-wince.c b/arch/arm/mach-msm/clock-wince.c index a2b601b6..1903449b 100644 --- a/arch/arm/mach-msm/clock-wince.c +++ b/arch/arm/mach-msm/clock-wince.c @@ -34,6 +34,8 @@ //#define ENABLE_CLOCK_INFO 1 +extern struct clk msm_clocks[]; + static DEFINE_MUTEX(clocks_mutex); static DEFINE_SPINLOCK(clocks_lock); static LIST_HEAD(clocks); @@ -233,8 +235,16 @@ struct mdns_clock_params msm_clock_freq_parameters[] = { MSM_CLOCK_REG(64000000,0x19, 0x60, 0x30, 0, 2, 4, 1, 245760000), /* BT, 4000000 (*16) */ }; +int status_set_grp_clk = 0; +int i_set_grp_clk = 0; +int control_set_grp_clk; + static void set_grp_clk( int on ) { + int i = 0; + int status = 0; + int control; + if ( on != 0 ) { //axi_reset @@ -274,8 +284,7 @@ static void set_grp_clk( int on ) writel(readl(MSM_CLK_CTL_BASE) |0x8, MSM_CLK_CTL_BASE); //grp MD writel(readl(MSM_CLK_CTL_BASE+0x80) |0x1, MSM_CLK_CTL_BASE+0x80); //PRPH_WEB_NS_REG - int i = 0; - int status = 0; + while ( status == 0 && i < 100) { i++; status = readl(MSM_CLK_CTL_BASE+0x84) & 0x1; @@ -297,7 +306,7 @@ static void set_grp_clk( int on ) writel(readl(MSM_CLK_CTL_BASE+0x290) |0x4, MSM_CLK_CTL_BASE+0x290); //MSM_RAIL_CLAMP_IO writel( 0x11f, MSM_CLK_CTL_BASE+0x284); //VDD_GRP_GFS_CTL - int control = readl(MSM_CLK_CTL_BASE+0x288); //VDD_VDC_GFS_CTL + control = readl(MSM_CLK_CTL_BASE+0x288); //VDD_VDC_GFS_CTL if ( control & 0x100 ) writel(readl(MSM_CLK_CTL_BASE) &(~(0x8)), MSM_CLK_CTL_BASE); } @@ -1291,5 +1300,18 @@ static int __init clock_late_init(void) //pr_info("reset imem_config\n"); return 0; } - late_initcall(clock_late_init); + +struct clk_ops clk_ops_pcom = { + .enable = pc_clk_enable, + .disable = pc_clk_disable, + .auto_off = pc_clk_disable, +// .reset = pc_clk_reset, + .set_rate = pc_clk_set_rate, + .set_min_rate = pc_clk_set_min_rate, + .set_max_rate = pc_clk_set_max_rate, + .set_flags = pc_clk_set_flags, + .get_rate = pc_clk_get_rate, + .is_enabled = pc_clk_is_enabled, +// .round_rate = pc_clk_round_rate, +}; diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index 81d2e296..5abc7d91 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c index 1fffb585..1c576c6d 100644 --- a/arch/arm/mach-msm/cpufreq.c +++ b/arch/arm/mach-msm/cpufreq.c @@ -17,6 +17,13 @@ * */ +#include +#include +#include +#include +#include +#include + #include #include #include diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index fd5133dc..69f0e09f 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -138,13 +138,14 @@ dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, complete(&cmd->complete); } -int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) +int msm_dmov_exec_cmd(unsigned id, unsigned int crci_mask, unsigned int cmdptr) { struct msm_dmov_exec_cmdptr_cmd cmd; PRINT_FLOW("dmov_exec_cmdptr(%d, %x)\n", id, cmdptr); cmd.dmov_cmd.cmdptr = cmdptr; + cmd.dmov_cmd.crci_mask = crci_mask; cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func; cmd.dmov_cmd.execute_func = NULL; cmd.id = id; diff --git a/arch/arm/mach-msm/include/mach/board-htcleo-audio.h b/arch/arm/mach-msm/include/mach/board-htcleo-audio.h new file mode 100644 index 00000000..65b89af1 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/board-htcleo-audio.h @@ -0,0 +1,29 @@ +/* board-htcleo-mmc.h + * + * Copyright (C) 2011 marc1706 + * + * 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 HTCLEO_AUDIO_H +#define HTCLEO_AUDIO_H + +void htcleo_headset_enable(int en); +void htcleo_speaker_enable(int en); +void htcleo_receiver_enable(int en); +void htcleo_bt_sco_enable(int en); +void htcleo_mic_enable(int en); +void htcleo_analog_init(void); +int htcleo_get_rx_vol(uint8_t hw, int level); +void __init htcleo_audio_init(void); + +#endif // HTCLEO_AUDIO_H + diff --git a/arch/arm/mach-msm/include/mach/board-htcleo-microp.h b/arch/arm/mach-msm/include/mach/board-htcleo-microp.h index dd77879e..39dc5516 100644 --- a/arch/arm/mach-msm/include/mach/board-htcleo-microp.h +++ b/arch/arm/mach-msm/include/mach/board-htcleo-microp.h @@ -136,4 +136,14 @@ struct microp_i2c_client_data { int microp_i2c_read(uint8_t addr, uint8_t *data, int length); int microp_i2c_write(uint8_t addr, uint8_t *data, int length); int capella_cm3602_power(int pwr_device, uint8_t enable); +int microp_read_gpo_status(uint16_t *status); +int microp_gpo_enable(uint16_t gpo_mask); +int microp_gpo_disable(uint16_t gpo_mask); + +#ifdef CONFIG_HAS_EARLYSUSPEND +void microp_early_suspend(struct early_suspend *h); +void microp_early_resume(struct early_suspend *h); +#endif // CONFIG_HAS_EARLYSUSPEND + + #endif diff --git a/arch/arm/mach-msm/include/mach/board-htcleo-mmc.h b/arch/arm/mach-msm/include/mach/board-htcleo-mmc.h new file mode 100644 index 00000000..8eaf392c --- /dev/null +++ b/arch/arm/mach-msm/include/mach/board-htcleo-mmc.h @@ -0,0 +1,31 @@ +/* board-htcleo-mmc.h + * + * Copyright (C) 2011 marc1706 + * + * 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 HTCLEO_MMC_H +#define HTCLEO_MMC_H + +static bool opt_disable_sdcard; +static void (*wifi_status_cb)(int card_present, void *dev_id); +static void *wifi_status_cb_devid; +static int htcleo_wifi_power_state; +static int htcleo_wifi_reset_state; + +int htcleo_wifi_set_carddetect(int val); +int htcleo_wifi_power(int on); +int htcleo_wifi_reset(int on); +int __init htcleo_init_mmc(unsigned debug_uart); + +#endif // HTCLEO_MMC_H + diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index 91016443..cebfe9d0 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -178,6 +178,8 @@ enum { BOOTMODE_OFFMODE_CHARGING = 0x5, }; +void msm_hsusb_set_vbus_state(int online); + #define MSM_MAX_DEC_CNT 14 /* 7k target ADSP information */ /* Bit 23:0, for codec identification like mp3, wav etc * diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h index 7166756a..1dafddc2 100644 --- a/arch/arm/mach-msm/include/mach/camera.h +++ b/arch/arm/mach-msm/include/mach/camera.h @@ -32,6 +32,7 @@ #define NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS 16 #define NUM_STAT_OUTPUT_BUFFERS 3 #define NUM_AF_STAT_OUTPUT_BUFFERS 3 +#define max_control_command_size 150 enum msm_queue { MSM_CAM_Q_CTRL, /* control command or control command status */ diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h index 41a393b8..c45f6936 100644 --- a/arch/arm/mach-msm/include/mach/clk.h +++ b/arch/arm/mach-msm/include/mach/clk.h @@ -51,4 +51,7 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate); int clk_reset(struct clk *clk, enum clk_reset_action action); int clk_set_flags(struct clk *clk, unsigned long flags); + +unsigned long acpuclk_get_max_axi_rate(void); + #endif diff --git a/arch/arm/mach-msm/include/mach/debug_mm.h b/arch/arm/mach-msm/include/mach/debug_mm.h new file mode 100644 index 00000000..c46efa06 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/debug_mm.h @@ -0,0 +1,47 @@ +/* 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 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 __ARCH_ARM_MACH_MSM_DEBUG_MM_H_ +#define __ARCH_ARM_MACH_MSM_DEBUG_MM_H_ + +/* The below macro removes the directory path name and retains only the + * file name to avoid long path names in log messages that comes as + * part of __FILE__ to compiler. + */ +#define __MM_FILE__ strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/')+1) : \ + __FILE__ + +#define MM_DBG(fmt, args...) pr_debug("[%s] " fmt,\ + __func__, ##args) + +#define MM_INFO(fmt, args...) pr_info("[%s:%s] " fmt,\ + __MM_FILE__, __func__, ##args) + +#define MM_ERR(fmt, args...) pr_err("[%s:%s] " fmt,\ + __MM_FILE__, __func__, ##args) +#endif /* __ARCH_ARM_MACH_MSM_DEBUG_MM_H_ */ diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h index a6e7446d..6bd3de10 100644 --- a/arch/arm/mach-msm/include/mach/dma.h +++ b/arch/arm/mach-msm/include/mach/dma.h @@ -27,6 +27,7 @@ struct msm_dmov_errdata { struct msm_dmov_cmd { struct list_head list; unsigned int cmdptr; + unsigned int crci_mask; void (*complete_func)(struct msm_dmov_cmd *cmd, unsigned int result, struct msm_dmov_errdata *err); @@ -38,7 +39,7 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd); void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd); void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful); void msm_dmov_flush(unsigned int id); -int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr); +int msm_dmov_exec_cmd(unsigned id, unsigned int crci_mask, unsigned int cmdptr); diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h index e6bc7680..26d314af 100644 --- a/arch/arm/mach-msm/include/mach/irqs.h +++ b/arch/arm/mach-msm/include/mach/irqs.h @@ -311,6 +311,7 @@ #define INT_MDDI_CLIENT INT_MDC #define INT_NAND_WR_ER_DONE INT_EBI2_WR_ER_DONE #define INT_NAND_OP_DONE INT_EBI2_OP_DONE +#define INT_GRAPHICS INT_GRP_3D #define NR_SIRC_IRQS 0 diff --git a/arch/arm/mach-msm/include/mach/msm_fb.h b/arch/arm/mach-msm/include/mach/msm_fb.h index e49eb454..8d20e545 100644 --- a/arch/arm/mach-msm/include/mach/msm_fb.h +++ b/arch/arm/mach-msm/include/mach/msm_fb.h @@ -27,10 +27,12 @@ struct mddi_info; #define MSM_MDP_OUT_IF_FMT_RGB888 2 /* mdp override operations */ -#define MSM_MDP_PANEL_IGNORE_PIXEL_DATA (1 << 0) +#define MSM_MDP_PANEL_IGNORE_PIXEL_DATA (1 << 0) #define MSM_MDP_PANEL_FLIP_UD (1 << 1) #define MSM_MDP_PANEL_FLIP_LR (1 << 2) #define MSM_MDP4_MDDI_DMA_SWITCH (1 << 3) +#define MSM_MDP_DMA_PACK_ALIGN_LSB (1 << 4) +#define MSM_MDP_RGB_PANEL_SELF_REFRESH (1 << 5) /* mddi type */ #define MSM_MDP_MDDI_TYPE_I 0 @@ -190,6 +192,7 @@ struct msm_lcdc_panel_ops { int (*uninit)(struct msm_lcdc_panel_ops *); int (*blank)(struct msm_lcdc_panel_ops *); int (*unblank)(struct msm_lcdc_panel_ops *); + int (*shutdown)(struct msm_lcdc_panel_ops *); }; struct msm_lcdc_platform_data { @@ -211,6 +214,8 @@ struct msm_tvenc_platform_data { struct mdp_blit_req; struct fb_info; +struct mdp_overlay; +struct msmfb_overlay_data; struct mdp_device { struct device dev; void (*dma)(struct mdp_device *mdp, uint32_t addr, @@ -227,14 +232,17 @@ struct mdp_device { int (*overlay_unset)(struct mdp_device *mdp, struct fb_info *fb, int ndx); int (*overlay_play)(struct mdp_device *mdp, struct fb_info *fb, - struct msmfb_overlay_data *req, struct file *p_src_file); + struct msmfb_overlay_data *req, struct file **p_src_file); #endif void (*set_grp_disp)(struct mdp_device *mdp, uint32_t disp_id); void (*configure_dma)(struct mdp_device *mdp); int (*check_output_format)(struct mdp_device *mdp, int bpp); int (*set_output_format)(struct mdp_device *mdp, int bpp); + void (*set_panel_size)(struct mdp_device *mdp, int width, int height); unsigned color_format; unsigned overrides; + uint32_t width; /*panel width*/ + uint32_t height; /*panel height*/ }; struct class_interface; diff --git a/arch/arm/mach-msm/include/mach/msm_qdsp6_audio_1550.h b/arch/arm/mach-msm/include/mach/msm_qdsp6_audio_1550.h index 1f6df9a4..fcbfbfcd 100644 --- a/arch/arm/mach-msm/include/mach/msm_qdsp6_audio_1550.h +++ b/arch/arm/mach-msm/include/mach/msm_qdsp6_audio_1550.h @@ -19,12 +19,14 @@ #define AUDIO_FLAG_READ 0 #define AUDIO_FLAG_WRITE 1 +#define AUDIO_FLAG_INCALL_MIXED 2 struct audio_buffer { dma_addr_t phys; void *data; uint32_t size; uint32_t used; /* 1 = CPU is waiting for DSP to consume this buf */ + uint32_t actual_size; /* actual number of bytes read by DSP */ }; struct audio_client { @@ -79,8 +81,10 @@ struct audio_client *q6audio_open_mp3(uint32_t bufsz, uint32_t rate, struct audio_client *q6fm_open(void); -struct audio_client *q6audio_open_aac(uint32_t bufsz, uint32_t rate, - uint32_t flags, void *data, uint32_t acdb_id); +struct audio_client *q6audio_open_aac(uint32_t bufsz, uint32_t samplerate, + uint32_t channels, uint32_t bitrate, + uint32_t stream_format, uint32_t flags, + uint32_t acdb_id); struct audio_client *q6audio_open_qcelp(uint32_t bufsz, uint32_t rate, void *data, uint32_t acdb_id); @@ -102,7 +106,7 @@ int q6audio_set_tx_mute(int mute); int q6audio_reinit_acdb(char* filename); int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst); int q6audio_set_rx_volume(int level); -int q6audio_set_tx_volume(int level); +int q6audio_set_tx_volume(int mute); int q6audio_set_stream_volume(struct audio_client *ac, int vol); int q6audio_set_tx_dev_volume(int device_id, int level); int q6audio_get_tx_dev_volume(int device_id); diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h index 80c2b369..6d6c0de1 100644 --- a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h +++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h @@ -132,6 +132,8 @@ uint32_t msm_rpc_get_vers(struct msm_rpc_endpoint *ept); /* check if server version can handle client requested version */ int msm_rpc_is_compatible_version(uint32_t server_version, uint32_t client_version); +struct msm_rpc_endpoint *msm_rpc_connect_compatible(uint32_t prog, + uint32_t vers, unsigned flags); int msm_rpc_close(struct msm_rpc_endpoint *ept); int msm_rpc_write(struct msm_rpc_endpoint *ept, @@ -164,7 +166,7 @@ struct msm_rpc_xdr { void *in_buf; uint32_t in_size; uint32_t in_index; - struct mutex in_lock; + wait_queue_head_t in_buf_wait_q; void *out_buf; uint32_t out_size; @@ -174,6 +176,22 @@ struct msm_rpc_xdr { struct msm_rpc_endpoint *ept; }; +int xdr_send_int8(struct msm_rpc_xdr *xdr, const int8_t *value); +int xdr_send_uint8(struct msm_rpc_xdr *xdr, const uint8_t *value); +int xdr_send_int16(struct msm_rpc_xdr *xdr, const int16_t *value); +int xdr_send_uint16(struct msm_rpc_xdr *xdr, const uint16_t *value); +int xdr_send_int32(struct msm_rpc_xdr *xdr, const int32_t *value); +int xdr_send_uint32(struct msm_rpc_xdr *xdr, const uint32_t *value); +int xdr_send_bytes(struct msm_rpc_xdr *xdr, const void **data, uint32_t *size); + +int xdr_recv_int8(struct msm_rpc_xdr *xdr, int8_t *value); +int xdr_recv_uint8(struct msm_rpc_xdr *xdr, uint8_t *value); +int xdr_recv_int16(struct msm_rpc_xdr *xdr, int16_t *value); +int xdr_recv_uint16(struct msm_rpc_xdr *xdr, uint16_t *value); +int xdr_recv_int32(struct msm_rpc_xdr *xdr, int32_t *value); +int xdr_recv_uint32(struct msm_rpc_xdr *xdr, uint32_t *value); +int xdr_recv_bytes(struct msm_rpc_xdr *xdr, void **data, uint32_t *size); + struct msm_rpc_server { struct list_head list; diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h index d9418bab..4dde12dc 100644 --- a/arch/arm/mach-msm/include/mach/msm_smd.h +++ b/arch/arm/mach-msm/include/mach/msm_smd.h @@ -63,6 +63,8 @@ int smd_wait_until_writable(smd_channel_t *ch, int bytes); #endif int smd_wait_until_opened(smd_channel_t *ch, int timeout_us); +int smd_total_fifo_size(smd_channel_t *ch); + typedef enum { SMD_PORT_DS = 0, diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c index f3b17f22..ed19e679 100644 --- a/arch/arm/mach-msm/pm.c +++ b/arch/arm/mach-msm/pm.c @@ -142,13 +142,15 @@ int msm_irq_idle_sleep_allowed(void); int msm_irq_pending(void); int clks_allow_tcxo_locked_debug(void); extern int board_mfg_mode(void); -extern char * board_get_mfg_sleep_gpio_table(void); +extern unsigned long * board_get_mfg_sleep_gpio_table(void); extern void gpio_set_diag_gpio_table(unsigned long * dwMFG_gpio_table); extern void wait_rmt_final_call_back(int timeout); +#ifdef CONFIG_AXI_SCREEN_POLICY static int axi_rate; static int sleep_axi_rate; static struct clk *axi_clk; +#endif static uint32_t *msm_pm_reset_vector; static uint32_t msm_pm_max_sleep_time; @@ -654,8 +656,8 @@ static int msm_wakeup_after; /* default, no wakeup by alarm */ static int msm_power_wakeup_after(const char *val, struct kernel_param *kp) { int ret; - struct uart_port *port; - struct msm_port *msm_port; + //struct uart_port *port; + //struct msm_port *msm_port; ret = param_set_int(val, kp); printk(KERN_INFO "+msm_power_wakeup_after, ret=%d\r\n", ret); @@ -681,7 +683,7 @@ static void msm_pm_power_off(void) pmic_glb_power_down(); -#if CONFIG_MSM_RMT_STORAGE_SERVER +#ifdef CONFIG_MSM_RMT_STORAGE_SERVER printk(KERN_INFO "from %s\r\n", __func__); wait_rmt_final_call_back(10); printk(KERN_INFO "back %s\r\n", __func__); @@ -715,7 +717,7 @@ void msm_pm_flush_console(void) } #if defined(CONFIG_MACH_HTCLEO) -static void htcleo_save_reset_reason() +static void htcleo_save_reset_reason(void) { /* save restart_reason to be accesible in bootloader @ ramconsole - 0x1000*/ uint32_t *bootloader_reset_reason = ioremap(0x2FFB0000, PAGE_SIZE); @@ -728,7 +730,7 @@ static void htcleo_save_reset_reason() } #endif -static void msm_pm_restart(char str) +static void msm_pm_restart(char str, const char *cmd) { msm_pm_flush_console(); @@ -742,7 +744,7 @@ static void msm_pm_restart(char str) else msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); -#if CONFIG_MSM_RMT_STORAGE_SERVER +#ifdef CONFIG_MSM_RMT_STORAGE_SERVER printk(KERN_INFO "from %s\r\n", __func__); wait_rmt_final_call_back(10); printk(KERN_INFO "back %s\r\n", __func__); @@ -858,6 +860,7 @@ void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) EXPORT_SYMBOL(msm_pm_set_max_sleep_time); #ifdef CONFIG_EARLYSUSPEND +#ifdef CONFIG_AXI_SCREEN_POLICY /* axi 128 screen on, 61mhz screen off */ static void axi_early_suspend(struct early_suspend *handler) { @@ -877,7 +880,9 @@ static struct early_suspend axi_screen_suspend = { .resume = axi_late_resume, }; #endif +#endif +#ifdef CONFIG_AXI_SCREEN_POLICY static void __init msm_pm_axi_init(void) { #ifdef CONFIG_EARLYSUSPEND @@ -895,19 +900,18 @@ static void __init msm_pm_axi_init(void) axi_rate = 0; #endif } +#endif static int __init msm_pm_init(void) { pm_power_off = msm_pm_power_off; arm_pm_restart = msm_pm_restart; msm_pm_max_sleep_time = 0; -#if defined(CONFIG_ARCH_MSM_SCORPION) #ifdef CONFIG_AXI_SCREEN_POLICY msm_pm_axi_init(); #endif -#endif - register_reboot_notifier(&msm_reboot_notifier); + msm_pm_reset_vector = ioremap(0x0, PAGE_SIZE); #if defined(CONFIG_MACH_HTCLEO) diff --git a/arch/arm/mach-msm/pwrtest.c b/arch/arm/mach-msm/pwrtest.c index cc451be5..18c87196 100644 --- a/arch/arm/mach-msm/pwrtest.c +++ b/arch/arm/mach-msm/pwrtest.c @@ -14,6 +14,7 @@ * */ #include +#include #include "devices.h" #include "proc_comm.h" diff --git a/arch/arm/mach-msm/qdsp6_1550/aac_in.c b/arch/arm/mach-msm/qdsp6_1550/aac_in.c index 9b9f1c46..23455666 100644 --- a/arch/arm/mach-msm/qdsp6_1550/aac_in.c +++ b/arch/arm/mach-msm/qdsp6_1550/aac_in.c @@ -1,7 +1,7 @@ -/* arch/arm/mach-msm/qdsp6/aac_in.c - * +/* * Copyright (C) 2009 Google, Inc. * Copyright (C) 2009 HTC Corporation + * Copyright (c) 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 @@ -12,8 +12,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * -*/ + */ +#include #include #include #include @@ -21,197 +22,449 @@ #include #include #include -#include +#include +#include +#include + +#include +#include #include +#include -#define BUFSZ (4096) -#define DMASZ (BUFSZ * 2) +#define AAC_FC_BUFF_CNT 10 +#define AAC_READ_TIMEOUT 2000 +struct aac_fc_buff { + struct mutex lock; + int empty; + void *data; + int size; + int actual_size; +}; -#if 0 -#define TRACE(x...) pr_info("Q6: "x) -#else -#define TRACE(x...) do{}while(0) -#endif +struct aac_fc { + struct task_struct *task; + wait_queue_head_t fc_wq; + struct aac_fc_buff fc_buff[AAC_FC_BUFF_CNT]; + int buff_index; +}; +struct aac { + struct mutex lock; + struct msm_audio_aac_enc_config cfg; + struct msm_audio_stream_config str_cfg; + struct audio_client *audio_client; + struct msm_voicerec_mode voicerec_mode; + struct aac_fc *aac_fc; +}; -static DEFINE_MUTEX(aac_in_lock); -static int aac_in_opened = 0; -static struct aac_format *af; - -void audio_client_dump(struct audio_client *ac); - -static long aac_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0; - - switch (cmd) { - case AUDIO_SET_VOLUME: - break; - case AUDIO_GET_STATS: { - struct msm_audio_stats stats; - memset(&stats, 0, sizeof(stats)); - if (copy_to_user((void*) arg, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - case AUDIO_START: { - uint32_t acdb_id; - rc = 0; - - if (arg == 0) { - acdb_id = 0; - } else if (copy_from_user(&acdb_id, - (void*) arg, sizeof(acdb_id))) { - rc = -EFAULT; - break; - } - - mutex_lock(&aac_in_lock); - if (file->private_data) { - rc = -EBUSY; - } else { - file->private_data = q6audio_open_aac( - BUFSZ, 48000, AUDIO_FLAG_READ, af, acdb_id); - if (!file->private_data) - rc = -ENOMEM; - } - mutex_unlock(&aac_in_lock); - break; - } - case AUDIO_STOP: - break; - case AUDIO_FLUSH: - break; - case AUDIO_SET_CONFIG: { - struct msm_audio_config config; - if (copy_from_user(&config, (void*) arg, sizeof(config))) { - rc = -EFAULT; - break; - } - if (config.sample_rate != 48000) - pr_info("only 48KHz AAC encode supported\n"); - af->channel_config = config.channel_count; - break; - } - case AUDIO_GET_CONFIG: { - struct msm_audio_config config; - config.buffer_size = BUFSZ; - config.buffer_count = 2; - config.sample_rate = 48000; - config.channel_count = af->channel_config; - config.unused[0] = 0; - config.unused[1] = 0; - config.unused[2] = 0; - if (copy_to_user((void*) arg, &config, sizeof(config))) { - rc = -EFAULT; - } - break; - } - default: - rc = -EINVAL; - } - return rc; -} - -static int aac_in_open(struct inode *inode, struct file *file) -{ - int rc; - - pr_info("aac_in: open\n"); - mutex_lock(&aac_in_lock); - if (aac_in_opened) { - pr_err("aac_in: busy\n"); - rc = -EBUSY; - } else { - af = kzalloc(sizeof(*af), GFP_KERNEL); - memset(af, 0, sizeof(struct aac_format)); - af->sample_rate = 3; /* 48000 */ - af->channel_config = 1; - af->block_formats = AUDIO_AAC_FORMAT_ADTS; - af->audio_object_type = 2; /* CAD to ADSP format */ - af->bit_rate = 192000; - - aac_in_opened = 1; - rc = 0; - } - mutex_unlock(&aac_in_lock); - return rc; -} - -static ssize_t aac_in_read(struct file *file, char __user *buf, - size_t count, loff_t *pos) +static int q6_aac_flowcontrol(void *data) { struct audio_client *ac; struct audio_buffer *ab; - const char __user *start = buf; - int xfer, res = 0; + struct aac *aac = data; + int buff_index = 0; + int xfer = 0; + struct aac_fc *fc; + + + ac = aac->audio_client; + fc = aac->aac_fc; + if (!ac) { + pr_err("[%s:%s] audio_client is NULL\n", __MM_FILE__, __func__); + return 0; + } + + while (!kthread_should_stop()) { + ab = ac->buf + ac->cpu_buf; + if (ab->used) + wait_event(ac->wait, (ab->used == 0)); + pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d\n", __MM_FILE__, + __func__, ab->data, ac->cpu_buf); + xfer = ab->actual_size; + + mutex_lock(&(fc->fc_buff[buff_index].lock)); + if (!fc->fc_buff[buff_index].empty) { + pr_err("[%s:%s] flow control buffer[%d] not read!\n", + __MM_FILE__, __func__, buff_index); + } + + if (fc->fc_buff[buff_index].size < xfer) { + pr_err("[%s:%s] buffer %d too small\n", __MM_FILE__, + __func__, buff_index); + memcpy(fc->fc_buff[buff_index].data, + ab->data, fc->fc_buff[buff_index].size); + fc->fc_buff[buff_index].empty = 0; + fc->fc_buff[buff_index].actual_size = + fc->fc_buff[buff_index].size; + } else { + memcpy(fc->fc_buff[buff_index].data, ab->data, xfer); + fc->fc_buff[buff_index].empty = 0; + fc->fc_buff[buff_index].actual_size = xfer; + } + mutex_unlock(&(fc->fc_buff[buff_index].lock)); + /*wake up client, if any*/ + wake_up(&fc->fc_wq); + + buff_index++; + if (buff_index >= AAC_FC_BUFF_CNT) + buff_index = 0; + + ab->used = 1; + + q6audio_read(ac, ab); + ac->cpu_buf ^= 1; + } + + return 0; +} +static long q6_aac_in_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct aac *aac = file->private_data; + int rc = 0; + int i = 0; + struct aac_fc *fc; + int size = 0; + + mutex_lock(&aac->lock); + switch (cmd) { + case AUDIO_SET_VOLUME: + break; + case AUDIO_GET_STATS: + { + struct msm_audio_stats stats; + pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__); + memset(&stats, 0, sizeof(stats)); + if (copy_to_user((void *) arg, &stats, sizeof(stats))) + return -EFAULT; + return 0; + } + case AUDIO_START: + { + uint32_t acdb_id; + pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__); + if (arg == 0) { + acdb_id = 0; + } else { + if (copy_from_user(&acdb_id, (void *) arg, + sizeof(acdb_id))) { + rc = -EFAULT; + break; + } + } + if (aac->audio_client) { + rc = -EBUSY; + pr_err("[%s:%s] active session already existing\n", + __MM_FILE__, __func__); + break; + } else { + aac->audio_client = q6audio_open_aac( + aac->str_cfg.buffer_size, + aac->cfg.sample_rate, + aac->cfg.channels, + aac->cfg.bit_rate, + aac->cfg.stream_format, + aac->voicerec_mode.rec_mode, acdb_id); + + if (aac->audio_client < 0) { + pr_err("[%s:%s] aac open session failed\n", + __MM_FILE__, __func__); + rc = -ENOMEM; + break; + } + } + + /*allocate flow control buffers*/ + fc = aac->aac_fc; + size = ((aac->str_cfg.buffer_size < 1543) ? 1543 : + aac->str_cfg.buffer_size); + for (i = 0; i < AAC_FC_BUFF_CNT; ++i) { + mutex_init(&(fc->fc_buff[i].lock)); + fc->fc_buff[i].empty = 1; + fc->fc_buff[i].data = kmalloc(size, GFP_KERNEL); + if (fc->fc_buff[i].data == NULL) { + pr_err("[%s:%s] No memory for FC buffers\n", + __MM_FILE__, __func__); + rc = -ENOMEM; + goto fc_fail; + } + fc->fc_buff[i].size = size; + fc->fc_buff[i].actual_size = 0; + } + + /*create flow control thread*/ + fc->task = kthread_run(q6_aac_flowcontrol, + aac, "aac_flowcontrol"); + if (IS_ERR(fc->task)) { + rc = PTR_ERR(fc->task); + pr_err("[%s:%s] error creating flow control thread\n", + __MM_FILE__, __func__); + goto fc_fail; + } + break; +fc_fail: + /*free flow control buffers*/ + --i; + for (; i >= 0; i--) { + kfree(fc->fc_buff[i].data); + fc->fc_buff[i].data = NULL; + } + break; + } + case AUDIO_STOP: + pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__); + break; + case AUDIO_FLUSH: + break; + case AUDIO_SET_INCALL: { + pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__); + if (copy_from_user(&aac->voicerec_mode, + (void *)arg, sizeof(struct msm_voicerec_mode))) + rc = -EFAULT; + + if (aac->voicerec_mode.rec_mode != AUDIO_FLAG_READ + && aac->voicerec_mode.rec_mode != + AUDIO_FLAG_INCALL_MIXED) { + aac->voicerec_mode.rec_mode = AUDIO_FLAG_READ; + pr_err("[%s:%s] Invalid rec_mode\n", __MM_FILE__, + __func__); + rc = -EINVAL; + } + break; + } + case AUDIO_GET_STREAM_CONFIG: + if (copy_to_user((void *)arg, &aac->str_cfg, + sizeof(struct msm_audio_stream_config))) + rc = -EFAULT; + pr_debug("[%s:%s] GET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n", + __MM_FILE__, __func__, aac->str_cfg.buffer_size, + aac->str_cfg.buffer_count); + break; + case AUDIO_SET_STREAM_CONFIG: + if (copy_from_user(&aac->str_cfg, (void *)arg, + sizeof(struct msm_audio_stream_config))) { + rc = -EFAULT; + break; + } + pr_debug("[%s:%s] SET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n", + __MM_FILE__, __func__, aac->str_cfg.buffer_size, + aac->str_cfg.buffer_count); + if (aac->str_cfg.buffer_size < 1543) { + pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__, + __func__); + rc = -EINVAL; + break; + } + if (aac->str_cfg.buffer_count != 2) + pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__, + __func__); + + break; + case AUDIO_SET_AAC_ENC_CONFIG: + if (copy_from_user(&aac->cfg, (void *) arg, + sizeof(struct msm_audio_aac_enc_config))) { + rc = -EFAULT; + } + pr_debug("[%s:%s] SET_AAC_ENC_CONFIG: channels=%d, rate=%d\n", + __MM_FILE__, __func__, aac->cfg.channels, + aac->cfg.sample_rate); + if (aac->cfg.channels < 1 || aac->cfg.channels > 2) { + pr_err("[%s:%s]invalid number of channels\n", + __MM_FILE__, __func__); + rc = -EINVAL; + } + if (aac->cfg.sample_rate != 48000) { + pr_err("[%s:%s] only 48KHz is supported\n", + __MM_FILE__, __func__); + rc = -EINVAL; + } + if (aac->cfg.stream_format != AUDIO_AAC_FORMAT_RAW && + aac->cfg.stream_format != AUDIO_AAC_FORMAT_ADTS) { + pr_err("[%s:%s] unsupported AAC format\n", __MM_FILE__, + __func__); + rc = -EINVAL; + } + break; + case AUDIO_GET_AAC_ENC_CONFIG: + if (copy_to_user((void *) arg, &aac->cfg, + sizeof(struct msm_audio_aac_enc_config))) { + rc = -EFAULT; + } + pr_debug("[%s:%s] GET_AAC_ENC_CONFIG: channels=%d, rate=%d\n", + __MM_FILE__, __func__, aac->cfg.channels, + aac->cfg.sample_rate); + break; + default: + rc = -EINVAL; + } + + mutex_unlock(&aac->lock); + pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc); + return rc; +} + +static int q6_aac_in_open(struct inode *inode, struct file *file) +{ + + struct aac *aac; + struct aac_fc *fc; + int i; + pr_info("[%s:%s] open\n", __MM_FILE__, __func__); + aac = kmalloc(sizeof(struct aac), GFP_KERNEL); + if (aac == NULL) { + pr_err("[%s:%s] Could not allocate memory for aac driver\n", + __MM_FILE__, __func__); + return -ENOMEM; + } + + mutex_init(&aac->lock); + file->private_data = aac; + aac->audio_client = NULL; + aac->str_cfg.buffer_size = 1543; + aac->str_cfg.buffer_count = 2; + aac->cfg.channels = 1; + aac->cfg.bit_rate = 192000; + aac->cfg.stream_format = AUDIO_AAC_FORMAT_ADTS; + aac->cfg.sample_rate = 48000; + aac->voicerec_mode.rec_mode = AUDIO_FLAG_READ; + + aac->aac_fc = kmalloc(sizeof(struct aac_fc), GFP_KERNEL); + if (aac->aac_fc == NULL) { + pr_err("[%s:%s] Could not allocate memory for aac_fc\n", + __MM_FILE__, __func__); + kfree(aac); + return -ENOMEM; + } + fc = aac->aac_fc; + fc->task = NULL; + fc->buff_index = 0; + for (i = 0; i < AAC_FC_BUFF_CNT; ++i) { + fc->fc_buff[i].data = NULL; + fc->fc_buff[i].size = 0; + fc->fc_buff[i].actual_size = 0; + } + /*initialize wait queue head*/ + init_waitqueue_head(&fc->fc_wq); + return 0; +} + +static ssize_t q6_aac_in_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct audio_client *ac; + const char __user *start = buf; + struct aac *aac = file->private_data; + struct aac_fc *fc; + int xfer = 0; + int res = 0; + + pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count); + mutex_lock(&aac->lock); + ac = aac->audio_client; - mutex_lock(&aac_in_lock); - ac = file->private_data; if (!ac) { res = -ENODEV; goto fail; } - while (count > 0) { - ab = ac->buf + ac->cpu_buf; + fc = aac->aac_fc; - if (ab->used) - if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) { - audio_client_dump(ac); - pr_err("aac_read: timeout. dsp dead?\n"); - BUG(); - } + /*wait for buffer to full*/ + if (fc->fc_buff[fc->buff_index].empty != 0) { + res = wait_event_interruptible_timeout(fc->fc_wq, + (fc->fc_buff[fc->buff_index].empty == 0), + msecs_to_jiffies(AAC_READ_TIMEOUT)); - xfer = count; - if (xfer > ab->size) - xfer = ab->size; - - if (copy_to_user(buf, ab->data, xfer)) { - res = -EFAULT; + pr_debug("[%s:%s] buff_index = %d\n", __MM_FILE__, + __func__, fc->buff_index); + if (res == 0) { + pr_err("[%s:%s] Timeout!\n", __MM_FILE__, __func__); + res = -ETIMEDOUT; + goto fail; + } else if (res < 0) { + pr_err("[%s:%s] Returning on Interrupt\n", __MM_FILE__, + __func__); goto fail; } - - buf += xfer; - count -= xfer; - - ab->used = 1; - q6audio_read(ac, ab); - ac->cpu_buf ^= 1; } -fail: + /*lock the buffer*/ + mutex_lock(&(fc->fc_buff[fc->buff_index].lock)); + xfer = fc->fc_buff[fc->buff_index].actual_size; + + if (xfer > count) { + mutex_unlock(&(fc->fc_buff[fc->buff_index].lock)); + pr_err("[%s:%s] read failed! byte count too small\n", + __MM_FILE__, __func__); + res = -EINVAL; + goto fail; + } + + if (copy_to_user(buf, fc->fc_buff[fc->buff_index].data, xfer)) { + mutex_unlock(&(fc->fc_buff[fc->buff_index].lock)); + pr_err("[%s:%s] copy_to_user failed at index %d\n", + __MM_FILE__, __func__, fc->buff_index); + res = -EFAULT; + goto fail; + } + + buf += xfer; + + fc->fc_buff[fc->buff_index].empty = 1; + fc->fc_buff[fc->buff_index].actual_size = 0; + + mutex_unlock(&(fc->fc_buff[fc->buff_index].lock)); + ++(fc->buff_index); + if (fc->buff_index >= AAC_FC_BUFF_CNT) + fc->buff_index = 0; + res = buf - start; - mutex_unlock(&aac_in_lock); +fail: + mutex_unlock(&aac->lock); + return res; } -static int aac_in_release(struct inode *inode, struct file *file) +static int q6_aac_in_release(struct inode *inode, struct file *file) { int rc = 0; - pr_info("aac_in: release\n"); - mutex_lock(&aac_in_lock); - if (file->private_data) - rc = q6audio_close(file->private_data); - kfree(af); - aac_in_opened = 0; - mutex_unlock(&aac_in_lock); + struct aac *aac = file->private_data; + int i = 0; + struct aac_fc *fc; + + mutex_lock(&aac->lock); + fc = aac->aac_fc; + kthread_stop(fc->task); + fc->task = NULL; + + /*free flow control buffers*/ + for (i = 0; i < AAC_FC_BUFF_CNT; ++i) { + kfree(fc->fc_buff[i].data); + fc->fc_buff[i].data = NULL; + } + kfree(fc); + if (aac->audio_client) + rc = q6audio_close(aac->audio_client); + mutex_unlock(&aac->lock); + kfree(aac); + pr_info("[%s:%s] release\n", __MM_FILE__, __func__); return rc; } -static struct file_operations aac_in_fops = { - .owner = THIS_MODULE, - .open = aac_in_open, - .read = aac_in_read, - .release = aac_in_release, - .unlocked_ioctl = aac_in_ioctl, +static const struct file_operations q6_aac_in_fops = { + .owner = THIS_MODULE, + .open = q6_aac_in_open, + .read = q6_aac_in_read, + .release = q6_aac_in_release, + .unlocked_ioctl = q6_aac_in_ioctl, }; -struct miscdevice aac_in_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_aac_in", - .fops = &aac_in_fops, +struct miscdevice q6_aac_in_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "msm_aac_in", + .fops = &q6_aac_in_fops, }; -static int __init aac_in_init(void) { - return misc_register(&aac_in_misc); +static int __init q6_aac_in_init(void) +{ + return misc_register(&q6_aac_in_misc); } -device_initcall(aac_in_init); +device_initcall(q6_aac_in_init); diff --git a/arch/arm/mach-msm/qdsp6_1550/audio_ctl.c b/arch/arm/mach-msm/qdsp6_1550/audio_ctl.c index eaf5a942..e37296a4 100644 --- a/arch/arm/mach-msm/qdsp6_1550/audio_ctl.c +++ b/arch/arm/mach-msm/qdsp6_1550/audio_ctl.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -133,8 +133,7 @@ static int q6_open(struct inode *inode, struct file *file) return 0; } -static int q6_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long q6_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int rc; uint32_t n; @@ -147,28 +146,40 @@ static int q6_ioctl(struct inode *inode, struct file *file, case AUDIO_SWITCH_DEVICE: rc = copy_from_user(&id, (void *)arg, sizeof(id)); AUDIO_INFO("SWITCH DEVICE %d, acdb %d\n", id[0], id[1]); - if (!rc) + if (rc) { + pr_err("%s: bad user address\n", __func__); + rc = -EFAULT; + } else rc = q6audio_do_routing(id[0], id[1]); break; case AUDIO_SET_VOLUME: rc = copy_from_user(&n, (void *)arg, sizeof(n)); - if (!rc) + if (rc) { + pr_err("%s: bad user address\n", __func__); + rc = -EFAULT; + } else rc = q6audio_set_rx_volume(n); break; case AUDIO_SET_MUTE: rc = copy_from_user(&n, (void *)arg, sizeof(n)); - if (!rc) + if (rc) { + pr_err("%s: bad user address\n", __func__); + rc = -EFAULT; + } else rc = q6audio_set_tx_mute(n); break; case AUDIO_UPDATE_ACDB: rc = copy_from_user(&id, (void *)arg, sizeof(id)); - if (!rc) + if (rc) { + pr_err("%s: bad user address\n", __func__); + rc = -EFAULT; + } else rc = q6audio_update_acdb(id[0], id[1]); break; case AUDIO_START_VOICE: - if (arg == 0) { + if (arg == 0) id[0] = id[1] = 0; - } else if (copy_from_user(&id, (void*) arg, sizeof(id))) { + else if (copy_from_user(&id, (void*) arg, sizeof(id))) { pr_info("voice: copy acdb_id from user failed\n"); rc = -EFAULT; break; diff --git a/arch/arm/mach-msm/qdsp6_1550/dal.c b/arch/arm/mach-msm/qdsp6_1550/dal.c index d05ccfb0..f0374dfc 100644 --- a/arch/arm/mach-msm/qdsp6_1550/dal.c +++ b/arch/arm/mach-msm/qdsp6_1550/dal.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-msm/qdsp6_1550/mp3.c b/arch/arm/mach-msm/qdsp6_1550/mp3.c index c04fc5d1..6b402c27 100644 --- a/arch/arm/mach-msm/qdsp6_1550/mp3.c +++ b/arch/arm/mach-msm/qdsp6_1550/mp3.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-msm/qdsp6_1550/msm_q6vdec.c b/arch/arm/mach-msm/qdsp6_1550/msm_q6vdec.c index 69ce1804..2f525c8c 100644 --- a/arch/arm/mach-msm/qdsp6_1550/msm_q6vdec.c +++ b/arch/arm/mach-msm/qdsp6_1550/msm_q6vdec.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-msm/qdsp6_1550/msm_q6venc.c b/arch/arm/mach-msm/qdsp6_1550/msm_q6venc.c index f32f2825..269b0a41 100644 --- a/arch/arm/mach-msm/qdsp6_1550/msm_q6venc.c +++ b/arch/arm/mach-msm/qdsp6_1550/msm_q6venc.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -358,7 +359,7 @@ static int q6_encode(struct q6venc_dev *q6venc, struct encode_param *enc_param) { struct q6_encode_param *q6_param = &enc_param->q6_encode_param; struct file *file; - struct buf_info *buf; + struct buf_info *buf = 0; int i; int ret; int rlc_buf_index; diff --git a/arch/arm/mach-msm/qdsp6_1550/pcm_in.c b/arch/arm/mach-msm/qdsp6_1550/pcm_in.c index ad84f53f..36abf17b 100644 --- a/arch/arm/mach-msm/qdsp6_1550/pcm_in.c +++ b/arch/arm/mach-msm/qdsp6_1550/pcm_in.c @@ -14,6 +14,7 @@ * */ +#include #include #include #include diff --git a/arch/arm/mach-msm/qdsp6_1550/pcm_out.c b/arch/arm/mach-msm/qdsp6_1550/pcm_out.c index b3fbc8e6..eb8dae95 100644 --- a/arch/arm/mach-msm/qdsp6_1550/pcm_out.c +++ b/arch/arm/mach-msm/qdsp6_1550/pcm_out.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,12 @@ static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (cmd) { case AUDIO_SET_VOLUME: { int vol; + if (!pcm->ac) { + pr_err("%s: cannot set volume before AUDIO_START!\n", + __func__); + rc = -EINVAL; + break; + } if (copy_from_user(&vol, (void*) arg, sizeof(vol))) { rc = -EFAULT; break; diff --git a/arch/arm/mach-msm/qdsp6_1550/q6audio.c b/arch/arm/mach-msm/qdsp6_1550/q6audio.c index 8113ca19..0c8b2d30 100644 --- a/arch/arm/mach-msm/qdsp6_1550/q6audio.c +++ b/arch/arm/mach-msm/qdsp6_1550/q6audio.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -32,11 +33,12 @@ #include "dal_acdb.h" #include "dal_adie.h" #include -#include +#include #include #include #include +#include #include "q6audio_devices.h" #include "../dex_comm.h" @@ -172,7 +174,7 @@ static struct audio_client * audio_test(void); static void callback(void *data, int len, void *cookie); static int audio_init(struct audio_client *ac); static int audio_info(struct audio_client *ac); -static int q6audio_init_rx_volumes(); +static int q6audio_init_rx_volumes(void); static struct wake_lock wakelock; static struct wake_lock idlelock; @@ -215,6 +217,7 @@ static char acdb_file[64] = "default.acdb"; static uint32_t tx_acdb = 0; static uint32_t rx_acdb = 0; static int acdb_use_rpc = 0; +static int acdb_use_map = 0; ///////////////////////////////////////////////////////////////////////////////// // helper functions for device parameters @@ -699,10 +702,18 @@ static int audio_mp3_open(struct audio_client *ac, uint32_t bufsz, return ac->open_status; } -static int audio_aac_open(struct audio_client *ac, uint32_t bufsz, void *data) +/* + * ported code for audio_aac_open from Code Aurora in order to work + * with new aac code from Code Aurora + * by marc1706 + */ +static int audio_aac_open(struct audio_client *ac, uint32_t bufsz, + uint32_t sample_rate, uint32_t channels, + uint32_t bit_rate, uint32_t flags, + uint32_t stream_format) { int r; - struct aac_format *af = data; + int audio_object_type; struct adsp_open_command rpc; uint32_t *aac_type; int idx = 0; // sizeof(uint32_t); @@ -723,77 +734,33 @@ static int audio_aac_open(struct audio_client *ac, uint32_t bufsz, void *data) rpc.pblock = params_phys; aac_type = (uint32_t *)(fmt->data); - switch (af->block_formats) + switch (stream_format) { - case 0xffff: - if (ac->flags & AUDIO_FLAG_WRITE) - *aac_type = ADSP_AUDIO_AAC_ADTS; - else - *aac_type = ADSP_AUDIO_AAC_MPEG4_ADTS; - break; - case 0: - if (ac->flags & AUDIO_FLAG_WRITE) - *aac_type = ADSP_AUDIO_AAC_ADIF; - else - *aac_type = ADSP_AUDIO_AAC_RAW; - break; - case 1: - *aac_type = ADSP_AUDIO_AAC_RAW; - break; - case 2: - *aac_type = ADSP_AUDIO_AAC_LOAS; - break; - case 3: - *aac_type = ADSP_AUDIO_AAC_FRAMED_RAW; - break; - case 4: - *aac_type = ADSP_AUDIO_AAC_RAW; - break; + case AUDIO_AAC_FORMAT_ADTS: + /* AAC Encoder expect MPEG4_ADTS media type */ + *aac_type = ADSP_AUDIO_AAC_MPEG4_ADTS; + break; + case AUDIO_AAC_FORMAT_RAW: + /* for ADIF recording */ + *aac_type = ADSP_AUDIO_AAC_RAW; + break; default: - pr_err("unsupported AAC type %d\n", af->block_formats); + pr_err("unsupported AAC type %d\n", stream_format); mutex_unlock(&open_mem_lock); return -EINVAL; } + + /* AAC OBJECT LC */ + audio_object_type = 2; AUDIO_INFO("aac_open: type %x, obj %d, idx %d\n", - *aac_type, af->audio_object_type, idx); - fmt->data[idx++] = (u8)(((af->audio_object_type & 0x1F) << 3) | - ((af->sample_rate >> 1) & 0x7)); - fmt->data[idx] = (u8)(((af->sample_rate & 0x1) << 7) | - ((af->channel_config & 0x7) << 3)); + *aac_type, audio_object_type, idx); - switch (af->audio_object_type) { - case AAC_OBJECT_ER_LC: - case AAC_OBJECT_ER_LTP: - case AAC_OBJECT_ER_LD: - /* extension flag */ - fmt->data[idx++] |= 0x1; - fmt->data[idx] = (u8)( - ((af->aac_section_data_resilience_flag & 0x1) << 7) | - ((af->aac_scalefactor_data_resilience_flag & 0x1) << 6) | - ((af->aac_spectral_data_resilience_flag & 0x1) << 5) | - ((af->ep_config & 0x3) << 2)); - break; + fmt->data[idx++] = (u8)(((audio_object_type & 0x1F) << 3) | + ((sample_rate >> 1) & 0x7)); + fmt->data[idx] = (u8)(((sample_rate & 0x1) << 7) | + ((channels & 0x7) << 3)); - case AAC_OBJECT_ER_SCALABLE: - fmt->data[idx++] |= 0x1; - /* extension flag */ - fmt->data[idx++] = (u8)( - ((af->aac_section_data_resilience_flag & 0x1) << 4) | - ((af->aac_scalefactor_data_resilience_flag & 0x1) << 3) | - ((af->aac_spectral_data_resilience_flag & 0x1) << 2) | - ((af->ep_config >> 1) & 0x1)); - fmt->data[idx] = (u8)((af->ep_config & 0x1) << 7); - break; - - case AAC_OBJECT_BSAC: - fmt->data[++idx] = (u8)((af->ep_config & 0x3) << 6); - break; - - default: - pr_err("dbg unknown object type \n"); - break; - } // fmt->num_bytes = idx + 1; rpc.blocklen = idx + 1; @@ -801,8 +768,8 @@ static int audio_aac_open(struct audio_client *ac, uint32_t bufsz, void *data) fmt->data[0], fmt->data[1], fmt->data[2], fmt->data[3], fmt->data[4], fmt->data[5], fmt->data[6], fmt->data[7]); - rpc.config.aac.bit_rate = af->bit_rate; - if (ac->flags & AUDIO_FLAG_WRITE) + rpc.config.aac.bit_rate = bit_rate; + if (flags & AUDIO_FLAG_WRITE) { rpc.opcode = ADSP_AUDIO_OPCODE_OPEN_WRITE; rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK; @@ -813,25 +780,13 @@ static int audio_aac_open(struct audio_client *ac, uint32_t bufsz, void *data) rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD; } - if ((af->sbr_on_flag == 0) && (af->sbr_ps_on_flag == 0)) - { - rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE; - } - else if ((af->sbr_on_flag == 1) && (af->sbr_ps_on_flag == 0)) - { - rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_AAC_PLUS_MODE; - } - else if ((af->sbr_on_flag == 1) && (af->sbr_ps_on_flag == 1)) - { - rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_ENHANCED_AAC_PLUS_MODE; - } - else - { - pr_err("unsupported SBR flag\n"); - mutex_unlock(&open_mem_lock); - return -EINVAL; - } - rpc.buf_max_size = bufsz; /* XXX ??? */ + /* + * Always use ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE as encoder_mode + * from Code Aurora + * by marc1706 + */ + rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE; + rpc.buf_max_size = bufsz; TRACE("aac_open: opcode %x, stream_context 0x%x, " "mode %d, bytes %d, bbuffer size %d\n", @@ -1233,11 +1188,29 @@ static int acdb_init(char *filename) const struct firmware *fw; int n; + // return -ENODEV; + AUDIO_INFO("%s\n", __func__); +#ifdef CONFIG_MACH_HTCLEO + pr_info("acdb: trying htcleo.acdb\n"); + if(request_firmware(&fw, "htcleo.acdb", q6_control_device.this_device) < 0) { + pr_info("acdb: load 'htcleo.acdb' failed, trying 'default.acdb'\n"); + acdb_use_map = 0; + if (request_firmware(&fw, filename, q6_control_device.this_device) < 0) { + pr_err("acdb: load 'default.acdb' failed...\n"); + return -ENODEV; + } + } else { + pr_info("acdb: 'htcleo.acdb' found, using translation\n"); + acdb_use_map = 1; + } +#else pr_info("acdb: load '%s'\n", filename); + acd_use_map = 0; if (request_firmware(&fw, filename, q6_control_device.this_device) < 0) { pr_err("acdb: load 'default.acdb' failed...\n"); return -ENODEV; } +#endif db = (void*) fw->data; if (fw->size < sizeof(struct audio_config_database)) { @@ -1448,6 +1421,9 @@ static int acdb_get_config_table(uint32_t device_id, uint32_t sample_rate) int n; printk("table\n"); + // htcleo use custom table with wince values, it must be mapped + if(acdb_use_map) + device_id = map_cad_dev_to_virtual(device_id); db = acdb_data; for (n = 0; n < db->entry_count; n++) { @@ -2209,7 +2185,7 @@ int q6audio_set_rx_volume(int level) } EXPORT_SYMBOL_GPL(q6audio_set_rx_volume); -static int q6audio_init_rx_volumes() +static int q6audio_init_rx_volumes(void) { int vol; struct q6_device_info *di = q6_audio_devices; @@ -2628,14 +2604,19 @@ int q6audio_async(struct audio_client *ac) } - -struct audio_client *q6audio_open_aac(uint32_t bufsz, uint32_t rate, - uint32_t flags, void *data, uint32_t acdb_id) +/* + * ported code for q6audio_open_aac from Code Aurora + * by marc1706 + */ +struct audio_client *q6audio_open_aac(uint32_t bufsz, uint32_t samplerate, + uint32_t channels, uint32_t bitrate, + uint32_t stream_format, uint32_t flags, + uint32_t acdb_id) { struct audio_client *ac; AUDIO_INFO("%s\n", __func__); - TRACE("q6audio_open_aac flags=%d rate=%d\n", flags, rate); + TRACE("q6audio_open_aac flags=%d samplerate=%d, channels = %d\n", flags, samplerate, channels); if (q6audio_init()) return 0; @@ -2648,12 +2629,13 @@ struct audio_client *q6audio_open_aac(uint32_t bufsz, uint32_t rate, if (ac->flags & AUDIO_FLAG_WRITE) audio_rx_path_enable(1, acdb_id); else { - /* TODO: consider concourrency with voice call */ - tx_clk_freq = rate; + if (!audio_tx_path_refcount) + tx_clk_freq = 48000; audio_tx_path_enable(1, acdb_id); } - audio_aac_open(ac, bufsz, data); + audio_aac_open(ac, bufsz, samplerate, channels, bitrate, flags, + stream_format); audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START); if (!(ac->flags & AUDIO_FLAG_WRITE)) { diff --git a/arch/arm/mach-msm/qdsp6_1550/qcelp_in.c b/arch/arm/mach-msm/qdsp6_1550/qcelp_in.c index 50c74259..80bb903d 100644 --- a/arch/arm/mach-msm/qdsp6_1550/qcelp_in.c +++ b/arch/arm/mach-msm/qdsp6_1550/qcelp_in.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-msm/sirc.c b/arch/arm/mach-msm/sirc.c index 1b4ff1cb..50ee773f 100644 --- a/arch/arm/mach-msm/sirc.c +++ b/arch/arm/mach-msm/sirc.c @@ -188,6 +188,12 @@ static void sirc_irq_handler(unsigned int irq, struct irq_desc *desc) (sirc_reg_table[reg].cascade_irq != irq)) reg++; + if (reg == ARRAY_SIZE(sirc_reg_table)) { + printk(KERN_ERR "%s: incorrect irq %d called\n", + __func__, irq); + return; + } + status = readl(sirc_reg_table[reg].int_status); status &= SIRC_MASK; if (status == 0) diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index b8423029..23d67e8d 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c @@ -381,17 +381,18 @@ static void update_packet_state(struct smd_channel *ch) int r; /* can't do anything if we're in the middle of a packet */ - if (ch->current_packet != 0) - return; + while (ch->current_packet == 0) { + /* discard 0 length packets if any */ - /* don't bother unless we can get the full header */ - if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE) - return; + /* don't bother unless we can get the full header */ + if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE) + return; - r = ch_read(ch, hdr, SMD_HEADER_SIZE); - BUG_ON(r != SMD_HEADER_SIZE); + r = ch_read(ch, hdr, SMD_HEADER_SIZE); + BUG_ON(r != SMD_HEADER_SIZE); - ch->current_packet = hdr[0]; + ch->current_packet = hdr[0]; + } } /* provide a pointer and length to next free space in the fifo */ @@ -490,7 +491,7 @@ static void handle_smd_irq(struct list_head *list, void (*notify)(void)) #ifdef CONFIG_BUILD_CIQ /* put here to make sure we got the disable/enable index */ if (!msm_smd_ciq_info) - msm_smd_ciq_info = (*(volatile uint32_t *)(MSM_SHARED_RAM_BASE + 0xFC11C)); + msm_smd_ciq_info = (*(volatile uint32_t *)(MSM_SHARED_RAM_BASE + SMD_CIQ_BASE)); #endif spin_lock_irqsave(&smd_lock, flags); list_for_each_entry(ch, list, ch_list) { @@ -641,6 +642,8 @@ static int smd_stream_write(smd_channel_t *ch, const void *_data, int len) if (len < 0) return -EINVAL; + else if (len == 0) + return 0; while ((xfer = ch_write_buffer(ch, &ptr)) != 0) { if (!ch_is_open(ch)) @@ -911,6 +914,7 @@ int smd_close(smd_channel_t *ch) return 0; } +EXPORT_SYMBOL(smd_close); int smd_read(smd_channel_t *ch, void *data, int len) { @@ -922,6 +926,7 @@ int smd_write(smd_channel_t *ch, const void *data, int len) { return ch->write(ch, data, len); } +EXPORT_SYMBOL(smd_write); int smd_write_atomic(smd_channel_t *ch, const void *data, int len) { @@ -944,6 +949,7 @@ int smd_write_avail(smd_channel_t *ch) { return ch->write_avail(ch); } +EXPORT_SYMBOL_GPL(smd_write_avail); int smd_wait_until_readable(smd_channel_t *ch, int bytes) { @@ -981,6 +987,11 @@ int smd_cur_packet_size(smd_channel_t *ch) } EXPORT_SYMBOL(smd_cur_packet_size); +/* Returns SMD buffer size */ +int smd_total_fifo_size(smd_channel_t *ch) +{ + return ch->fifo_size; +} /* ------------------------------------------------------------------------- */ diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h index 71088e90..3dc0a203 100644 --- a/arch/arm/mach-msm/smd_private.h +++ b/arch/arm/mach-msm/smd_private.h @@ -89,6 +89,33 @@ struct smsm_interrupt_info { }; #endif +#if defined(CONFIG_MSM_N_WAY_SMSM) +enum { + SMSM_APPS_STATE, + SMSM_MODEM_STATE, + SMSM_Q6_STATE, + SMSM_APPS_DEM, + SMSM_MODEM_DEM, + SMSM_Q6_DEM, + SMSM_POWER_MASTER_DEM, + SMSM_TIME_MASTER_DEM, + SMSM_NUM_ENTRIES, +}; +#else +enum { + SMSM_APPS_STATE = 1, + SMSM_MODEM_STATE = 3, + SMSM_NUM_ENTRIES, +}; +#endif + +enum { + SMSM_APPS, + SMSM_MODEM, + SMSM_Q6, + SMSM_NUM_HOSTS, +}; + #define SZ_DIAG_ERR_MSG 0xC8 #define ID_DIAG_ERR_MSG SMEM_DIAG_ERR_MESSAGE #define ID_SMD_CHANNELS SMEM_SMD_BASE_ID diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c index 413139af..4c0476eb 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.c +++ b/arch/arm/mach-msm/smd_rpcrouter.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -105,7 +106,7 @@ static struct wake_lock rpcrouter_wake_lock; static int rpcrouter_need_len; static atomic_t next_xid = ATOMIC_INIT(1); -static uint8_t next_pacmarkid; +static atomic_t next_mid = ATOMIC_INIT(0); static void do_read_data(struct work_struct *work); static void do_create_pdevs(struct work_struct *work); @@ -114,12 +115,16 @@ static void do_create_rpcrouter_pdev(struct work_struct *work); static DECLARE_WORK(work_read_data, do_read_data); static DECLARE_WORK(work_create_pdevs, do_create_pdevs); static DECLARE_WORK(work_create_rpcrouter_pdev, do_create_rpcrouter_pdev); +static atomic_t rpcrouter_pdev_created = ATOMIC_INIT(0); #define RR_STATE_IDLE 0 #define RR_STATE_HEADER 1 #define RR_STATE_BODY 2 #define RR_STATE_ERROR 3 +#define RMT_STORAGE_APIPROG_BE32 0xa7000030 +#define RMT_STORAGE_SRV_APIPROG_BE32 0x9c000030 + struct rr_context { struct rr_packet *pkt; uint8_t *ptr; @@ -262,6 +267,7 @@ struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev) { struct msm_rpc_endpoint *ept; unsigned long flags; + int i; ept = kmalloc(sizeof(struct msm_rpc_endpoint), GFP_KERNEL); if (!ept) @@ -269,7 +275,9 @@ struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev) memset(ept, 0, sizeof(struct msm_rpc_endpoint)); /* mark no reply outstanding */ - ept->reply_pid = 0xffffffff; + ept->next_rroute = 0; + for (i = 0; i < MAX_REPLY_ROUTE; i++) + ept->rroute[i].pid = 0xffffffff; ept->cid = (uint32_t) ept; ept->pid = RPCROUTER_PID_LOCAL; @@ -530,7 +538,8 @@ static int process_control_msg(union rr_control_msg *msg, int len) static void do_create_rpcrouter_pdev(struct work_struct *work) { - platform_device_register(&rpcrouter_pdev); + if (atomic_cmpxchg(&rpcrouter_pdev_created, 0, 1) == 0) + platform_device_register(&rpcrouter_pdev); } static void do_create_pdevs(struct work_struct *work) @@ -652,11 +661,13 @@ static void do_read_data(struct work_struct *work) hdr.size -= sizeof(pm); - frag = rr_malloc(hdr.size + sizeof(*frag)); + frag = rr_malloc(sizeof(*frag)); frag->next = NULL; frag->length = hdr.size; - if (rr_read(frag->data, hdr.size)) + if (rr_read(frag->data, hdr.size)) { + kfree(frag); goto fail_io; + } ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid); if (!ept) { @@ -758,19 +769,77 @@ int msm_rpc_close(struct msm_rpc_endpoint *ept) } EXPORT_SYMBOL(msm_rpc_close); +static int msm_rpc_write_pkt(struct msm_rpc_endpoint *ept, + struct rr_remote_endpoint *r_ept, + struct rr_header *hdr, + uint32_t pacmark, + void *buffer, int count) +{ + DEFINE_WAIT(__wait); + unsigned long flags; + int needed; + + for (;;) { + prepare_to_wait(&r_ept->quota_wait, &__wait, + TASK_INTERRUPTIBLE); + spin_lock_irqsave(&r_ept->quota_lock, flags); + if (r_ept->tx_quota_cntr < RPCROUTER_DEFAULT_RX_QUOTA) + break; + if (signal_pending(current) && + (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) + break; + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + schedule(); + } + finish_wait(&r_ept->quota_wait, &__wait); + + if (signal_pending(current) && + (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) { + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + return -ERESTARTSYS; + } + r_ept->tx_quota_cntr++; + if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA) + hdr->confirm_rx = 1; + + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + + spin_lock_irqsave(&smd_lock, flags); + + needed = sizeof(*hdr) + hdr->size; + while (smd_write_avail(smd_channel) < needed) { + spin_unlock_irqrestore(&smd_lock, flags); + msleep(250); + spin_lock_irqsave(&smd_lock, flags); + } + + /* TODO: deal with full fifo */ + smd_write(smd_channel, hdr, sizeof(*hdr)); + smd_write(smd_channel, &pacmark, sizeof(pacmark)); + smd_write(smd_channel, buffer, count); + + spin_unlock_irqrestore(&smd_lock, flags); + + return 0; +} + int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) { struct rr_header hdr; uint32_t pacmark; + uint32_t mid; struct rpc_request_hdr *rq = buffer; struct rr_remote_endpoint *r_ept; - unsigned long flags; - int needed; - DEFINE_WAIT(__wait); + int ret; + int total; - /* TODO: fragmentation for large outbound packets */ - if (count > (RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t)) || !count) - return -EINVAL; + if (((rq->prog&0xFFFFFFF0) == RMT_STORAGE_APIPROG_BE32) || + ((rq->prog&0xFFFFFFF0) == RMT_STORAGE_SRV_APIPROG_BE32)) { + printk(KERN_DEBUG + "rpc_write: prog = %x , procedure = %d, type = %d, xid = %d\n" + , be32_to_cpu(rq->prog), be32_to_cpu(rq->procedure) + , be32_to_cpu(rq->type), be32_to_cpu(rq->xid)); + } /* snoop the RPC packet and enforce permissions */ @@ -818,23 +887,21 @@ int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) } else { /* RPC REPLY */ /* TODO: locking */ - if (ept->reply_pid == 0xffffffff) { - printk(KERN_ERR - "rr_write: rejecting unexpected reply\n"); - return -EINVAL; - } - if (ept->reply_xid != rq->xid) { - printk(KERN_ERR - "rr_write: rejecting packet w/ bad xid\n"); - return -EINVAL; + for (ret = 0; ret < MAX_REPLY_ROUTE; ret++) + if (ept->rroute[ret].xid == rq->xid) { + if (ept->rroute[ret].pid == 0xffffffff) + continue; + hdr.dst_pid = ept->rroute[ret].pid; + hdr.dst_cid = ept->rroute[ret].cid; + /* consume this reply */ + ept->rroute[ret].pid = 0xffffffff; + goto found_rroute; } - hdr.dst_pid = ept->reply_pid; - hdr.dst_cid = ept->reply_cid; - - /* consume this reply */ - ept->reply_pid = 0xffffffff; + printk(KERN_ERR "rr_write: rejecting packet w/ bad xid\n"); + return -EINVAL; +found_rroute: IO("REPLY on ept %p to xid=%d @ %d:%08x (%d bytes)\n", ept, be32_to_cpu(rq->xid), hdr.dst_pid, hdr.dst_cid, count); @@ -854,56 +921,36 @@ int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) hdr.version = RPCROUTER_VERSION; hdr.src_pid = ept->pid; hdr.src_cid = ept->cid; - hdr.confirm_rx = 0; - hdr.size = count + sizeof(uint32_t); - for (;;) { - prepare_to_wait(&r_ept->quota_wait, &__wait, - TASK_INTERRUPTIBLE); - spin_lock_irqsave(&r_ept->quota_lock, flags); - if (r_ept->tx_quota_cntr < RPCROUTER_DEFAULT_RX_QUOTA) - break; - if (signal_pending(current) && - (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) - break; - spin_unlock_irqrestore(&r_ept->quota_lock, flags); - schedule(); - } - finish_wait(&r_ept->quota_wait, &__wait); + total = count; - if (signal_pending(current) && - (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) { - spin_unlock_irqrestore(&r_ept->quota_lock, flags); - return -ERESTARTSYS; - } - r_ept->tx_quota_cntr++; - if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA) - hdr.confirm_rx = 1; + mid = atomic_add_return(1, &next_mid) & 0xFF; - /* bump pacmark while interrupts disabled to avoid race - * probably should be atomic op instead - */ - pacmark = PACMARK(count, ++next_pacmarkid, 0, 1); + while (count > 0) { + unsigned xfer; - spin_unlock_irqrestore(&r_ept->quota_lock, flags); + if (count > RPCROUTER_DATASIZE_MAX) + xfer = RPCROUTER_DATASIZE_MAX; + else + xfer = count; - spin_lock_irqsave(&smd_lock, flags); + hdr.confirm_rx = 0; + hdr.size = xfer + sizeof(uint32_t); - needed = sizeof(hdr) + hdr.size; - while (smd_write_avail(smd_channel) < needed) { - spin_unlock_irqrestore(&smd_lock, flags); - msleep(250); - spin_lock_irqsave(&smd_lock, flags); + /* total == count -> must be first packet + * xfer == count -> must be last packet + */ + pacmark = PACMARK(xfer, mid, (total == count), (xfer == count)); + + ret = msm_rpc_write_pkt(ept, r_ept, &hdr, pacmark, buffer, xfer); + if (ret < 0) + return ret; + + buffer += xfer; + count -= xfer; } - /* TODO: deal with full fifo */ - smd_write(smd_channel, &hdr, sizeof(hdr)); - smd_write(smd_channel, &pacmark, sizeof(pacmark)); - smd_write(smd_channel, buffer, count); - - spin_unlock_irqrestore(&smd_lock, flags); - - return count; + return total; } EXPORT_SYMBOL(msm_rpc_write); @@ -1104,20 +1151,30 @@ int __msm_rpc_read(struct msm_rpc_endpoint *ept, *frag_ret = pkt->first; rq = (void*) pkt->first->data; + + if (((rq->prog&0xFFFFFFF0) == RMT_STORAGE_APIPROG_BE32) || + ((rq->prog&0xFFFFFFF0) == RMT_STORAGE_SRV_APIPROG_BE32)) { + printk(KERN_DEBUG + "rpc_read: prog = %x , procedure = %d, type = %d, xid = %d\n" + , be32_to_cpu(rq->prog), be32_to_cpu(rq->procedure) + , be32_to_cpu(rq->type), be32_to_cpu(rq->xid)); + } + if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 0)) { IO("READ on ept %p is a CALL on %08x:%08x proc %d xid %d\n", ept, be32_to_cpu(rq->prog), be32_to_cpu(rq->vers), be32_to_cpu(rq->procedure), be32_to_cpu(rq->xid)); /* RPC CALL */ - if (ept->reply_pid != 0xffffffff) { + if (ept->rroute[ept->next_rroute].pid != 0xffffffff) { printk(KERN_WARNING "rr_read: lost previous reply xid...\n"); } /* TODO: locking? */ - ept->reply_pid = pkt->hdr.src_pid; - ept->reply_cid = pkt->hdr.src_cid; - ept->reply_xid = rq->xid; + ept->rroute[ept->next_rroute].pid = pkt->hdr.src_pid; + ept->rroute[ept->next_rroute].cid = pkt->hdr.src_cid; + ept->rroute[ept->next_rroute].xid = rq->xid; + ept->next_rroute = (ept->next_rroute + 1) & (MAX_REPLY_ROUTE - 1); } #if TRACE_RPC_MSG else if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 1)) diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h index aaf49f72..b86a01f1 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.h +++ b/arch/arm/mach-msm/smd_rpcrouter.h @@ -32,6 +32,7 @@ #define RPCROUTER_VERSION 1 #define RPCROUTER_PROCESSORS_MAX 4 #define RPCROUTER_MSGSIZE_MAX 512 +#define RPCROUTER_DATASIZE_MAX 500 #if defined(CONFIG_ARCH_MSM7X30) #define RPCROUTER_PEND_REPLIES_MAX 32 #endif @@ -50,6 +51,7 @@ #define RPCROUTER_CTRL_CMD_REMOVE_CLIENT 6 #define RPCROUTER_CTRL_CMD_RESUME_TX 7 #define RPCROUTER_CTRL_CMD_EXIT 8 +#define RPCROUTER_CTRL_CMD_PING 9 #define RPCROUTER_DEFAULT_RX_QUOTA 5 @@ -141,6 +143,15 @@ struct rr_remote_endpoint { struct list_head list; }; +struct msm_reply_route { + uint32_t xid; + uint32_t pid; + uint32_t cid; + uint32_t unused; +}; + +#define MAX_REPLY_ROUTE 4 + #if defined(CONFIG_ARCH_MSM7X30) struct msm_rpc_reply { struct list_head list; @@ -183,15 +194,12 @@ struct msm_rpc_endpoint { uint32_t dst_prog; /* be32 */ uint32_t dst_vers; /* be32 */ - /* reply remote address - * if reply_pid == 0xffffffff, none available - * RPC_REPLY writes may only go to the pid/cid/xid of the - * last RPC_CALL we received. + /* RPC_REPLY writes must be routed to the pid/cid of the + * RPC_CALL they are in reply to. Keep a cache of valid + * xid/pid/cid groups. pid 0xffffffff -> not valid. */ - uint32_t reply_pid; - uint32_t reply_cid; - uint32_t reply_xid; /* be32 */ - uint32_t next_pm; /* Pacmark sequence */ + unsigned next_rroute; + struct msm_reply_route rroute[MAX_REPLY_ROUTE]; #if defined(CONFIG_ARCH_MSM7X30) /* reply queue for inbound messages */ @@ -224,6 +232,7 @@ void msm_rpcrouter_exit_devices(void); #if defined(CONFIG_ARCH_MSM7X30) void get_requesting_client(struct msm_rpc_endpoint *ept, uint32_t xid, struct msm_rpc_client_info *clnt_info); +int msm_rpc_clear_netreset(struct msm_rpc_endpoint *ept); #endif extern dev_t msm_rpcrouter_devno; diff --git a/arch/arm/mach-msm/smd_rpcrouter_device.c b/arch/arm/mach-msm/smd_rpcrouter_device.c index bdea3d01..aa2cd45d 100644 --- a/arch/arm/mach-msm/smd_rpcrouter_device.c +++ b/arch/arm/mach-msm/smd_rpcrouter_device.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-msm/smd_rpcrouter_servers.c b/arch/arm/mach-msm/smd_rpcrouter_servers.c index 14dd2f1d..fe6e3c91 100644 --- a/arch/arm/mach-msm/smd_rpcrouter_servers.c +++ b/arch/arm/mach-msm/smd_rpcrouter_servers.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include diff --git a/arch/arm/mach-msm/smd_rpcrouter_xdr.c b/arch/arm/mach-msm/smd_rpcrouter_xdr.c index d6ba2c80..84ec14dc 100644 --- a/arch/arm/mach-msm/smd_rpcrouter_xdr.c +++ b/arch/arm/mach-msm/smd_rpcrouter_xdr.c @@ -78,6 +78,8 @@ #include #include #include +#include +#include #include @@ -421,7 +423,7 @@ int xdr_send_msg(struct msm_rpc_xdr *xdr) void xdr_init(struct msm_rpc_xdr *xdr) { mutex_init(&xdr->out_lock); - mutex_init(&xdr->in_lock); + init_waitqueue_head(&xdr->in_buf_wait_q); xdr->in_buf = NULL; xdr->in_size = 0; @@ -434,7 +436,7 @@ void xdr_init(struct msm_rpc_xdr *xdr) void xdr_init_input(struct msm_rpc_xdr *xdr, void *buf, uint32_t size) { - mutex_lock(&xdr->in_lock); + wait_event(xdr->in_buf_wait_q, !(xdr->in_buf)); xdr->in_buf = buf; xdr->in_size = size; @@ -455,7 +457,7 @@ void xdr_clean_input(struct msm_rpc_xdr *xdr) xdr->in_size = 0; xdr->in_index = 0; - mutex_unlock(&xdr->in_lock); + wake_up(&xdr->in_buf_wait_q); } void xdr_clean_output(struct msm_rpc_xdr *xdr) diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c index 639989d0..fb2e856f 100644 --- a/arch/arm/mach-msm/smd_tty.c +++ b/arch/arm/mach-msm/smd_tty.c @@ -30,6 +30,7 @@ #include "board-htcleo.h" #define MAX_SMD_TTYS 32 +#define MAX_TTY_BUF_SIZE 2048 static DEFINE_MUTEX(smd_tty_lock); @@ -75,6 +76,9 @@ static void smd_tty_work_func(struct work_struct *work) tty->low_latency = 0; tty_flip_buffer_push(tty); break; + if (avail > MAX_TTY_BUF_SIZE) + avail = MAX_TTY_BUF_SIZE; + } ptr = NULL; diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 75ba6c8e..f3120b33 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -169,18 +169,10 @@ static int msm_timer_set_next_event(unsigned long cycles, clock->last_set = now; clock->alarm_vtime = alarm + clock->offset; late = now - alarm; - if (late >= (int)(-clock->write_delay << clock->shift) && late < DGT_HZ*5) { - static int print_limit = 10; - if (print_limit > 0) { - print_limit--; - printk(KERN_NOTICE "msm_timer_set_next_event(%lu) " - "clock %s, alarm already expired, now %x, " - "alarm %x, late %d%s\n", - cycles, clock->clockevent.name, now, alarm, late, - print_limit ? "" : " stop printing"); - } + if (late >= (int)(-clock->write_delay << clock->shift) && + late < clock->freq*5) return -ETIME; - } + return 0; } @@ -582,9 +574,12 @@ static struct msm_clock msm_clocks[] = { #endif .freq = GPT_HZ, .flags = +#ifdef CONFIG_ARCH_MSM_ARM11 MSM_CLOCK_FLAGS_UNSTABLE_COUNT | MSM_CLOCK_FLAGS_ODD_MATCH_WRITE | - MSM_CLOCK_FLAGS_DELAYED_WRITE_POST, + MSM_CLOCK_FLAGS_DELAYED_WRITE_POST | +#endif + 0, .write_delay = 9, }, [MSM_CLOCK_DGT] = { diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c old mode 100644 new mode 100755 index 6c09d7c6..9e9fb56d --- a/drivers/misc/pmem.c +++ b/drivers/misc/pmem.c @@ -4386,4 +4386,4 @@ static void __exit pmem_exit(void) module_init(pmem_init); module_exit(pmem_exit); -#endif \ No newline at end of file +#endif diff --git a/drivers/mtd/devices/htcleo_nand.c b/drivers/mtd/devices/htcleo_nand.c index 2150bcc2..e4e347e0 100755 --- a/drivers/mtd/devices/htcleo_nand.c +++ b/drivers/mtd/devices/htcleo_nand.c @@ -33,12 +33,15 @@ #include #include #include +#include #include #include #include +unsigned crci_mask; + #if defined(CONFIG_ARCH_MSM7X30) #define MSM_NAND_BASE 0xA0200000 #else @@ -178,6 +181,11 @@ static void *msm_nand_get_dma_buffer(struct msm_nand_chip *chip, size_t size) do { free_index = __ffs(free_bitmask); current_need_mask = need_mask << free_index; + + if (size + free_index * MSM_NAND_DMA_BUFFER_SLOTS >= + MSM_NAND_DMA_BUFFER_SIZE) + return NULL; + if ((bitmask & current_need_mask) == 0) { old_bitmask = atomic_cmpxchg(&chip->dma_buffer_busy, @@ -262,7 +270,7 @@ uint32_t flash_read_id(struct msm_nand_chip *chip) dsb(); msm_dmov_exec_cmd( - chip->dma_channel, DMOV_CMD_PTR_LIST | + chip->dma_channel, crci_mask, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr))); dsb(); @@ -306,7 +314,7 @@ int flash_read_config(struct msm_nand_chip *chip) dsb(); msm_dmov_exec_cmd( - chip->dma_channel, DMOV_CMD_PTR_LIST | + chip->dma_channel, crci_mask, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr))); dsb(); @@ -346,7 +354,7 @@ unsigned flash_rd_reg(struct msm_nand_chip *chip, unsigned addr) dsb(); msm_dmov_exec_cmd( - chip->dma_channel, DMOV_CMD_PTR_LIST | + chip->dma_channel, crci_mask, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr))); dsb(); rv = dma_buffer->data; @@ -379,7 +387,7 @@ void flash_wr_reg(struct msm_nand_chip *chip, unsigned addr, unsigned val) dsb(); msm_dmov_exec_cmd( - chip->dma_channel, DMOV_CMD_PTR_LIST | + chip->dma_channel, crci_mask, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr))); dsb(); @@ -750,7 +758,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_o dsb(); msm_dmov_exec_cmd( - chip->dma_channel, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR( + chip->dma_channel, crci_mask, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR( msm_virt_to_dma(chip, &dma_buffer->cmdptr))); dsb(); @@ -893,13 +901,13 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_o dma_buffer->data.result[2].buffer_status, dma_buffer->data.result[3].flash_status, dma_buffer->data.result[3].buffer_status, + dma_buffer->data.result[4].flash_status, dma_buffer->data.result[4].buffer_status, - dma_buffer->data.result[4].buffer_status, - dma_buffer->data.result[5].buffer_status, + dma_buffer->data.result[5].flash_status, dma_buffer->data.result[5].buffer_status, + dma_buffer->data.result[6].flash_status, dma_buffer->data.result[6].buffer_status, - dma_buffer->data.result[6].buffer_status, - dma_buffer->data.result[7].buffer_status, + dma_buffer->data.result[7].flash_status, dma_buffer->data.result[7].buffer_status); } #endif @@ -1364,7 +1372,7 @@ msm_nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) dma_buffer->cmdptr = (msm_virt_to_dma(chip, dma_buffer->cmd) >> 3) | CMD_PTR_LP; dsb(); - msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr))); + msm_dmov_exec_cmd(chip->dma_channel, crci_mask, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr))); dsb(); /* if any of the writes failed (0x10), or there was a @@ -1576,7 +1584,7 @@ msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr) dsb(); msm_dmov_exec_cmd( - chip->dma_channel, DMOV_CMD_PTR_LIST | + chip->dma_channel, crci_mask, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr))); dsb(); @@ -1727,7 +1735,7 @@ msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs) dma_buffer->cmd) >> 3) | CMD_PTR_LP; dsb(); - msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST | + msm_dmov_exec_cmd(chip->dma_channel, crci_mask, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr))); dsb(); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 99bbd282..e1f2111c 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -697,9 +697,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; - u32 *buffer, *dst; - u32 __iomem *src; - int c, i, cnt = 0, err = 0; + u8 *buffer, *dst; + u8 __iomem *src; + int c, cnt = 0, err = 0; unsigned long total_size; if (!info || ! info->screen_base) @@ -730,7 +730,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (!buffer) return -ENOMEM; - src = (u32 __iomem *) (info->screen_base + p); + src = (u8 __iomem *) (info->screen_base + p); if (info->fbops->fb_sync) info->fbops->fb_sync(info); @@ -738,17 +738,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) while (count) { c = (count > PAGE_SIZE) ? PAGE_SIZE : count; dst = buffer; - for (i = c >> 2; i--; ) - *dst++ = fb_readl(src++); - if (c & 3) { - u8 *dst8 = (u8 *) dst; - u8 __iomem *src8 = (u8 __iomem *) src; - - for (i = c & 3; i--;) - *dst8++ = fb_readb(src8++); - - src = (u32 __iomem *) src8; - } + fb_memcpy_fromfb(dst, src, c); + dst += c; + src += c; if (copy_to_user(buf, buffer, c)) { err = -EFAULT; @@ -772,9 +764,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; - u32 *buffer, *src; - u32 __iomem *dst; - int c, i, cnt = 0, err = 0; + u8 *buffer, *src; + u8 __iomem *dst; + int c, cnt = 0, err = 0; unsigned long total_size; if (!info || !info->screen_base) @@ -811,7 +803,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) if (!buffer) return -ENOMEM; - dst = (u32 __iomem *) (info->screen_base + p); + dst = (u8 __iomem *) (info->screen_base + p); if (info->fbops->fb_sync) info->fbops->fb_sync(info); @@ -825,19 +817,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) break; } - for (i = c >> 2; i--; ) - fb_writel(*src++, dst++); - - if (c & 3) { - u8 *src8 = (u8 *) src; - u8 __iomem *dst8 = (u8 __iomem *) dst; - - for (i = c & 3; i--; ) - fb_writeb(*src8++, dst8++); - - dst = (u32 __iomem *) dst8; - } - + fb_memcpy_tofb(dst, src, c); + dst += c; + src += c; *ppos += c; buf += c; cnt += c; @@ -877,13 +859,13 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) if ((err = info->fbops->fb_pan_display(var, info))) return err; - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) - info->var.vmode |= FB_VMODE_YWRAP; - else - info->var.vmode &= ~FB_VMODE_YWRAP; - return 0; + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; } static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, @@ -1438,6 +1420,7 @@ static const struct file_operations fb_fops = { #ifdef CONFIG_FB_DEFERRED_IO .fsync = fb_deferred_io_fsync, #endif + .llseek = default_llseek, }; struct class *fb_class; @@ -1468,16 +1451,70 @@ static int fb_check_foreignness(struct fb_info *fi) return 0; } -static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) +static bool apertures_overlap(struct aperture *gen, struct aperture *hw) { /* is the generic aperture base the same as the HW one */ - if (gen->aperture_base == hw->aperture_base) + if (gen->base == hw->base) return true; /* is the generic aperture base inside the hw base->hw base+size */ - if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size) + if (gen->base > hw->base && gen->base < hw->base + hw->size) return true; return false; } + +static bool fb_do_apertures_overlap(struct apertures_struct *gena, + struct apertures_struct *hwa) +{ + int i, j; + if (!hwa || !gena) + return false; + + for (i = 0; i < hwa->count; ++i) { + struct aperture *h = &hwa->ranges[i]; + for (j = 0; j < gena->count; ++j) { + struct aperture *g = &gena->ranges[j]; + printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n", + (unsigned long long)g->base, + (unsigned long long)g->size, + (unsigned long long)h->base, + (unsigned long long)h->size); + if (apertures_overlap(g, h)) + return true; + } + } + + return false; +} + +#define VGA_FB_PHYS 0xA0000 +void remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) +{ + int i; + + /* check all firmware fbs and kick off if the base addr overlaps */ + for (i = 0 ; i < FB_MAX; i++) { + struct apertures_struct *gen_aper; + if (!registered_fb[i]) + continue; + + if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) + continue; + + gen_aper = registered_fb[i]->apertures; + if (fb_do_apertures_overlap(gen_aper, a) || + (primary && gen_aper && gen_aper->count && + gen_aper->ranges[0].base == VGA_FB_PHYS)) { + + printk(KERN_ERR "fb: conflicting fb hw usage " + "%s vs %s - removing generic driver\n", + name, registered_fb[i]->fix.id); + unregister_framebuffer(registered_fb[i]); + } + } +} +EXPORT_SYMBOL(remove_conflicting_framebuffers); + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig old mode 100644 new mode 100755 index 5f445724..46921131 --- a/drivers/video/msm/Kconfig +++ b/drivers/video/msm/Kconfig @@ -1,3 +1,26 @@ +config FB_MSM + tristate "MSM Framebuffer" + depends on FB && ARCH_MSM + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + default y + +config FB_MSM_MDP_PPP + bool "MSM MDP PPP" + depends on FB_MSM_LEGACY_MDP + default y + +config FB_MSM_LCDC + bool "Support for integrated LCD controller in MDP3/4" + depends on FB_MSM && (MSM_MDP31 || MSM_MDP302 || MSM_MDP40) + default y + +config FB_MSM_MDDI + bool "Support for MSM MDDI controllers" + depends on FB_MSM + default y + config FB_MSM tristate depends on FB && ARCH_MSM @@ -6,43 +29,35 @@ config FB_MSM select FB_CFB_IMAGEBLIT default y +config FB_MSM_LEGACY_MDP + bool "MSM Legacy MDP (qsd8k)" + depends on FB_MSM && (MSM_MDP30 || MSM_MDP31 || MSM_MDP302) + default y + +config FB_MSM_MDP_PPP + bool "MSM MDP PPP" + depends on FB_MSM_LEGACY_MDP + default y + config FB_MSM_LCDC - bool "Support for integrated LCD controller in qsd8x50 and MSM7x27" - depends on FB_MSM && (MSM_MDP31 || MSM_MDP302) + bool "Support for integrated LCD controller in qsd8x50 ,MSM7x27 and MSM7x30" + depends on FB_MSM && (MSM_MDP31 || MSM_MDP302 || MSM_MDP40) default y -config FB_MSM_TVOUT - bool "Support for TV-Out in qsd8x50" - depends on FB_MSM && MSM_MDP31 - default n - -config FB_MSM_OVERLAY - bool "Support for overlay in MSM7X30" - depends on FB_MSM && MSM_MDP40 +config FB_MSM_MDDI + bool "Support for MSM MDDI controllers" + depends on FB_MSM default y -config FB_MSM_DTV - depends on FB_MSM_OVERLAY - bool +config FB_MSM_MDDI_EPSON + bool "Support for Epson MDDI panels" + depends on FB_MSM_MDDI default n -config MSM_ROTATOR - tristate "MSM Offline Image Rotator Driver" - depends on ARCH_MSM7X30 && ANDROID_PMEM - default y - help - This driver provides support for the image rotator HW block in the - MSM 7x30 SoC. - -config MSM_ROTATOR_USE_IMEM - bool "Enable rotator driver to use iMem" - depends on MSM_ROTATOR - default y - help - This option enables the msm_rotator driver to use the move efficient - iMem. Some MSM platforms may not have iMem available for the rotator - block. Or some systems may want the iMem to be dedicated to a - different function. +config FB_MSM_MDDI_NOVTEC + bool "Support for Novtec MDDI panels" + depends on FB_MSM_MDDI + default n config MSM_HDMI bool "Support for HDMI in QCT platform" diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile old mode 100644 new mode 100755 index b7380f17..4146ff66 --- a/drivers/video/msm/Makefile +++ b/drivers/video/msm/Makefile @@ -14,6 +14,8 @@ obj-$(CONFIG_FB_MSM_OVERLAY) += mdp4_overlay.o obj-$(CONFIG_FB_MSM_OVERLAY) += mdp4_overlay_mddi.o obj-$(CONFIG_MSM_MDP40) += msm_rotator.o +obj-$(CONFIG_FB_MSM_LEGACY_MDP) += mdp_hw_legacy.o + obj-$(CONFIG_MSM_MDP22) += mdp_ppp22.o obj-$(CONFIG_MSM_MDP30) += mdp_ppp22.o obj-$(CONFIG_MSM_MDP302)+= mdp_ppp22.o @@ -25,11 +27,10 @@ obj-y += mddi.o # MDDI client/panel drivers # -obj-y += mddi_client_dummy.o +obj-y += mddi_client_simple.o +obj-y += mddi_client_toshiba.o obj-y += mddi_client_epson.o obj-y += mddi_client_novb9f6_5582.o # MDP LCD controller driver obj-$(CONFIG_FB_MSM_LCDC) += mdp_lcdc.o -obj-$(CONFIG_FB_MSM_TVOUT) += tvenc.o tvfb.o - diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c index 0c39572c..7dbf8a6c 100644 --- a/drivers/video/msm/mddi.c +++ b/drivers/video/msm/mddi.c @@ -31,7 +31,7 @@ #include #include #include - +#include #include #include "mddi_hw.h" @@ -106,7 +106,9 @@ struct mddi_info { }; static void mddi_init_rev_encap(struct mddi_info *mddi); +/* FIXME: Workaround for Novatek static void mddi_skew_calibration(struct mddi_info *mddi); +*/ #define mddi_readl(r) readl(mddi->base + (MDDI_##r)) #define mddi_writel(v, r) writel((v), mddi->base + (MDDI_##r)) @@ -204,10 +206,8 @@ static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask); static void mddi_handle_rev_data_avail(struct mddi_info *mddi) { - union mddi_rev *rev = mddi->rev_data; uint32_t rev_data_count; uint32_t rev_crc_err_count; - int i; struct reg_read_info *ri; size_t prev_offset; uint16_t length; @@ -242,6 +242,8 @@ static void mddi_handle_rev_data_avail(struct mddi_info *mddi) return; if (mddi_debug_flags & 1) { + int i; + union mddi_rev *rev = mddi->rev_data; printk(KERN_INFO "INT %x, STAT %x, CURR_REV_PTR %x\n", mddi_readl(INT), mddi_readl(STAT), mddi_readl(CURR_REV_PTR)); @@ -355,7 +357,7 @@ static irqreturn_t mddi_isr(int irq, void *data) static long mddi_wait_interrupt_timeout(struct mddi_info *mddi, uint32_t intmask, int timeout) { - unsigned long irq_flags; + unsigned long irq_flags=0; spin_lock_irqsave(&mddi->int_lock, irq_flags); mddi->got_int &= ~intmask; @@ -369,7 +371,7 @@ static long mddi_wait_interrupt_timeout(struct mddi_info *mddi, static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask) { if (mddi_wait_interrupt_timeout(mddi, intmask, HZ/10) == 0) - printk(KERN_INFO KERN_ERR "mddi_wait_interrupt %d, timeout " + printk(KERN_INFO "mddi_wait_interrupt %d, timeout " "waiting for %x, INT = %x, STAT = %x gotint = %x\n", current->pid, intmask, mddi_readl(INT), mddi_readl(STAT), mddi->got_int); @@ -399,7 +401,10 @@ static uint16_t mddi_init_registers(struct mddi_info *mddi) mddi_writel(0x0001, VERSION); mddi_writel(MDDI_HOST_BYTES_PER_SUBFRAME, BPS); mddi_writel(0x0003, SPM); /* subframes per media */ - mddi_writel(0x0005, TA1_LEN); + if (mddi->type == MSM_MDP_MDDI_TYPE_II) + mddi_writel(0x00C8, TA1_LEN); + else + mddi_writel(0x0005, TA1_LEN); mddi_writel(MDDI_HOST_TA2_LEN, TA2_LEN); mddi_writel(0x003C, DISP_WAKE); /* wakeup counter */ mddi_writel(MDDI_HOST_REV_RATE_DIV, REV_RATE_DIV); @@ -431,7 +436,7 @@ static uint16_t mddi_init_registers(struct mddi_info *mddi) mddi_writel(0x0050, DRIVE_LO); mddi_writel(0x00320000, PAD_IO_CTL); if (mddi->type == MSM_MDP_MDDI_TYPE_II) - mddi_writel(0x40884020, PAD_CAL); + mddi_writel(0x40880020, PAD_CAL); else mddi_writel(0x00220020, PAD_CAL); #else @@ -469,7 +474,7 @@ static void mddi_suspend(struct msm_mddi_client_data *cdata) mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); /* turn off the clock */ clk_disable(mddi->clk); -#if CONFIG_MSM_MDP40 +#ifdef CONFIG_MSM_MDP40 clk_disable(mdp_clk); #endif wake_unlock(&mddi->idle_lock); @@ -484,7 +489,7 @@ static void mddi_resume(struct msm_mddi_client_data *cdata) /* turn on the client */ if (mddi->power_client) mddi->power_client(&mddi->client_data, 1); -#if CONFIG_MSM_MDP40 +#ifdef CONFIG_MSM_MDP40 clk_enable(mdp_clk); #endif /* turn on the clock */ @@ -498,7 +503,8 @@ static void mddi_resume(struct msm_mddi_client_data *cdata) */ mddi_writel(mddi->int_enable, INTEN); mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD); - mddi_writel(MDDI_CMD_SEND_RTD, CMD); + if (mddi->type == MSM_MDP_MDDI_TYPE_I) + mddi_writel(MDDI_CMD_SEND_RTD, CMD); mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); mddi_set_auto_hibernate(&mddi->client_data, 1); wake_unlock(&mddi->idle_lock); @@ -689,7 +695,7 @@ uint32_t mddi_remote_read(struct msm_mddi_client_data *cdata, uint32_t reg) struct reg_read_info ri; unsigned s; int retry_count = 2; - unsigned long irq_flags; + unsigned long irq_flags=0; mutex_lock(&mddi->reg_read_lock); @@ -720,6 +726,9 @@ uint32_t mddi_remote_read(struct msm_mddi_client_data *cdata, uint32_t reg) do { init_completion(&ri.done); + if (mddi->type == MSM_MDP_MDDI_TYPE_II) + mddi_set_auto_hibernate(&mddi->client_data, 0); + mddi_writel(MDDI_CMD_SEND_RTD, CMD); mddi->reg_read = &ri; mddi_writel(mddi->reg_read_addr, PRI_PTR); @@ -732,10 +741,14 @@ uint32_t mddi_remote_read(struct msm_mddi_client_data *cdata, uint32_t reg) /* while((s & MDDI_STAT_PRI_LINK_LIST_DONE) == 0){ */ /* s = mddi_readl(STAT); */ /* } */ - - /* Enable Periodic Reverse Encapsulation. */ - mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 1, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); + if (mddi->type == MSM_MDP_MDDI_TYPE_II) { + mddi_writel(MDDI_CMD_SEND_REV_ENCAP, CMD); + mddi_wait_interrupt(mddi, MDDI_INT_REV_DATA_AVAIL); + } else { + /* Enable Periodic Reverse Encapsulation. */ + mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 1, CMD); + mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); + } if (wait_for_completion_timeout(&ri.done, HZ/10) == 0 && !ri.done.done) { printk(KERN_INFO "mddi_remote_read(%x) timeout " @@ -763,6 +776,8 @@ uint32_t mddi_remote_read(struct msm_mddi_client_data *cdata, uint32_t reg) "MDDI_CMD_SEND_RTD: int %x, stat %x, rtd val %x " "curr_rev_ptr %x\n", mddi_readl(INT), mddi_readl(STAT), mddi_readl(RTD_VAL), mddi_readl(CURR_REV_PTR)); + if (mddi->type == MSM_MDP_MDDI_TYPE_II) + mddi_set_auto_hibernate(&mddi->client_data, 1); } while (retry_count-- > 0); /* Disable Periodic Reverse Encapsulation. */ mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 0, CMD); @@ -830,7 +845,7 @@ static int __init mddi_rev_data_setup(struct mddi_info *mddi) sizeof(*mddi->reg_write_data); return 0; } - +/* FIXME: Workaround for Novatek static void mddi_skew_calibration(struct mddi_info *mddi) { struct msm_mddi_platform_data *pdata = mddi->client_pdev.dev.platform_data; @@ -842,6 +857,7 @@ static void mddi_skew_calibration(struct mddi_info *mddi) clk_set_rate( mddi->clk, pdata->clk_rate); mdelay(1); } +*/ static int __init mddi_probe(struct platform_device *pdev) { @@ -871,7 +887,7 @@ static int __init mddi_probe(struct platform_device *pdev) printk(KERN_INFO "mddi: init() base=0x%p irq=%d\n", mddi->base, mddi->irq); mddi->power_client = pdata->power_client; - if (pdata->type != NULL) + if ((pdata->type != NULL) && (pdata->type != MSM_MDP_MDDI_TYPE_I)) mddi->type = pdata->type; mutex_init(&mddi->reg_write_lock); diff --git a/drivers/video/msm/mddi_client_dummy.c b/drivers/video/msm/mddi_client_dummy.c deleted file mode 100644 index ebbae878..00000000 --- a/drivers/video/msm/mddi_client_dummy.c +++ /dev/null @@ -1,97 +0,0 @@ -/* drivers/video/msm_fb/mddi_client_dummy.c - * - * Support for "dummy" mddi client devices which require no - * special initialization code. - * - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include - -#include - -struct panel_info { - struct platform_device pdev; - struct msm_panel_data panel_data; -}; - -static int mddi_dummy_suspend(struct msm_panel_data *panel_data) -{ - return 0; -} - -static int mddi_dummy_resume(struct msm_panel_data *panel_data) -{ - return 0; -} - -static int mddi_dummy_blank(struct msm_panel_data *panel_data) -{ - return 0; -} - -static int mddi_dummy_unblank(struct msm_panel_data *panel_data) -{ - return 0; -} - -static int mddi_dummy_probe(struct platform_device *pdev) -{ - struct msm_mddi_client_data *client_data = pdev->dev.platform_data; - struct panel_info *panel = - kzalloc(sizeof(struct panel_info), GFP_KERNEL); - int ret; - if (!panel) - return -ENOMEM; - platform_set_drvdata(pdev, panel); - panel->panel_data.suspend = mddi_dummy_suspend; - panel->panel_data.resume = mddi_dummy_resume; - panel->panel_data.blank = mddi_dummy_blank; - panel->panel_data.unblank = mddi_dummy_unblank; - panel->panel_data.caps = MSMFB_CAP_PARTIAL_UPDATES; - panel->pdev.name = "msm_panel"; - panel->pdev.id = pdev->id; - platform_device_add_resources(&panel->pdev, - client_data->fb_resource, 1); - panel->panel_data.fb_data = client_data->private_client_data; - panel->pdev.dev.platform_data = &panel->panel_data; - ret = platform_device_register(&panel->pdev); - if (ret) { - kfree(panel); - return ret; - } - return 0; -} - -static int mddi_dummy_remove(struct platform_device *pdev) -{ - struct panel_info *panel = platform_get_drvdata(pdev); - kfree(panel); - return 0; -} - -static struct platform_driver mddi_client_dummy = { - .probe = mddi_dummy_probe, - .remove = mddi_dummy_remove, - .driver = { .name = "mddi_c_dummy" }, -}; - -static int __init mddi_client_dummy_init(void) -{ - platform_driver_register(&mddi_client_dummy); - return 0; -} - -module_init(mddi_client_dummy_init); - diff --git a/drivers/video/msm/mddi_client_epson.c b/drivers/video/msm/mddi_client_epson.c index 577b09c8..d5ea5e3e 100644 --- a/drivers/video/msm/mddi_client_epson.c +++ b/drivers/video/msm/mddi_client_epson.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include static DECLARE_WAIT_QUEUE_HEAD(epson_vsync_wait); diff --git a/drivers/video/msm/mddi_client_novb9f6_5582.c b/drivers/video/msm/mddi_client_novb9f6_5582.c index defd92de..1d8030b9 100644 --- a/drivers/video/msm/mddi_client_novb9f6_5582.c +++ b/drivers/video/msm/mddi_client_novb9f6_5582.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include static DECLARE_WAIT_QUEUE_HEAD(novtec_vsync_wait); @@ -145,7 +147,6 @@ static irqreturn_t novtec_vsync_interrupt(int irq, void *data) panel->novtec_got_int = 1; if (panel->novtec_callback) { - mdelay(3); panel->novtec_callback->func(panel->novtec_callback); panel->novtec_callback = 0; } diff --git a/drivers/video/msm/mddi_client_nt35399.c b/drivers/video/msm/mddi_client_nt35399.c index c9e93494..f239f4a2 100644 --- a/drivers/video/msm/mddi_client_nt35399.c +++ b/drivers/video/msm/mddi_client_nt35399.c @@ -21,6 +21,7 @@ #include #include #include +#include #include static DECLARE_WAIT_QUEUE_HEAD(nt35399_vsync_wait); diff --git a/drivers/video/msm/mddi_client_simple.c b/drivers/video/msm/mddi_client_simple.c new file mode 100644 index 00000000..b27a809d --- /dev/null +++ b/drivers/video/msm/mddi_client_simple.c @@ -0,0 +1,236 @@ +/* drivers/video/msm_fb/mddi_client_simple.c + * + * Support for simple mddi client devices which require no special + * initialization code except for what may be provided in the board file. + * If the clients do not provide board specific code, this driver's + * panel operations are no-ops. + * + * Copyright (C) 2007-2010, 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 +#include +#include +#include +#include +#include +#include + +#include + +struct panel_info { + struct platform_device pdev; + struct msm_mddi_client_data *client_data; + struct msm_panel_data panel_data; + struct msmfb_callback *fb_callback; + wait_queue_head_t vsync_wait; + int got_vsync; + int irq; +}; + +#define to_panel_info(pd) container_of((pd), struct panel_info, panel_data) + +static void mddi_simple_request_vsync(struct msm_panel_data *panel_data, + struct msmfb_callback *callback) +{ + struct panel_info *panel = to_panel_info(panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + + panel->fb_callback = callback; + if (panel->got_vsync) { + panel->got_vsync = 0; + client_data->activate_link(client_data); /* clears interrupt */ + } +} + +static void mddi_simple_wait_vsync(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = to_panel_info(panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + int ret; + + if (panel->got_vsync) { + panel->got_vsync = 0; + client_data->activate_link(client_data); /* clears interrupt */ + } + + ret = wait_event_timeout(panel->vsync_wait, panel->got_vsync, HZ/2); + if (!ret && !panel->got_vsync) + pr_err("mddi_client_simple: timeout waiting for vsync\n"); + + panel->got_vsync = 0; + /* interrupt clears when screen dma starts */ +} + + +static int mddi_simple_suspend(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = to_panel_info(panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + int ret; + + if (!bridge_data->uninit) + return 0; + + ret = bridge_data->uninit(bridge_data, client_data); + if (ret) { + pr_info("%s: non zero return from uninit\n", __func__); + return ret; + } + client_data->suspend(client_data); + return 0; +} + +static int mddi_simple_resume(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = to_panel_info(panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + + if (!bridge_data->init) + return 0; + + client_data->resume(client_data); + return bridge_data->init(bridge_data, client_data); +} + +static int mddi_simple_blank(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = to_panel_info(panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + + if (!bridge_data->blank) + return 0; + return bridge_data->blank(bridge_data, client_data); +} + +static int mddi_simple_unblank(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = to_panel_info(panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + + if (!bridge_data->unblank) + return 0; + return bridge_data->unblank(bridge_data, client_data); +} + +static irqreturn_t handle_vsync_irq(int irq, void *data) +{ + struct panel_info *panel = data; + + panel->got_vsync = 1; + if (panel->fb_callback) { + panel->fb_callback->func(panel->fb_callback); + panel->fb_callback = NULL; + } + + wake_up(&panel->vsync_wait); + return IRQ_HANDLED; +} + +static int mddi_simple_probe(struct platform_device *pdev) +{ + struct msm_mddi_client_data *client_data = pdev->dev.platform_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + struct panel_info *panel; + int ret; + + pr_debug("%s()\n", __func__); + + panel = kzalloc(sizeof(struct panel_info), GFP_KERNEL); + if (!panel) + return -ENOMEM; + + platform_set_drvdata(pdev, panel); + + init_waitqueue_head(&panel->vsync_wait); + + panel->irq = platform_get_irq_byname(pdev, "vsync"); + if (panel->irq >= 0) { + ret = request_irq(panel->irq, handle_vsync_irq, + IRQF_TRIGGER_RISING, "mddi_c_simple_vsync", + panel); + if (ret) { + pr_err("%s: request vsync irq %d failed (%d)\n", + __func__, panel->irq, ret); + goto err_req_irq; + } + + panel->panel_data.wait_vsync = mddi_simple_wait_vsync; + panel->panel_data.request_vsync = mddi_simple_request_vsync; + } + + panel->client_data = client_data; + panel->panel_data.suspend = mddi_simple_suspend; + panel->panel_data.resume = mddi_simple_resume; + panel->panel_data.blank = mddi_simple_blank; + panel->panel_data.unblank = mddi_simple_unblank; + panel->panel_data.caps = bridge_data->caps; + panel->panel_data.fb_data = &bridge_data->fb_data; + + panel->pdev.name = "msm_panel"; + panel->pdev.id = pdev->id; + platform_device_add_resources(&panel->pdev, + client_data->fb_resource, 1); + panel->pdev.dev.platform_data = &panel->panel_data; + + if (bridge_data->init) + bridge_data->init(bridge_data, client_data); + + ret = platform_device_register(&panel->pdev); + if (ret) { + pr_err("%s: Can't register platform device\n", __func__); + goto err_plat_dev_reg; + } + + return 0; + +err_plat_dev_reg: + if (panel->irq >= 0) + free_irq(panel->irq, panel); +err_req_irq: + platform_set_drvdata(pdev, NULL); + kfree(panel); + return ret; +} + +static int mddi_simple_remove(struct platform_device *pdev) +{ + struct panel_info *panel = platform_get_drvdata(pdev); + kfree(panel); + return 0; +} + +static struct platform_driver mddi_client_simple = { + .probe = mddi_simple_probe, + .remove = mddi_simple_remove, + .driver = { + .owner = THIS_MODULE, + .name = "mddi_c_simple" + }, +}; + +static int __init mddi_client_simple_init(void) +{ + platform_driver_register(&mddi_client_simple); + return 0; +} + +module_init(mddi_client_simple_init); diff --git a/drivers/video/msm/mddi_client_toshiba.c b/drivers/video/msm/mddi_client_toshiba.c index 71048e78..f9bc932a 100644 --- a/drivers/video/msm/mddi_client_toshiba.c +++ b/drivers/video/msm/mddi_client_toshiba.c @@ -21,6 +21,7 @@ #include #include #include +#include #include diff --git a/drivers/video/msm/mddi_hw.h b/drivers/video/msm/mddi_hw.h index 16e80126..2e1dd206 100644 --- a/drivers/video/msm/mddi_hw.h +++ b/drivers/video/msm/mddi_hw.h @@ -53,8 +53,9 @@ #define MDDI_MF_CNT 0x0084 #define MDDI_CURR_REV_PTR 0x0088 #define MDDI_CORE_VER 0x008c -#define MDDI_PAD_IO_CTL 0x00a0 -#define MDDI_PAD_CAL 0x00a4 +#define MDDI_SF_LEN_CTL_REG 0x0094 +#define MDDI_PAD_IO_CTL 0x00a0 +#define MDDI_PAD_CAL 0x00a4 #define MDDI_INT_PRI_PTR_READ 0x0001 #define MDDI_INT_SEC_PTR_READ 0x0002 @@ -131,8 +132,10 @@ #define MDDI_HOST_TA2_LEN 0x000c #endif -#if defined (CONFIG_ARCH_QSD8X50) || defined (CONFIG_ARCH_MSM7X30) +#if defined (CONFIG_ARCH_QSD8X50) #define MDDI_HOST_REV_RATE_DIV 0x0004 +#elif defined (CONFIG_ARCH_MSM7X30) +#define MDDI_HOST_REV_RATE_DIV 0x0010 #else #define MDDI_HOST_REV_RATE_DIV 0x0002 #endif diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index 5e21cf86..0d17f68b 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -21,10 +21,10 @@ #include #include #include +#include #include #include #include -#include #include #include @@ -36,10 +36,16 @@ struct class *mdp_class; +#ifdef CONFIG_MSM_HDMI +/* Used to report LCDC underflows */ +void reportUnderflow(void); +#endif + #define MDP_CMD_DEBUG_ACCESS_BASE (0x10000) static DECLARE_WAIT_QUEUE_HEAD(mdp_ppp_waitqueue); static unsigned int mdp_irq_mask; +static unsigned int mdp_dma_timer_enable = 0; struct clk *mdp_clk_to_disable_later = 0; static struct mdp_blit_req *timeout_req; #ifdef CONFIG_FB_MSM_OVERLAY @@ -53,7 +59,19 @@ extern void mdp4_mddi_overlay(void *priv, uint32_t addr, uint32_t stride, uint32_t y); #include "mdp4.h" #endif -DEFINE_MUTEX(mdp_mutex); + + +static void mdp_do_standby_timer(unsigned long data) +{ + struct mdp_info *mdp = (struct mdp_info *) data; + if (!mdp_irq_mask) { + clk_set_rate(mdp->ebi1_clk, 0); + mdp->state |= MDP_STATE_STANDBY; + } else { + mod_timer(&mdp->standby_timer, + jiffies + msecs_to_jiffies(200)); + } +} static int locked_enable_mdp_irq(struct mdp_info *mdp, uint32_t mask) { @@ -69,7 +87,17 @@ static int locked_enable_mdp_irq(struct mdp_info *mdp, uint32_t mask) if (!mdp_irq_mask) { clk_enable(mdp->clk); enable_irq(mdp->irq); - clk_set_rate(mdp->ebi1_clk, 128000000); + if (mdp->state & MDP_STATE_STANDBY) { +#ifdef CONFIG_MSM_MDP40 + clk_set_rate(mdp->ebi1_clk, 153000000); +#else + clk_set_rate(mdp->ebi1_clk, 128000000); +#endif + mdp->state &= ~MDP_STATE_STANDBY; + } else { + del_timer_sync(&mdp->standby_timer); + barrier(); + } } /* clear out any previous irqs for the requested mask*/ @@ -84,7 +112,7 @@ static int locked_enable_mdp_irq(struct mdp_info *mdp, uint32_t mask) static int enable_mdp_irq(struct mdp_info *mdp, uint32_t mask) { - unsigned long flags; + unsigned long flags=0; int ret; spin_lock_irqsave(&mdp->lock, flags); @@ -111,14 +139,16 @@ static int locked_disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) disable_irq_nosync(mdp->irq); if (mdp->clk) clk_disable(mdp->clk); - clk_set_rate(mdp->ebi1_clk, 0); + if (!(mdp->state & MDP_STATE_STANDBY)) + mod_timer(&mdp->standby_timer, + jiffies + msecs_to_jiffies(200)); } return 0; } int disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) { - unsigned long irq_flags; + unsigned long irq_flags=0; int ret; spin_lock_irqsave(&mdp->lock, irq_flags); @@ -130,7 +160,7 @@ int disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) static irqreturn_t mdp_isr(int irq, void *data) { uint32_t status; - unsigned long irq_flags; + unsigned long irq_flags=0; struct mdp_info *mdp = data; int i; @@ -139,13 +169,22 @@ static irqreturn_t mdp_isr(int irq, void *data) status = mdp_readl(mdp, MDP_INTR_STATUS); mdp_writel(mdp, status, MDP_INTR_CLEAR); - -#if defined(CONFIG_MACH_HTCLEO) - status &= ~0x10000; // Cotulla -#endif - // pr_info("%s: status=%08x (irq_mask=%08x)\n", __func__, status, // mdp_irq_mask); + + if (mdp_dma_timer_enable) { + del_timer_sync(&mdp->dma_timer); + mdp_dma_timer_enable = 0; + } + +#ifdef CONFIG_MSM_HDMI + if (status & MDP_LCDC_UNDERFLOW) + { + pr_err("%s: LCDC Underflow\n", __func__); + reportUnderflow(); + } +#endif + status &= ~0x10000; // Cotulla status &= mdp_irq_mask; #ifdef CONFIG_MSM_MDP40 if (mdp->mdp_dev.overrides & MSM_MDP4_MDDI_DMA_SWITCH) { @@ -168,9 +207,9 @@ static irqreturn_t mdp_isr(int irq, void *data) } } - if (status & DL0_ROI_DONE) - wake_up(&mdp_ppp_waitqueue); - +#ifndef CONFIG_MSM_MDP40 + mdp_ppp_handle_isr(mdp, status); +#endif if (status) locked_disable_mdp_irq(mdp, status); @@ -178,10 +217,43 @@ static irqreturn_t mdp_isr(int irq, void *data) return IRQ_HANDLED; } +static void mdp_do_dma_timer(unsigned long data) +{ + uint32_t status; + struct mdp_info *mdp = (struct mdp_info *) data; + unsigned long irq_flags=0; + int i; + + spin_lock_irqsave(&mdp->lock, irq_flags); + + status = mdp_readl(mdp, MDP_INTR_STATUS); + mdp_writel(mdp, mdp_irq_mask, MDP_INTR_CLEAR); + + for (i = 0; i < MSM_MDP_NUM_INTERFACES; ++i) { + struct mdp_out_interface *out_if = &mdp->out_if[i]; + if (mdp_irq_mask & out_if->dma_mask) { + if (out_if->dma_cb) { + out_if->dma_cb->func(out_if->dma_cb); + out_if->dma_cb = NULL; + } + wake_up(&out_if->dma_waitqueue); + } + if (mdp_irq_mask & out_if->irq_mask) { + out_if->irq_cb->func(out_if->irq_cb); + out_if->irq_cb = NULL; + } + } + + locked_disable_mdp_irq(mdp, mdp_irq_mask); + + spin_unlock_irqrestore(&mdp->lock, irq_flags); + +} + static uint32_t mdp_check_mask(struct mdp_info *mdp, uint32_t mask) { uint32_t ret; - unsigned long irq_flags; + unsigned long irq_flags=0; spin_lock_irqsave(&mdp->lock, irq_flags); ret = mdp_irq_mask & mask; @@ -189,10 +261,29 @@ static uint32_t mdp_check_mask(struct mdp_info *mdp, uint32_t mask) return ret; } -static int mdp_wait(struct mdp_info *mdp, uint32_t mask, wait_queue_head_t *wq) +void mdp_dump_blit(struct mdp_blit_req *req) +{ + pr_info("%s: src: w=%d h=%d f=0x%x offs=0x%x mem_id=%d\n", __func__, + req->src.width, req->src.height, req->src.format, + req->src.offset, req->src.memory_id); + pr_info("%s: dst: w=%d h=%d f=0x%x offs=0x%x mem_id=%d\n", __func__, + req->dst.width, req->dst.height, req->dst.format, + req->dst.offset, req->dst.memory_id); + pr_info("%s: src_rect: x=%d y=%d w=%d h=%d\n", __func__, + req->src_rect.x, req->src_rect.y, req->src_rect.w, + req->src_rect.h); + pr_info("%s: dst_rect: x=%d y=%d w=%d h=%d\n", __func__, + req->dst_rect.x, req->dst_rect.y, req->dst_rect.w, + req->dst_rect.h); + pr_info("%s: alpha=0x%08x\n", __func__, req->alpha); + pr_info("%s: transp_max=0x%08x\n", __func__, req->transp_mask); + pr_info("%s: flags=%08x\n", __func__, req->flags); +} + +int mdp_wait(struct mdp_info *mdp, uint32_t mask, wait_queue_head_t *wq) { int ret = 0; - unsigned long irq_flags; + unsigned long irq_flags=0; // pr_info("%s: WAITING for 0x%x\n", __func__, mask); wait_event_timeout(*wq, !mdp_check_mask(mdp, mask), HZ); @@ -214,7 +305,7 @@ static int mdp_wait(struct mdp_info *mdp, uint32_t mask, wait_queue_head_t *wq) return ret; } -void mdp_dma_wait(struct mdp_device *mdp_dev, int interface) +static void mdp_dma_wait(struct mdp_device *mdp_dev, int interface) { #define MDP_MAX_TIMEOUTS 20 static int timeout_count; @@ -247,54 +338,42 @@ void mdp_dma_wait(struct mdp_device *mdp_dev, int interface) BUG(); } } - +/* static int mdp_ppp_wait(struct mdp_info *mdp) { return mdp_wait(mdp, DL0_ROI_DONE, &mdp_ppp_waitqueue); } - +*/ +#ifndef CONFIG_MSM_MDP40 static void mdp_dmas_to_mddi(void *priv, uint32_t addr, uint32_t stride, uint32_t width, uint32_t height, uint32_t x, uint32_t y) { struct mdp_info *mdp = priv; uint32_t dma2_cfg; - uint32_t video_packet_parameter; + uint32_t video_packet_parameter = 0; uint16_t ld_param = 1; + dma2_cfg = DMA_PACK_TIGHT | + DMA_PACK_ALIGN_LSB | + DMA_OUT_SEL_AHB | + DMA_IBUF_NONCONTIGUOUS; - if(machine_is_htcleo()) { - dma2_cfg = DMA_PACK_ALIGN_MSB | - DMA_PACK_PATTERN_RGB; + dma2_cfg |= mdp->dma_format; - dma2_cfg |= mdp->format; +#if defined CONFIG_MSM_MDP22 || defined CONFIG_MSM_MDP30 + if (mdp->dma_format == DMA_IBUF_FORMAT_RGB888_OR_ARGB8888) +#else + if (mdp->dma_format == DMA_IBUF_FORMAT_XRGB8888) +#endif + dma2_cfg |= DMA_PACK_PATTERN_BGR; + else + dma2_cfg |= DMA_PACK_PATTERN_RGB; - dma2_cfg |= DMA_OUT_SEL_LCDC; + dma2_cfg |= DMA_OUT_SEL_MDDI; - dma2_cfg |= DMA_IBUF_FORMAT_RGB565; - - } else { - dma2_cfg = DMA_PACK_TIGHT | - DMA_PACK_ALIGN_LSB | - DMA_OUT_SEL_AHB | - DMA_IBUF_NONCONTIGUOUS; + dma2_cfg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY; - dma2_cfg |= mdp->format; - - #if defined CONFIG_MSM_MDP22 || defined CONFIG_MSM_MDP30 - if (mdp->format == DMA_IBUF_FORMAT_RGB888_OR_ARGB8888) - #else - if (mdp->format == DMA_IBUF_FORMAT_XRGB8888) - #endif - dma2_cfg |= DMA_PACK_PATTERN_BGR; - else - dma2_cfg |= DMA_PACK_PATTERN_RGB; - - dma2_cfg |= DMA_OUT_SEL_MDDI; - - dma2_cfg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY; - - dma2_cfg |= DMA_DITHER_EN; - } + dma2_cfg |= DMA_DITHER_EN; if (mdp->mdp_dev.color_format == MSM_MDP_OUT_IF_FMT_RGB565) { dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; @@ -341,12 +420,12 @@ static void mdp_dma_to_mddi(void *priv, uint32_t addr, uint32_t stride, DMA_IBUF_NONCONTIGUOUS; #endif - dma2_cfg |= mdp->format; + dma2_cfg |= mdp->dma_format; #if defined CONFIG_MSM_MDP22 || defined CONFIG_MSM_MDP30 - if (mdp->format == DMA_IBUF_FORMAT_RGB888_OR_ARGB8888) + if (mdp->dma_format == DMA_IBUF_FORMAT_RGB888_OR_ARGB8888) #else - if (mdp->format == DMA_IBUF_FORMAT_XRGB8888) + if (mdp->dma_format == DMA_IBUF_FORMAT_XRGB8888) #endif dma2_cfg |= DMA_PACK_PATTERN_BGR; else @@ -417,6 +496,7 @@ static void mdp_dma_to_mddi(void *priv, uint32_t addr, uint32_t stride, mdp_writel(mdp, 0, MDP_DMA_P_START); #endif } +#endif /* ifndef CONFIG_MSM_MDP40 */ void mdp_dma(struct mdp_device *mdp_dev, uint32_t addr, uint32_t stride, uint32_t width, uint32_t height, uint32_t x, uint32_t y, @@ -435,54 +515,21 @@ void mdp_dma(struct mdp_device *mdp_dev, uint32_t addr, uint32_t stride, spin_lock_irqsave(&mdp->lock, flags); if (locked_enable_mdp_irq(mdp, out_if->dma_mask)) { + /* something wrong in dma, workaround it */ + mdp_dma_timer_enable = 1; pr_err("%s: busy\n", __func__); - goto done; } out_if->dma_cb = callback; out_if->dma_start(out_if->priv, addr, stride, width, height, x, y); -done: + + if (mdp_dma_timer_enable) + mod_timer(&mdp->dma_timer, + jiffies + msecs_to_jiffies(17)); + spin_unlock_irqrestore(&mdp->lock, flags); } -static int get_img(struct mdp_img *img, struct fb_info *info, - unsigned long *start, unsigned long *len, - struct file** filep) -{ - int put_needed, ret = 0; - struct file *file; - unsigned long vstart; - - if (!get_pmem_file(img->memory_id, start, &vstart, len, filep)) - return 0; - else if (!get_msm_hw3d_file(img->memory_id, &img->offset, start, len, - filep)) - return 0; - - 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; - ret = 0; - } else - ret = -1; - fput_light(file, put_needed); - - return ret; -} - -static void put_img(struct file *file) -{ - if (file) { - if (is_pmem_file(file)) - put_pmem_file(file); - else if (is_msm_hw3d_file(file)) - put_msm_hw3d_file(file); - } -} void mdp_configure_dma(struct mdp_device *mdp_dev) { @@ -494,7 +541,7 @@ void mdp_configure_dma(struct mdp_device *mdp_dev) dma_cfg = mdp_readl(mdp, MDP_DMA_P_CONFIG); dma_cfg &= ~DMA_IBUF_FORMAT_MASK; dma_cfg &= ~DMA_PACK_PATTERN_MASK; - dma_cfg |= (mdp->format | mdp->pack_pattern); + dma_cfg |= (mdp->dma_format | mdp->dma_pack_pattern); mdp_writel(mdp, dma_cfg, MDP_DMA_P_CONFIG); mdp->dma_config_dirty = false; @@ -514,6 +561,13 @@ int mdp_check_output_format(struct mdp_device *mdp_dev, int bpp) return 0; } +void mdp_set_panel_size(struct mdp_device *mdp_dev, int width, int height) +{ + struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); + mdp->mdp_dev.width = width; + mdp->mdp_dev.height = height; +} + int mdp_set_output_format(struct mdp_device *mdp_dev, int bpp) { struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); @@ -542,214 +596,24 @@ int mdp_set_output_format(struct mdp_device *mdp_dev, int bpp) default: return -EINVAL; } - if (format != mdp->format || pack_pattern != mdp->pack_pattern) { - mdp->format = format; - mdp->pack_pattern = pack_pattern; + if (format != mdp->dma_format || pack_pattern != mdp->dma_pack_pattern) { + mdp->dma_format = format; + mdp->dma_pack_pattern = pack_pattern; mdp->dma_config_dirty = true; } return 0; } -static void dump_req(struct mdp_blit_req *req, - unsigned long src_start, unsigned long src_len, - unsigned long dst_start, unsigned long dst_len) -{ - pr_err("flags: 0x%x\n", req->flags); - pr_err("src_start: 0x%08lx\n", src_start); - pr_err("src_len: 0x%08lx\n", src_len); - pr_err("src.offset: 0x%x\n", req->src.offset); - pr_err("src.format: 0x%x\n", req->src.format); - pr_err("src.width: %d\n", req->src.width); - pr_err("src.height: %d\n", req->src.height); - pr_err("src_rect.x: %d\n", req->src_rect.x); - pr_err("src_rect.y: %d\n", req->src_rect.y); - pr_err("src_rect.w: %d\n", req->src_rect.w); - pr_err("src_rect.h: %d\n", req->src_rect.h); - - pr_err("dst_start: 0x%08lx\n", dst_start); - pr_err("dst_len: 0x%08lx\n", dst_len); - pr_err("dst.offset: 0x%x\n", req->dst.offset); - pr_err("dst.format: 0x%x\n", req->dst.format); - pr_err("dst.width: %d\n", req->dst.width); - pr_err("dst.height: %d\n", req->dst.height); - pr_err("dst_rect.x: %d\n", req->dst_rect.x); - pr_err("dst_rect.y: %d\n", req->dst_rect.y); - pr_err("dst_rect.w: %d\n", req->dst_rect.w); - pr_err("dst_rect.h: %d\n", req->dst_rect.h); -} - -int mdp_blit_and_wait(struct mdp_info *mdp, struct mdp_blit_req *req, - struct file *src_file, unsigned long src_start, unsigned long src_len, - struct file *dst_file, unsigned long dst_start, unsigned long dst_len) -{ - int ret; - enable_mdp_irq(mdp, DL0_ROI_DONE); - ret = mdp_ppp_blit(mdp, req, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); - if (unlikely(ret)) { - disable_mdp_irq(mdp, DL0_ROI_DONE); - return ret; - } - ret = mdp_ppp_wait(mdp); - if (unlikely(ret)) { - printk(KERN_ERR "%s: failed!\n", __func__); - pr_err("original request:\n"); - dump_req(mdp->req, src_start, src_len, dst_start, dst_len); - pr_err("dead request:\n"); - dump_req(req, src_start, src_len, dst_start, dst_len); - BUG(); - return ret; - } - return 0; -} - int mdp_blit(struct mdp_device *mdp_dev, struct fb_info *fb, struct mdp_blit_req *req) { - int ret; - unsigned long src_start = 0, src_len = 0, dst_start = 0, dst_len = 0; struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); - struct file *src_file = 0, *dst_file = 0; - -#if defined(CONFIG_MSM_MDP31) || defined(CONFIG_MSM_MDP302) - if (req->flags & MDP_ROT_90) { - if (unlikely(((req->dst_rect.h == 1) && - ((req->src_rect.w != 1) || - (req->dst_rect.w != req->src_rect.h))) || - ((req->dst_rect.w == 1) && ((req->src_rect.h != 1) || - (req->dst_rect.h != req->src_rect.w))))) { - pr_err("mpd_ppp: error scaling when size is 1!\n"); - return -EINVAL; - } - } else { - if (unlikely(((req->dst_rect.w == 1) && - ((req->src_rect.w != 1) || - (req->dst_rect.h != req->src_rect.h))) || - ((req->dst_rect.h == 1) && ((req->src_rect.h != 1) || - (req->dst_rect.h != req->src_rect.h))))) { - pr_err("mpd_ppp: error scaling when size is 1!\n"); - return -EINVAL; - } - } -#endif - - /* WORKAROUND FOR HARDWARE BUG IN BG TILE FETCH */ - if (unlikely(req->src_rect.h == 0 || - req->src_rect.w == 0)) { - printk(KERN_ERR "mdp_ppp: src img of zero size!\n"); - return -EINVAL; - } - if (unlikely(req->dst_rect.h == 0 || - req->dst_rect.w == 0)) - return -EINVAL; - - /* do this first so that if this fails, the caller can always - * safely call put_img */ - if (unlikely(get_img(&req->src, fb, &src_start, &src_len, &src_file))) { - printk(KERN_ERR "mdp_ppp: could not retrieve src image from " - "memory\n"); - return -EINVAL; - } - - if (unlikely(get_img(&req->dst, fb, &dst_start, &dst_len, &dst_file))) { - printk(KERN_ERR "mdp_ppp: could not retrieve dst image from " - "memory\n"); - put_img(src_file); - return -EINVAL; - } - mutex_lock(&mdp_mutex); - timeout_req = req; - /* transp_masking unimplemented */ - req->transp_mask = MDP_TRANSP_NOP; - mdp->req = req; -#if !defined(CONFIG_MSM_MDP31) && !defined(CONFIG_MSM_MDP302) - if (unlikely((req->transp_mask != MDP_TRANSP_NOP || - req->alpha != MDP_ALPHA_NOP || - HAS_ALPHA(req->src.format)) && - (req->flags & MDP_ROT_90 && - req->dst_rect.w <= 16 && req->dst_rect.h >= 16))) { - int i; - unsigned int tiles = req->dst_rect.h / 16; - unsigned int remainder = req->dst_rect.h % 16; - req->src_rect.w = 16*req->src_rect.w / req->dst_rect.h; - req->dst_rect.h = 16; - for (i = 0; i < tiles; i++) { - ret = mdp_blit_and_wait(mdp, req, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); - if (ret) - goto end; - req->dst_rect.y += 16; - req->src_rect.x += req->src_rect.w; - } - if (!remainder) - goto end; - req->src_rect.w = remainder*req->src_rect.w / req->dst_rect.h; - req->dst_rect.h = remainder; - } -#else - /* Workarounds for MDP 3.1 hardware bugs */ - if (unlikely((mdp_get_bytes_per_pixel(req->dst.format) == 4) && - (req->dst_rect.w != 1) && - (((req->dst_rect.w % 8) == 6) || - ((req->dst_rect.w % 32) == 3) || - ((req->dst_rect.w % 32) == 1)))) { - ret = mdp_ppp_blit_split_width(mdp, req, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); - goto end; - } else if (unlikely((req->dst_rect.w != 1) && (req->dst_rect.h != 1) && - ((req->dst_rect.h % 32) == 3 || - (req->dst_rect.h % 32) == 1))) { - ret = mdp_ppp_blit_split_height(mdp, req, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); - goto end; - } -#endif - ret = mdp_blit_and_wait(mdp, req, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); -end: - put_img(src_file); - put_img(dst_file); - mutex_unlock(&mdp_mutex); - return ret; + return mdp_ppp_blit(mdp, fb, req); } -int mdp_fb_mirror(struct mdp_device *mdp_dev, - struct fb_info *src_fb, struct fb_info *dst_fb, - struct mdp_blit_req *req) -{ - int ret; - struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); - if (!src_fb || !dst_fb) - return -EINVAL; - - enable_mdp_irq(mdp, DL0_ROI_DONE); - ret = mdp_ppp_blit(mdp, req, - -1, src_fb->fix.smem_start, src_fb->fix.smem_len, - -1, dst_fb->fix.smem_start, dst_fb->fix.smem_len); - if (ret) - goto err_bad_blit; - - ret = mdp_ppp_wait(mdp); - if (ret) { - pr_err("mdp_ppp_wait error\n"); - goto err_wait_failed; - } - return 0; - -err_bad_blit: - disable_mdp_irq(mdp, DL0_ROI_DONE); - -err_wait_failed: - return ret; -} void mdp_set_grp_disp(struct mdp_device *mdp_dev, unsigned disp_id) { @@ -765,7 +629,7 @@ int mdp_out_if_register(struct mdp_device *mdp_dev, int interface, mdp_dma_start_func_t dma_start) { struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); - unsigned long flags; + unsigned long flags=0; int ret = 0; if (interface < 0 || interface >= MSM_MDP_NUM_INTERFACES) { @@ -798,7 +662,7 @@ int mdp_out_if_req_irq(struct mdp_device *mdp_dev, int interface, uint32_t mask, struct msmfb_callback *cb) { struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); - unsigned long flags; + unsigned long flags=0; int ret = 0; if (interface < 0 || interface >= MSM_MDP_NUM_INTERFACES) { @@ -841,94 +705,6 @@ int register_mdp_client(struct class_interface *cint) return class_interface_register(cint); } -#ifdef CONFIG_MSM_MDP40 -void mdp_hw_init(struct mdp_info *mdp) -{ - mdp_irq_mask = 0; - mdp_writel(mdp, 0, MDP_INTR_ENABLE); -} -#else -#include "mdp_csc_table.h" - -void mdp_check_tearing(struct mdp_info *mdp, struct msm_mdp_platform_data *pdata) -{ - mdp_writel(mdp, pdata->sync_config, MDP_SYNC_CONFIG_0); - mdp_writel(mdp, 1, MDP_TEAR_CHECK_EN); - mdp_writel(mdp, pdata->sync_thresh, MDP_SYNC_THRESH_0); - mdp_writel(mdp, pdata->sync_start_pos, MDP_PRIM_START_POS); -} -void mdp_hw_init(struct mdp_info *mdp) -{ - int n; - int lcdc_enabled; - - mdp_irq_mask = 0; - - mdp_writel(mdp, 0, MDP_INTR_ENABLE); - - /* debug interface write access */ - mdp_writel(mdp, 1, 0x60); - mdp_writel(mdp, 1, MDP_EBI2_PORTMAP_MODE); - -#ifndef CONFIG_MSM_MDP22 - lcdc_enabled = mdp_readl(mdp, MDP_LCDC_EN); - /* disable lcdc */ - mdp_writel(mdp, 0, MDP_LCDC_EN); - /* enable auto clock gating for all blocks by default */ - mdp_writel(mdp, 0xffffffff, MDP_CGC_EN); - /* reset color/gamma correct parms */ - mdp_writel(mdp, 0, MDP_DMA_P_COLOR_CORRECT_CONFIG); -#endif - - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc); - mdp_writel(mdp, 1, 0x60); - - for (n = 0; n < ARRAY_SIZE(csc_color_lut); n++) - mdp_writel(mdp, csc_color_lut[n].val, csc_color_lut[n].reg); - - /* clear up unused fg/main registers */ - /* comp.plane 2&3 ystride */ - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0120); - - /* unpacked pattern */ - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x012c); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0130); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0134); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0158); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x015c); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0160); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0170); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0174); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x017c); - - /* comp.plane 2 & 3 */ - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0114); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0118); - - /* clear unused bg registers */ - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4); - - for (n = 0; n < ARRAY_SIZE(csc_matrix_config_table); n++) - mdp_writel(mdp, csc_matrix_config_table[n].val, - csc_matrix_config_table[n].reg); - - mdp_ppp_init_scale(mdp); - -#ifndef CONFIG_MSM_MDP31 - mdp_writel(mdp, 0x04000400, MDP_COMMAND_CONFIG); -#endif -#ifndef CONFIG_MSM_MDP22 - if(lcdc_enabled) - mdp_writel(mdp, 1, MDP_LCDC_EN); -#endif -} -#endif //CONFIG_MSM_MDP40 - int mdp_probe(struct platform_device *pdev) { struct resource *resource; @@ -974,9 +750,13 @@ int mdp_probe(struct platform_device *pdev) #endif mdp->mdp_dev.set_grp_disp = mdp_set_grp_disp; mdp->mdp_dev.set_output_format = mdp_set_output_format; + mdp->mdp_dev.set_panel_size = mdp_set_panel_size; mdp->mdp_dev.check_output_format = mdp_check_output_format; mdp->mdp_dev.configure_dma = mdp_configure_dma; + mdp->enable_irq = enable_mdp_irq; + mdp->disable_irq = disable_mdp_irq; + if (pdata == NULL || pdata->overrides == 0) mdp->mdp_dev.overrides = 0; else if(pdata->overrides) @@ -987,27 +767,27 @@ int mdp_probe(struct platform_device *pdev) else if(pdata->color_format) mdp->mdp_dev.color_format = pdata->color_format; - if (pdata == NULL || pdata->dma_channel == MDP_DMA_P) { #ifdef CONFIG_MSM_MDP40 - if (mdp->mdp_dev.overrides & MSM_MDP4_MDDI_DMA_SWITCH) { - ret = mdp_out_if_register(&mdp->mdp_dev, - MSM_MDDI_PMDH_INTERFACE, mdp, INTR_OVERLAY0_DONE - | MDP_DMA_S_DONE, mdp4_mddi_overlay); - } else { - ret = mdp_out_if_register(&mdp->mdp_dev, - MSM_MDDI_PMDH_INTERFACE, mdp, INTR_OVERLAY0_DONE, - mdp4_mddi_overlay); - } + if (mdp->mdp_dev.overrides & MSM_MDP4_MDDI_DMA_SWITCH) { + ret = mdp_out_if_register(&mdp->mdp_dev, + MSM_MDDI_PMDH_INTERFACE, mdp, INTR_OVERLAY0_DONE + | MDP_DMA_S_DONE, mdp4_mddi_overlay); + } else { + ret = mdp_out_if_register(&mdp->mdp_dev, + MSM_MDDI_PMDH_INTERFACE, mdp, INTR_OVERLAY0_DONE, + mdp4_mddi_overlay); + } #else + if (pdata == NULL || pdata->dma_channel == MDP_DMA_P) { ret = mdp_out_if_register(&mdp->mdp_dev, MSM_MDDI_PMDH_INTERFACE, mdp, MDP_DMA_P_DONE, mdp_dma_to_mddi); -#endif } else if (pdata->dma_channel == MDP_DMA_S) { ret = mdp_out_if_register(&mdp->mdp_dev, MSM_MDDI_PMDH_INTERFACE, mdp, MDP_DMA_S_DONE, mdp_dmas_to_mddi); } +#endif if (ret) goto error_mddi_pmdh_register; @@ -1019,13 +799,12 @@ int mdp_probe(struct platform_device *pdev) goto error_get_mdp_clk; } - mdp->ebi1_clk = clk_get(NULL, "ebi1_clk"); - if (IS_ERR(mdp->ebi1_clk)) { - pr_err("mdp: failed to get ebi1 clk\n"); - ret = PTR_ERR(mdp->ebi1_clk); - goto error_get_ebi1_clk; - } - + mdp->ebi1_clk = clk_get(NULL, "ebi1_clk"); + if (IS_ERR(mdp->ebi1_clk)) { + pr_err("mdp: failed to get ebi1 clk\n"); + ret = PTR_ERR(mdp->ebi1_clk); + goto error_get_ebi1_clk; + } ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp); if (ret) @@ -1034,6 +813,7 @@ int mdp_probe(struct platform_device *pdev) clk_enable(mdp->clk); mdp_clk_to_disable_later = mdp->clk; + #ifdef CONFIG_MSM_MDP40 //MDP_DISP_INTF_SEL if (mdp_readl(mdp, 0xc0000)) @@ -1045,7 +825,6 @@ int mdp_probe(struct platform_device *pdev) #endif #ifdef CONFIG_MSM_MDP40 -extern void mdp4_hw_init(struct mdp_info *mdp); mdp4_hw_init(mdp); #else mdp_hw_init(mdp); @@ -1069,6 +848,10 @@ extern void mdp4_hw_init(struct mdp_info *mdp); if (ret) goto error_device_register; + setup_timer(&mdp->standby_timer, mdp_do_standby_timer, (unsigned long )mdp); + setup_timer(&mdp->dma_timer, mdp_do_dma_timer, (unsigned long )mdp); + + pr_info("%s: initialized\n", __func__); return 0; diff --git a/drivers/video/msm/mdp_hw.h b/drivers/video/msm/mdp_hw.h index c9784f2b..2f51ed40 100644 --- a/drivers/video/msm/mdp_hw.h +++ b/drivers/video/msm/mdp_hw.h @@ -47,12 +47,61 @@ struct mdp_info { char * __iomem base; int irq; struct clk *clk; + struct clk *pclk; struct clk *ebi1_clk; struct mdp_out_interface out_if[MSM_MDP_NUM_INTERFACES]; - int format; - int pack_pattern; + int dma_format; + int dma_pack_pattern; bool dma_config_dirty; struct mdp_blit_req *req; + uint32_t state; + struct timer_list standby_timer; + struct timer_list dma_timer; + + int (*enable_irq)(struct mdp_info *mdp, uint32_t mask); + int (*disable_irq)(struct mdp_info *mdp, uint32_t mask); +}; + +struct mdp_lcdc_info { + struct mdp_info *mdp; + struct clk *mdp_clk; + struct clk *mdp_pclk; + struct clk *pclk; + struct clk *pad_pclk; + struct msm_panel_data fb_panel_data; + struct platform_device fb_pdev; + struct msm_lcdc_platform_data *pdata; + uint32_t fb_start; + + struct msmfb_callback frame_start_cb; + wait_queue_head_t vsync_waitq; + int got_vsync; + unsigned color_format; + struct { + uint32_t clk_rate; + uint32_t hsync_ctl; + uint32_t vsync_period; + uint32_t vsync_pulse_width; + uint32_t display_hctl; + uint32_t display_vstart; + uint32_t display_vend; + uint32_t hsync_skew; + uint32_t polarity; + } parms; + atomic_t blank_count; + struct mutex blank_lock; +}; + +struct panel_icm_info { + bool icm_mode; + bool icm_doable; + bool clock_enabled; + int panel_update; + bool icm_suspend; + struct mutex icm_lock; + struct mdp_lcdc_info *lcdc; + spinlock_t lock; + void (*force_leave)(void); }; extern int mdp_out_if_register(struct mdp_device *mdp_dev, int interface, @@ -64,15 +113,21 @@ extern int mdp_out_if_req_irq(struct mdp_device *mdp_dev, int interface, struct mdp_blit_req; struct mdp_device; -int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, - struct file *src_file, unsigned long src_start, - unsigned long src_len, struct file *dst_file, - unsigned long dst_start, unsigned long dst_len); void mdp_ppp_dump_debug(const struct mdp_info *mdp); +int mdp_hw_init(struct mdp_info *mdp); +void mdp_check_tearing(struct mdp_info *mdp, struct msm_mdp_platform_data *pdata); +void mdp_dump_blit(struct mdp_blit_req *req); +int mdp_wait(struct mdp_info *mdp, uint32_t mask, wait_queue_head_t *wq); #define mdp_writel(mdp, value, offset) writel(value, mdp->base + offset) #define mdp_readl(mdp, offset) readl(mdp->base + offset) +#define panel_to_lcdc(p) container_of((p), struct mdp_lcdc_info, fb_panel_data) +#define panel_to_dtv(p) container_of((p), struct mdp_dtv_info, fb_panel_data) + +/* define mdp state for multi purpose */ +#define MDP_STATE_STANDBY (1 << 0) + #ifdef CONFIG_MSM_MDP302 #define MDP_SYNC_CONFIG_0 ( 0x00300) @@ -142,6 +197,7 @@ void mdp_ppp_dump_debug(const struct mdp_info *mdp); #define MDP_VSYNC_CTRL (0x0008c) #define MDP_MDDI_PARAM_WR_SEL (0x00090) #define MDP_MDDI_PARAM (0x00094) +#define MDP_MDDI_DATA_XFR (0x00098) #define MDP_CGC_EN (0x00100) #define MDP_CMD_STATUS (0x10008) #define MDP_PROFILE_EN (0x10010) @@ -292,6 +348,21 @@ void mdp_ppp_dump_debug(const struct mdp_info *mdp); #define MDP_LCDC_HSYNC_SKEW (0xc0030) #define MDP_LCDC_TEST_CTL (0xc0034) #define MDP_LCDC_CTL_POLARITY (0xc0038) + +#define MDP_DTV_EN (0xd0000) +#define MDP_DTV_HSYNC_CTL (0xd0004) +#define MDP_DTV_VSYNC_PERIOD (0xd0008) +#define MDP_DTV_VSYNC_PULSE_WIDTH (0xd000c) +#define MDP_DTV_DISPLAY_HCTL (0xd0018) +#define MDP_DTV_DISPLAY_V_START (0xd001c) +#define MDP_DTV_DISPLAY_V_END (0xd0020) +#define MDP_DTV_ACTIVE_HCTL (0xd002c) +#define MDP_DTV_ACTIVE_V_START (0xd0030) +#define MDP_DTV_ACTIVE_V_END (0xd0038) +#define MDP_DTV_BORDER_CLR (0xd0040) +#define MDP_DTV_UNDERFLOW_CTL (0xd0044) +#define MDP_DTV_HSYNC_SKEW (0xd0048) +#define MDP_DTV_CTL_POLARITY (0xd0050) #else #define MDP_LCDC_EN (0xe0000) #define MDP_LCDC_HSYNC_CTL (0xe0004) @@ -321,6 +392,7 @@ void mdp_ppp_dump_debug(const struct mdp_info *mdp); #define TV_OUT_DMA3_DONE (1<<6) #define TV_ENC_UNDERRUN (1<<7) #define TV_OUT_FRAME_START (1<<13) +#define MDP_HIST_DONE (1<<20) #ifdef CONFIG_MSM_MDP22 #define MDP_DMA_P_DONE (1 << 2) @@ -800,6 +872,7 @@ void mdp_ppp_dump_debug(const struct mdp_info *mdp); #define DMA_PACK_LOOSE 0 #define DMA_PACK_ALIGN_LSB 0 #define DMA_PACK_ALIGN_MSB (1<<7) +#define DMA_PACK_ALIGN_MASK (1<<7) #define DMA_PACK_PATTERN_MASK (0x3f<<8) #define DMA_PACK_PATTERN_RGB \ (MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 2)<<8) @@ -823,31 +896,14 @@ void mdp_ppp_dump_debug(const struct mdp_info *mdp); #define DMA_IBUF_FORMAT_MASK (1 << 20) #define DMA_IBUF_NONCONTIGUOUS (1<<21) -#elif defined(CONFIG_MSM_MDP30) - -#define DMA_OUT_SEL_AHB 0 -#define DMA_OUT_SEL_MDDI (1<<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 (1<<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_MASK (1 << 20) -#define DMA_IBUF_FORMAT_RGB565 (1<<25) -#define DMA_IBUF_FORMAT_RGB888_OR_ARGB8888 (1<<26) -#define DMA_IBUF_NONCONTIGUOUS (0) - -#else /* CONFIG_MSM_MDP31 | CONFIG_MSM_MDP302 */ +#else /* CONFIG_MSM_MDP31 || CONFIG_MSM_MDP40 */ #define DMA_OUT_SEL_AHB (0 << 19) #define DMA_OUT_SEL_MDDI (1 << 19) #define DMA_OUT_SEL_LCDC (2 << 19) #define DMA_OUT_SEL_LCDC_MDDI (3 << 19) #define DMA_DITHER_EN (1 << 24) +#define DMA_DEFLKR_EN (1 << 24) /* dma_e */ #define DMA_IBUF_FORMAT_RGB888 (0 << 25) #define DMA_IBUF_FORMAT_RGB565 (1 << 25) #define DMA_IBUF_FORMAT_XRGB8888 (2 << 25) @@ -862,6 +918,7 @@ void mdp_ppp_dump_debug(const struct mdp_info *mdp); /* MDDI REGISTER ? */ #define MDDI_VDO_PACKET_DESC_RGB565 0x5565 #define MDDI_VDO_PACKET_DESC_RGB666 0x5666 +#define MDDI_VDO_PACKET_DESC_RGB888 0x5888 #define MDDI_VDO_PACKET_PRIM 0xC3 #define MDDI_VDO_PACKET_SECD 0xC0 diff --git a/drivers/video/msm/mdp_hw_legacy.c b/drivers/video/msm/mdp_hw_legacy.c new file mode 100644 index 00000000..20970643 --- /dev/null +++ b/drivers/video/msm/mdp_hw_legacy.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2010 Google, Inc. + * Author: Dima Zavin + * + * 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 + +#include "mdp_hw.h" +#include "mdp_ppp.h" +#include "mdp_csc_table.h" + +#define MDP_CMD_DEBUG_ACCESS_BASE (0x10000) +static unsigned int mdp_irq_mask; +#if 0 +static void mdp_dma_to_mddi(void *priv, uint32_t addr, uint32_t stride, + uint32_t width, uint32_t height, uint32_t x, + uint32_t y) +{ + struct mdp_info *mdp = priv; + uint32_t dma2_cfg; + uint16_t ld_param = 0; /* 0=PRIM, 1=SECD, 2=EXT */ + + dma2_cfg = DMA_PACK_TIGHT | + DMA_PACK_ALIGN_LSB | + DMA_OUT_SEL_AHB | + DMA_IBUF_NONCONTIGUOUS; + + dma2_cfg |= mdp->dma_format; + dma2_cfg |= mdp->dma_pack_pattern; + + dma2_cfg |= DMA_OUT_SEL_MDDI; + + dma2_cfg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY; + + dma2_cfg |= DMA_DITHER_EN; + + /* 666 18BPP */ + dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + +#ifdef CONFIG_MSM_MDP22 + /* setup size, address, and stride */ + mdp_writel(mdp, (height << 16) | (width), + MDP_CMD_DEBUG_ACCESS_BASE + 0x0184); + mdp_writel(mdp, addr, MDP_CMD_DEBUG_ACCESS_BASE + 0x0188); + mdp_writel(mdp, stride, MDP_CMD_DEBUG_ACCESS_BASE + 0x018C); + + /* set y & x offset and MDDI transaction parameters */ + mdp_writel(mdp, (y << 16) | (x), MDP_CMD_DEBUG_ACCESS_BASE + 0x0194); + mdp_writel(mdp, ld_param, MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0); + if (mdp->mdp_dev.color_format == MSM_MDP_OUT_IF_FMT_RGB565) + mdp_writel(mdp, (MDDI_VDO_PACKET_DESC_RGB565 << 16) | MDDI_VDO_PACKET_PRIM, + MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4); + else + mdp_writel(mdp, (MDDI_VDO_PACKET_DESC_RGB666 << 16) | MDDI_VDO_PACKET_PRIM, + MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4); + mdp_writel(mdp, dma2_cfg, MDP_CMD_DEBUG_ACCESS_BASE + 0x0180); + + /* start DMA2 */ + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0044); +#else + /* setup size, address, and stride */ + mdp_writel(mdp, (height << 16) | (width), MDP_DMA_P_SIZE); + mdp_writel(mdp, addr, MDP_DMA_P_IBUF_ADDR); + mdp_writel(mdp, stride, MDP_DMA_P_IBUF_Y_STRIDE); + + /* set y & x offset and MDDI transaction parameters */ + mdp_writel(mdp, (y << 16) | (x), MDP_DMA_P_OUT_XY); + mdp_writel(mdp, ld_param, MDP_MDDI_PARAM_WR_SEL); + if (mdp->mdp_dev.color_format == MSM_MDP_OUT_IF_FMT_RGB565) + mdp_writel(mdp, (MDDI_VDO_PACKET_DESC_RGB565 << 16) | MDDI_VDO_PACKET_PRIM, + MDP_MDDI_PARAM); + else + mdp_writel(mdp, (MDDI_VDO_PACKET_DESC_RGB666 << 16) | MDDI_VDO_PACKET_PRIM, + MDP_MDDI_PARAM); + + mdp_writel(mdp, 0x1, MDP_MDDI_DATA_XFR); + mdp_writel(mdp, dma2_cfg, MDP_DMA_P_CONFIG); + mdp_writel(mdp, 0, MDP_DMA_P_START); +#endif +} +#endif +#if defined CONFIG_MSM_MDP302 +void mdp_check_tearing(struct mdp_info *mdp, struct msm_mdp_platform_data *pdata) +{ mdp_writel(mdp, pdata->sync_config, MDP_SYNC_CONFIG_0); + mdp_writel(mdp, 1, MDP_TEAR_CHECK_EN); + mdp_writel(mdp, pdata->sync_thresh, MDP_SYNC_THRESH_0); + mdp_writel(mdp, pdata->sync_start_pos, MDP_PRIM_START_POS); +} +#endif +#if 0 +int mdp_hw_init(struct mdp_info *mdp) +{ + int n; + + n = mdp_out_if_register(&mdp->mdp_dev, MSM_MDDI_PMDH_INTERFACE, mdp, + MDP_DMA_P_DONE, mdp_dma_to_mddi); + if (n) + return n; + + mdp_writel(mdp, 0, MDP_INTR_ENABLE); + + /* debug interface write access */ + mdp_writel(mdp, 1, 0x60); + mdp_writel(mdp, 1, MDP_EBI2_PORTMAP_MODE); + +#ifndef CONFIG_MSM_MDP22 + /* disable lcdc */ + mdp_writel(mdp, 0, MDP_LCDC_EN); + /* enable auto clock gating for all blocks by default */ + mdp_writel(mdp, 0xffffffff, MDP_CGC_EN); + /* reset color/gamma correct parms */ + mdp_writel(mdp, 0, MDP_DMA_P_COLOR_CORRECT_CONFIG); +#endif + + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc); + mdp_writel(mdp, 1, 0x60); + + for (n = 0; n < ARRAY_SIZE(csc_color_lut); n++) + mdp_writel(mdp, csc_color_lut[n].val, csc_color_lut[n].reg); + + /* clear up unused fg/main registers */ + /* comp.plane 2&3 ystride */ + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0120); + + /* unpacked pattern */ + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x012c); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0130); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0134); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0158); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x015c); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0160); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0170); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0174); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x017c); + + /* comp.plane 2 & 3 */ + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0114); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0118); + + /* clear unused bg registers */ + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4); + + for (n = 0; n < ARRAY_SIZE(csc_matrix_config_table); n++) + mdp_writel(mdp, csc_matrix_config_table[n].val, + csc_matrix_config_table[n].reg); + + mdp_ppp_init_scale(mdp); + +#ifndef CONFIG_MSM_MDP31 + mdp_writel(mdp, 0x04000400, MDP_COMMAND_CONFIG); +#endif + + return 0; +} +#endif + +int mdp_hw_init(struct mdp_info *mdp) +{ + int n; + int lcdc_enabled; + + mdp_irq_mask = 0; + + mdp_writel(mdp, 0, MDP_INTR_ENABLE); + + /* debug interface write access */ + mdp_writel(mdp, 1, 0x60); + mdp_writel(mdp, 1, MDP_EBI2_PORTMAP_MODE); + +#ifndef CONFIG_MSM_MDP22 + lcdc_enabled = mdp_readl(mdp, MDP_LCDC_EN); + /* disable lcdc */ + mdp_writel(mdp, 0, MDP_LCDC_EN); + /* enable auto clock gating for all blocks by default */ + mdp_writel(mdp, 0xffffffff, MDP_CGC_EN); + /* reset color/gamma correct parms */ + mdp_writel(mdp, 0, MDP_DMA_P_COLOR_CORRECT_CONFIG); +#endif + + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc); + mdp_writel(mdp, 1, 0x60); + + for (n = 0; n < ARRAY_SIZE(csc_color_lut); n++) + mdp_writel(mdp, csc_color_lut[n].val, csc_color_lut[n].reg); + + /* clear up unused fg/main registers */ + /* comp.plane 2&3 ystride */ + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0120); + + /* unpacked pattern */ + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x012c); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0130); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0134); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0158); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x015c); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0160); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0170); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0174); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x017c); + + /* comp.plane 2 & 3 */ + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0114); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0118); + + /* clear unused bg registers */ + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0); + mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4); + + for (n = 0; n < ARRAY_SIZE(csc_matrix_config_table); n++) + mdp_writel(mdp, csc_matrix_config_table[n].val, + csc_matrix_config_table[n].reg); + + mdp_ppp_init_scale(mdp); + +#ifndef CONFIG_MSM_MDP31 + mdp_writel(mdp, 0x04000400, MDP_COMMAND_CONFIG); +#endif +#ifndef CONFIG_MSM_MDP22 + if (lcdc_enabled) + mdp_writel(mdp, 1, MDP_LCDC_EN); +#endif + return 0; +} diff --git a/drivers/video/msm/mdp_lcdc.c b/drivers/video/msm/mdp_lcdc.c index bb2a9698..def3a7d3 100644 --- a/drivers/video/msm/mdp_lcdc.c +++ b/drivers/video/msm/mdp_lcdc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,9 @@ #ifdef CONFIG_MSM_MDP40 #include "mdp4.h" #endif +#ifdef CONFIG_PANEL_SELF_REFRESH +#include +#endif #if 0 #define D(fmt, args...) printk(KERN_INFO "Dispaly: " fmt, ##args) @@ -43,32 +47,6 @@ #if defined(CONFIG_ARCH_MSM7227) #define LCDC_MUX_CTL (MSM_TGPIO1_BASE + 0x278) #endif -struct mdp_lcdc_info { - struct mdp_info *mdp; - struct clk *mdp_clk; - struct clk *pclk; - struct clk *pad_pclk; - struct msm_panel_data fb_panel_data; - struct platform_device fb_pdev; - struct msm_lcdc_platform_data *pdata; - uint32_t fb_start; - - struct msmfb_callback frame_start_cb; - wait_queue_head_t vsync_waitq; - int got_vsync; - unsigned color_format; - struct { - uint32_t clk_rate; - uint32_t hsync_ctl; - uint32_t vsync_period; - uint32_t vsync_pulse_width; - uint32_t display_hctl; - uint32_t display_vstart; - uint32_t display_vend; - uint32_t hsync_skew; - uint32_t polarity; - } parms; -}; static struct mdp_device *mdp_dev; @@ -76,7 +54,142 @@ static struct mdp_device *mdp_dev; static struct mdp4_overlay_pipe *lcdc_pipe; #endif -#define panel_to_lcdc(p) container_of((p), struct mdp_lcdc_info, fb_panel_data) +#ifdef CONFIG_PANEL_SELF_REFRESH +#if 0 +#define ICM_DBG(s...) printk("[icm]" s) +#else +#define ICM_DBG(s...) do {} while (0) +#endif + +/* set the timeout to 200 milliseconds */ +#define PANEL_ENTER_IDLE_TIMEOUT HZ/5 +/* Afetr setting ICM=1, we need to keep sending the RGB signal more than 2-frame */ +#define PANEL_IDLE_STABLE_TIMEOUT 48 + +static struct task_struct *th_display; +struct panel_icm_info *panel_icm; +DECLARE_WAIT_QUEUE_HEAD(panel_update_wait_queue); +#endif + +#ifdef CONFIG_PANEL_SELF_REFRESH +static int icm_check_panel_update(void) +{ + int ret; + unsigned long irq_flags = 0; + + spin_lock_irqsave(&panel_icm->lock, irq_flags); + ret = panel_icm->panel_update; + spin_unlock_irqrestore(&panel_icm->lock, irq_flags); + return ret; +} + +static int icm_thread(void *data) +{ + struct mdp_lcdc_info *lcdc; + struct msm_lcdc_panel_ops *panel_ops; + int rc; + unsigned long irq_flags = 0; + + lcdc = data; + panel_ops = lcdc->pdata->panel_ops; + while (1) { + rc = wait_event_timeout(panel_update_wait_queue, icm_check_panel_update() == 1, PANEL_ENTER_IDLE_TIMEOUT); + ICM_DBG("ICM Thread:wake up rc=%d \n", rc); + mutex_lock(&panel_icm->icm_lock); + if (rc == 0 && icm_check_panel_update() != 1) {/* wait_timeout */ + ICM_DBG("EnterICM: icm_mode=%d icm_doable=%d \n", panel_icm->icm_mode, panel_icm->icm_doable); + if (panel_icm->icm_mode == false && panel_icm->icm_doable == true) { + + if (panel_ops->refresh_enable) + panel_ops->refresh_enable(panel_ops); + + panel_icm->icm_mode = true; + msleep(PANEL_IDLE_STABLE_TIMEOUT); + + mdp_writel(lcdc->mdp, 0, MDP_LCDC_EN); + clk_disable(lcdc->pad_pclk); + clk_disable(lcdc->pclk); + clk_disable(lcdc->mdp_clk); + panel_icm->clock_enabled = false; + pr_info("EnterICM: enter ICM MODE done!!!\n"); + } + } else {/* get update event, no timeout */ + ICM_DBG("Leave ICM: icm_mode=%d icm_doable=%d \n", panel_icm->icm_mode, panel_icm->icm_doable); + if (panel_icm->icm_mode == true && panel_icm->icm_doable == true) { + clk_enable(lcdc->mdp_clk); + clk_enable(lcdc->pclk); + clk_enable(lcdc->pad_pclk); + mdp_writel(lcdc->mdp, 1, MDP_LCDC_EN); + panel_icm->clock_enabled = true; + + if (panel_ops->refresh_disable) + panel_ops->refresh_disable(panel_ops); + + panel_icm->icm_mode = false; + pr_info("LeaveICM: leave ICM MODE done !!!\n"); + } + spin_lock_irqsave(&panel_icm->lock, irq_flags); + panel_icm->panel_update = 0; + spin_unlock_irqrestore(&panel_icm->lock, irq_flags); + } + mutex_unlock(&panel_icm->icm_lock); + } /* end while */ + return 0; +} + +static void icm_force_leave(void) +{ + struct msm_lcdc_panel_ops *panel_ops; + unsigned long irq_flags = 0; + + panel_ops = panel_icm->lcdc->pdata->panel_ops; + + mutex_lock(&panel_icm->icm_lock); + ICM_DBG("Force Leave ICM: icm_mode=%d icm_doable=%d \n", panel_icm->icm_mode, panel_icm->icm_doable); + if (panel_icm->icm_mode == true) { + clk_enable(panel_icm->lcdc->mdp_clk); + clk_enable(panel_icm->lcdc->pclk); + clk_enable(panel_icm->lcdc->pad_pclk); + mdp_writel(panel_icm->lcdc->mdp, 1, MDP_LCDC_EN); + panel_icm->clock_enabled = true; + if (panel_ops->refresh_disable) + panel_ops->refresh_disable(panel_ops); + panel_icm->icm_mode = false; + panel_icm->icm_doable = true; + pr_info("ForceLeaveICM: leave ICM MODE done !!!\n"); + } + spin_lock_irqsave(&panel_icm->lock, irq_flags); + panel_icm->panel_update = 0; + spin_unlock_irqrestore(&panel_icm->lock, irq_flags); + mutex_unlock(&panel_icm->icm_lock); +} + +static int icm_init(struct mdp_lcdc_info *lcdc) +{ + int ret = 0; + + /* init panel_icm_info */ + panel_icm = kzalloc(sizeof(struct panel_icm_info), GFP_KERNEL); + if (!panel_icm) + return -ENOMEM; + panel_icm->icm_doable = 1; + panel_icm->clock_enabled = true; + panel_icm->lcdc = lcdc; + panel_icm->force_leave = icm_force_leave; + panel_icm->icm_suspend = false; + mutex_init(&panel_icm->icm_lock); + th_display = kthread_run(icm_thread, lcdc, "panel-enterIdle"); + if (IS_ERR(th_display)) { + ret = PTR_ERR(th_display); + pr_err("%s: panel_icm_thread create fail:%d!!!\n", __func__, ret); + goto error_create_thread; + } + return ret; +error_create_thread: + kfree(panel_icm); + return ret; +} +#endif static int lcdc_unblank(struct msm_panel_data *fb_panel) { @@ -85,7 +198,8 @@ static int lcdc_unblank(struct msm_panel_data *fb_panel) pr_info("%s: ()\n", __func__); - panel_ops->unblank(panel_ops); + if (panel_ops->unblank) + panel_ops->unblank(panel_ops); return 0; } @@ -96,14 +210,28 @@ static int lcdc_blank(struct msm_panel_data *fb_panel) struct msm_lcdc_panel_ops *panel_ops = lcdc->pdata->panel_ops; pr_info("%s: ()\n", __func__); - panel_ops->blank(panel_ops); + + if (panel_ops->blank) + panel_ops->blank(panel_ops); return 0; } +static int lcdc_shutdown(struct msm_panel_data *fb_panel) +{ + struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel); + struct msm_lcdc_panel_ops *panel_ops = lcdc->pdata->panel_ops; + + pr_info("%s: ()\n", __func__); + + if (panel_ops->shutdown) + panel_ops->shutdown(panel_ops); + + return 0; +} + static int lcdc_suspend(struct msm_panel_data *fb_panel) { - int status; struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel); struct msm_lcdc_panel_ops *panel_ops = lcdc->pdata->panel_ops; @@ -111,13 +239,39 @@ static int lcdc_suspend(struct msm_panel_data *fb_panel) #if defined(CONFIG_ARCH_MSM7227) writel(0x0, LCDC_MUX_CTL); - status = readl(LCDC_MUX_CTL); - D("suspend_lcdc_mux_ctl = %x\n", status); + D("suspend_lcdc_mux_ctl = %x\n", readl(LCDC_MUX_CTL)); #endif +#ifdef CONFIG_PANEL_SELF_REFRESH + if (lcdc->mdp->mdp_dev.overrides & MSM_MDP_RGB_PANEL_SELE_REFRESH) { + mutex_lock(&panel_icm->icm_lock); + panel_icm->icm_doable = false; + pr_info("[ICM %s]: icm mode=%d, clock_enabled=%d\n", __func__, panel_icm->icm_mode, panel_icm->clock_enabled); + if (panel_icm->icm_mode == true && panel_icm->clock_enabled == false) { + if (panel_ops->refresh_disable) + panel_ops->refresh_disable(panel_ops); + panel_icm->icm_mode = false; + } else { + mdp_writel(lcdc->mdp, 0, MDP_LCDC_EN); + clk_disable(lcdc->pad_pclk); + clk_disable(lcdc->pclk); + clk_disable(lcdc->mdp_clk); + } + panel_icm->clock_enabled = false; + mutex_unlock(&panel_icm->icm_lock); + } else { + mdp_writel(lcdc->mdp, 0, MDP_LCDC_EN); + clk_disable(lcdc->pad_pclk); + clk_disable(lcdc->pclk); + clk_disable(lcdc->mdp_clk); + } +#else mdp_writel(lcdc->mdp, 0, MDP_LCDC_EN); clk_disable(lcdc->pad_pclk); clk_disable(lcdc->pclk); + if (lcdc->mdp_pclk) + clk_disable(lcdc->mdp_pclk); clk_disable(lcdc->mdp_clk); +#endif if (panel_ops->uninit) panel_ops->uninit(panel_ops); @@ -126,7 +280,6 @@ static int lcdc_suspend(struct msm_panel_data *fb_panel) static int lcdc_resume(struct msm_panel_data *fb_panel) { - unsigned int status; struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel); struct msm_lcdc_panel_ops *panel_ops = lcdc->pdata->panel_ops; @@ -136,17 +289,26 @@ static int lcdc_resume(struct msm_panel_data *fb_panel) if (panel_ops->init(panel_ops) < 0) printk(KERN_ERR "LCD init fail!\n"); } - clk_enable(lcdc->mdp_clk); + if (lcdc->mdp_pclk) + clk_enable(lcdc->mdp_pclk); clk_enable(lcdc->pclk); clk_enable(lcdc->pad_pclk); #if defined(CONFIG_ARCH_MSM7227) writel(0x1, LCDC_MUX_CTL); - status = readl(LCDC_MUX_CTL); - D("resume_lcdc_mux_ctl = %x\n",status); + D("resume_lcdc_mux_ctl = %x\n", readl(LCDC_MUX_CTL)); #endif mdp_writel(lcdc->mdp, 1, MDP_LCDC_EN); +#ifdef CONFIG_PANEL_SELF_REFRESH + if (lcdc->mdp->mdp_dev.overrides & MSM_MDP_RGB_PANEL_SELE_REFRESH) { + mutex_lock(&panel_icm->icm_lock); + panel_icm->icm_doable = true; + panel_icm->clock_enabled = true; + panel_icm->icm_suspend = false; + mutex_unlock(&panel_icm->icm_lock); + } +#endif return 0; } @@ -157,12 +319,13 @@ static int lcdc_hw_init(struct mdp_lcdc_info *lcdc) uint32_t dma_cfg; clk_enable(lcdc->mdp_clk); + if (lcdc->mdp_pclk) + clk_enable(lcdc->mdp_pclk); clk_enable(lcdc->pclk); clk_enable(lcdc->pad_pclk); clk_set_rate(lcdc->pclk, lcdc->parms.clk_rate); clk_set_rate(lcdc->pad_pclk, lcdc->parms.clk_rate); - /* write the lcdc params */ mdp_writel(lcdc->mdp, lcdc->parms.hsync_ctl, MDP_LCDC_HSYNC_CTL); mdp_writel(lcdc->mdp, lcdc->parms.vsync_period, MDP_LCDC_VSYNC_PERIOD); @@ -175,46 +338,45 @@ static int lcdc_hw_init(struct mdp_lcdc_info *lcdc) mdp_writel(lcdc->mdp, lcdc->parms.hsync_skew, MDP_LCDC_HSYNC_SKEW); mdp_writel(lcdc->mdp, 0, MDP_LCDC_BORDER_CLR); - mdp_writel(lcdc->mdp, 0xff, MDP_LCDC_UNDERFLOW_CTL); + mdp_writel(lcdc->mdp, 0x80000000 | 0xff, MDP_LCDC_UNDERFLOW_CTL); mdp_writel(lcdc->mdp, 0, MDP_LCDC_ACTIVE_HCTL); mdp_writel(lcdc->mdp, 0, MDP_LCDC_ACTIVE_V_START); mdp_writel(lcdc->mdp, 0, MDP_LCDC_ACTIVE_V_END); mdp_writel(lcdc->mdp, lcdc->parms.polarity, MDP_LCDC_CTL_POLARITY); - /* config the dma_p block that drives the lcdc data */ mdp_writel(lcdc->mdp, lcdc->fb_start, MDP_DMA_P_IBUF_ADDR); mdp_writel(lcdc->mdp, (((fb_panel->fb_data->yres & 0x7ff) << 16) | (fb_panel->fb_data->xres & 0x7ff)), MDP_DMA_P_SIZE); - mdp_writel(lcdc->mdp, 0, MDP_DMA_P_OUT_XY); dma_cfg = mdp_readl(lcdc->mdp, MDP_DMA_P_CONFIG); -#if defined(CONFIG_MACH_HTCLEO) + dma_cfg &= ~(DMA_PACK_PATTERN_MASK | DMA_PACK_ALIGN_MASK); dma_cfg |= (DMA_PACK_ALIGN_MSB | - DMA_PACK_PATTERN_RGB | - DMA_DITHER_EN); + DMA_PACK_PATTERN_RGB | + DMA_DITHER_EN); dma_cfg |= DMA_OUT_SEL_LCDC; - dma_cfg |= DMA_IBUF_FORMAT_RGB565; - //dma_cfg &= ~DMA_DITHER_EN; // solve color banding issue - marc1706 + //zeusk: dma_cfg |= DMA_IBUF_FORMAT_RGB565; dma_cfg &= ~DMA_DST_BITS_MASK; -#else - dma_cfg |= (DMA_PACK_ALIGN_LSB | - DMA_PACK_PATTERN_RGB | - DMA_DITHER_EN); - dma_cfg |= DMA_OUT_SEL_LCDC; - dma_cfg &= ~DMA_DST_BITS_MASK; -#endif - if(lcdc->color_format == MSM_MDP_OUT_IF_FMT_RGB565) - dma_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; - else if (lcdc->color_format == MSM_MDP_OUT_IF_FMT_RGB666) - dma_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + if (fb_panel->fb_data->output_format == MSM_MDP_OUT_IF_FMT_RGB666) + dma_cfg |= DMA_DSTC0G_6BITS | + DMA_DSTC1B_6BITS | + DMA_DSTC2R_6BITS; + else if (fb_panel->fb_data->output_format == MSM_MDP_OUT_IF_FMT_RGB888) + dma_cfg |= DMA_DSTC0G_8BITS | + DMA_DSTC1B_8BITS | + DMA_DSTC2R_8BITS; + else + dma_cfg |= DMA_DSTC0G_6BITS | + DMA_DSTC1B_5BITS | + DMA_DSTC2R_5BITS; mdp_writel(lcdc->mdp, dma_cfg, MDP_DMA_P_CONFIG); /* enable the lcdc timing generation */ mdp_writel(lcdc->mdp, 1, MDP_LCDC_EN); + return 0; } @@ -301,35 +463,6 @@ static void lcdc_dma_start(void *priv, uint32_t addr, uint32_t stride, mdp_writel(lcdc->mdp, addr, MDP_DMA_P_IBUF_ADDR); } -#ifdef CONFIG_MSM_MDP40 -static void lcdc_overlay_start(void *priv, uint32_t addr, uint32_t stride, - uint32_t width, uint32_t height, uint32_t x, - uint32_t y) -{ - struct mdp_lcdc_info *lcdc = priv; - struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); - - struct mdp4_overlay_pipe *pipe; - pipe = lcdc_pipe; - pipe->srcp0_addr = addr; - - if (mdp->dma_config_dirty) - { - if(mdp->format == DMA_IBUF_FORMAT_RGB565) { - pipe->src_format = MDP_RGB_565; - pipe->srcp0_ystride = pipe->src_width * 2; - } else if(mdp->format == DMA_IBUF_FORMAT_XRGB8888) { - pipe->src_format = MDP_RGBA_8888; - pipe->srcp0_ystride = pipe->src_width * 4; - } - mdp4_overlay_format2pipe(pipe); - mdp->dma_config_dirty = false; - } - mdp4_overlay_rgb_setup(pipe); - mdp4_overlay_reg_flush(pipe, 1); /* rgb1 and mixer0 */ - -} -#endif static void precompute_timing_parms(struct mdp_lcdc_info *lcdc) { struct msm_lcdc_timing *timing = lcdc->pdata->timing; @@ -404,6 +537,10 @@ static int mdp_lcdc_probe(struct platform_device *pdev) goto err_get_mdp_clk; } + lcdc->mdp_pclk = clk_get(mdp_dev->dev.parent, "mdp_pclk"); + if (IS_ERR(lcdc->mdp_pclk)) + lcdc->mdp_pclk = NULL; + lcdc->pclk = clk_get(mdp_dev->dev.parent, "lcdc_pclk_clk"); if (IS_ERR(lcdc->pclk)) { pr_err("%s: failed to get lcdc_pclk\n", __func__); @@ -443,7 +580,10 @@ static int mdp_lcdc_probe(struct platform_device *pdev) if (lcdc_pipe == NULL) { ptype = mdp4_overlay_format2type(MDP_RGB_565); pipe = mdp4_overlay_pipe_alloc(ptype); + if (!pipe) + goto err_mdp4_overlay_pipe_alloc; pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + pipe->pipe_used = 1; pipe->mixer_num = MDP4_MIXER0; pipe->src_format = MDP_RGB_565; mdp4_overlay_format2pipe(pipe); @@ -463,15 +603,8 @@ static int mdp_lcdc_probe(struct platform_device *pdev) pipe->srcp0_addr = (uint32_t) lcdc->fb_start; pipe->srcp0_ystride = pdata->fb_data->xres * 2; - mdp4_overlay_dmap_xy(pipe); - mdp4_overlay_dmap_cfg(pipe, 1); - mdp4_overlay_rgb_setup(pipe); - mdp4_mixer_stage_up(pipe); - - mdp4_overlayproc_cfg(pipe); - mdp4_overlay_reg_flush(pipe, 1); #endif lcdc->fb_panel_data.suspend = lcdc_suspend; @@ -483,13 +616,12 @@ static int mdp_lcdc_probe(struct platform_device *pdev) lcdc->fb_panel_data.unblank = lcdc_unblank; lcdc->fb_panel_data.fb_data = pdata->fb_data; lcdc->fb_panel_data.interface_type = MSM_LCDC_INTERFACE; - + lcdc->fb_panel_data.shutdown = lcdc_shutdown; ret = lcdc_hw_init(lcdc); if (ret) { pr_err("%s: Cannot initialize the mdp_lcdc\n", __func__); goto err_hw_init; } - lcdc->fb_pdev.name = "msm_panel"; lcdc->fb_pdev.id = pdata->fb_id; lcdc->fb_pdev.resource = pdata->fb_resource; @@ -504,16 +636,30 @@ static int mdp_lcdc_probe(struct platform_device *pdev) } pr_info("%s: initialized\n", __func__); +#ifdef CONFIG_PANEL_SELF_REFRESH + if (lcdc->mdp->mdp_dev.overrides & MSM_MDP_RGB_PANEL_SELE_REFRESH) { + ret = icm_init(lcdc); + if (ret) { + pr_err("%s: Cannot init dispaly selfrefresh \n", __func__); + goto err_plat_dev_reg; + } + } +#endif return 0; err_plat_dev_reg: err_hw_init: +#ifdef CONFIG_MSM_MDP40 +err_mdp4_overlay_pipe_alloc: +#endif platform_set_drvdata(pdev, NULL); clk_put(lcdc->pad_pclk); err_get_pad_pclk: clk_put(lcdc->pclk); err_get_pclk: + if (lcdc->mdp_pclk) + clk_put(lcdc->mdp_pclk); clk_put(lcdc->mdp_clk); err_get_mdp_clk: kfree(lcdc); diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c index 334e2ebb..dd778035 100644 --- a/drivers/video/msm/mdp_ppp.c +++ b/drivers/video/msm/mdp_ppp.c @@ -15,8 +15,12 @@ #include #include #include +#include +#include #include +#include #include +#include #include #include "mdp_hw.h" @@ -52,19 +56,19 @@ static uint32_t dst_img_cfg[] = { PPP_ARRAY1(CFG, DST) }; -static uint32_t bytes_per_pixel[] = { +static const uint32_t bytes_per_pixel[] = { [MDP_RGB_565] = 2, - [MDP_RGB_888] = 3, [MDP_XRGB_8888] = 4, + [MDP_Y_CBCR_H2V2] = 1, [MDP_ARGB_8888] = 4, + [MDP_RGB_888] = 3, + [MDP_Y_CRCB_H2V2] = 1, + [MDP_YCRYCB_H2V1] = 2, + [MDP_Y_CRCB_H2V1] = 1, + [MDP_Y_CBCR_H2V1] = 1, [MDP_RGBA_8888] = 4, [MDP_BGRA_8888] = 4, [MDP_RGBX_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 }; static uint32_t dst_op_chroma[] = { @@ -79,6 +83,9 @@ static uint32_t bg_op_chroma[] = { PPP_ARRAY1(CHROMA_SAMP, BG) }; +static DECLARE_WAIT_QUEUE_HEAD(mdp_ppp_waitqueue); +DEFINE_MUTEX(mdp_mutex); + static uint32_t get_luma_offset(struct mdp_img *img, struct mdp_rect *rect, uint32_t bpp) { @@ -268,7 +275,6 @@ static void blit_blend(struct mdp_blit_req *req, struct ppp_regs *regs) req->alpha &= 0xff; /* ALPHA BLEND */ if (HAS_ALPHA(req->src.format)) { -#if !defined(CONFIG_MACH_HTCLEO) regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON; if (req->flags & MDP_BLEND_FG_PREMULT) { #ifdef CONFIG_MSM_MDP31 @@ -285,10 +291,6 @@ static void blit_blend(struct mdp_blit_req *req, struct ppp_regs *regs) } else { regs->op |= PPP_OP_BLEND_SRCPIXEL_ALPHA; } -#else - regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON; - regs->op |= PPP_OP_BLEND_SRCPIXEL_ALPHA; -#endif } else if (req->alpha < MDP_ALPHA_NOP) { /* just blend by alpha */ regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON | @@ -309,7 +311,7 @@ static void blit_blend(struct mdp_blit_req *req, struct ppp_regs *regs) set_blend_region(&req->dst, &req->dst_rect, regs); } -static int blit_scale(const struct mdp_info *mdp, struct mdp_blit_req *req, +static int blit_scale(struct mdp_info *mdp, struct mdp_blit_req *req, struct ppp_regs *regs) { struct mdp_rect dst_rect; @@ -330,7 +332,7 @@ static int blit_scale(const struct mdp_info *mdp, struct mdp_blit_req *req, } if (mdp_ppp_cfg_scale(mdp, regs, &req->src_rect, &dst_rect, - req->src.format, req->dst.format)) { + req->src.format, req->dst.format)) { DLOG("crap, bad scale\n"); return -1; } @@ -339,7 +341,7 @@ static int blit_scale(const struct mdp_info *mdp, struct mdp_blit_req *req, return 0; } -static void blit_blur(const struct mdp_info *mdp, struct mdp_blit_req *req, +static void blit_blur(struct mdp_info *mdp, struct mdp_blit_req *req, struct ppp_regs *regs) { int ret; @@ -411,21 +413,23 @@ static void flush_imgs(struct mdp_blit_req *req, struct ppp_regs *regs, #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, regs->src_bpp, &src0_len, - &src1_len); - flush_pmem_file(src_file, req->src.offset, src0_len); - if (IS_PSEUDOPLNR(req->src.format)) - flush_pmem_file(src_file, req->src.offset + src0_len, - src1_len); + if (!(req->flags & MDP_BLIT_NON_CACHED)) { + /* flush src images to memory before dma to mdp */ + get_len(&req->src, &req->src_rect, regs->src_bpp, &src0_len, + &src1_len); + flush_pmem_file(src_file, req->src.offset, src0_len); + if (IS_PSEUDOPLNR(req->src.format)) + flush_pmem_file(src_file, req->src.offset + src0_len, + src1_len); - /* flush dst images */ - get_len(&req->dst, &req->dst_rect, regs->dst_bpp, &dst0_len, - &dst1_len); - flush_pmem_file(dst_file, req->dst.offset, dst0_len); - if (IS_PSEUDOPLNR(req->dst.format)) - flush_pmem_file(dst_file, req->dst.offset + dst0_len, - dst1_len); + /* flush dst images */ + get_len(&req->dst, &req->dst_rect, regs->dst_bpp, &dst0_len, + &dst1_len); + flush_pmem_file(dst_file, req->dst.offset, dst0_len); + if (IS_PSEUDOPLNR(req->dst.format)) + flush_pmem_file(dst_file, req->dst.offset + dst0_len, + dst1_len); + } #endif } @@ -439,6 +443,13 @@ static uint32_t get_chroma_base(struct mdp_img *img, uint32_t base, return addr; } +int mdp_get_bytes_per_pixel(int format) +{ + if (format < 0 || format >= MDP_IMGTYPE_LIMIT) + return -1; + return bytes_per_pixel[format]; +} + #if PPP_DUMP_BLITS #define mdp_writel_dbg(mdp, val, reg) do { \ pr_info("%s: writing 0x%08x=0x%08x\n", __func__, (reg), (val));\ @@ -501,19 +512,17 @@ static int send_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, mdp_writel_dbg(mdp, regs->bg_img_sz, MDP_PPP_BG_IMAGE_SIZE); mdp_writel_dbg(mdp, regs->bg_alpha_sel, MDP_PPP_BLEND_BG_ALPHA_SEL); - -#if defined(CONFIG_MACH_HTCLEO) +#if 0 /* zeusk: defined(CONFIG_MACH_HTCLEO) */ mdp_writel_dbg(mdp, 0, MDP_TFETCH_TEST_MODE); #endif #endif } - if( src_file != -1 && dst_file != -1 ) - flush_imgs(req, regs, src_file, dst_file); + flush_imgs(req, regs, src_file, dst_file); mdp_writel_dbg(mdp, 0x1000, MDP_DISPLAY0_START); return 0; } - -void mdp_dump_blit(struct mdp_blit_req *req) +/* +static void mdp_dump_blit(struct mdp_blit_req *req) { pr_info("%s: src: w=%d h=%d f=0x%x offs=0x%x mem_id=%d\n", __func__, req->src.width, req->src.height, req->src.format, @@ -531,8 +540,8 @@ void mdp_dump_blit(struct mdp_blit_req *req) pr_info("%s: transp_max=0x%08x\n", __func__, req->transp_mask); pr_info("%s: flags=%08x\n", __func__, req->flags); } - -int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, +*/ +static int process_blit(struct mdp_info *mdp, struct mdp_blit_req *req, struct file *src_file, unsigned long src_start, unsigned long src_len, struct file *dst_file, unsigned long dst_start, unsigned long dst_len) { @@ -644,13 +653,6 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, return 0; } -int mdp_get_bytes_per_pixel(int format) -{ - if (format < 0 || format >= MDP_IMGTYPE_LIMIT) - return -1; - return bytes_per_pixel[format]; -} - #define mdp_dump_register(mdp, reg) \ printk(# reg ": %08x\n", mdp_readl((mdp), (reg))) @@ -668,234 +670,164 @@ void mdp_ppp_dump_debug(const struct mdp_info *mdp) mdp_dump_register(mdp, MDP_INTR_ENABLE); } - -/* Splits a blit into two horizontal stripes. Used to work around MDP bugs */ -int mdp_ppp_blit_split_height(struct mdp_info *mdp, const struct mdp_blit_req *req, - struct file *src_file, unsigned long src_start, unsigned long src_len, - struct file *dst_file, unsigned long dst_start, unsigned long dst_len) +static int mdp_ppp_wait(struct mdp_info *mdp) { int ret; - struct mdp_blit_req splitreq; - int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1; - int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1; - splitreq = *req; - /* break dest roi at height*/ - d_x_0 = d_x_1 = req->dst_rect.x; - d_w_0 = d_w_1 = req->dst_rect.w; - d_y_0 = req->dst_rect.y; - if (req->dst_rect.h % 32 == 3) - d_h_1 = (req->dst_rect.h - 3) / 2 - 1; - else - d_h_1 = (req->dst_rect.h - 1) / 2 - 1; - d_h_0 = req->dst_rect.h - d_h_1; - d_y_1 = d_y_0 + d_h_0; - if (req->dst_rect.h == 3) { - d_h_1 = 2; - d_h_0 = 2; - d_y_1 = d_y_0 + 1; - } - /* break source roi */ - if (splitreq.flags & MDP_ROT_90) { - s_y_0 = s_y_1 = req->src_rect.y; - s_h_0 = s_h_1 = req->src_rect.h; - s_x_0 = req->src_rect.x; - s_w_1 = (req->src_rect.w * d_h_1) / req->dst_rect.h; - s_w_0 = req->src_rect.w - s_w_1; - s_x_1 = s_x_0 + s_w_0; - if (d_h_1 >= 8 * s_w_1) { - s_w_1++; - s_x_1--; - } - } else { - s_x_0 = s_x_1 = req->src_rect.x; - s_w_0 = s_w_1 = req->src_rect.w; - s_y_0 = req->src_rect.y; - s_h_1 = (req->src_rect.h * d_h_1) / req->dst_rect.h; - s_h_0 = req->src_rect.h - s_h_1; - s_y_1 = s_y_0 + s_h_0; - if (d_h_1 >= 8 * s_h_1) { - s_h_1++; - s_y_1--; - } - } - - /* blit first region */ - if (((splitreq.flags & MDP_ROT_MASK) == MDP_ROT_90) || - ((splitreq.flags & MDP_ROT_MASK) == 0x0)) { - splitreq.src_rect.h = s_h_0; - splitreq.src_rect.y = s_y_0; - splitreq.dst_rect.h = d_h_0; - splitreq.dst_rect.y = d_y_0; - splitreq.src_rect.x = s_x_0; - splitreq.src_rect.w = s_w_0; - splitreq.dst_rect.x = d_x_0; - splitreq.dst_rect.w = d_w_0; - } else { - splitreq.src_rect.h = s_h_0; - splitreq.src_rect.y = s_y_0; - splitreq.dst_rect.h = d_h_1; - splitreq.dst_rect.y = d_y_1; - splitreq.src_rect.x = s_x_0; - splitreq.src_rect.w = s_w_0; - splitreq.dst_rect.x = d_x_1; - splitreq.dst_rect.w = d_w_1; - } - ret = mdp_blit_and_wait(mdp, &splitreq, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); + ret = mdp_wait(mdp, DL0_ROI_DONE, &mdp_ppp_waitqueue); if (ret) - return ret; - - /* blit second region */ - if (((splitreq.flags & MDP_ROT_MASK) == MDP_ROT_90) || - ((splitreq.flags & MDP_ROT_MASK) == 0x0)) { - splitreq.src_rect.h = s_h_1; - splitreq.src_rect.y = s_y_1; - splitreq.dst_rect.h = d_h_1; - splitreq.dst_rect.y = d_y_1; - splitreq.src_rect.x = s_x_1; - splitreq.src_rect.w = s_w_1; - splitreq.dst_rect.x = d_x_1; - splitreq.dst_rect.w = d_w_1; - } else { - splitreq.src_rect.h = s_h_1; - splitreq.src_rect.y = s_y_1; - splitreq.dst_rect.h = d_h_0; - splitreq.dst_rect.y = d_y_0; - splitreq.src_rect.x = s_x_1; - splitreq.src_rect.w = s_w_1; - splitreq.dst_rect.x = d_x_0; - splitreq.dst_rect.w = d_w_0; - } - ret = mdp_blit_and_wait(mdp, &splitreq, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); + mdp_ppp_dump_debug(mdp); return ret; } -/* Splits a blit into two vertical stripes. Used to work around MDP bugs */ -int mdp_ppp_blit_split_width(struct mdp_info *mdp, const struct mdp_blit_req *req, - struct file *src_file, unsigned long src_start, unsigned long src_len, - struct file *dst_file, unsigned long dst_start, unsigned long dst_len) +static int get_img(struct mdp_img *img, struct fb_info *info, + unsigned long *start, unsigned long *len, + struct file** filep) +{ + int put_needed, ret = 0; + struct file *file; + unsigned long vstart; + + if (img->memory_id & 0x40000000) + { + struct fb_info *fb = registered_fb[img->memory_id & 0x0000FFFF]; + if (fb) + { + *start = fb->fix.smem_start; + *len = fb->fix.smem_len; + } + *filep = NULL; + return 0; + } + + if (!get_pmem_file(img->memory_id, start, &vstart, len, filep)) + return 0; + else if (!get_msm_hw3d_file(img->memory_id, &img->offset, start, len, + filep)) + return 0; + + 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; + ret = 0; + } else + ret = -1; + fput_light(file, put_needed); + + return ret; +} +void put_img(struct file *p_src_file) +{ +#ifdef CONFIG_ANDROID_PMEM + if (p_src_file) + put_pmem_file(p_src_file); +#else + if (is_msm_hw3d_file(p_src_file)) + put_msm_hw3d_file(p_src_file); +#endif +} + +static void dump_req(struct mdp_blit_req *req, + unsigned long src_start, unsigned long src_len, + unsigned long dst_start, unsigned long dst_len) +{ + pr_err("flags: 0x%x\n", req->flags); + pr_err("src_start: 0x%08lx\n", src_start); + pr_err("src_len: 0x%08lx\n", src_len); + pr_err("src.offset: 0x%x\n", req->src.offset); + pr_err("src.format: 0x%x\n", req->src.format); + pr_err("src.width: %d\n", req->src.width); + pr_err("src.height: %d\n", req->src.height); + pr_err("src_rect.x: %d\n", req->src_rect.x); + pr_err("src_rect.y: %d\n", req->src_rect.y); + pr_err("src_rect.w: %d\n", req->src_rect.w); + pr_err("src_rect.h: %d\n", req->src_rect.h); + + pr_err("dst_start: 0x%08lx\n", dst_start); + pr_err("dst_len: 0x%08lx\n", dst_len); + pr_err("dst.offset: 0x%x\n", req->dst.offset); + pr_err("dst.format: 0x%x\n", req->dst.format); + pr_err("dst.width: %d\n", req->dst.width); + pr_err("dst.height: %d\n", req->dst.height); + pr_err("dst_rect.x: %d\n", req->dst_rect.x); + pr_err("dst_rect.y: %d\n", req->dst_rect.y); + pr_err("dst_rect.w: %d\n", req->dst_rect.w); + pr_err("dst_rect.h: %d\n", req->dst_rect.h); +} + +int mdp_ppp_blit_and_wait(struct mdp_info *mdp, struct mdp_blit_req *req, + struct file *src_file, unsigned long src_start, unsigned long src_len, + struct file *dst_file, unsigned long dst_start, unsigned long dst_len) { int ret; - struct mdp_blit_req splitreq; - int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1; - int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1; - splitreq = *req; - - /* break dest roi at width*/ - d_y_0 = d_y_1 = req->dst_rect.y; - d_h_0 = d_h_1 = req->dst_rect.h; - d_x_0 = req->dst_rect.x; - if (req->dst_rect.w % 32 == 6) - d_w_1 = req->dst_rect.w / 2 - 1; - else if (req->dst_rect.w % 2 == 0) - d_w_1 = req->dst_rect.w / 2; - else if (req->dst_rect.w % 32 == 3) - d_w_1 = (req->dst_rect.w - 3) / 2 - 1; - else - d_w_1 = (req->dst_rect.w - 1) / 2 - 1; - d_w_0 = req->dst_rect.w - d_w_1; - d_x_1 = d_x_0 + d_w_0; - if (req->dst_rect.w == 3) { - d_w_1 = 2; - d_w_0 = 2; - d_x_1 = d_x_0 + 1; + mdp->enable_irq(mdp, DL0_ROI_DONE); + ret = process_blit(mdp, req, src_file, src_start, src_len, + dst_file, dst_start, dst_len); + if (unlikely(ret)) { + mdp->disable_irq(mdp, DL0_ROI_DONE); + return ret; } - - /* break src roi at height or width*/ - if (splitreq.flags & MDP_ROT_90) { - s_x_0 = s_x_1 = req->src_rect.x; - s_w_0 = s_w_1 = req->src_rect.w; - s_y_0 = req->src_rect.y; - s_h_1 = (req->src_rect.h * d_w_1) / req->dst_rect.w; - s_h_0 = req->src_rect.h - s_h_1; - s_y_1 = s_y_0 + s_h_0; - if (d_w_1 >= 8 * s_h_1) { - s_h_1++; - s_y_1--; - } - } else { - s_y_0 = s_y_1 = req->src_rect.y; - s_h_0 = s_h_1 = req->src_rect.h; - s_x_0 = req->src_rect.x; - s_w_1 = (req->src_rect.w * d_w_1) / req->dst_rect.w; - s_w_0 = req->src_rect.w - s_w_1; - s_x_1 = s_x_0 + s_w_0; - if (d_w_1 >= 8 * s_w_1) { - s_w_1++; - s_x_1--; - } + ret = mdp_ppp_wait(mdp); + if (unlikely(ret)) { + printk(KERN_ERR "%s: failed!\n", __func__); + pr_err("original request:\n"); + dump_req(mdp->req, src_start, src_len, dst_start, dst_len); + pr_err("dead request:\n"); + dump_req(req, src_start, src_len, dst_start, dst_len); + BUG(); + return ret; } + return 0; +} - /* blit first region */ - if (((splitreq.flags & MDP_ROT_MASK) == MDP_ROT_270) || - ((splitreq.flags & MDP_ROT_MASK) == 0x0)) { - splitreq.src_rect.h = s_h_0; - splitreq.src_rect.y = s_y_0; - splitreq.dst_rect.h = d_h_0; - splitreq.dst_rect.y = d_y_0; - splitreq.src_rect.x = s_x_0; - splitreq.src_rect.w = s_w_0; - splitreq.dst_rect.x = d_x_0; - splitreq.dst_rect.w = d_w_0; - } else { - splitreq.src_rect.h = s_h_0; - splitreq.src_rect.y = s_y_0; - splitreq.dst_rect.h = d_h_1; - splitreq.dst_rect.y = d_y_1; - splitreq.src_rect.x = s_x_0; - splitreq.src_rect.w = s_w_0; - splitreq.dst_rect.x = d_x_1; - splitreq.dst_rect.w = d_w_1; - } +int mdp_ppp_blit(struct mdp_info *mdp, struct fb_info *fb, + struct mdp_blit_req *req) +{ + int ret; + unsigned long src_start = 0, src_len = 0, dst_start = 0, dst_len = 0; + struct file *src_file = 0, *dst_file = 0; - if (unlikely((splitreq.dst_rect.h != 1) && - ((splitreq.dst_rect.h % 32 == 3) || - (splitreq.dst_rect.h % 32) == 1))) - ret = mdp_ppp_blit_split_height(mdp, &splitreq, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); - else - ret = mdp_blit_and_wait(mdp, &splitreq, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); + ret = mdp_ppp_validate_blit(mdp, req); if (ret) return ret; - /* blit second region */ - if (((splitreq.flags & MDP_ROT_MASK) == MDP_ROT_270) || - ((splitreq.flags & MDP_ROT_MASK) == 0x0)) { - splitreq.src_rect.h = s_h_1; - splitreq.src_rect.y = s_y_1; - splitreq.dst_rect.h = d_h_1; - splitreq.dst_rect.y = d_y_1; - splitreq.src_rect.x = s_x_1; - splitreq.src_rect.w = s_w_1; - splitreq.dst_rect.x = d_x_1; - splitreq.dst_rect.w = d_w_1; - } else { - splitreq.src_rect.h = s_h_1; - splitreq.src_rect.y = s_y_1; - splitreq.dst_rect.h = d_h_0; - splitreq.dst_rect.y = d_y_0; - splitreq.src_rect.x = s_x_1; - splitreq.src_rect.w = s_w_1; - splitreq.dst_rect.x = d_x_0; - splitreq.dst_rect.w = d_w_0; + /* do this first so that if this fails, the caller can always + * safely call put_img */ + if (unlikely(get_img(&req->src, fb, &src_start, &src_len, &src_file))) { + printk(KERN_ERR "mdp_ppp: could not retrieve src image from " + "memory\n"); + return -EINVAL; } - if (unlikely((splitreq.dst_rect.h != 1) && - ((splitreq.dst_rect.h % 32 == 3) || - (splitreq.dst_rect.h % 32) == 1))) - ret = mdp_ppp_blit_split_height(mdp, &splitreq, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); - else - ret = mdp_blit_and_wait(mdp, &splitreq, - src_file, src_start, src_len, - dst_file, dst_start, dst_len); + if (unlikely(get_img(&req->dst, fb, &dst_start, &dst_len, &dst_file))) { + printk(KERN_ERR "mdp_ppp: could not retrieve dst image from " + "memory\n"); + put_img(src_file); + return -EINVAL; + } + mutex_lock(&mdp_mutex); + + /* transp_masking unimplemented */ + req->transp_mask = MDP_TRANSP_NOP; + mdp->req = req; + + ret = mdp_ppp_do_blit(mdp, req, src_file, src_start, src_len, + dst_file, dst_start, dst_len); + + put_img(src_file); + put_img(dst_file); + mutex_unlock(&mdp_mutex); return ret; -} \ No newline at end of file +} + +void mdp_ppp_handle_isr(struct mdp_info *mdp, uint32_t mask) +{ + if (mask & DL0_ROI_DONE) + wake_up(&mdp_ppp_waitqueue); +} + + diff --git a/drivers/video/msm/mdp_ppp.h b/drivers/video/msm/mdp_ppp.h index 357a7f06..03a15068 100644 --- a/drivers/video/msm/mdp_ppp.h +++ b/drivers/video/msm/mdp_ppp.h @@ -16,7 +16,6 @@ #define _VIDEO_MSM_MDP_PPP_H_ #include -#define PPP_DUMP_BLITS 0 struct ppp_regs { uint32_t src0; @@ -63,40 +62,57 @@ struct ppp_regs { struct mdp_info; struct mdp_rect; struct mdp_blit_req; +struct fb_info; -void mdp_ppp_init_scale(const struct mdp_info *mdp); -int mdp_ppp_cfg_scale(const struct mdp_info *mdp, struct ppp_regs *regs, - struct mdp_rect *src_rect, struct mdp_rect *dst_rect, - uint32_t src_format, uint32_t dst_format); -int mdp_ppp_load_blur(const struct mdp_info *mdp); -void mdp_dump_blit(struct mdp_blit_req *req); - - -#if defined(CONFIG_MSM_MDP31) || defined(CONFIG_MSM_MDP302) -int mdp_ppp_blit_split_width(struct mdp_info *mdp, const struct mdp_blit_req *req, - struct file *src_file, unsigned long src_start, unsigned long src_len, - struct file *dst_file, unsigned long dst_start, unsigned long dst_len); -int mdp_ppp_blit_split_height(struct mdp_info *mdp, const struct mdp_blit_req *req, - struct file *src_file, unsigned long src_start, unsigned long src_len, - struct file *dst_file, unsigned long dst_start, unsigned long dst_len); - -#if defined(CONFIG_MSM_MDP302) -int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs); -#else -static inline int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, - struct ppp_regs *regs) -{ - return 0; -} -#endif - -#else -int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs); -#endif - +#ifdef CONFIG_FB_MSM_MDP_PPP int mdp_get_bytes_per_pixel(int format); -int mdp_blit_and_wait(struct mdp_info *mdp, struct mdp_blit_req *req, - struct file *src_file, unsigned long src_start, unsigned long src_len, - struct file *dst_file, unsigned long dst_start, unsigned long dst_len); +int mdp_ppp_blit(struct mdp_info *mdp, struct fb_info *fb, + struct mdp_blit_req *req); +void mdp_ppp_handle_isr(struct mdp_info *mdp, uint32_t mask); +int mdp_ppp_blit_and_wait(struct mdp_info *mdp, struct mdp_blit_req *req, + struct file *src_file, unsigned long src_start, + unsigned long src_len, struct file *dst_file, + unsigned long dst_start, unsigned long dst_len); + +/* these must be provided by h/w specific ppp files */ +void mdp_ppp_init_scale(struct mdp_info *mdp); +int mdp_ppp_cfg_scale(struct mdp_info *mdp, struct ppp_regs *regs, + struct mdp_rect *src_rect, struct mdp_rect *dst_rect, + uint32_t src_format, uint32_t dst_format); +int mdp_ppp_load_blur(struct mdp_info *mdp); +int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs); +int mdp_ppp_validate_blit(struct mdp_info *mdp, struct mdp_blit_req *req); +int mdp_ppp_do_blit(struct mdp_info *mdp, struct mdp_blit_req *req, + struct file *src_file, unsigned long src_start, + unsigned long src_len, struct file *dst_file, + unsigned long dst_start, unsigned long dst_len); + +#else + +static inline int mdp_get_bytes_per_pixel(int format) { return -1; } +static inline int mdp_ppp_blit(struct mdp_info *mdp, struct fb_info *fb, + struct mdp_blit_req *req) { return -EINVAL; } +static inline void mdp_ppp_handle_isr(struct mdp_info *mdp, uint32_t mask) {} +static inline int mdp_ppp_blit_and_wait(struct mdp_info *mdp, + struct mdp_blit_req *req, struct file *src_file, + unsigned long src_start, unsigned long src_len, + struct file *dst_file, unsigned long dst_start, + unsigned long dst_len) { return 0; } + +static inline void mdp_ppp_init_scale(struct mdp_info *mdp) {} +static inline int mdp_ppp_cfg_scale(struct mdp_info *mdp, struct ppp_regs *regs, + struct mdp_rect *src_rect, struct mdp_rect *dst_rect, + uint32_t src_format, uint32_t dst_format) { return 0; } +static inline int mdp_ppp_load_blur(struct mdp_info *mdp) { return 0; } +static inline int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs) { return 0; } +static inline int mdp_ppp_validate_blit(struct mdp_info *mdp, struct mdp_blit_req *req) { return -EINVAL; } +static inline int mdp_ppp_do_blit(struct mdp_info *mdp, + struct mdp_blit_req *req, + struct file *src_file, unsigned long src_start, + unsigned long src_len, struct file *dst_file, + unsigned long dst_start, unsigned long dst_len) { return 0; } + + +#endif /* CONFIG_FB_MSM_MDP_PPP */ #endif /* _VIDEO_MSM_MDP_PPP_H_ */ diff --git a/drivers/video/msm/mdp_ppp22.c b/drivers/video/msm/mdp_ppp22.c index 02fca9a3..dc4cc279 100644 --- a/drivers/video/msm/mdp_ppp22.c +++ b/drivers/video/msm/mdp_ppp22.c @@ -1016,7 +1016,7 @@ static int scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t origin, return 0; } -int mdp_ppp_cfg_scale(const struct mdp_info *mdp, struct ppp_regs *regs, +int mdp_ppp_cfg_scale(struct mdp_info *mdp, struct ppp_regs *regs, struct mdp_rect *src_rect, struct mdp_rect *dst_rect, uint32_t src_format, uint32_t dst_format) { @@ -1070,7 +1070,7 @@ int mdp_ppp_cfg_scale(const struct mdp_info *mdp, struct ppp_regs *regs, } -int mdp_ppp_load_blur(const struct mdp_info *mdp) +int mdp_ppp_load_blur(struct mdp_info *mdp) { if (!(downscale_x_table == MDP_DOWNSCALE_BLUR && downscale_y_table == MDP_DOWNSCALE_BLUR)) { @@ -1082,10 +1082,64 @@ int mdp_ppp_load_blur(const struct mdp_info *mdp) return 0; } -void mdp_ppp_init_scale(const struct mdp_info *mdp) +void mdp_ppp_init_scale(struct mdp_info *mdp) { downscale_x_table = MDP_DOWNSCALE_MAX; downscale_y_table = MDP_DOWNSCALE_MAX; load_table(mdp, mdp_upscale_table, ARRAY_SIZE(mdp_upscale_table)); } + +int mdp_ppp_validate_blit(struct mdp_info *mdp, struct mdp_blit_req *req) +{ + /* WORKAROUND FOR HARDWARE BUG IN BG TILE FETCH */ + if (unlikely(req->src_rect.h == 0 || + req->src_rect.w == 0)) { + pr_info("mdp_ppp: src img of zero size!\n"); + return -EINVAL; + } + if (unlikely(req->dst_rect.h == 0 || + req->dst_rect.w == 0)) + return -EINVAL; + + return 0; +} + +int mdp_ppp_do_blit(struct mdp_info *mdp, struct mdp_blit_req *req, + struct file *src_file, unsigned long src_start, + unsigned long src_len, struct file *dst_file, + unsigned long dst_start, unsigned long dst_len) +{ + int ret; + + if (unlikely((req->transp_mask != MDP_TRANSP_NOP || + req->alpha != MDP_ALPHA_NOP || + HAS_ALPHA(req->src.format)) && + (req->flags & MDP_ROT_90 && + req->dst_rect.w <= 16 && req->dst_rect.h >= 16))) { + int i; + unsigned int tiles = req->dst_rect.h / 16; + unsigned int remainder = req->dst_rect.h % 16; + req->src_rect.w = 16*req->src_rect.w / req->dst_rect.h; + req->dst_rect.h = 16; + for (i = 0; i < tiles; i++) { + ret = mdp_ppp_blit_and_wait(mdp, req, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); + if (ret) + goto end; + req->dst_rect.y += 16; + req->src_rect.x += req->src_rect.w; + } + if (!remainder) + goto end; + req->src_rect.w = remainder*req->src_rect.w / req->dst_rect.h; + req->dst_rect.h = remainder; + } + + ret = mdp_ppp_blit_and_wait(mdp, req, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); +end: + return ret; +} diff --git a/drivers/video/msm/mdp_ppp31.c b/drivers/video/msm/mdp_ppp31.c index cc7b513c..fa36002e 100644 --- a/drivers/video/msm/mdp_ppp31.c +++ b/drivers/video/msm/mdp_ppp31.c @@ -276,7 +276,7 @@ static int scale_idx(int factor) return idx; } -int mdp_ppp_cfg_scale(const struct mdp_info *mdp, struct ppp_regs *regs, +int mdp_ppp_cfg_scale(struct mdp_info *mdp, struct ppp_regs *regs, struct mdp_rect *src_rect, struct mdp_rect *dst_rect, uint32_t src_format, uint32_t dst_format) { @@ -319,16 +319,319 @@ int mdp_ppp_cfg_scale(const struct mdp_info *mdp, struct ppp_regs *regs, return 0; } -int mdp_ppp_load_blur(const struct mdp_info *mdp) +int mdp_ppp_load_blur(struct mdp_info *mdp) { return -ENOTSUPP; } -void mdp_ppp_init_scale(const struct mdp_info *mdp) +int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs) +{ + return 0; +} + +void mdp_ppp_init_scale(struct mdp_info *mdp) { int scale; for (scale = 0; scale < MDP_SCALE_MAX; ++scale) load_table(mdp, scale, 0); } +/* Splits a blit into two horizontal stripes. Used to work around MDP bugs */ +static int blit_split_height(struct mdp_info *mdp, const struct mdp_blit_req *req, + struct file *src_file, unsigned long src_start, unsigned long src_len, + struct file *dst_file, unsigned long dst_start, unsigned long dst_len) +{ + int ret; + struct mdp_blit_req splitreq; + int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1; + int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1; + splitreq = *req; + /* break dest roi at height*/ + d_x_0 = d_x_1 = req->dst_rect.x; + d_w_0 = d_w_1 = req->dst_rect.w; + d_y_0 = req->dst_rect.y; + if (req->dst_rect.h % 32 == 3) + d_h_1 = (req->dst_rect.h - 3) / 2 - 1; + else + d_h_1 = (req->dst_rect.h - 1) / 2 - 1; + d_h_0 = req->dst_rect.h - d_h_1; + d_y_1 = d_y_0 + d_h_0; + if (req->dst_rect.h == 3) { + d_h_1 = 2; + d_h_0 = 2; + d_y_1 = d_y_0 + 1; + } + /* break source roi */ + if (splitreq.flags & MDP_ROT_90) { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_h_1) / req->dst_rect.h; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_h_1 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } else { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_h_1) / req->dst_rect.h; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_h_1 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } + + /* blit first region */ + if (((splitreq.flags & 0x07) == MDP_ROT_90) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } else { + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } + ret = mdp_ppp_blit_and_wait(mdp, &splitreq, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); + if (ret) + return ret; + + /* blit second region */ + if (((splitreq.flags & 0x07) == MDP_ROT_90) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } else { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } + ret = mdp_ppp_blit_and_wait(mdp, &splitreq, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); + return ret; +} + +/* Splits a blit into two vertical stripes. Used to work around MDP bugs */ +static int blit_split_width(struct mdp_info *mdp, const struct mdp_blit_req *req, + struct file *src_file, unsigned long src_start, unsigned long src_len, + struct file *dst_file, unsigned long dst_start, unsigned long dst_len) +{ + int ret; + struct mdp_blit_req splitreq; + int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1; + int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1; + splitreq = *req; + + /* break dest roi at width*/ + d_y_0 = d_y_1 = req->dst_rect.y; + d_h_0 = d_h_1 = req->dst_rect.h; + d_x_0 = req->dst_rect.x; + if (req->dst_rect.w % 32 == 6) + d_w_1 = req->dst_rect.w / 2 - 1; + else if (req->dst_rect.w % 2 == 0) + d_w_1 = req->dst_rect.w / 2; + else if (req->dst_rect.w % 32 == 3) + d_w_1 = (req->dst_rect.w - 3) / 2 - 1; + else + d_w_1 = (req->dst_rect.w - 1) / 2 - 1; + d_w_0 = req->dst_rect.w - d_w_1; + d_x_1 = d_x_0 + d_w_0; + if (req->dst_rect.w == 3) { + d_w_1 = 2; + d_w_0 = 2; + d_x_1 = d_x_0 + 1; + } + + /* break src roi at height or width*/ + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_1) / req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_1 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_1) / req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_1 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + + /* blit first region */ + if (((splitreq.flags & 0x07) == MDP_ROT_270) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } else { + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } + + if (unlikely((splitreq.dst_rect.h != 1) && + ((splitreq.dst_rect.h % 32 == 3) || + (splitreq.dst_rect.h % 32) == 1))) + ret = blit_split_height(mdp, &splitreq, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); + else + ret = mdp_ppp_blit_and_wait(mdp, &splitreq, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); + if (ret) + return ret; + + /* blit second region */ + if (((splitreq.flags & 0x07) == MDP_ROT_270) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } else { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } + + if (unlikely((splitreq.dst_rect.h != 1) && + ((splitreq.dst_rect.h % 32 == 3) || + (splitreq.dst_rect.h % 32) == 1))) + ret = blit_split_height(mdp, &splitreq, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); + else + ret = mdp_ppp_blit_and_wait(mdp, &splitreq, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); + return ret; +} + + +int mdp_ppp_validate_blit(struct mdp_info *mdp, struct mdp_blit_req *req) +{ + if (req->flags & MDP_ROT_90) { + if (unlikely(((req->dst_rect.h == 1) && + ((req->src_rect.w != 1) || + (req->dst_rect.w != req->src_rect.h))) || + ((req->dst_rect.w == 1) && ((req->src_rect.h != 1) || + (req->dst_rect.h != req->src_rect.w))))) { + pr_err("mpd_ppp: error scaling when size is 1!\n"); + return -EINVAL; + } + } else { + if (unlikely(((req->dst_rect.w == 1) && + ((req->src_rect.w != 1) || + (req->dst_rect.h != req->src_rect.h))) || + ((req->dst_rect.h == 1) && ((req->src_rect.h != 1) || + (req->dst_rect.h != req->src_rect.h))))) { + pr_err("mpd_ppp: error scaling when size is 1!\n"); + return -EINVAL; + } + } + + /* WORKAROUND FOR HARDWARE BUG IN BG TILE FETCH */ + if (unlikely(req->src_rect.h == 0 || + req->src_rect.w == 0)) { + pr_info("mdp_ppp: src img of zero size!\n"); + return -EINVAL; + } + if (unlikely(req->dst_rect.h == 0 || + req->dst_rect.w == 0)) + return -EINVAL; + + return 0; +} + +int mdp_ppp_do_blit(struct mdp_info *mdp, struct mdp_blit_req *req, + struct file *src_file, unsigned long src_start, + unsigned long src_len, struct file *dst_file, + unsigned long dst_start, unsigned long dst_len) +{ + int ret; + + /* Workarounds for MDP 3.1 hardware bugs */ + if (unlikely((mdp_get_bytes_per_pixel(req->dst.format) == 4) && + (req->dst_rect.w != 1) && + (((req->dst_rect.w % 8) == 6) || + ((req->dst_rect.w % 32) == 3) || + ((req->dst_rect.w % 32) == 1)))) { + ret = blit_split_width(mdp, req, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); + goto end; + } else if (unlikely((req->dst_rect.w != 1) && (req->dst_rect.h != 1) && + ((req->dst_rect.h % 32) == 3 || + (req->dst_rect.h % 32) == 1))) { + ret = blit_split_height(mdp, req, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); + goto end; + } + + ret = mdp_ppp_blit_and_wait(mdp, req, + src_file, src_start, src_len, + dst_file, dst_start, dst_len); +end: + return ret; +} diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c index aa27389d..82e110ce 100644 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -33,11 +33,17 @@ #include #include #include +#include "mdp_hw.h" extern void start_drawing_late_resume(struct early_suspend *h); static void msmfb_resume_handler(struct early_suspend *h); static void msmfb_resume(struct work_struct *work); +#ifdef CONFIG_MSM_HDMI +void hdmi_DoBlit(int offset); +int hdmi_usePanelSync(void); +#endif + #define MSMFB_DEBUG 1 #ifdef CONFIG_FB_MSM_LOGO #define INIT_IMAGE_FILE "/logo.rle" @@ -59,6 +65,11 @@ extern int load_565rle_image(char *filename); #define BLIT_TIME 0x4 #define SHOW_UPDATES 0x8 +#ifdef CONFIG_PANEL_SELF_REFRESH +extern struct panel_icm_info *panel_icm; +extern wait_queue_head_t panel_update_wait_queue; +#endif + #define DLOG(mask, fmt, args...) \ do { \ if ((msmfb_debug_mask | SUSPEND_RESUME) & mask) \ @@ -72,6 +83,7 @@ module_param_named(msmfb_debug_mask, msmfb_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); struct mdp_device *mdp; +static atomic_t mdpclk_on = ATOMIC_INIT(1); struct msmfb_info { struct fb_info *fb; @@ -91,9 +103,13 @@ struct msmfb_info { int ebottom; /* exclusive */ } update_info; char *black; - +#ifdef CONFIG_HTC_ONMODE_CHARGING + struct early_suspend onchg_earlier_suspend; + struct early_suspend onchg_suspend; +#endif struct early_suspend earlier_suspend; struct early_suspend early_suspend; + struct wake_lock idle_lock; spinlock_t update_lock; struct mutex panel_init_lock; @@ -166,7 +182,7 @@ static int msmfb_release(struct fb_info *info, int user) /* Called from dma interrupt handler, must not sleep */ static void msmfb_handle_dma_interrupt(struct msmfb_callback *callback) { - unsigned long irq_flags; + unsigned long irq_flags=0; struct msmfb_info *msmfb = container_of(callback, struct msmfb_info, dma_callback); #if PRINT_FPS @@ -178,6 +194,7 @@ static void msmfb_handle_dma_interrupt(struct msmfb_callback *callback) spin_lock_irqsave(&msmfb->update_lock, irq_flags); msmfb->frame_done = msmfb->frame_requested; + if (msmfb->sleeping == UPDATING && msmfb->frame_done == msmfb->update_frame) { DLOG(SUSPEND_RESUME, "full update completed\n"); @@ -203,7 +220,7 @@ static int msmfb_start_dma(struct msmfb_info *msmfb) { uint32_t x, y, w, h; unsigned addr; - unsigned long irq_flags; + unsigned long irq_flags=0; uint32_t yoffset; s64 time_since_request; struct msm_panel_data *panel = msmfb->panel; @@ -230,11 +247,13 @@ static int msmfb_start_dma(struct msmfb_info *msmfb) y = msmfb->update_info.top; w = msmfb->update_info.eright - x; h = msmfb->update_info.ebottom - y; - +#if 0 /* zeusk: */ +;;;;;;ASD #if defined(CONFIG_FRAMEBUFFER_CONSOLE) x = 0; y = 0; w = msmfb->xres; h = msmfb->yres; #endif - +ASD;;;;;; +#endif yoffset = msmfb->yoffset; msmfb->update_info.left = msmfb->xres + 1; msmfb->update_info.top = msmfb->yres + 1; @@ -287,7 +306,10 @@ static void msmfb_pan_update(struct fb_info *info, uint32_t left, uint32_t top, { struct msmfb_info *msmfb = info->par; struct msm_panel_data *panel = msmfb->panel; - unsigned long irq_flags; +#ifdef CONFIG_PANEL_SELF_REFRESH + struct mdp_lcdc_info *lcdc = panel_to_lcdc(panel); +#endif + unsigned long irq_flags=0; int sleeping; int retry = 1; #if PRINT_FPS @@ -300,16 +322,21 @@ static void msmfb_pan_update(struct fb_info *info, uint32_t left, uint32_t top, DLOG(SHOW_UPDATES, "update %d %d %d %d %d %d\n", left, top, eright, ebottom, yoffset, pan_display); -#if !defined(CONFIG_MACH_HTCLEO) - // For some reason we need to remove it here, state is 1, we have to look later to this problem - if (msmfb->sleeping != AWAKE) - DLOG(SUSPEND_RESUME, "pan_update in state(%d)\n", msmfb->sleeping); +#ifdef CONFIG_PANEL_SELF_REFRESH + if (lcdc->mdp->mdp_dev.overrides & MSM_MDP_RGB_PANEL_SELE_REFRESH) { + spin_lock_irqsave(&panel_icm->lock, irq_flags); + panel_icm->panel_update = 1; + spin_unlock_irqrestore(&panel_icm->lock, irq_flags); + wake_up(&panel_update_wait_queue); + } #endif #if (defined(CONFIG_USB_FUNCTION_PROJECTOR) || defined(CONFIG_USB_ANDROID_PROJECTOR)) /* Jay, 8/1/09' */ msmfb_set_var(msmfb->fb->screen_base, yoffset); #endif + if (msmfb->sleeping != AWAKE) + DLOG(SUSPEND_RESUME, "pan_update in state(%d)\n", msmfb->sleeping); restart: spin_lock_irqsave(&msmfb->update_lock, irq_flags); @@ -401,19 +428,35 @@ restart: msmfb->yoffset); spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - /* if the panel is all the way on wait for vsync, otherwise sleep - * for 16 ms (long enough for the dma to panel) and then begin dma */ - msmfb->vsync_request_time = ktime_get(); - if (panel->request_vsync && (sleeping == AWAKE)) { - wake_lock_timeout(&msmfb->idle_lock, HZ/4); - panel->request_vsync(panel, &msmfb->vsync_callback); - } else { - if (!hrtimer_active(&msmfb->fake_vsync)) { - hrtimer_start(&msmfb->fake_vsync, - ktime_set(0, NSEC_PER_SEC/60), - HRTIMER_MODE_REL); - } - } +#ifdef CONFIG_MSM_HDMI + if (!hdmi_usePanelSync()) + { + msmfb->vsync_request_time = ktime_get(); + msmfb_start_dma(msmfb); + } + else + { +#endif + /* if the panel is all the way on wait for vsync, otherwise sleep + * for 16 ms (long enough for the dma to panel) and then begin dma */ + msmfb->vsync_request_time = ktime_get(); + if (panel->request_vsync && (sleeping == AWAKE)) { + wake_lock_timeout(&msmfb->idle_lock, HZ/4); + panel->request_vsync(panel, &msmfb->vsync_callback); + } else { + if (!hrtimer_active(&msmfb->fake_vsync)) { + hrtimer_start(&msmfb->fake_vsync, + ktime_set(0, NSEC_PER_SEC/60), + HRTIMER_MODE_REL); + } + } +#ifdef CONFIG_MSM_HDMI + } + + /* We did the DMA, now blit the data to the other display */ + hdmi_DoBlit(msmfb->xres * msmfb->yoffset * BYTES_PER_PIXEL(msmfb)); +#endif + return; } static void msmfb_update(struct fb_info *info, uint32_t left, uint32_t top, @@ -427,7 +470,7 @@ static void power_on_panel(struct work_struct *work) struct msmfb_info *msmfb = container_of(work, struct msmfb_info, resume_work); struct msm_panel_data *panel = msmfb->panel; - unsigned long irq_flags; + unsigned long irq_flags=0; mutex_lock(&msmfb->panel_init_lock); DLOG(SUSPEND_RESUME, "turning on panel\n"); if (msmfb->sleeping == UPDATING) { @@ -447,34 +490,33 @@ error: mutex_unlock(&msmfb->panel_init_lock); } -static BLOCKING_NOTIFIER_HEAD(display_chain_head); -int register_display_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&display_chain_head, nb); -} -static int display_notifier_callback(struct notifier_block *nfb, - unsigned long action, - void *ignored) -{ - struct msmfb_info *msm_fb = (struct msmfb_info *)ignored; - +static BLOCKING_NOTIFIER_HEAD(display_chain_head); +int register_display_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&display_chain_head, nb); +} +static int display_notifier_callback(struct notifier_block *nfb, + unsigned long action, + void *ignored) +{ + //struct msmfb_info *msm_fb = (struct msmfb_info *)ignored; + switch (action) { case NOTIFY_MSM_FB: - printk(KERN_DEBUG "NOTIFY_MSM_FB\n"); - msmfb_resume(&msm_fb->early_suspend); - break; + printk(KERN_DEBUG "NOTIFY_MSM_FB\n"); + //msmfb_resume(&msm_fb->early_suspend); + break; case NOTIFY_POWER: - /* nothing to do */ - break; + /* nothing to do */ + break; default: - printk(KERN_ERR "%s: unknown action in 0x%lx\n", - __func__, action); - return NOTIFY_BAD; + printk(KERN_ERR "%s: unknown action in 0x%lx\n", + __func__, action); + return NOTIFY_BAD; } return NOTIFY_OK; -} +} -/* -------------------------------------------------------------------------- */ #ifdef CONFIG_HAS_EARLYSUSPEND /* turn off the panel */ static void msmfb_earlier_suspend(struct early_suspend *h) @@ -482,7 +524,7 @@ static void msmfb_earlier_suspend(struct early_suspend *h) struct msmfb_info *msmfb = container_of(h, struct msmfb_info, earlier_suspend); struct msm_panel_data *panel = msmfb->panel; - unsigned long irq_flags; + unsigned long irq_flags=0; mutex_lock(&msmfb->panel_init_lock); msmfb->sleeping = SLEEPING; @@ -513,6 +555,8 @@ static void msmfb_suspend(struct early_suspend *h) overlay_event.event_wait, (overlay_event.waked_up == ~USE_OVERLAY), 10*HZ); + /*wait until USE_OVERLAY flag is off and set mdpclk_on as off*/ + atomic_set(&mdpclk_on, 0); pr_info("wait event : %X\n", overlay_event.waked_up); #endif panel->suspend(panel); @@ -523,17 +567,81 @@ static void msmfb_suspend(struct early_suspend *h) static void msmfb_resume_handler(struct early_suspend *h) { struct msmfb_info *msmfb = container_of(h, struct msmfb_info, - early_suspend); + early_suspend); +#ifdef CONFIG_HTC_ONMODE_CHARGING + if (msmfb->fb_resumed == 1) { + DLOG(SUSPEND_RESUME, "fb is resumed by onchg. skip resume\n"); + return; + } +#endif queue_work(msmfb->resume_workqueue, &msmfb->msmfb_resume_work); wait_event_interruptible_timeout(msmfb->frame_wq, msmfb->fb_resumed==1,HZ/2); } +#ifdef CONFIG_HTC_ONMODE_CHARGING +static void msmfb_onchg_earlier_suspend(struct early_suspend *h) +{ + struct msmfb_info *msmfb = container_of(h, struct msmfb_info, + onchg_earlier_suspend); + + struct msm_panel_data *panel = msmfb->panel; + unsigned long irq_flags=0; + + mutex_lock(&msmfb->panel_init_lock); + msmfb->sleeping = SLEEPING; + wake_up(&msmfb->frame_wq); + spin_lock_irqsave(&msmfb->update_lock, irq_flags); + spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); + +#ifndef CONFIG_MSM_MDP40 + mdp->dma(mdp, virt_to_phys(msmfb->black), 0, + msmfb->fb->var.xres, msmfb->fb->var.yres, 0, 0, + NULL, panel->interface_type); + mdp->dma_wait(mdp, panel->interface_type); +#endif + wait_event_timeout(msmfb->frame_wq, + msmfb->frame_requested == msmfb->frame_done, HZ/10); + + /* turn off the panel */ + panel->blank(panel); +} + +static void msmfb_onchg_suspend(struct early_suspend *h) +{ + struct msmfb_info *msmfb = container_of(h, struct msmfb_info, + onchg_suspend); + struct msm_panel_data *panel = msmfb->panel; + /* suspend the panel */ +#ifdef CONFIG_FB_MSM_OVERLAY + /*check whether overlay done*/ + wait_event_interruptible_timeout( + overlay_event.event_wait, + (overlay_event.waked_up == ~USE_OVERLAY), + 10*HZ); + /*wait until USE_OVERLAY flag is off and set mdpclk_on as off*/ + atomic_set(&mdpclk_on, 0); + pr_info("wait event : %X\n", overlay_event.waked_up); +#endif + panel->suspend(panel); + msmfb->fb_resumed = 0; + mutex_unlock(&msmfb->panel_init_lock); +} + +static void msmfb_onchg_resume_handler(struct early_suspend *h) +{ + struct msmfb_info *msmfb = container_of(h, struct msmfb_info, + onchg_suspend); + queue_work(msmfb->resume_workqueue, &msmfb->msmfb_resume_work); + wait_event_interruptible_timeout(msmfb->frame_wq, msmfb->fb_resumed == 1, HZ/2); +} +#endif + static void msmfb_resume(struct work_struct *work) { struct msmfb_info *msmfb = container_of(work, struct msmfb_info, msmfb_resume_work); struct msm_panel_data *panel = msmfb->panel; - unsigned long irq_flags; + unsigned long irq_flags=0; if (panel->resume(panel)) { printk(KERN_INFO "msmfb: panel resume failed, not resuming " @@ -545,15 +653,16 @@ static void msmfb_resume(struct work_struct *work) msmfb->sleeping = WAKING; DLOG(SUSPEND_RESUME, "ready, waiting for full update\n"); spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - start_drawing_late_resume(NULL); msmfb->fb_resumed = 1; wake_up(&msmfb->frame_wq); + + atomic_set(&mdpclk_on, 1); } #endif static int msmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - u32 size; + uint32_t size; if ((var->xres != info->var.xres) || (var->yres != info->var.yres) || @@ -625,28 +734,22 @@ int msmfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) static void msmfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) { cfb_fillrect(p, rect); -#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) msmfb_update(p, rect->dx, rect->dy, rect->dx + rect->width, rect->dy + rect->height); -#endif } static void msmfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) { cfb_copyarea(p, area); -#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) msmfb_update(p, area->dx, area->dy, area->dx + area->width, area->dy + area->height); -#endif } static void msmfb_imageblit(struct fb_info *p, const struct fb_image *image) { cfb_imageblit(p, image); -#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) msmfb_update(p, image->dx, image->dy, image->dx + image->width, image->dy + image->height); -#endif } @@ -705,6 +808,7 @@ static int msmfb_overlay_set(struct fb_info *info, void __user *p) if (copy_from_user(&req, p, sizeof(req))) return -EFAULT; + printk(KERN_INFO "%s(%d) dst rect info w=%d h=%d x=%d y=%d rotator=%d\n", __func__, __LINE__, req.dst_rect.w, req.dst_rect.h, req.dst_rect.x, req.dst_rect.y, req.user_data[0]); ret = mdp->overlay_set(mdp, info, &req); if (ret) { printk(KERN_ERR "%s:ioctl failed \n", @@ -764,7 +868,7 @@ DEFINE_MUTEX(mdp_ppp_lock); static int msmfb_ioctl(struct fb_info *p, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; - int ret; + int ret = 0; #if PRINT_BLIT_TIME ktime_t t1, t2; #endif @@ -788,41 +892,41 @@ static int msmfb_ioctl(struct fb_info *p, unsigned int cmd, unsigned long arg) break; #ifdef CONFIG_FB_MSM_OVERLAY case MSMFB_OVERLAY_GET: - printk("CONFIG_FB_MSM_OVERLAY\n"); - //down(&mdp_ppp_lock); ret = msmfb_overlay_get(p, argp); - //up(&mdp_ppp_lock); break; case MSMFB_OVERLAY_SET: - printk("MSMFB_OVERLAY_SET\n"); - //down(&mdp_ppp_lock); - ret = msmfb_overlay_set(p, argp); - mutex_lock(&overlay_event_lock); - overlay_event.waked_up = USE_OVERLAY; - mutex_unlock(&overlay_event_lock); - //up(&mdp_ppp_lock); + if(!atomic_read(&mdpclk_on)) { + printk(KERN_ERR "MSMFB_OVERLAY_SET during suspend\n"); + ret = -EINVAL; + } else { + mutex_lock(&overlay_event_lock); + overlay_event.waked_up = USE_OVERLAY; + mutex_unlock(&overlay_event_lock); + ret = msmfb_overlay_set(p, argp); + } + printk(KERN_INFO "MSMFB_OVERLAY_SET ret=%d\n", ret); break; case MSMFB_OVERLAY_UNSET: - printk("MSMFB_OVERLAY_UNSET\n"); - //down(&mdp_ppp_lock); ret = msmfb_overlay_unset(p, argp); mutex_lock(&overlay_event_lock); overlay_event.waked_up = ~USE_OVERLAY; wake_up(&overlay_event.event_wait); mutex_unlock(&overlay_event_lock); - //up(&mdp_ppp_lock); + printk(KERN_INFO "MSMFB_OVERLAY_UNSET ret=%d\n", ret); break; case MSMFB_OVERLAY_PLAY: - //down(&mdp_ppp_lock); - ret = msmfb_overlay_play(p, argp); - //up(&mdp_ppp_lock); + if(!atomic_read(&mdpclk_on)) { + printk(KERN_ERR "MSMFB_OVERLAY_PLAY during suspend\n"); + ret = -EINVAL; + } else + ret = msmfb_overlay_play(p, argp); break; #endif default: printk(KERN_INFO "msmfb unknown ioctl: %d\n", cmd); return -EINVAL; } - return 0; + return ret; } static struct fb_ops msmfb_ops = { @@ -856,7 +960,7 @@ static ssize_t debug_read(struct file *file, char __user *buf, size_t count, static char buffer[4096]; int n = 0; struct msmfb_info *msmfb = (struct msmfb_info *)file->private_data; - unsigned long irq_flags; + unsigned long irq_flags=0; spin_lock_irqsave(&msmfb->update_lock, irq_flags); n = scnprintf(buffer, debug_bufmax, "yoffset %d\n", msmfb->yoffset); @@ -880,7 +984,7 @@ static struct file_operations debug_fops = { }; #endif -#define BITS_PER_PIXEL 16 +#define BITS_PER_PIXEL_DEF 32 static void setup_fb_info(struct msmfb_info *msmfb) { @@ -904,8 +1008,9 @@ static void setup_fb_info(struct msmfb_info *msmfb) fb_info->var.height = msmfb->panel->fb_data->height; fb_info->var.xres_virtual = msmfb->xres; fb_info->var.yres_virtual = msmfb->yres * 2; - fb_info->var.bits_per_pixel = BITS_PER_PIXEL; + fb_info->var.bits_per_pixel = BITS_PER_PIXEL_DEF; fb_info->var.accel_flags = 0; + fb_info->var.reserved[4] = 60; fb_info->var.yoffset = 0; @@ -938,6 +1043,7 @@ static void setup_fb_info(struct msmfb_info *msmfb) fb_info->var.blue.msb_right = 0; mdp->set_output_format(mdp, fb_info->var.bits_per_pixel); + mdp->set_panel_size(mdp, msmfb->xres, msmfb->yres); r = fb_alloc_cmap(&fb_info->cmap, 16, 0); fb_info->pseudo_palette = PP; @@ -1027,7 +1133,7 @@ static int msmfb_probe(struct platform_device *pdev) spin_lock_init(&msmfb->update_lock); mutex_init(&msmfb->panel_init_lock); init_waitqueue_head(&msmfb->frame_wq); - msmfb->resume_workqueue = create_rt_workqueue("panel_on"); + msmfb->resume_workqueue = create_workqueue("panel_on"); if (msmfb->resume_workqueue == NULL) { printk(KERN_ERR "failed to create panel_on workqueue\n"); ret = -ENOMEM; @@ -1049,6 +1155,16 @@ static int msmfb_probe(struct platform_device *pdev) msmfb->earlier_suspend.suspend = msmfb_earlier_suspend; msmfb->earlier_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; register_early_suspend(&msmfb->earlier_suspend); +#ifdef CONFIG_HTC_ONMODE_CHARGING + msmfb->onchg_suspend.suspend = msmfb_onchg_suspend; + msmfb->onchg_suspend.resume = msmfb_onchg_resume_handler; + msmfb->onchg_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; + register_onchg_suspend(&msmfb->onchg_suspend); + + msmfb->onchg_earlier_suspend.suspend = msmfb_onchg_earlier_suspend; + msmfb->onchg_earlier_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; + register_onchg_suspend(&msmfb->onchg_earlier_suspend); +#endif #endif #if MSMFB_DEBUG @@ -1082,10 +1198,10 @@ static int msmfb_probe(struct platform_device *pdev) #ifdef CONFIG_FB_MSM_LOGO if (!load_565rle_image(INIT_IMAGE_FILE)) { /* Flip buffer */ - msmfb->update_info.left = 0; + msmfb->update_info.left = 0; msmfb->update_info.top = 0; msmfb->update_info.eright = msmfb->xres; - msmfb->update_info.ebottom = msmfb->yres; + msmfb->update_info.ebottom = msmfb->yres; msmfb_pan_update(msmfb->fb, 0, 0, msmfb->xres, msmfb->yres, 0, 1); } diff --git a/include/linux/fb.h b/include/linux/fb.h index de9c722e..f4dc55ed 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -3,13 +3,31 @@ #include #include - struct dentry; /* Definitions of frame buffers */ #define FB_MAX 32 /* sufficient for now */ +struct fbcon_decor_iowrapper +{ + unsigned short vc; /* Virtual console */ + unsigned char origin; /* Point of origin of the request */ + void *data; +}; + +#ifdef __KERNEL__ +#ifdef CONFIG_COMPAT +#include +struct fbcon_decor_iowrapper32 +{ + unsigned short vc; /* Virtual console */ + unsigned char origin; /* Point of origin of the request */ + compat_uptr_t data; +}; +#endif /* CONFIG_COMPAT */ +#endif /* __KERNEL__ */ + /* ioctls 0x46 is 'F' */ #define FBIOGET_VSCREENINFO 0x4600 @@ -37,7 +55,24 @@ struct dentry; #define FBIOGET_HWCINFO 0x4616 #define FBIOPUT_MODEINFO 0x4617 #define FBIOGET_DISPINFO 0x4618 +#define FBIOCONDECOR_SETCFG _IOWR('F', 0x19, struct fbcon_decor_iowrapper) +#define FBIOCONDECOR_GETCFG _IOR('F', 0x1A, struct fbcon_decor_iowrapper) +#define FBIOCONDECOR_SETSTATE _IOWR('F', 0x1B, struct fbcon_decor_iowrapper) +#define FBIOCONDECOR_GETSTATE _IOR('F', 0x1C, struct fbcon_decor_iowrapper) +#define FBIOCONDECOR_SETPIC _IOWR('F', 0x1D, struct fbcon_decor_iowrapper) +#ifdef __KERNEL__ +#ifdef CONFIG_COMPAT +#define FBIOCONDECOR_SETCFG32 _IOWR('F', 0x19, struct fbcon_decor_iowrapper32) +#define FBIOCONDECOR_GETCFG32 _IOR('F', 0x1A, struct fbcon_decor_iowrapper32) +#define FBIOCONDECOR_SETSTATE32 _IOWR('F', 0x1B, struct fbcon_decor_iowrapper32) +#define FBIOCONDECOR_GETSTATE32 _IOR('F', 0x1C, struct fbcon_decor_iowrapper32) +#define FBIOCONDECOR_SETPIC32 _IOWR('F', 0x1D, struct fbcon_decor_iowrapper32) +#endif /* CONFIG_COMPAT */ +#endif /* __KERNEL__ */ +#define FBCON_DECOR_THEME_LEN 128 /* Maximum lenght of a theme name */ +#define FBCON_DECOR_IO_ORIG_KERNEL 0 /* Kernel ioctl origin */ +#define FBCON_DECOR_IO_ORIG_USER 1 /* User ioctl origin */ #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ @@ -282,6 +317,28 @@ struct fb_cmap { __u16 *transp; /* transparency, can be NULL */ }; +#ifdef __KERNEL__ +#ifdef CONFIG_COMPAT +struct fb_cmap32 { + __u32 start; + __u32 len; /* Number of entries */ + compat_uptr_t red; /* Red values */ + compat_uptr_t green; + compat_uptr_t blue; + compat_uptr_t transp; /* transparency, can be NULL */ +}; + +#define fb_cmap_from_compat(to, from) \ + (to).start = (from).start; \ + (to).len = (from).len; \ + (to).red = compat_ptr((from).red); \ + (to).green = compat_ptr((from).green); \ + (to).blue = compat_ptr((from).blue); \ + (to).transp = compat_ptr((from).transp) + +#endif /* CONFIG_COMPAT */ +#endif /* __KERNEL__ */ + struct fb_con2fbmap { __u32 console; __u32 framebuffer; @@ -363,6 +420,34 @@ struct fb_image { struct fb_cmap cmap; /* color map info */ }; +#ifdef __KERNEL__ +#ifdef CONFIG_COMPAT +struct fb_image32 { + __u32 dx; /* Where to place image */ + __u32 dy; + __u32 width; /* Size of image */ + __u32 height; + __u32 fg_color; /* Only used when a mono bitmap */ + __u32 bg_color; + __u8 depth; /* Depth of the image */ + const compat_uptr_t data; /* Pointer to image data */ + struct fb_cmap32 cmap; /* color map info */ +}; + +#define fb_image_from_compat(to, from) \ + (to).dx = (from).dx; \ + (to).dy = (from).dy; \ + (to).width = (from).width; \ + (to).height = (from).height; \ + (to).fg_color = (from).fg_color; \ + (to).bg_color = (from).bg_color; \ + (to).depth = (from).depth; \ + (to).data = compat_ptr((from).data); \ + fb_cmap_from_compat((to).cmap, (from).cmap) + +#endif /* CONFIG_COMPAT */ +#endif /* __KERNEL__ */ + /* * hardware cursor control */ @@ -403,6 +488,7 @@ struct fb_cursor { #include #include #include +#include #include struct vm_area_struct; @@ -543,6 +629,8 @@ struct fb_cursor_user { #define FB_EVENT_GET_REQ 0x0D /* Unbind from the console if possible */ #define FB_EVENT_FB_UNBIND 0x0E +/* CONSOLE-SPECIFIC: remap all consoles to new fb - for vga switcheroo */ +#define FB_EVENT_REMAP_ALL_CONSOLE 0x0F struct fb_event { struct fb_info *info; @@ -606,6 +694,12 @@ struct fb_deferred_io { * LOCKING NOTE: those functions must _ALL_ be called with the console * semaphore held, this is the only suitable locking mechanism we have * in 2.6. Some may be called at interrupt time at this point though. + * + * The exception to this is the debug related hooks. Putting the fb + * into a debug state (e.g. flipping to the kernel console) and restoring + * it must be done in a lock-free manner, so low level drivers should + * keep track of the initial console (if applicable) and may need to + * perform direct, unlocked hardware writes in these hooks. */ struct fb_ops { @@ -675,6 +769,10 @@ struct fb_ops { /* teardown any resources to do with this framebuffer */ void (*fb_destroy)(struct fb_info *info); + + /* called at KDB enter and leave time to prepare the console */ + int (*fb_debug_enter)(struct fb_info *info); + int (*fb_debug_leave)(struct fb_info *info); }; #ifdef CONFIG_FB_TILEBLITTING @@ -763,6 +861,7 @@ struct fb_tile_ops { * takes over; acceleration engine should be in a quiescent state */ /* hints */ +#define FBINFO_VIRTFB 0x0004 /* FB is System RAM, not device. */ #define FBINFO_PARTIAL_PAN_OK 0x0040 /* otw use pan only for double-buffering */ #define FBINFO_READS_FAST 0x0080 /* soft-copy faster than rendering */ @@ -784,8 +883,6 @@ struct fb_tile_ops { #define FBINFO_MISC_USEREVENT 0x10000 /* event request from userspace */ #define FBINFO_MISC_TILEBLITTING 0x20000 /* use tile blitting */ -#define FBINFO_MISC_FIRMWARE 0x40000 /* a replaceable firmware - inited framebuffer */ /* A driver may set this flag to indicate that it does want a set_par to be * called every time when fbcon_switch is executed. The advantage is that with @@ -799,6 +896,8 @@ struct fb_tile_ops { */ #define FBINFO_MISC_ALWAYS_SETPAR 0x40000 +/* where the fb is a firmware driver, and can be replaced with a proper one */ +#define FBINFO_MISC_FIRMWARE 0x80000 /* * Host and GPU endianness differ. */ @@ -810,6 +909,10 @@ struct fb_tile_ops { */ #define FBINFO_BE_MATH 0x100000 +/* report to the VT layer that this fb driver can accept forced console + output like oopses */ +#define FBINFO_CAN_FORCE_OUTPUT 0x200000 + struct fb_info { int node; int flags; @@ -854,15 +957,32 @@ struct fb_info { #define FBINFO_STATE_SUSPENDED 1 u32 state; /* Hardware state i.e suspend */ void *fbcon_par; /* fbcon use-only private area */ + + struct fb_image bgdecor; + /* From here on everything is device dependent */ void *par; /* we need the PCI or similiar aperture base/size not smem_start/size as smem_start may just be an object allocated inside the aperture so may not actually overlap */ - resource_size_t aperture_base; - resource_size_t aperture_size; + struct apertures_struct { + unsigned int count; + struct aperture { + resource_size_t base; + resource_size_t size; + } ranges[0]; + } *apertures; }; +static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { + struct apertures_struct *a = kzalloc(sizeof(struct apertures_struct) + + max_num * sizeof(struct aperture), GFP_KERNEL); + if (!a) + return NULL; + a->count = max_num; + return a; +} + #ifdef MODULE #define FBINFO_DEFAULT FBINFO_MODULE #else @@ -898,6 +1018,8 @@ struct fb_info { #define fb_writel sbus_writel #define fb_writeq sbus_writeq #define fb_memset sbus_memset_io +#define fb_memcpy_fromfb sbus_memcpy_fromio +#define fb_memcpy_tofb sbus_memcpy_toio #elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || defined(__avr32__) || defined(__bfin__) @@ -910,6 +1032,8 @@ struct fb_info { #define fb_writel __raw_writel #define fb_writeq __raw_writeq #define fb_memset memset_io +#define fb_memcpy_fromfb memcpy_fromio +#define fb_memcpy_tofb memcpy_toio #else @@ -922,6 +1046,8 @@ struct fb_info { #define fb_writel(b,addr) (*(volatile u32 *) (addr) = (b)) #define fb_writeq(b,addr) (*(volatile u64 *) (addr) = (b)) #define fb_memset memset +#define fb_memcpy_fromfb memcpy +#define fb_memcpy_tofb memcpy #endif @@ -955,6 +1081,8 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, /* drivers/video/fbmem.c */ extern int register_framebuffer(struct fb_info *fb_info); extern int unregister_framebuffer(struct fb_info *fb_info); +extern void remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary); extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); extern int fb_show_logo(struct fb_info *fb_info, int rotate); extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size); @@ -1052,6 +1180,8 @@ extern int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var); extern const unsigned char *fb_firmware_edid(struct device *device); extern void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs); +extern void fb_edid_add_monspecs(unsigned char *edid, + struct fb_monspecs *specs); extern void fb_destroy_modedb(struct fb_videomode *modedb); extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb); extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter); @@ -1082,6 +1212,7 @@ extern const struct fb_videomode *fb_find_best_display(const struct fb_monspecs /* drivers/video/fbcmap.c */ extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp); +extern int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags); extern void fb_dealloc_cmap(struct fb_cmap *cmap); extern int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to); extern int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to); diff --git a/include/linux/msm_audio_1550.h b/include/linux/msm_audio_1550.h new file mode 100644 index 00000000..35203c94 --- /dev/null +++ b/include/linux/msm_audio_1550.h @@ -0,0 +1,209 @@ +/* include/linux/msm_audio.h + * + * Copyright (C) 2008 Google, Inc. + * + * 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 __LINUX_MSM_AUDIO_H +#define __LINUX_MSM_AUDIO_H + +#include +#include +#include + +/* PCM Audio */ + +#define AUDIO_IOCTL_MAGIC 'a' + +#define AUDIO_ENABLE_AUDPRE _IOW(AUDIO_IOCTL_MAGIC, 11, unsigned) +#define AUDIO_SET_AGC _IOW(AUDIO_IOCTL_MAGIC, 12, unsigned) +#define AUDIO_SET_NS _IOW(AUDIO_IOCTL_MAGIC, 13, unsigned) +#define AUDIO_SET_TX_IIR _IOW(AUDIO_IOCTL_MAGIC, 14, unsigned) +#define AUDIO_PLAY_DTMF _IOW(AUDIO_IOCTL_MAGIC, 19, unsigned) + +#define AUDIO_START _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned) +#define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned) +#define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned) +#define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned) +#define AUDIO_SET_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned) +#define AUDIO_GET_STATS _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned) +#define AUDIO_ENABLE_AUDPP _IOW(AUDIO_IOCTL_MAGIC, 6, unsigned) +#define AUDIO_SET_ADRC _IOW(AUDIO_IOCTL_MAGIC, 7, unsigned) +#define AUDIO_SET_EQ _IOW(AUDIO_IOCTL_MAGIC, 8, unsigned) +#define AUDIO_SET_RX_IIR _IOW(AUDIO_IOCTL_MAGIC, 9, unsigned) +#define AUDIO_SET_VOLUME _IOW(AUDIO_IOCTL_MAGIC, 10, unsigned) +#define AUDIO_PAUSE _IOW(AUDIO_IOCTL_MAGIC, 11, unsigned) +#define AUDIO_GET_EVENT _IOR(AUDIO_IOCTL_MAGIC, 13, unsigned) +#define AUDIO_ABORT_GET_EVENT _IOW(AUDIO_IOCTL_MAGIC, 14, unsigned) +#define AUDIO_REGISTER_PMEM _IOW(AUDIO_IOCTL_MAGIC, 15, unsigned) +#define AUDIO_DEREGISTER_PMEM _IOW(AUDIO_IOCTL_MAGIC, 16, unsigned) +#define AUDIO_WAIT_ADSP_DONE _IOR(AUDIO_IOCTL_MAGIC, 16, unsigned) +#define AUDIO_ADSP_PAUSE _IOR(AUDIO_IOCTL_MAGIC, 17, unsigned) +#define AUDIO_ASYNC_WRITE _IOW(AUDIO_IOCTL_MAGIC, 17, unsigned) +#define AUDIO_ADSP_RESUME _IOR(AUDIO_IOCTL_MAGIC, 18, unsigned) +#define AUDIO_ASYNC_READ _IOW(AUDIO_IOCTL_MAGIC, 18, unsigned) +#define AUDIO_SET_INCALL _IOW(AUDIO_IOCTL_MAGIC, 19, \ + struct msm_voicerec_mode) +#define AUDIO_GET_NUM_SND_DEVICE _IOR(AUDIO_IOCTL_MAGIC, 20, unsigned) +#define AUDIO_GET_AMRNB_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 21, unsigned) +#define AUDIO_GET_SND_DEVICES _IOWR(AUDIO_IOCTL_MAGIC, 21, \ + struct msm_snd_device_list) +#define AUDIO_SET_AMRNB_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 22, unsigned) +#define AUDIO_ENABLE_SND_DEVICE _IOW(AUDIO_IOCTL_MAGIC, 22, unsigned) +#define AUDIO_DISABLE_SND_DEVICE _IOW(AUDIO_IOCTL_MAGIC, 23, unsigned) +#define AUDIO_ROUTE_STREAM _IOW(AUDIO_IOCTL_MAGIC, 24, \ + struct msm_audio_route_config) +#define AUDIO_GET_PCM_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 30, unsigned) +#define AUDIO_SET_PCM_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 31, unsigned) +#define AUDIO_SWITCH_DEVICE _IOW(AUDIO_IOCTL_MAGIC, 32, unsigned) +#define AUDIO_SET_MUTE _IOW(AUDIO_IOCTL_MAGIC, 33, unsigned) +#define AUDIO_UPDATE_ACDB _IOW(AUDIO_IOCTL_MAGIC, 34, unsigned) +#define AUDIO_START_VOICE _IOW(AUDIO_IOCTL_MAGIC, 35, unsigned) +#define AUDIO_STOP_VOICE _IOW(AUDIO_IOCTL_MAGIC, 36, unsigned) +#define AUDIO_START_FM _IOW(AUDIO_IOCTL_MAGIC, 37, unsigned) +#define AUDIO_STOP_FM _IOW(AUDIO_IOCTL_MAGIC, 38, unsigned) +#define AUDIO_REINIT_ACDB _IOW(AUDIO_IOCTL_MAGIC, 39, unsigned) +#define AUDIO_ENABLE_AUXPGA_LOOPBACK _IOW(AUDIO_IOCTL_MAGIC, 40, unsigned) +#define AUDIO_OUTPORT_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 40, \ + unsigned short) +#define AUDIO_SET_AUXPGA_GAIN _IOW(AUDIO_IOCTL_MAGIC, 41, unsigned) +#define AUDIO_SET_ERR_THRESHOLD_VALUE _IOW(AUDIO_IOCTL_MAGIC, 41, \ + unsigned short) +#define AUDIO_SET_RX_MUTE _IOW(AUDIO_IOCTL_MAGIC, 42, unsigned) +#define AUDIO_GET_BITSTREAM_ERROR_INFO _IOR(AUDIO_IOCTL_MAGIC, 42, \ + struct msm_audio_bitstream_error_info) + +/* Qualcomm extensions */ +#define AUDIO_SET_STREAM_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 80, \ + struct msm_audio_stream_config) +#define AUDIO_GET_STREAM_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 81, \ + struct msm_audio_stream_config) +#define AUDIO_GET_SESSION_ID _IOR(AUDIO_IOCTL_MAGIC, 82, \ + unsigned short) +#define AUDIO_GET_STREAM_INFO _IOR(AUDIO_IOCTL_MAGIC, 83, \ + struct msm_audio_bitstream_info) +#define AUDIO_SET_PAN _IOW(AUDIO_IOCTL_MAGIC, 84, unsigned) +#define AUDIO_SET_QCONCERT_PLUS _IOW(AUDIO_IOCTL_MAGIC, 85, unsigned) +#define AUDIO_SET_MBADRC _IOW(AUDIO_IOCTL_MAGIC, 86, unsigned) +#define AUDIO_SET_VOLUME_PATH _IOW(AUDIO_IOCTL_MAGIC, 87, \ + struct msm_vol_info) +#define AUDIO_SET_MAX_VOL_ALL _IOW(AUDIO_IOCTL_MAGIC, 88, unsigned) +#define AUDIO_GET_BUF_CFG _IOW(AUDIO_IOCTL_MAGIC, 93, \ + struct msm_audio_buf_cfg) +#define AUDIO_SET_BUF_CFG _IOW(AUDIO_IOCTL_MAGIC, 94, \ + struct msm_audio_buf_cfg) +#define AUDIO_SET_ACDB_BLK _IOW(AUDIO_IOCTL_MAGIC, 95, \ + struct msm_acdb_cmd_device) +#define AUDIO_GET_ACDB_BLK _IOW(AUDIO_IOCTL_MAGIC, 96, \ + struct msm_acdb_cmd_device) + +#define AUDIO_MAX_COMMON_IOCTL_NUM 100 + +struct msm_audio_config { + uint32_t buffer_size; + uint32_t buffer_count; + uint32_t channel_count; + uint32_t sample_rate; + uint32_t type; + uint32_t unused[3]; +}; + +struct msm_audio_stats { + uint32_t byte_count; + uint32_t sample_count; + uint32_t unused[2]; +}; + +struct msm_mute_info { + uint32_t mute; + uint32_t path; +}; + +#define AAC_OBJECT_ER_LC 17 +#define AAC_OBJECT_ER_LTP 19 +#define AAC_OBJECT_ER_SCALABLE 20 +#define AAC_OBJECT_BSAC 22 +#define AAC_OBJECT_ER_LD 23 + +struct aac_format { + uint16_t sample_rate; + uint16_t channel_config; + uint16_t block_formats; + uint16_t audio_object_type; + uint16_t ep_config; + uint16_t aac_section_data_resilience_flag; + uint16_t aac_scalefactor_data_resilience_flag; + uint16_t aac_spectral_data_resilience_flag; + uint16_t sbr_on_flag; + uint16_t sbr_ps_on_flag; + uint32_t bit_rate; +}; + +struct msm_audio_stream_config { + uint32_t buffer_size; + uint32_t buffer_count; +}; + +/* Audio routing */ + +#define SND_IOCTL_MAGIC 's' + +#define SND_MUTE_UNMUTED 0 +#define SND_MUTE_MUTED 1 + +struct msm_voicerec_mode { + uint32_t rec_mode; +}; + +struct msm_snd_device_config { + uint32_t device; + uint32_t ear_mute; + uint32_t mic_mute; +}; + +#define SND_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_device_config *) + +#define SND_METHOD_VOICE 0 + +struct msm_snd_volume_config { + uint32_t device; + uint32_t method; + uint32_t volume; +}; + +#define SND_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_snd_volume_config *) + +/* Returns the number of SND endpoints supported. */ + +#define SND_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned *) + +struct msm_snd_endpoint { + int id; /* input and output */ + char name[64]; /* output only */ +}; + +/* Takes an index between 0 and one less than the number returned by + * SND_GET_NUM_ENDPOINTS, and returns the SND index and name of a + * SND endpoint. On input, the .id field contains the number of the + * endpoint, and on exit it contains the SND index, while .name contains + * the description of the endpoint. + */ + +#define SND_GET_ENDPOINT _IOWR(SND_IOCTL_MAGIC, 5, struct msm_snd_endpoint *) + +struct msm_audio_pcm_config { + uint32_t pcm_feedback; /* 0 - disable > 0 - enable */ + uint32_t buffer_count; /* Number of buffers to allocate */ + uint32_t buffer_size; /* Size of buffer for capturing of + PCM samples */ +}; +#endif diff --git a/include/linux/msm_audio_aac.h b/include/linux/msm_audio_aac.h new file mode 100644 index 00000000..b2eea5e5 --- /dev/null +++ b/include/linux/msm_audio_aac.h @@ -0,0 +1,91 @@ +/* arch/arm/mach-msm/include/mach/msm_audio_aac.h + * + * Copyright (c) 2009, 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can find it at http://www.fsf.org. + * + */ + +#ifndef __MSM_AUDIO_AAC_H +#define __MSM_AUDIO_AAC_H + +#include + +#define AUDIO_SET_AAC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned) +#define AUDIO_GET_AAC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned) + +#define AUDIO_SET_AAC_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_aac_enc_config) + +#define AUDIO_GET_AAC_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+4), struct msm_audio_aac_enc_config) + +#define AUDIO_AAC_FORMAT_ADTS -1 +#define AUDIO_AAC_FORMAT_RAW 0x0000 +#define AUDIO_AAC_FORMAT_PSUEDO_RAW 0x0001 +#define AUDIO_AAC_FORMAT_LOAS 0x0002 +#define AUDIO_AAC_FORMAT_ADIF 0x0003 + + +#define AUDIO_AAC_OBJECT_LC 0x0002 +#define AUDIO_AAC_OBJECT_LTP 0x0004 +#define AUDIO_AAC_OBJECT_ERLC 0x0011 +#define AUDIO_AAC_OBJECT_BSAC 0x0016 + +#define AUDIO_AAC_SEC_DATA_RES_ON 0x0001 +#define AUDIO_AAC_SEC_DATA_RES_OFF 0x0000 + +#define AUDIO_AAC_SCA_DATA_RES_ON 0x0001 +#define AUDIO_AAC_SCA_DATA_RES_OFF 0x0000 + +#define AUDIO_AAC_SPEC_DATA_RES_ON 0x0001 +#define AUDIO_AAC_SPEC_DATA_RES_OFF 0x0000 + +#define AUDIO_AAC_SBR_ON_FLAG_ON 0x0001 +#define AUDIO_AAC_SBR_ON_FLAG_OFF 0x0000 + +#define AUDIO_AAC_SBR_PS_ON_FLAG_ON 0x0001 +#define AUDIO_AAC_SBR_PS_ON_FLAG_OFF 0x0000 + +/* Primary channel on both left and right channels */ +#define AUDIO_AAC_DUAL_MONO_PL_PR 0 +/* Secondary channel on both left and right channels */ +#define AUDIO_AAC_DUAL_MONO_SL_SR 1 +/* Primary channel on right channel and 2nd on left channel */ +#define AUDIO_AAC_DUAL_MONO_SL_PR 2 +/* 2nd channel on right channel and primary on left channel */ +#define AUDIO_AAC_DUAL_MONO_PL_SR 3 + +struct msm_audio_aac_config { + signed short format; + unsigned short audio_object; + unsigned short ep_config; /* 0 ~ 3 useful only obj = ERLC */ + unsigned short aac_section_data_resilience_flag; + unsigned short aac_scalefactor_data_resilience_flag; + unsigned short aac_spectral_data_resilience_flag; + unsigned short sbr_on_flag; + unsigned short sbr_ps_on_flag; + unsigned short dual_mono_mode; + unsigned short channel_configuration; +}; + +struct msm_audio_aac_enc_config { + uint32_t channels; + uint32_t sample_rate; + uint32_t bit_rate; + uint32_t stream_format; +}; + +#endif /* __MSM_AUDIO_AAC_H */ diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h index a5a75638..a933facc 100644 --- a/include/linux/msm_mdp.h +++ b/include/linux/msm_mdp.h @@ -19,36 +19,21 @@ #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) -#ifdef CONFIG_MSM_MDP40 -#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_OVERLAY_GET _IOR(MSMFB_IOCTL_MAGIC, 140, \ - struct mdp_overlay) -#endif 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, // ARGB 888 - MDP_RGBX_8888, // RGBX 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, // Non valid image type after this enum - MDP_IMGTYPE2_START = 0x10000, - MDP_BGR_565 = MDP_IMGTYPE2_START, /* BGR 565 planer */ - MDP_FB_FORMAT, /* framebuffer format */ - MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */ + MDP_RGB_565, /* RGB 565 planar */ + MDP_XRGB_8888, /* RGB 888 padded */ + MDP_Y_CBCR_H2V2, /* Y and CbCr, pseudo planar w/ Cb is in MSB */ + MDP_ARGB_8888, /* ARGB 888 */ + MDP_RGB_888, /* RGB 888 planar */ + MDP_Y_CRCB_H2V2, /* Y and CrCb, pseudo planar w/ Cr is in MSB */ + MDP_YCRYCB_H2V1, /* YCrYCb interleave */ + MDP_Y_CRCB_H2V1, /* Y and CrCb, pseduo planar w/ Cr is in MSB */ + MDP_Y_CBCR_H2V1, /* Y and CrCb, pseduo planar w/ Cr is in MSB */ + MDP_RGBA_8888, /* ARGB 888 */ + MDP_BGRA_8888, /* ABGR 888 */ + MDP_RGBX_8888, /* RGBX 888 */ + MDP_IMGTYPE_LIMIT /* Non valid image type after this enum */ }; enum { @@ -57,20 +42,23 @@ enum { }; /* 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_ROT_MASK 0x7 -#define MDP_DITHER 0x8 -#define MDP_BLUR 0x10 +#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_ROT_MASK 0x7 +#define MDP_DITHER 0x8 +#define MDP_BLUR 0x10 #define MDP_BLEND_FG_PREMULT 0x20000 -#define MDP_DEINTERLACE 0x80000000 -#define MDP_SHARPENING 0x40000000 -#define MDP_TRANSP_NOP 0xffffffff -#define MDP_ALPHA_NOP 0xff + +#define MDP_TRANSP_NOP 0xffffffff +#define MDP_ALPHA_NOP 0xff + +/* drewis: added for android 4.0 */ +#define MDP_BLIT_NON_CACHED 0x01000000 +/* drewis: end */ struct mdp_rect { uint32_t x; @@ -95,7 +83,6 @@ struct mdp_blit_req { uint32_t alpha; uint32_t transp_mask; uint32_t flags; - int sharpening_strength; /* -127 <--> 127, default 64 */ }; struct mdp_blit_req_list { @@ -103,37 +90,4 @@ struct mdp_blit_req_list { struct mdp_blit_req req[]; }; -#ifdef CONFIG_MSM_MDP40 -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]; -}; -#endif -#endif //_MSM_MDP_H_ +#endif /* _MSM_MDP_H_ */