Merge "msm: msm_bus: Fix aggregation of clocks in active-only context" into msm-3.0
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
new file mode 100644
index 0000000..5839f63
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -0,0 +1,16 @@
+Qualcomm Serial Peripheral Interface (SPI)
+
+Required properties:
+- compatible : should be "qcom,spi-qup-v2".
+- reg : offset and length of the QUP register map.
+- interrupts : should contain the QUP core interrupt.
+- spi-max-frequency : specifies maximum SPI clock frequency, Units - Hz.
+
+Example:
+ spi@f9924000 {
+ compatible = "qcom,spi-qup-v2";
+ reg = <0xf9924000 0x1000>;
+ interrupts = <96>;
+ spi-max-frequency = <24000000>;
+ };
+
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index d79aead..b1db115 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -266,3 +266,6 @@
pcim_iounmap()
pcim_iomap_table() : array of mapped addresses indexed by BAR
pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
+
+REGULATOR
+ devm_regulator_get()
diff --git a/arch/arm/boot/dts/msmcopper.dts b/arch/arm/boot/dts/msmcopper.dts
index 6561c71..b00237a 100644
--- a/arch/arm/boot/dts/msmcopper.dts
+++ b/arch/arm/boot/dts/msmcopper.dts
@@ -70,4 +70,10 @@
qcom,bam-dma-res-pipes = <6>;
};
+ spi@f9924000 {
+ compatible = "qcom,spi-qup-v2";
+ reg = <0xf9924000 0x1000>;
+ interrupts = <96>;
+ spi-max-frequency = <24000000>;
+ };
};
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index a6b5d0b..0455878 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -788,7 +788,7 @@
{
struct gic_chip_data *gic;
struct irq_domain *domain;
- int gic_irqs;
+ int gic_irqs, rc;
BUG_ON(gic_nr >= MAX_GIC_NR);
@@ -801,11 +801,8 @@
gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
if (WARN_ON(!gic->dist_base.percpu_base ||
- !gic->cpu_base.percpu_base)) {
- free_percpu(gic->dist_base.percpu_base);
- free_percpu(gic->cpu_base.percpu_base);
- return;
- }
+ !gic->cpu_base.percpu_base))
+ goto init_bases_err;
for_each_possible_cpu(cpu) {
unsigned long offset = percpu_offset * cpu_logical_map(cpu);
@@ -857,12 +854,23 @@
}
domain->priv = gic;
domain->ops = &gic_irq_domain_ops;
- irq_domain_add(domain);
+ rc = irq_domain_add(domain);
+ if (rc) {
+ WARN(1, "Unable to create irq_domain\n");
+ goto init_bases_err;
+ }
+ irq_domain_register(domain);
gic_chip.flags |= gic_arch_extn.flags;
gic_dist_init(gic);
gic_cpu_init(gic);
gic_pm_init(gic);
+
+ return;
+
+init_bases_err:
+ free_percpu(gic->dist_base.percpu_base);
+ free_percpu(gic->cpu_base.percpu_base);
}
void __cpuinit gic_secondary_init(unsigned int gic_nr)
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 1379334..d69305c 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -94,6 +94,8 @@
CONFIG_DCC_TTY=y
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
# CONFIG_HWMON is not set
# CONFIG_MFD_SUPPORT is not set
# CONFIG_HID_SUPPORT is not set
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index ca974b2..00ff580 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -45,6 +45,7 @@
CONFIG_MSM7X27A_AUDIO=y
CONFIG_MSM_DMA_TEST=y
# CONFIG_MSM_JTAG_V7 is not set
+CONFIG_MSM_SLEEP_STATS_DEVICE=y
CONFIG_BT_MSM_PINTEST=y
CONFIG_MSM_RPC_VIBRATOR=y
CONFIG_PM8XXX_RPC_VIBRATOR=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index cfa06a8..3cf01a1 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -45,6 +45,7 @@
CONFIG_MSM7X27A_AUDIO=y
CONFIG_MSM_DMA_TEST=y
# CONFIG_MSM_JTAG_V7 is not set
+CONFIG_MSM_SLEEP_STATS_DEVICE=y
CONFIG_BT_MSM_PINTEST=y
CONFIG_MSM_RPC_VIBRATOR=y
CONFIG_PM8XXX_RPC_VIBRATOR=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index d8d2e35..0780d20 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -257,6 +257,7 @@
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_HS=y
# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
@@ -320,6 +321,7 @@
CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_SOUND=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 5e90492..bd92fe3 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -260,6 +260,7 @@
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_HS=y
# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
@@ -323,6 +324,7 @@
CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_SOUND=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 0f403b5..d34f5df 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -24,6 +24,7 @@
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
+# CONFIG_PERF_EVENTS is not set
CONFIG_PROFILING=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
@@ -167,6 +168,8 @@
CONFIG_USB_G_ANDROID=y
CONFIG_RMNET_SMD_CTL_CHANNEL="DATA36_CNTL"
CONFIG_RMNET_SMD_DATA_CHANNEL="DATA36"
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
@@ -201,14 +204,13 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
-CONFIG_FUNCTION_TRACER=y
-# CONFIG_FUNCTION_GRAPH_TRACER is not set
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_KEYS=y
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 0faa7ea..4328ac3 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -383,8 +383,7 @@
*/
if (max_cpus > ncores)
max_cpus = ncores;
-
- if (max_cpus > 1) {
+ if (ncores > 1 && max_cpus) {
/*
* Enable the local timer or broadcast device for the
* boot CPU, but only if we have more than one CPU.
@@ -392,6 +391,14 @@
percpu_timer_setup();
/*
+ * Initialise the present map, which describes the set of CPUs
+ * actually populated at the present time. A platform should
+ * re-initialize the map in platform_smp_prepare_cpus() if
+ * present != possible (e.g. physical hotplug).
+ */
+ init_cpu_present(&cpu_possible_map);
+
+ /*
* Initialise the SCU if there are more than one CPU
* and let them know where to start.
*/
diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos4/platsmp.c
index c5e65a0..b68d5bd 100644
--- a/arch/arm/mach-exynos4/platsmp.c
+++ b/arch/arm/mach-exynos4/platsmp.c
@@ -154,14 +154,6 @@
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- int i;
-
- /*
- * Initialise the present map, which describes the set of CPUs
- * actually populated at the present time.
- */
- for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
scu_enable(scu_base_addr());
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index ee9b2de..9df90cd 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1845,6 +1845,9 @@
depends on CPU_IDLE
default n
+config MSM_SLEEP_STATS_DEVICE
+ bool "Enable exporting of MSM sleep device stats to userspace"
+
config MSM_STANDALONE_POWER_COLLAPSE
bool "Enable standalone power collapse"
default n
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index ec15245..8b866d8 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -219,10 +219,10 @@
obj-$(CONFIG_MACH_MSM7X27_SURF) += board-msm7x27.o devices-msm7x27.o
obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o devices-msm7x27.o
obj-$(CONFIG_ARCH_MSM7X27A) += clock-pcom-lookup.o devices-msm7x27a.o
-obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
-obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
-obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
-obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o
+obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
+obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
+obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
+obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o memory_topology.o
obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o clock-7x30.o acpuclock-7x30.o
obj-$(CONFIG_MACH_MSM7X25_SURF) += board-msm7x27.o devices-msm7x25.o
@@ -301,7 +301,8 @@
endif
endif
-obj-$(CONFIG_MSM_SLEEP_STATS) += msm_rq_stats.o idle_stats.o idle_stats_device.o
+obj-$(CONFIG_MSM_SLEEP_STATS) += msm_rq_stats.o idle_stats.o
+obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
obj-$(CONFIG_MSM_SHOW_RESUME_IRQ) += msm_show_resume_irq.o
obj-$(CONFIG_BT_MSM_PINTEST) += btpintest.o
obj-$(CONFIG_MSM_FAKE_BATTERY) += fish_battery.o
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 2720774..0e4c756 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -212,6 +212,7 @@
static struct completion dfab_unvote_completion;
static DEFINE_SPINLOCK(wakelock_reference_lock);
static int wakelock_reference_count;
+static struct delayed_work msm9615_bam_init_work;
/* End A2 power collaspe */
/* subsystem restart */
@@ -1240,9 +1241,25 @@
struct dentry *dent,
int (*fill)(char *buf, int max))
{
- debugfs_create_file(name, mode, dent, fill, &debug_ops);
+ struct dentry *file;
+
+ file = debugfs_create_file(name, mode, dent, fill, &debug_ops);
+ if (IS_ERR(file))
+ pr_err("%s: debugfs create failed %d\n", __func__,
+ (int)PTR_ERR(file));
}
+static void debug_create_multiple(const char *name, mode_t mode,
+ struct dentry *dent,
+ int (*fill)(char *buf, int max, loff_t *ppos))
+{
+ struct dentry *file;
+
+ file = debugfs_create_file(name, mode, dent, fill, &debug_ops_multiple);
+ if (IS_ERR(file))
+ pr_err("%s: debugfs create failed %d\n", __func__,
+ (int)PTR_ERR(file));
+}
#endif
static void notify_all(int event, unsigned long data)
@@ -1369,7 +1386,7 @@
else
called_before = 1;
if (wait_for_dfab) {
- ret = wait_for_completion_interruptible_timeout(
+ ret = wait_for_completion_timeout(
&dfab_unvote_completion, HZ);
BUG_ON(ret == 0);
}
@@ -1388,7 +1405,7 @@
*/
if (wait_for_ack) {
bam_dmux_log("%s waiting for previous ack\n", __func__);
- ret = wait_for_completion_interruptible_timeout(
+ ret = wait_for_completion_timeout(
&ul_wakeup_ack_completion, HZ);
BUG_ON(ret == 0);
wait_for_ack = 0;
@@ -1396,12 +1413,10 @@
INIT_COMPLETION(ul_wakeup_ack_completion);
power_vote(1);
bam_dmux_log("%s waiting for wakeup ack\n", __func__);
- ret = wait_for_completion_interruptible_timeout(
- &ul_wakeup_ack_completion, HZ);
+ ret = wait_for_completion_timeout(&ul_wakeup_ack_completion, HZ);
BUG_ON(ret == 0);
bam_dmux_log("%s waiting completion\n", __func__);
- ret = wait_for_completion_interruptible_timeout(
- &bam_connection_completion, HZ);
+ ret = wait_for_completion_timeout(&bam_connection_completion, HZ);
BUG_ON(ret == 0);
bam_is_connected = 1;
@@ -1496,7 +1511,7 @@
mutex_unlock(&dfab_status_lock);
return;
}
- rc = clk_enable(dfab_clk);
+ rc = clk_prepare_enable(dfab_clk);
if (rc)
DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n", rc);
dfab_is_on = 1;
@@ -1513,7 +1528,7 @@
mutex_unlock(&dfab_status_lock);
return;
}
- clk_disable(dfab_clk);
+ clk_disable_unprepare(dfab_clk);
dfab_is_on = 0;
mutex_unlock(&dfab_status_lock);
}
@@ -1814,6 +1829,19 @@
return ret;
}
+static void msm9615_bam_init(struct work_struct *work)
+{
+ int ret = 0;
+
+ ret = bam_init();
+ if (ret) {
+ ret = bam_init_fallback();
+ if (ret)
+ pr_err("%s: bam init fallback failed: %d",
+ __func__, ret);
+ }
+}
+
static void toggle_apps_ack(void)
{
static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
@@ -1828,8 +1856,6 @@
static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
{
- int ret = 0;
-
bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
new_state);
@@ -1846,12 +1872,18 @@
} else if (new_state & SMSM_A2_POWER_CONTROL) {
bam_dmux_log("%s: init\n", __func__);
grab_wakelock();
- ret = bam_init();
- if (ret) {
- ret = bam_init_fallback();
- if (ret)
- pr_err("%s: bam init fallback failed: %d",
- __func__, ret);
+ if (cpu_is_msm9615()) {
+ /*
+ * even though a2 has signaled it is ready via the
+ * SMSM_A2_POWER_CONTROL bit, it has not yet
+ * enabled the pipes as needed by sps_connect
+ * in satallite mode. Add a short delay to give modem
+ * time to enable the pipes.
+ */
+ schedule_delayed_work(&msm9615_bam_init_work,
+ msecs_to_jiffies(100));
+ } else {
+ bam_init();
}
} else {
bam_dmux_log("%s: bad state change\n", __func__);
@@ -1914,6 +1946,7 @@
init_completion(&bam_connection_completion);
init_completion(&dfab_unvote_completion);
INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
+ INIT_DELAYED_WORK(&msm9615_bam_init_work, msm9615_bam_init);
wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
@@ -1967,8 +2000,7 @@
debug_create("tbl", 0444, dent, debug_tbl);
debug_create("ul_pkt_cnt", 0444, dent, debug_ul_pkt_cnt);
debug_create("stats", 0444, dent, debug_stats);
- debugfs_create_file("log", 0444, dent, debug_log,
- &debug_ops_multiple);
+ debug_create_multiple("log", 0444, dent, debug_log);
}
#endif
ret = kfifo_alloc(&bam_dmux_state_log, PAGE_SIZE, GFP_KERNEL);
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 9f66e5d..0ba7434 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -22,6 +22,7 @@
#include <linux/spi/spi.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/qcom_crypto_device.h>
+#include <linux/ion.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
@@ -29,6 +30,7 @@
#include <mach/board.h>
#include <mach/msm_iomap.h>
+#include <mach/ion.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/usb/android.h>
#include <mach/socinfo.h>
@@ -37,36 +39,48 @@
#include "devices.h"
#include <mach/gpio.h>
#include <mach/gpiomux.h>
+#ifdef CONFIG_ANDROID_PMEM
#include <linux/android_pmem.h>
+#endif
#include <mach/msm_memtypes.h>
#include <linux/bootmem.h>
#include <asm/setup.h>
#include <mach/dma.h>
+#include <mach/msm_bus_board.h>
#include "msm_watchdog.h"
#include "board-8064.h"
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x600000
-#define MSM_PMEM_ADSP_SIZE 0x3800000
+#define MSM_PMEM_ADSP_SIZE 0x7800000
#define MSM_PMEM_AUDIO_SIZE 0x2B4000
-#define MSM_PMEM_SIZE 0x1800000 /* 24 Mbytes */
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#else
+#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
+#endif
-static struct memtype_reserve apq8064_reserve_table[] __initdata = {
- [MEMTYPE_SMI] = {
- },
- [MEMTYPE_EBI0] = {
- .flags = MEMTYPE_FLAGS_1M_ALIGN,
- },
- [MEMTYPE_EBI1] = {
- .flags = MEMTYPE_FLAGS_1M_ALIGN,
- },
-};
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0xB0C000
+#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
+#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
+#define MSM_ION_MFC_SIZE SZ_8K
+#define MSM_ION_HEAP_NUM 5
+#else
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
+#define MSM_ION_HEAP_NUM 1
+#endif
-static int apq8064_paddr_to_memtype(unsigned int paddr)
+#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
+static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
{
- return MEMTYPE_EBI1;
+ pmem_kernel_ebi1_size = memparse(p, NULL);
+ return 0;
}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+#endif
+#ifdef CONFIG_ANDROID_PMEM
static unsigned pmem_size = MSM_PMEM_SIZE;
static int __init pmem_size_setup(char *p)
{
@@ -92,7 +106,10 @@
return 0;
}
early_param("pmem_audio_size", pmem_audio_size_setup);
+#endif
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct android_pmem_platform_data android_pmem_pdata = {
.name = "pmem",
.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
@@ -112,20 +129,12 @@
.cached = 0,
.memory_type = MEMTYPE_EBI1,
};
-
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
-{
- pmem_kernel_ebi1_size = memparse(p, NULL);
- return 0;
-}
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
-
static struct platform_device android_pmem_adsp_device = {
.name = "android_pmem",
.id = 2,
.dev = { .platform_data = &android_pmem_adsp_pdata },
};
+#endif
static struct android_pmem_platform_data android_pmem_audio_pdata = {
.name = "pmem_audio",
@@ -139,12 +148,28 @@
.id = 4,
.dev = { .platform_data = &android_pmem_audio_pdata },
};
+#endif
+
+static struct memtype_reserve apq8064_reserve_table[] __initdata = {
+ [MEMTYPE_SMI] = {
+ },
+ [MEMTYPE_EBI0] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+ [MEMTYPE_EBI1] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+};
static void __init size_pmem_devices(void)
{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
android_pmem_adsp_pdata.size = pmem_adsp_size;
android_pmem_pdata.size = pmem_size;
+#endif
android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
+#endif
}
static void __init reserve_memory_for(struct android_pmem_platform_data *p)
@@ -154,16 +179,97 @@
static void __init reserve_pmem_memory(void)
{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
reserve_memory_for(&android_pmem_adsp_pdata);
reserve_memory_for(&android_pmem_pdata);
+#endif
reserve_memory_for(&android_pmem_audio_pdata);
apq8064_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif
+}
+
+static int apq8064_paddr_to_memtype(unsigned int paddr)
+{
+ return MEMTYPE_EBI1;
+}
+
+#ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+ .permission_type = IPT_TYPE_MM_CARVEOUT,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+ .permission_type = IPT_TYPE_MFC_SHAREDMEM,
+};
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+};
+#endif
+static struct ion_platform_data ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .heaps = {
+ {
+ .id = ION_SYSTEM_HEAP_ID,
+ .type = ION_HEAP_TYPE_SYSTEM,
+ .name = ION_VMALLOC_HEAP_NAME,
+ },
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ {
+ .id = ION_SF_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_SF_HEAP_NAME,
+ .size = MSM_ION_SF_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_ion_pdata,
+ },
+ {
+ .id = ION_CP_MM_HEAP_ID,
+ .type = ION_HEAP_TYPE_CP,
+ .name = ION_MM_HEAP_NAME,
+ .size = MSM_ION_MM_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &cp_mm_ion_pdata,
+ },
+ {
+ .id = ION_CP_MFC_HEAP_ID,
+ .type = ION_HEAP_TYPE_CP,
+ .name = ION_MFC_HEAP_NAME,
+ .size = MSM_ION_MFC_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &cp_mfc_ion_pdata,
+ },
+ {
+ .id = ION_IOMMU_HEAP_ID,
+ .type = ION_HEAP_TYPE_IOMMU,
+ .name = ION_IOMMU_HEAP_NAME,
+ },
+#endif
+ }
+};
+
+static struct platform_device ion_dev = {
+ .name = "ion-msm",
+ .id = 1,
+ .dev = { .platform_data = &ion_pdata },
+};
+#endif
+
+static void reserve_ion_memory(void)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+ apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_SIZE;
+ apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
+ apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MFC_SIZE;
+#endif
}
static void __init apq8064_calculate_reserve_sizes(void)
{
size_pmem_devices();
reserve_pmem_memory();
+ reserve_ion_memory();
}
static struct reserve_info apq8064_reserve_info __initdata = {
@@ -453,6 +559,22 @@
},
};
+static void __init apq8064_init_buses(void)
+{
+ msm_bus_rpm_set_mt_mask();
+ msm_bus_8064_apps_fabric_pdata.rpm_enabled = 1;
+ msm_bus_8064_sys_fabric_pdata.rpm_enabled = 1;
+ msm_bus_8064_mm_fabric_pdata.rpm_enabled = 1;
+ msm_bus_8064_apps_fabric.dev.platform_data =
+ &msm_bus_8064_apps_fabric_pdata;
+ msm_bus_8064_sys_fabric.dev.platform_data =
+ &msm_bus_8064_sys_fabric_pdata;
+ msm_bus_8064_mm_fabric.dev.platform_data =
+ &msm_bus_8064_mm_fabric_pdata;
+ msm_bus_8064_sys_fpb.dev.platform_data = &msm_bus_8064_sys_fpb_pdata;
+ msm_bus_8064_cpss_fpb.dev.platform_data = &msm_bus_8064_cpss_fpb_pdata;
+}
+
static struct platform_device *common_devices[] __initdata = {
&apq8064_device_dmov,
&apq8064_device_qup_i2c_gsbi4,
@@ -464,9 +586,16 @@
&apq8064_device_otg,
&apq8064_device_gadget_peripheral,
&android_usb_device,
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
&android_pmem_device,
&android_pmem_adsp_device,
+#endif
&android_pmem_audio_device,
+#endif
+#ifdef CONFIG_ION_MSM
+ &ion_dev,
+#endif
&msm8064_device_watchdog,
&msm8064_device_saw_regulator_core0,
&msm8064_device_saw_regulator_core1,
@@ -507,6 +636,11 @@
&apq_pcm_afe,
&apq_cpudai_auxpcm_rx,
&apq_cpudai_auxpcm_tx,
+ &msm_bus_8064_apps_fabric,
+ &msm_bus_8064_sys_fabric,
+ &msm_bus_8064_mm_fabric,
+ &msm_bus_8064_sys_fpb,
+ &msm_bus_8064_cpss_fpb,
};
static struct platform_device *sim_devices[] __initdata = {
@@ -600,6 +734,7 @@
&apq8064_qup_spi_gsbi5_pdata;
apq8064_init_pmic();
apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
+ apq8064_init_buses();
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
apq8064_init_mmc();
slim_register_board_info(apq8064_slim_devices,
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 476ab93..84dbea8 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -156,29 +156,22 @@
.pull = GPIOMUX_PULL_DOWN,
};
#ifdef MSM8930_PHASE_2
-static struct gpiomux_setting hsusb_act_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
static struct gpiomux_setting hsusb_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_LOW,
};
static struct msm_gpiomux_config msm8930_hsusb_configs[] = {
{
.gpio = 63, /* HSUSB_EXTERNAL_5V_LDO_EN */
.settings = {
- [GPIOMUX_ACTIVE] = &hsusb_act_cfg,
[GPIOMUX_SUSPENDED] = &hsusb_sus_cfg,
},
},
{
.gpio = 97, /* HSUSB_5V_EN */
.settings = {
- [GPIOMUX_ACTIVE] = &hsusb_act_cfg,
[GPIOMUX_SUSPENDED] = &hsusb_sus_cfg,
},
},
@@ -631,6 +624,29 @@
};
#endif
+#ifdef MSM8930_PHASE_2
+static struct gpiomux_setting haptics_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm8930_haptics_configs[] __initdata = {
+ {
+ .gpio = 77,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &haptics_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 78,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &haptics_suspend_cfg,
+ },
+ },
+};
+#endif
+
int __init msm8930_init_gpiomux(void)
{
int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -676,6 +692,12 @@
msm_gpiomux_install(mdm_configs,
ARRAY_SIZE(mdm_configs));
+#ifdef MSM8930_PHASE_2
+ if (machine_is_msm8930_mtp() || machine_is_msm8930_fluid())
+ msm_gpiomux_install(msm8930_haptics_configs,
+ ARRAY_SIZE(msm8930_haptics_configs));
+#endif
+
#ifdef CONFIG_USB_EHCI_MSM_HSIC
if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
!machine_is_msm8930_mtp() &&
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 6cb69f6..2f59d9d 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -198,10 +198,49 @@
.wakeup = 1,
};
+static int pm8921_therm_mitigation[] = {
+ 1100,
+ 700,
+ 600,
+ 325,
+};
+
+#define MAX_VOLTAGE_MV 4200
+static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
+ .safety_time = 180,
+ .update_time = 60000,
+ .max_voltage = MAX_VOLTAGE_MV,
+ .min_voltage = 3200,
+ .resume_voltage_delta = 100,
+ .term_current = 100,
+ .cool_temp = 10,
+ .warm_temp = 40,
+ .temp_check_period = 1,
+ .max_bat_chg_current = 1100,
+ .cool_bat_chg_current = 350,
+ .warm_bat_chg_current = 350,
+ .cool_bat_voltage = 4100,
+ .warm_bat_voltage = 4100,
+ .thermal_mitigation = pm8921_therm_mitigation,
+ .thermal_levels = ARRAY_SIZE(pm8921_therm_mitigation),
+};
+
+static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
+ .r_sense = 10,
+};
+
static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
.priority = 0,
};
+static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+ .r_sense = 10,
+ .i_test = 2500,
+ .v_failure = 3000,
+ .calib_delay_ms = 600000,
+ .max_voltage_uv = MAX_VOLTAGE_MV * 1000,
+};
+
static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
.irq_pdata = &pm8xxx_irq_pdata,
.gpio_pdata = &pm8xxx_gpio_pdata,
@@ -210,7 +249,10 @@
.pwrkey_pdata = &pm8xxx_pwrkey_pdata,
.misc_pdata = &pm8xxx_misc_pdata,
.regulator_pdatas = msm8930_pm8038_regulator_pdata,
+ .charger_pdata = &pm8921_chg_pdata,
+ .bms_pdata = &pm8921_bms_pdata,
.adc_pdata = &pm8xxx_adc_pdata,
+ .ccadc_pdata = &pm8xxx_ccadc_pdata,
};
static struct msm_ssbi_platform_data msm8930_ssbi_pm8038_pdata __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index ccdb384..fc9b58f 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -42,9 +42,11 @@
};
VREG_CONSUMERS(L5) = {
REGULATOR_SUPPLY("8038_l5", NULL),
+ REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.1"),
};
VREG_CONSUMERS(L6) = {
REGULATOR_SUPPLY("8038_l6", NULL),
+ REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.3"),
};
VREG_CONSUMERS(L7) = {
REGULATOR_SUPPLY("8038_l7", NULL),
@@ -67,6 +69,7 @@
REGULATOR_SUPPLY("vdd_dig", "3-004a"),
REGULATOR_SUPPLY("iris_vddio", "wcnss_wlan.0"),
REGULATOR_SUPPLY("riva_vddpx", "wcnss_wlan.0"),
+ REGULATOR_SUPPLY("sdc_vccq", "msm_sdcc.1"),
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("8038_l12", NULL),
@@ -99,6 +102,7 @@
};
VREG_CONSUMERS(L22) = {
REGULATOR_SUPPLY("8038_l22", NULL),
+ REGULATOR_SUPPLY("sdc_vddp", "msm_sdcc.3"),
};
VREG_CONSUMERS(L23) = {
REGULATOR_SUPPLY("8038_l23", NULL),
@@ -146,6 +150,7 @@
REGULATOR_SUPPLY("8038_lvs2", NULL),
REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
+ REGULATOR_SUPPLY("vddp", "12-0048"),
};
VREG_CONSUMERS(EXT_5V) = {
REGULATOR_SUPPLY("ext_5v", NULL),
@@ -153,7 +158,7 @@
};
VREG_CONSUMERS(EXT_OTG_SW) = {
REGULATOR_SUPPLY("ext_otg_sw", NULL),
- REGULATOR_SUPPLY("vbus_otg", "msm_otg"),
+ REGULATOR_SUPPLY("vbus_otg", "msm_otg"),
};
#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index d655ead..eee6d09 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -250,6 +250,8 @@
/*TODO: Insert right replacement for PM8038 */
#ifndef MSM8930_PHASE_2
.wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(16),
+#else
+ .wpswitch_gpio = 66,
#endif
#endif
.vreg_data = &mmc_slot_vreg_data[SDCC3],
@@ -259,6 +261,9 @@
#ifndef MSM8930_PHASE_2
.status_gpio = PM8921_GPIO_PM_TO_SYS(26),
.status_irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26),
+#else
+ .status_gpio = 94,
+ .status_irq = MSM_GPIO_TO_INT(94),
#endif
.irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
.is_status_gpio_active_low = true,
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index b846c43..fe125e3 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -117,21 +117,24 @@
#endif
-#define MSM_PMEM_ADSP_SIZE 0x3800000
+#define MSM_PMEM_ADSP_SIZE 0x7800000
#define MSM_PMEM_AUDIO_SIZE 0x2B4000
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#else
-#define MSM_PMEM_SIZE 0x1C00000 /* 28 Mbytes */
+#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
#endif
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define MSM_PMEM_KERNEL_EBI1_SIZE 0xB0C000
-#define MSM_ION_SF_SIZE 0x1800000 /* 24MB */
-#define MSM_ION_MM_SIZE 0x4000000 /* (64MB) */
+#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
+#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
+#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
+#define MSM_ION_QSECOM_SIZE 0x100000 /* (1MB) */
#define MSM_ION_MFC_SIZE SZ_8K
-#define MSM_ION_HEAP_NUM 5
+#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
+#define MSM_ION_HEAP_NUM 8
#else
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
#define MSM_ION_HEAP_NUM 1
@@ -282,6 +285,25 @@
}
#ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+ .permission_type = IPT_TYPE_MM_CARVEOUT,
+ .align = PAGE_SIZE,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+ .permission_type = IPT_TYPE_MFC_SHAREDMEM,
+ .align = PAGE_SIZE,
+};
+static struct ion_co_heap_pdata co_ion_pdata = {
+ .adjacent_mem_id = INVALID_HEAP_ID,
+ .align = PAGE_SIZE,
+};
+static struct ion_co_heap_pdata fw_co_ion_pdata = {
+ .adjacent_mem_id = ION_CP_MM_HEAP_ID,
+ .align = SZ_128K,
+};
+#endif
static struct ion_platform_data ion_pdata = {
.nr = MSM_ION_HEAP_NUM,
.heaps = {
@@ -297,26 +319,53 @@
.name = ION_SF_HEAP_NAME,
.size = MSM_ION_SF_SIZE,
.memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_ion_pdata,
},
{
.id = ION_CP_MM_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
+ .type = ION_HEAP_TYPE_CP,
.name = ION_MM_HEAP_NAME,
.size = MSM_ION_MM_SIZE,
.memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &cp_mm_ion_pdata,
+ },
+ {
+ .id = ION_MM_FIRMWARE_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_MM_FIRMWARE_HEAP_NAME,
+ .size = MSM_ION_MM_FW_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &fw_co_ion_pdata,
},
{
.id = ION_CP_MFC_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
+ .type = ION_HEAP_TYPE_CP,
.name = ION_MFC_HEAP_NAME,
.size = MSM_ION_MFC_SIZE,
.memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &cp_mfc_ion_pdata,
},
{
.id = ION_IOMMU_HEAP_ID,
.type = ION_HEAP_TYPE_IOMMU,
.name = ION_IOMMU_HEAP_NAME,
},
+ {
+ .id = ION_QSECOM_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_QSECOM_HEAP_NAME,
+ .size = MSM_ION_QSECOM_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_ion_pdata,
+ },
+ {
+ .id = ION_AUDIO_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_AUDIO_HEAP_NAME,
+ .size = MSM_ION_AUDIO_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_ion_pdata,
+ },
#endif
}
};
@@ -333,7 +382,10 @@
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_SIZE;
+ msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_FW_SIZE;
msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MFC_SIZE;
+ msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
+ msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
#endif
}
@@ -993,12 +1045,19 @@
#ifndef MSM8930_PHASE_2
#define PM_HAP_EN_GPIO PM8921_GPIO_PM_TO_SYS(33)
#define PM_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20)
+#else
+#define ISA1200_HAP_EN_GPIO 77
+#define ISA1200_HAP_LEN_GPIO 78
+#define ISA1200_HAP_CLK PM8038_GPIO_PM_TO_SYS(7)
#endif
+#ifndef MSM8930_PHASE_2
static struct msm_xo_voter *xo_handle_d1;
+#endif
static int isa1200_power(int on)
{
+#ifndef MSM8930_PHASE_2
int rc = 0;
gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on);
@@ -1016,12 +1075,19 @@
err_xo_vote:
gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on);
return rc;
+#else
+ gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
+
+ return 0;
+#endif
+
}
static int isa1200_dev_setup(bool enable)
{
int rc = 0;
+#ifndef MSM8930_PHASE_2
struct pm_gpio hap_gpio_config = {
.direction = PM_GPIO_DIR_OUT,
.pull = PM_GPIO_PULL_NO,
@@ -1081,23 +1147,78 @@
free_gpio:
gpio_free(HAP_SHIFT_LVL_OE_GPIO);
return rc;
+#else
+ struct pm_gpio hap_clk_gpio_config = {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .out_strength = PM_GPIO_STRENGTH_HIGH,
+ .function = PM_GPIO_FUNC_1,
+ .inv_int_pol = 0,
+ .vin_sel = PM_GPIO_VIN_S4,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 0,
+ };
+
+ rc = pm8xxx_gpio_config(ISA1200_HAP_CLK, &hap_clk_gpio_config);
+ if (rc) {
+ pr_err("%s: pm8038 gpio %d config failed(%d)\n",
+ __func__, ISA1200_HAP_CLK, rc);
+ return rc;
+ }
+
+ rc = gpio_request(ISA1200_HAP_CLK, "haptics_clk");
+ if (rc) {
+ pr_err("%s: gpio_request for %d gpio failed rc(%d)\n",
+ __func__, ISA1200_HAP_CLK, rc);
+ goto fail_gpio_req;
+ }
+
+ rc = gpio_direction_output(ISA1200_HAP_CLK, 0);
+ if (rc) {
+ pr_err("%s: gpio_direction_output failed for %d gpio rc(%d)\n",
+ __func__, ISA1200_HAP_CLK, rc);
+ goto fail_gpio_dir;
+ }
+
+ return 0;
+
+fail_gpio_dir:
+ gpio_free(ISA1200_HAP_CLK);
+fail_gpio_req:
+ return rc;
+
+#endif
}
static struct isa1200_regulator isa1200_reg_data[] = {
+#ifndef MSM8930_PHASE_2
{
.name = "vcc_i2c",
.min_uV = ISA_I2C_VTG_MIN_UV,
.max_uV = ISA_I2C_VTG_MAX_UV,
.load_uA = ISA_I2C_CURR_UA,
},
+#else
+ {
+ .name = "vddp",
+ .min_uV = ISA_I2C_VTG_MIN_UV,
+ .max_uV = ISA_I2C_VTG_MAX_UV,
+ .load_uA = ISA_I2C_CURR_UA,
+ },
+#endif
};
static struct isa1200_platform_data isa1200_1_pdata = {
.name = "vibrator",
.dev_setup = isa1200_dev_setup,
.power_on = isa1200_power,
+#ifndef MSM8930_PHASE_2
.hap_en_gpio = PM_HAP_EN_GPIO,
.hap_len_gpio = PM_HAP_LEN_GPIO,
+#else
+ .hap_en_gpio = ISA1200_HAP_EN_GPIO,
+ .hap_len_gpio = ISA1200_HAP_LEN_GPIO,
+#endif
.max_timeout = 15000,
.mode_ctrl = PWM_GEN_MODE,
.pwm_fd = {
@@ -1933,12 +2054,21 @@
cyttsp_info,
ARRAY_SIZE(cyttsp_info),
},
+#ifndef MSM8930_PHASE_2
{
I2C_LIQUID,
MSM_8930_GSBI10_QUP_I2C_BUS_ID,
msm_isa1200_board_info,
ARRAY_SIZE(msm_isa1200_board_info),
},
+#else
+ {
+ I2C_FFA | I2C_FLUID,
+ MSM_8930_GSBI10_QUP_I2C_BUS_ID,
+ msm_isa1200_board_info,
+ ARRAY_SIZE(msm_isa1200_board_info),
+ },
+#endif
{
I2C_SURF,
MSM_8930_GSBI3_QUP_I2C_BUS_ID,
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 0a61b91..598e18d 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -130,7 +130,7 @@
#endif
-#define MSM_PMEM_ADSP_SIZE 0x4200000
+#define MSM_PMEM_ADSP_SIZE 0x7800000
#define MSM_PMEM_AUDIO_SIZE 0x2B4000
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
@@ -141,10 +141,13 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define MSM_PMEM_KERNEL_EBI1_SIZE 0xB0C000
-#define MSM_ION_SF_SIZE 0x2800000 /* (40MB) */
-#define MSM_ION_MM_SIZE 0x4000000 /* (64MB) */
+#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
+#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
+#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
+#define MSM_ION_QSECOM_SIZE 0x100000 /* (1MB) */
#define MSM_ION_MFC_SIZE SZ_8K
-#define MSM_ION_HEAP_NUM 5
+#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
+#define MSM_ION_HEAP_NUM 8
#define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000)
static unsigned int msm_ion_cp_mm_size = MSM_ION_MM_SIZE;
#else
@@ -309,6 +312,27 @@
}
#ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+ .permission_type = IPT_TYPE_MM_CARVEOUT,
+ .align = PAGE_SIZE,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+ .permission_type = IPT_TYPE_MFC_SHAREDMEM,
+ .align = PAGE_SIZE,
+};
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+ .adjacent_mem_id = INVALID_HEAP_ID,
+ .align = PAGE_SIZE,
+};
+
+static struct ion_co_heap_pdata fw_co_ion_pdata = {
+ .adjacent_mem_id = ION_CP_MM_HEAP_ID,
+ .align = SZ_128K,
+};
+#endif
static struct ion_platform_data ion_pdata = {
.nr = MSM_ION_HEAP_NUM,
.heaps = {
@@ -324,26 +348,53 @@
.name = ION_SF_HEAP_NAME,
.size = MSM_ION_SF_SIZE,
.memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_ion_pdata,
},
{
.id = ION_CP_MM_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
+ .type = ION_HEAP_TYPE_CP,
.name = ION_MM_HEAP_NAME,
.size = MSM_ION_MM_SIZE,
.memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &cp_mm_ion_pdata,
+ },
+ {
+ .id = ION_MM_FIRMWARE_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_MM_FIRMWARE_HEAP_NAME,
+ .size = MSM_ION_MM_FW_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &fw_co_ion_pdata,
},
{
.id = ION_CP_MFC_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
+ .type = ION_HEAP_TYPE_CP,
.name = ION_MFC_HEAP_NAME,
.size = MSM_ION_MFC_SIZE,
.memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &cp_mfc_ion_pdata,
},
{
.id = ION_IOMMU_HEAP_ID,
.type = ION_HEAP_TYPE_IOMMU,
.name = ION_IOMMU_HEAP_NAME,
},
+ {
+ .id = ION_QSECOM_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_QSECOM_HEAP_NAME,
+ .size = MSM_ION_QSECOM_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_ion_pdata,
+ },
+ {
+ .id = ION_AUDIO_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_AUDIO_HEAP_NAME,
+ .size = MSM_ION_AUDIO_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_ion_pdata,
+ },
#endif
}
};
@@ -378,8 +429,11 @@
}
}
msm8960_reserve_table[MEMTYPE_EBI1].size += msm_ion_cp_mm_size;
+ msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_FW_SIZE;
msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MFC_SIZE;
+ msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
+ msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
#endif
}
@@ -1475,6 +1529,12 @@
.msm_apps_ipc_rpm_val = 4,
};
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+ .base_addr = MSM_ACC0_BASE + 0x08,
+ .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+ .mask = 1UL << 13,
+};
+
static struct ks8851_pdata spi_eth_pdata = {
.irq_gpio = KS8851_IRQ_GPIO,
.rst_gpio = KS8851_RST_GPIO,
@@ -2151,6 +2211,7 @@
msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
msm_pm_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+ msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
}
static void __init msm8960_rumi3_init(void)
@@ -2182,6 +2243,7 @@
msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
msm_pm_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+ msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
}
static void __init msm8960_cdp_init(void)
@@ -2257,6 +2319,7 @@
msm_pm_data);
change_memory_power = &msm8960_change_memory_power;
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+ msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
if (PLATFORM_IS_CHARM25())
platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
}
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 4859f18..95a1347 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -69,6 +69,7 @@
VREG_CONSUMERS(S1) = {
REGULATOR_SUPPLY("8018_s1", NULL),
REGULATOR_SUPPLY("HSUSB_VDDCX", "msm_otg"),
+ REGULATOR_SUPPLY("HSIC_VDDCX", "msm_hsic_peripheral"),
};
VREG_CONSUMERS(S2) = {
REGULATOR_SUPPLY("8018_s2", NULL),
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 37e4606..f708b11 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -385,6 +385,7 @@
&msm_device_charger,
#endif
&msm_device_otg,
+ &msm_device_hsic_peripheral,
&msm_device_gadget_peripheral,
&msm_device_hsusb_host,
&msm_device_usb_bam,
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index f4fcb75..f26187e 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -70,12 +70,15 @@
CLK_DUMMY("iface_clk", SDC1_P_CLK, NULL, OFF),
CLK_DUMMY("core_clk", SDC3_CLK, NULL, OFF),
CLK_DUMMY("iface_clk", SDC3_P_CLK, NULL, OFF),
- CLK_DUMMY("usb_phy_clk", NULL, NULL, OFF),
- CLK_DUMMY("usb_hs_clk", NULL, NULL, OFF),
- CLK_DUMMY("usb_hs_pclk", NULL, NULL, OFF),
+ CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
+ CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
+ CLK_DUMMY("alt_core_clk", NULL, "msm_otg", OFF),
+ CLK_DUMMY("iface_clk", NULL, "msm_otg", OFF),
CLK_DUMMY("dfab_clk", DFAB_CLK, NULL, 0),
CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, NULL, 0),
CLK_DUMMY("mem_clk", NULL, NULL, 0),
+ CLK_DUMMY("core_clk", SPI_CLK, "spi_qsd.1", OFF),
+ CLK_DUMMY("iface_clk", SPI_P_CLK, "spi_qsd.1", OFF),
};
struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -86,6 +89,10 @@
static struct of_dev_auxdata msm_copper_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
"msm_serial_hsl.0", NULL),
+ OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
+ "msm_otg", NULL),
+ OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9924000, \
+ "spi_qsd.1", NULL),
{}
};
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
index d4f06fa..8b3b606 100644
--- a/arch/arm/mach-msm/board-msm7627a-bt.c
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -677,11 +677,9 @@
pr_err("%s: could not enable regulator: %d\n", __func__, rc);
goto reg_fail;
}
- if (machine_is_msm7627a_qrd1())
- gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
- GPIO_CFG_2MA), GPIO_CFG_ENABLE);
-
+ gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+ GPIO_CFG_2MA), GPIO_CFG_ENABLE);
/*setup Bahama_sys_reset_n*/
rc = gpio_request(gpio_bt_sys_rest_en, "bahama sys_rst_n");
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
new file mode 100644
index 0000000..a3c2da3
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -0,0 +1,541 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <asm/mach-types.h>
+#include <mach/msm_iomap.h>
+#include <mach/board.h>
+#include <mach/irqs-7xxx.h>
+#include "devices-msm7x2xa.h"
+#include "board-msm7627a.h"
+
+static uint32_t camera_off_gpio_table[] = {
+ GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+static uint32_t camera_on_gpio_table[] = {
+ GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+ .flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+ ._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
+ ._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
+};
+#endif
+
+static struct regulator_bulk_data regs_camera[] = {
+ { .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
+ { .supply = "gp2", .min_uV = 2850000, .max_uV = 2850000 },
+ { .supply = "usb2", .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+static void qrd1_camera_gpio_cfg(void)
+{
+
+ int rc = 0;
+
+ rc = gpio_request(QRD_GPIO_CAM_5MP_SHDN_EN, "ov5640");
+ if (rc < 0)
+ pr_err("%s: gpio_request---GPIO_CAM_5MP_SHDN_EN failed!",
+ __func__);
+
+
+ rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_CAM_5MP_SHDN_EN, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+ GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+ if (rc < 0) {
+ pr_err("%s: unable to enable Power Down gpio for main"
+ "camera!\n", __func__);
+ gpio_free(QRD_GPIO_CAM_5MP_SHDN_EN);
+ }
+
+
+ rc = gpio_request(QRD_GPIO_CAM_5MP_RESET, "ov5640");
+ if (rc < 0) {
+ pr_err("%s: gpio_request---GPIO_CAM_5MP_RESET failed!",
+ __func__);
+ gpio_free(QRD_GPIO_CAM_5MP_SHDN_EN);
+ }
+
+
+ rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_CAM_5MP_RESET, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+ GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+ if (rc < 0) {
+ pr_err("%s: unable to enable reset gpio for main camera!\n",
+ __func__);
+ gpio_free(QRD_GPIO_CAM_5MP_RESET);
+ }
+
+ rc = gpio_request(QRD_GPIO_CAM_3MP_PWDN, "ov7692");
+ if (rc < 0)
+ pr_err("%s: gpio_request---GPIO_CAM_3MP_PWDN failed!",
+ __func__);
+
+ rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_CAM_3MP_PWDN, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+ GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+ if (rc < 0) {
+ pr_err("%s: unable to enable Power Down gpio for front"
+ "camera!\n", __func__);
+ gpio_free(QRD_GPIO_CAM_3MP_PWDN);
+ }
+
+ gpio_direction_output(QRD_GPIO_CAM_5MP_SHDN_EN, 1);
+ gpio_direction_output(QRD_GPIO_CAM_5MP_RESET, 1);
+ gpio_direction_output(QRD_GPIO_CAM_3MP_PWDN, 1);
+}
+
+static void msm_camera_vreg_config(int vreg_en)
+{
+ int rc = vreg_en ?
+ regulator_bulk_enable(ARRAY_SIZE(regs_camera), regs_camera) :
+ regulator_bulk_disable(ARRAY_SIZE(regs_camera), regs_camera);
+
+ if (rc)
+ pr_err("%s: could not %sable regulators: %d\n",
+ __func__, vreg_en ? "en" : "dis", rc);
+}
+
+static int config_gpio_table(uint32_t *table, int len)
+{
+ int rc = 0, i = 0;
+
+ for (i = 0; i < len; i++) {
+ rc = gpio_tlmm_config(table[i], GPIO_CFG_ENABLE);
+ if (rc) {
+ pr_err("%s not able to get gpio\n", __func__);
+ for (i--; i >= 0; i--)
+ gpio_tlmm_config(camera_off_gpio_table[i],
+ GPIO_CFG_ENABLE);
+ break;
+ }
+ }
+ return rc;
+}
+
+static int config_camera_on_gpios_rear(void)
+{
+ int rc = 0;
+
+ if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+ || machine_is_msm7627a_qrd1())
+ msm_camera_vreg_config(1);
+
+ rc = config_gpio_table(camera_on_gpio_table,
+ ARRAY_SIZE(camera_on_gpio_table));
+ if (rc < 0) {
+ pr_err("%s: CAMSENSOR gpio table request"
+ "failed\n", __func__);
+ return rc;
+ }
+
+ return rc;
+}
+
+static void config_camera_off_gpios_rear(void)
+{
+ if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+ || machine_is_msm7627a_qrd1())
+ msm_camera_vreg_config(0);
+
+ config_gpio_table(camera_off_gpio_table,
+ ARRAY_SIZE(camera_off_gpio_table));
+}
+
+static int config_camera_on_gpios_front(void)
+{
+ int rc = 0;
+
+ if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+ || machine_is_msm7627a_qrd1())
+ msm_camera_vreg_config(1);
+
+ rc = config_gpio_table(camera_on_gpio_table,
+ ARRAY_SIZE(camera_on_gpio_table));
+ if (rc < 0) {
+ pr_err("%s: CAMSENSOR gpio table request"
+ "failed\n", __func__);
+ return rc;
+ }
+
+ return rc;
+}
+
+static void config_camera_off_gpios_front(void)
+{
+ if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+ || machine_is_msm7627a_qrd1())
+ msm_camera_vreg_config(0);
+
+ config_gpio_table(camera_off_gpio_table,
+ ARRAY_SIZE(camera_off_gpio_table));
+}
+
+struct msm_camera_device_platform_data msm_camera_device_data_rear = {
+ .camera_gpio_on = config_camera_on_gpios_rear,
+ .camera_gpio_off = config_camera_off_gpios_rear,
+ .ioext.csiphy = 0xA1000000,
+ .ioext.csisz = 0x00100000,
+ .ioext.csiirq = INT_CSI_IRQ_1,
+ .ioclk.mclk_clk_rate = 24000000,
+ .ioclk.vfe_clk_rate = 192000000,
+ .ioext.appphy = MSM_CLK_CTL_PHYS,
+ .ioext.appsz = MSM_CLK_CTL_SIZE,
+};
+
+struct msm_camera_device_platform_data msm_camera_device_data_front = {
+ .camera_gpio_on = config_camera_on_gpios_front,
+ .camera_gpio_off = config_camera_off_gpios_front,
+ .ioext.csiphy = 0xA0F00000,
+ .ioext.csisz = 0x00100000,
+ .ioext.csiirq = INT_CSI_IRQ_0,
+ .ioclk.mclk_clk_rate = 24000000,
+ .ioclk.vfe_clk_rate = 192000000,
+ .ioext.appphy = MSM_CLK_CTL_PHYS,
+ .ioext.appsz = MSM_CLK_CTL_SIZE,
+};
+
+#ifdef CONFIG_S5K4E1
+static struct msm_camera_sensor_platform_info s5k4e1_sensor_7627a_info = {
+ .mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_s5k4e1 = {
+ .flash_type = MSM_CAMERA_FLASH_LED,
+ .flash_src = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data = {
+ .sensor_name = "s5k4e1",
+ .sensor_reset_enable = 1,
+ .sensor_reset = GPIO_CAM_GP_CAMIF_RESET_N,
+ .sensor_pwd = 85,
+ .vcm_pwd = GPIO_CAM_GP_CAM_PWDN,
+ .vcm_enable = 1,
+ .pdata = &msm_camera_device_data_rear,
+ .flash_data = &flash_s5k4e1,
+ .sensor_platform_info = &s5k4e1_sensor_7627a_info,
+ .csi_if = 1
+};
+
+static struct platform_device msm_camera_sensor_s5k4e1 = {
+ .name = "msm_camera_s5k4e1",
+ .dev = {
+ .platform_data = &msm_camera_sensor_s5k4e1_data,
+ },
+};
+#endif
+
+#ifdef CONFIG_IMX072
+static struct msm_camera_sensor_platform_info imx072_sensor_7627a_info = {
+ .mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_imx072 = {
+ .flash_type = MSM_CAMERA_FLASH_LED,
+ .flash_src = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx072_data = {
+ .sensor_name = "imx072",
+ .sensor_reset_enable = 1,
+ .sensor_reset = GPIO_CAM_GP_CAMIF_RESET_N, /* TODO 106,*/
+ .sensor_pwd = 85,
+ .vcm_pwd = GPIO_CAM_GP_CAM_PWDN,
+ .vcm_enable = 1,
+ .pdata = &msm_camera_device_data_rear,
+ .flash_data = &flash_imx072,
+ .sensor_platform_info = &imx072_sensor_7627a_info,
+ .csi_if = 1
+};
+
+static struct platform_device msm_camera_sensor_imx072 = {
+ .name = "msm_camera_imx072",
+ .dev = {
+ .platform_data = &msm_camera_sensor_imx072_data,
+ },
+};
+#endif
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data;
+#ifdef CONFIG_WEBCAM_OV9726
+static struct msm_camera_sensor_platform_info ov9726_sensor_7627a_info = {
+ .mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_ov9726 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+ .flash_src = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
+ .sensor_name = "ov9726",
+ .sensor_reset_enable = 0,
+ .sensor_reset = GPIO_CAM_GP_CAM1MP_XCLR,
+ .sensor_pwd = 85,
+ .vcm_pwd = 1,
+ .vcm_enable = 0,
+ .pdata = &msm_camera_device_data_front,
+ .flash_data = &flash_ov9726,
+ .sensor_platform_info = &ov9726_sensor_7627a_info,
+ .csi_if = 1
+};
+
+static struct platform_device msm_camera_sensor_ov9726 = {
+ .name = "msm_camera_ov9726",
+ .dev = {
+ .platform_data = &msm_camera_sensor_ov9726_data,
+ },
+};
+#else
+static inline void msm_camera_vreg_init(void) { }
+#endif
+
+#ifdef CONFIG_MT9E013
+static struct msm_camera_sensor_platform_info mt9e013_sensor_7627a_info = {
+ .mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9e013 = {
+ .flash_type = MSM_CAMERA_FLASH_LED,
+ .flash_src = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
+ .sensor_name = "mt9e013",
+ .sensor_reset = 0,
+ .sensor_reset_enable = 1,
+ .sensor_pwd = 85,
+ .vcm_pwd = 1,
+ .vcm_enable = 0,
+ .pdata = &msm_camera_device_data_rear,
+ .flash_data = &flash_mt9e013,
+ .sensor_platform_info = &mt9e013_sensor_7627a_info,
+ .csi_if = 1
+};
+
+static struct platform_device msm_camera_sensor_mt9e013 = {
+ .name = "msm_camera_mt9e013",
+ .dev = {
+ .platform_data = &msm_camera_sensor_mt9e013_data,
+ },
+};
+#endif
+
+#ifdef CONFIG_OV5640
+static struct msm_camera_sensor_platform_info ov5640_sensor_info = {
+ .mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_src msm_flash_src_ov5640 = {
+ .flash_sr_type = MSM_CAMERA_FLASH_SRC_LED,
+ ._fsrc.led_src.led_name = "flashlight",
+ ._fsrc.led_src.led_name_len = 10,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov5640 = {
+ .flash_type = MSM_CAMERA_FLASH_LED,
+ .flash_src = &msm_flash_src_ov5640,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov5640_data = {
+ .sensor_name = "ov5640",
+ .sensor_reset_enable = 1,
+ .sensor_reset = QRD_GPIO_CAM_5MP_RESET,
+ .sensor_pwd = QRD_GPIO_CAM_5MP_SHDN_EN,
+ .vcm_pwd = 0,
+ .vcm_enable = 0,
+ .pdata = &msm_camera_device_data_rear,
+ .flash_data = &flash_ov5640,
+ .sensor_platform_info = &ov5640_sensor_info,
+ .csi_if = 1,
+};
+
+static struct platform_device msm_camera_sensor_ov5640 = {
+ .name = "msm_camera_ov5640",
+ .dev = {
+ .platform_data = &msm_camera_sensor_ov5640_data,
+ },
+};
+#endif
+
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+static struct msm_camera_sensor_platform_info ov7692_sensor_7627a_info = {
+ .mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_ov7692 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
+ .sensor_name = "ov7692",
+ .sensor_reset_enable = 0,
+ .sensor_reset = 0,
+ .sensor_pwd = QRD_GPIO_CAM_3MP_PWDN,
+ .vcm_pwd = 0,
+ .vcm_enable = 0,
+ .pdata = &msm_camera_device_data_front,
+ .flash_data = &flash_ov7692,
+ .sensor_platform_info = &ov7692_sensor_7627a_info,
+ .csi_if = 1,
+};
+
+static struct platform_device msm_camera_sensor_ov7692 = {
+ .name = "msm_camera_ov7692",
+ .dev = {
+ .platform_data = &msm_camera_sensor_ov7692_data,
+ },
+};
+#endif
+
+enum {
+ SX150X_CAM,
+};
+
+static struct sx150x_platform_data sx150x_data[] __initdata = {
+ [SX150X_CAM] = {
+ .gpio_base = GPIO_CAM_EXPANDER_BASE,
+ .oscio_is_gpo = false,
+ .io_pullup_ena = 0,
+ .io_pulldn_ena = 0,
+ .io_open_drain_ena = 0x23,
+ .irq_summary = -1,
+ },
+};
+
+static struct i2c_board_info cam_exp_i2c_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("sx1508q", 0x22),
+ .platform_data = &sx150x_data[SX150X_CAM],
+ },
+};
+
+static struct i2c_board_info i2c_camera_devices[] = {
+ #ifdef CONFIG_S5K4E1
+ {
+ I2C_BOARD_INFO("s5k4e1", 0x36),
+ },
+ {
+ I2C_BOARD_INFO("s5k4e1_af", 0x8c >> 1),
+ },
+ #endif
+ #ifdef CONFIG_WEBCAM_OV9726
+ {
+ I2C_BOARD_INFO("ov9726", 0x10),
+ },
+ #endif
+ #ifdef CONFIG_IMX072
+ {
+ I2C_BOARD_INFO("imx072", 0x34),
+ },
+ #endif
+ #ifdef CONFIG_MT9E013
+ {
+ I2C_BOARD_INFO("mt9e013", 0x6C >> 2),
+ },
+ #endif
+ {
+ I2C_BOARD_INFO("sc628a", 0x6E),
+ },
+};
+
+static struct i2c_board_info i2c_camera_devices_qrd[] = {
+ #ifdef CONFIG_OV5640
+ {
+ I2C_BOARD_INFO("ov5640", 0x78 >> 1),
+ },
+ #endif
+ #ifdef CONFIG_WEBCAM_OV7692_QRD
+ {
+ I2C_BOARD_INFO("ov7692", 0x78),
+ },
+ #endif
+};
+
+static struct platform_device *camera_devices_msm[] __initdata = {
+#ifdef CONFIG_S5K4E1
+ &msm_camera_sensor_s5k4e1,
+#endif
+#ifdef CONFIG_IMX072
+ &msm_camera_sensor_imx072,
+#endif
+#ifdef CONFIG_WEBCAM_OV9726
+ &msm_camera_sensor_ov9726,
+#endif
+#ifdef CONFIG_MT9E013
+ &msm_camera_sensor_mt9e013,
+#endif
+};
+
+static struct platform_device *camera_devices_qrd[] __initdata = {
+#ifdef CONFIG_OV5640
+ &msm_camera_sensor_ov5640,
+#endif
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+ &msm_camera_sensor_ov7692,
+#endif
+};
+
+static void __init register_i2c_devices(void)
+{
+ i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
+ cam_exp_i2c_info,
+ ARRAY_SIZE(cam_exp_i2c_info));
+}
+
+void __init msm7627a_camera_init(void)
+{
+ int rc;
+
+ if (machine_is_msm7627a_qrd1()) {
+ qrd1_camera_gpio_cfg();
+ platform_add_devices(camera_devices_qrd,
+ ARRAY_SIZE(camera_devices_qrd));
+ } else
+ platform_add_devices(camera_devices_msm,
+ ARRAY_SIZE(camera_devices_msm));
+
+ if (!machine_is_msm7627a_qrd1())
+ register_i2c_devices();
+
+ rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
+
+ if (rc) {
+ pr_err("%s: could not get regulators: %d\n", __func__, rc);
+ return;
+ }
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_camera), regs_camera);
+
+ if (rc) {
+ pr_err("%s: could not set voltages: %d\n", __func__, rc);
+ return;
+ }
+
+ if (machine_is_msm7627a_qrd1())
+ i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
+ i2c_camera_devices_qrd,
+ ARRAY_SIZE(i2c_camera_devices_qrd));
+ else
+ i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
+ i2c_camera_devices,
+ ARRAY_SIZE(i2c_camera_devices));
+}
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
index 4680a31..7d7da4f 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,53 @@
void __init msm7627a_init_mmc(void);
+enum {
+ GPIO_EXPANDER_IRQ_BASE = NR_MSM_IRQS + NR_GPIO_IRQS,
+ GPIO_EXPANDER_GPIO_BASE = NR_MSM_GPIOS,
+ /* SURF expander */
+ GPIO_CORE_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
+ GPIO_BT_SYS_REST_EN = GPIO_CORE_EXPANDER_BASE,
+ GPIO_WLAN_EXT_POR_N,
+ GPIO_DISPLAY_PWR_EN,
+ GPIO_BACKLIGHT_EN,
+ GPIO_PRESSURE_XCLR,
+ GPIO_VREG_S3_EXP,
+ GPIO_UBM2M_PWRDWN,
+ GPIO_ETM_MODE_CS_N,
+ GPIO_HOST_VBUS_EN,
+ GPIO_SPI_MOSI,
+ GPIO_SPI_MISO,
+ GPIO_SPI_CLK,
+ GPIO_SPI_CS0_N,
+ GPIO_CORE_EXPANDER_IO13,
+ GPIO_CORE_EXPANDER_IO14,
+ GPIO_CORE_EXPANDER_IO15,
+ /* Camera expander */
+ GPIO_CAM_EXPANDER_BASE = GPIO_CORE_EXPANDER_BASE + 16,
+ GPIO_CAM_GP_STROBE_READY = GPIO_CAM_EXPANDER_BASE,
+ GPIO_CAM_GP_AFBUSY,
+ GPIO_CAM_GP_CAM_PWDN,
+ GPIO_CAM_GP_CAM1MP_XCLR,
+ GPIO_CAM_GP_CAMIF_RESET_N,
+ GPIO_CAM_GP_STROBE_CE,
+ GPIO_CAM_GP_LED_EN1,
+ GPIO_CAM_GP_LED_EN2,
+};
+
+enum {
+ QRD_GPIO_HOST_VBUS_EN = 107,
+ QRD_GPIO_BT_SYS_REST_EN = 114,
+ QRD_GPIO_WAKE_ON_WIRELESS,
+ QRD_GPIO_BACKLIGHT_EN,
+ QRD_GPIO_NC,
+ QRD_GPIO_CAM_3MP_PWDN, /* CAM_VGA */
+ QRD_GPIO_WLAN_EN,
+ QRD_GPIO_CAM_5MP_SHDN_EN,
+ QRD_GPIO_CAM_5MP_RESET,
+ QRD_GPIO_TP,
+ QRD_GPIO_CAM_GP_CAMIF_RESET,
+};
+
#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
#define FPGA_MSM_CNTRL_REG2 0x90008010
@@ -30,7 +77,7 @@
#define FM_I2S_WS_MODE 0x8F
#define FM_I2S_SCK_MODE 0x90
#define I2C_PIN_CTL 0x15
-#define I2C_NORMAL 0x40
+#define I2C_NORMAL 0x40
struct bahama_config_register {
u8 reg;
@@ -52,4 +99,6 @@
void __init msm7627a_bt_power_init(void);
#endif
+void __init msm7627a_camera_init(void);
+
#endif
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 2e9e452..5bcd749 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -58,43 +58,9 @@
#define PMEM_KERNEL_EBI1_SIZE 0x3A000
#define MSM_PMEM_AUDIO_SIZE 0x5B000
-enum {
- GPIO_EXPANDER_IRQ_BASE = NR_MSM_IRQS + NR_GPIO_IRQS,
- GPIO_EXPANDER_GPIO_BASE = NR_MSM_GPIOS,
- /* SURF expander */
- GPIO_CORE_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
- GPIO_BT_SYS_REST_EN = GPIO_CORE_EXPANDER_BASE,
- GPIO_WLAN_EXT_POR_N,
- GPIO_DISPLAY_PWR_EN,
- GPIO_BACKLIGHT_EN,
- GPIO_PRESSURE_XCLR,
- GPIO_VREG_S3_EXP,
- GPIO_UBM2M_PWRDWN,
- GPIO_ETM_MODE_CS_N,
- GPIO_HOST_VBUS_EN,
- GPIO_SPI_MOSI,
- GPIO_SPI_MISO,
- GPIO_SPI_CLK,
- GPIO_SPI_CS0_N,
- GPIO_CORE_EXPANDER_IO13,
- GPIO_CORE_EXPANDER_IO14,
- GPIO_CORE_EXPANDER_IO15,
- /* Camera expander */
- GPIO_CAM_EXPANDER_BASE = GPIO_CORE_EXPANDER_BASE + 16,
- GPIO_CAM_GP_STROBE_READY = GPIO_CAM_EXPANDER_BASE,
- GPIO_CAM_GP_AFBUSY,
- GPIO_CAM_GP_CAM_PWDN,
- GPIO_CAM_GP_CAM1MP_XCLR,
- GPIO_CAM_GP_CAMIF_RESET_N,
- GPIO_CAM_GP_STROBE_CE,
- GPIO_CAM_GP_LED_EN1,
- GPIO_CAM_GP_LED_EN2,
-};
-
#if defined(CONFIG_GPIO_SX150X)
enum {
SX150X_CORE,
- SX150X_CAM,
};
static struct sx150x_platform_data sx150x_data[] __initdata = {
@@ -106,14 +72,6 @@
.io_open_drain_ena = 0xfef8,
.irq_summary = -1,
},
- [SX150X_CAM] = {
- .gpio_base = GPIO_CAM_EXPANDER_BASE,
- .oscio_is_gpo = false,
- .io_pullup_ena = 0,
- .io_pulldn_ena = 0,
- .io_open_drain_ena = 0x23,
- .irq_summary = -1,
- },
};
#endif
@@ -129,22 +87,9 @@
I2C_BOARD_INFO("sx1509q", 0x3e),
},
};
-static struct i2c_board_info cam_exp_i2c_info[] __initdata = {
- {
- I2C_BOARD_INFO("sx1508q", 0x22),
- .platform_data = &sx150x_data[SX150X_CAM],
- },
-};
-#endif
-#if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
static void __init register_i2c_devices(void)
{
-
- i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
- cam_exp_i2c_info,
- ARRAY_SIZE(cam_exp_i2c_info));
-
if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
sx150x_data[SX150X_CORE].io_open_drain_ena = 0xe0f0;
@@ -209,7 +154,7 @@
#define MSM_PMEM_MDP_SIZE 0x2300000
#define MSM7x25A_MSM_PMEM_MDP_SIZE 0x1500000
-#define MSM_PMEM_ADSP_SIZE 0x1000000
+#define MSM_PMEM_ADSP_SIZE 0x1100000
#define MSM7x25A_MSM_PMEM_ADSP_SIZE 0xB91000
@@ -953,311 +898,6 @@
gpio_set_value(ETH_FIFO_SEL_GPIO, 0);
}
-#ifdef CONFIG_MSM_CAMERA
-static uint32_t camera_off_gpio_table[] = {
- GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static uint32_t camera_on_gpio_table[] = {
- GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-#ifdef CONFIG_MSM_CAMERA_FLASH
-static struct msm_camera_sensor_flash_src msm_flash_src = {
- .flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
- ._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
- ._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
-};
-#endif
-
-static struct regulator_bulk_data regs_camera[] = {
- { .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
- { .supply = "gp2", .min_uV = 2850000, .max_uV = 2850000 },
- { .supply = "usb2", .min_uV = 1800000, .max_uV = 1800000 },
-};
-
-static void __init msm_camera_vreg_init(void)
-{
- int rc;
-
- rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
-
- if (rc) {
- pr_err("%s: could not get regulators: %d\n", __func__, rc);
- return;
- }
-
- rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_camera), regs_camera);
-
- if (rc) {
- pr_err("%s: could not set voltages: %d\n", __func__, rc);
- return;
- }
-}
-
-static void msm_camera_vreg_config(int vreg_en)
-{
- int rc = vreg_en ?
- regulator_bulk_enable(ARRAY_SIZE(regs_camera), regs_camera) :
- regulator_bulk_disable(ARRAY_SIZE(regs_camera), regs_camera);
-
- if (rc)
- pr_err("%s: could not %sable regulators: %d\n",
- __func__, vreg_en ? "en" : "dis", rc);
-}
-
-static int config_gpio_table(uint32_t *table, int len)
-{
- int rc = 0, i = 0;
-
- for (i = 0; i < len; i++) {
- rc = gpio_tlmm_config(table[i], GPIO_CFG_ENABLE);
- if (rc) {
- pr_err("%s not able to get gpio\n", __func__);
- for (i--; i >= 0; i--)
- gpio_tlmm_config(camera_off_gpio_table[i],
- GPIO_CFG_ENABLE);
- break;
- }
- }
- return rc;
-}
-
-static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data;
-static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data;
-static int config_camera_on_gpios_rear(void)
-{
- int rc = 0;
-
- if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
- msm_camera_vreg_config(1);
-
- rc = config_gpio_table(camera_on_gpio_table,
- ARRAY_SIZE(camera_on_gpio_table));
- if (rc < 0) {
- pr_err("%s: CAMSENSOR gpio table request"
- "failed\n", __func__);
- return rc;
- }
-
- return rc;
-}
-
-static void config_camera_off_gpios_rear(void)
-{
- if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
- msm_camera_vreg_config(0);
-
- config_gpio_table(camera_off_gpio_table,
- ARRAY_SIZE(camera_off_gpio_table));
-}
-
-static int config_camera_on_gpios_front(void)
-{
- int rc = 0;
-
- if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
- msm_camera_vreg_config(1);
-
- rc = config_gpio_table(camera_on_gpio_table,
- ARRAY_SIZE(camera_on_gpio_table));
- if (rc < 0) {
- pr_err("%s: CAMSENSOR gpio table request"
- "failed\n", __func__);
- return rc;
- }
-
- return rc;
-}
-
-static void config_camera_off_gpios_front(void)
-{
- if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
- msm_camera_vreg_config(0);
-
- config_gpio_table(camera_off_gpio_table,
- ARRAY_SIZE(camera_off_gpio_table));
-}
-
-struct msm_camera_device_platform_data msm_camera_device_data_rear = {
- .camera_gpio_on = config_camera_on_gpios_rear,
- .camera_gpio_off = config_camera_off_gpios_rear,
- .ioext.csiphy = 0xA1000000,
- .ioext.csisz = 0x00100000,
- .ioext.csiirq = INT_CSI_IRQ_1,
- .ioclk.mclk_clk_rate = 24000000,
- .ioclk.vfe_clk_rate = 192000000,
- .ioext.appphy = MSM_CLK_CTL_PHYS,
- .ioext.appsz = MSM_CLK_CTL_SIZE,
-};
-
-struct msm_camera_device_platform_data msm_camera_device_data_front = {
- .camera_gpio_on = config_camera_on_gpios_front,
- .camera_gpio_off = config_camera_off_gpios_front,
- .ioext.csiphy = 0xA0F00000,
- .ioext.csisz = 0x00100000,
- .ioext.csiirq = INT_CSI_IRQ_0,
- .ioclk.mclk_clk_rate = 24000000,
- .ioclk.vfe_clk_rate = 192000000,
- .ioext.appphy = MSM_CLK_CTL_PHYS,
- .ioext.appsz = MSM_CLK_CTL_SIZE,
-};
-
-#ifdef CONFIG_S5K4E1
-static struct msm_camera_sensor_platform_info s5k4e1_sensor_7627a_info = {
- .mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_s5k4e1 = {
- .flash_type = MSM_CAMERA_FLASH_LED,
- .flash_src = &msm_flash_src
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data = {
- .sensor_name = "s5k4e1",
- .sensor_reset_enable = 1,
- .sensor_reset = GPIO_CAM_GP_CAMIF_RESET_N,
- .sensor_pwd = 85,
- .vcm_pwd = GPIO_CAM_GP_CAM_PWDN,
- .vcm_enable = 1,
- .pdata = &msm_camera_device_data_rear,
- .flash_data = &flash_s5k4e1,
- .sensor_platform_info = &s5k4e1_sensor_7627a_info,
- .csi_if = 1
-};
-
-static struct platform_device msm_camera_sensor_s5k4e1 = {
- .name = "msm_camera_s5k4e1",
- .dev = {
- .platform_data = &msm_camera_sensor_s5k4e1_data,
- },
-};
-#endif
-
-#ifdef CONFIG_IMX072
-static struct msm_camera_sensor_platform_info imx072_sensor_7627a_info = {
- .mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_imx072 = {
- .flash_type = MSM_CAMERA_FLASH_LED,
- .flash_src = &msm_flash_src
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_imx072_data = {
- .sensor_name = "imx072",
- .sensor_reset_enable = 1,
- .sensor_reset = GPIO_CAM_GP_CAMIF_RESET_N, /* TODO 106,*/
- .sensor_pwd = 85,
- .vcm_pwd = GPIO_CAM_GP_CAM_PWDN,
- .vcm_enable = 1,
- .pdata = &msm_camera_device_data_rear,
- .flash_data = &flash_imx072,
- .sensor_platform_info = &imx072_sensor_7627a_info,
- .csi_if = 1
-};
-
-static struct platform_device msm_camera_sensor_imx072 = {
- .name = "msm_camera_imx072",
- .dev = {
- .platform_data = &msm_camera_sensor_imx072_data,
- },
-};
-#endif
-
-#ifdef CONFIG_WEBCAM_OV9726
-static struct msm_camera_sensor_platform_info ov9726_sensor_7627a_info = {
- .mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_ov9726 = {
- .flash_type = MSM_CAMERA_FLASH_NONE,
- .flash_src = &msm_flash_src
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
- .sensor_name = "ov9726",
- .sensor_reset_enable = 0,
- .sensor_reset = GPIO_CAM_GP_CAM1MP_XCLR,
- .sensor_pwd = 85,
- .vcm_pwd = 1,
- .vcm_enable = 0,
- .pdata = &msm_camera_device_data_front,
- .flash_data = &flash_ov9726,
- .sensor_platform_info = &ov9726_sensor_7627a_info,
- .csi_if = 1
-};
-
-static struct platform_device msm_camera_sensor_ov9726 = {
- .name = "msm_camera_ov9726",
- .dev = {
- .platform_data = &msm_camera_sensor_ov9726_data,
- },
-};
-#else
-static inline void msm_camera_vreg_init(void) { }
-#endif
-
-#ifdef CONFIG_MT9E013
-static struct msm_camera_sensor_platform_info mt9e013_sensor_7627a_info = {
- .mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_mt9e013 = {
- .flash_type = MSM_CAMERA_FLASH_LED,
- .flash_src = &msm_flash_src
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
- .sensor_name = "mt9e013",
- .sensor_reset = 0,
- .sensor_reset_enable = 1,
- .sensor_pwd = 85,
- .vcm_pwd = 1,
- .vcm_enable = 0,
- .pdata = &msm_camera_device_data_rear,
- .flash_data = &flash_mt9e013,
- .sensor_platform_info = &mt9e013_sensor_7627a_info,
- .csi_if = 1
-};
-
-static struct platform_device msm_camera_sensor_mt9e013 = {
- .name = "msm_camera_mt9e013",
- .dev = {
- .platform_data = &msm_camera_sensor_mt9e013_data,
- },
-};
-#endif
-
-static struct i2c_board_info i2c_camera_devices[] = {
- #ifdef CONFIG_S5K4E1
- {
- I2C_BOARD_INFO("s5k4e1", 0x36),
- },
- {
- I2C_BOARD_INFO("s5k4e1_af", 0x8c >> 1),
- },
- #endif
- #ifdef CONFIG_WEBCAM_OV9726
- {
- I2C_BOARD_INFO("ov9726", 0x10),
- },
- #endif
- #ifdef CONFIG_IMX072
- {
- I2C_BOARD_INFO("imx072", 0x34),
- },
- #endif
- #ifdef CONFIG_MT9E013
- {
- I2C_BOARD_INFO("mt9e013", 0x6C >> 2),
- },
- #endif
- {
- I2C_BOARD_INFO("sc628a", 0x6E),
- },
-};
-#endif
#if defined(CONFIG_SERIAL_MSM_HSL_CONSOLE) \
&& defined(CONFIG_MSM_SHARED_GPIO_FOR_UART2DM)
static struct msm_gpio uart2dm_gpios[] = {
@@ -1315,18 +955,6 @@
&lcdc_toshiba_panel_device,
&msm_batt_device,
&smsc911x_device,
-#ifdef CONFIG_S5K4E1
- &msm_camera_sensor_s5k4e1,
-#endif
-#ifdef CONFIG_IMX072
- &msm_camera_sensor_imx072,
-#endif
-#ifdef CONFIG_WEBCAM_OV9726
- &msm_camera_sensor_ov9726,
-#endif
-#ifdef CONFIG_MT9E013
- &msm_camera_sensor_mt9e013,
-#endif
#ifdef CONFIG_FB_MSM_MIPI_DSI
&mipi_dsi_renesas_panel_device,
#endif
@@ -2026,10 +1654,7 @@
ARRAY_SIZE(atmel_ts_i2c_info));
#if defined(CONFIG_MSM_CAMERA)
- msm_camera_vreg_init();
- i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
- i2c_camera_devices,
- ARRAY_SIZE(i2c_camera_devices));
+ msm7627a_camera_init();
#endif
platform_device_register(&kp_pdev);
platform_device_register(&hs_pdev);
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 8f9b3f8..7699aa8 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2672,12 +2672,13 @@
#define MSM_ION_SF_SIZE 0x1800000 /* 24MB */
#define MSM_ION_CAMERA_SIZE MSM_PMEM_ADSP_SIZE
-#define MSM_ION_MM_SIZE 0x3800000 /* 56MB */
+#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
+#define MSM_ION_MM_SIZE 0x3600000 /* (54MB) */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_WB_SIZE 0x600000 /* 6MB */
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_ION_HEAP_NUM 6
+#define MSM_ION_HEAP_NUM 7
#else
#define MSM_ION_HEAP_NUM 1
#endif
@@ -5239,6 +5240,38 @@
};
#ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+ .permission_type = IPT_TYPE_MM_CARVEOUT,
+ .align = PAGE_SIZE,
+ .request_region = request_smi_region,
+ .release_region = release_smi_region,
+ .setup_region = setup_smi_region,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+ .permission_type = IPT_TYPE_MFC_SHAREDMEM,
+ .align = PAGE_SIZE,
+ .request_region = request_smi_region,
+ .release_region = release_smi_region,
+ .setup_region = setup_smi_region,
+};
+
+static struct ion_cp_heap_pdata cp_wb_ion_pdata = {
+ .permission_type = IPT_TYPE_MDP_WRITEBACK,
+ .align = PAGE_SIZE,
+};
+
+static struct ion_co_heap_pdata fw_co_ion_pdata = {
+ .adjacent_mem_id = ION_CP_MM_HEAP_ID,
+ .align = SZ_128K,
+};
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+ .adjacent_mem_id = INVALID_HEAP_ID,
+ .align = PAGE_SIZE,
+};
+#endif
static struct ion_platform_data ion_pdata = {
.nr = MSM_ION_HEAP_NUM,
.heaps = {
@@ -5254,16 +5287,23 @@
.name = ION_SF_HEAP_NAME,
.size = MSM_ION_SF_SIZE,
.memory_type = ION_EBI_TYPE,
+ .extra_data = (void *)&co_ion_pdata,
},
{
.id = ION_CP_MM_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
+ .type = ION_HEAP_TYPE_CP,
.name = ION_MM_HEAP_NAME,
.size = MSM_ION_MM_SIZE,
.memory_type = ION_SMI_TYPE,
- .request_region = request_smi_region,
- .release_region = release_smi_region,
- .setup_region = setup_smi_region,
+ .extra_data = (void *) &cp_mm_ion_pdata,
+ },
+ {
+ .id = ION_MM_FIRMWARE_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_MM_FIRMWARE_HEAP_NAME,
+ .size = MSM_ION_MM_FW_SIZE,
+ .memory_type = ION_SMI_TYPE,
+ .extra_data = (void *) &fw_co_ion_pdata,
},
{
.id = ION_CAMERA_HEAP_ID,
@@ -5271,23 +5311,23 @@
.name = ION_CAMERA_HEAP_NAME,
.size = MSM_ION_CAMERA_SIZE,
.memory_type = ION_EBI_TYPE,
+ .extra_data = &co_ion_pdata,
},
{
.id = ION_CP_MFC_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
+ .type = ION_HEAP_TYPE_CP,
.name = ION_MFC_HEAP_NAME,
.size = MSM_ION_MFC_SIZE,
.memory_type = ION_SMI_TYPE,
- .request_region = request_smi_region,
- .release_region = release_smi_region,
- .setup_region = setup_smi_region,
+ .extra_data = (void *) &cp_mfc_ion_pdata,
},
{
.id = ION_CP_WB_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
+ .type = ION_HEAP_TYPE_CP,
.name = ION_WB_HEAP_NAME,
.size = MSM_ION_WB_SIZE,
.memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &cp_wb_ion_pdata,
},
#endif
}
@@ -5332,6 +5372,7 @@
{
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
+ msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_FW_SIZE;
msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_SIZE;
msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MFC_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 594a084..9d4818a 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -68,20 +68,6 @@
#define I2C_PIN_CTL 0x15
#define I2C_NORMAL 0x40
-enum {
- GPIO_HOST_VBUS_EN = 107,
- GPIO_BT_SYS_REST_EN = 114,
- GPIO_WAKE_ON_WIRELESS,
- GPIO_BACKLIGHT_EN,
- GPIO_NC,
- GPIO_CAM_3MP_PWDN, /* CAM_VGA */
- GPIO_WLAN_EN,
- GPIO_CAM_5MP_SHDN_EN,
- GPIO_CAM_5MP_RESET,
- GPIO_TP,
- GPIO_CAM_GP_CAMIF_RESET,
-};
-
static struct platform_device msm_wlan_ar6000_pm_device = {
.name = "wlan_ar6000_pm_dev",
.id = -1,
@@ -295,7 +281,7 @@
int rc = 0;
unsigned gpio;
- gpio = GPIO_HOST_VBUS_EN;
+ gpio = QRD_GPIO_HOST_VBUS_EN;
rc = gpio_request(gpio, "i2c_host_vbus_en");
if (rc < 0) {
@@ -517,7 +503,7 @@
static int mipi_truly_set_bl(int on)
{
- gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, !!on);
+ gpio_set_value_cansleep(QRD_GPIO_BACKLIGHT_EN, !!on);
return 1;
}
@@ -739,275 +725,6 @@
.dev.platform_data = &msm_psy_batt_data,
};
-#ifdef CONFIG_MSM_CAMERA
-static uint32_t camera_off_gpio_table[] = {
- GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static uint32_t camera_on_gpio_table[] = {
- GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static void qrd1_camera_gpio_cfg(void)
-{
-
- int rc = 0;
-
- rc = gpio_request(GPIO_CAM_5MP_SHDN_EN, "ov5640");
- if (rc < 0)
- pr_err("%s: gpio_request---GPIO_CAM_5MP_SHDN_EN failed!",
- __func__);
-
-
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_CAM_5MP_SHDN_EN, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_2MA), GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("%s: unable to enable Power Down gpio for main"
- "camera!\n", __func__);
- gpio_free(GPIO_CAM_5MP_SHDN_EN);
- }
-
-
- rc = gpio_request(GPIO_CAM_5MP_RESET, "ov5640");
- if (rc < 0) {
- pr_err("%s: gpio_request---GPIO_CAM_5MP_RESET failed!",
- __func__);
- gpio_free(GPIO_CAM_5MP_SHDN_EN);
- }
-
-
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_CAM_5MP_RESET, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_2MA), GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("%s: unable to enable reset gpio for main camera!\n",
- __func__);
- gpio_free(GPIO_CAM_5MP_RESET);
- }
-
- rc = gpio_request(GPIO_CAM_3MP_PWDN, "ov7692");
- if (rc < 0)
- pr_err("%s: gpio_request---GPIO_CAM_3MP_PWDN failed!",
- __func__);
-
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_CAM_3MP_PWDN, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_2MA), GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("%s: unable to enable Power Down gpio for front"
- "camera!\n", __func__);
- gpio_free(GPIO_CAM_3MP_PWDN);
- }
-
- gpio_direction_output(GPIO_CAM_5MP_SHDN_EN, 1);
- gpio_direction_output(GPIO_CAM_5MP_RESET, 1);
- gpio_direction_output(GPIO_CAM_3MP_PWDN, 1);
-}
-
-#endif
-static struct regulator_bulk_data regs_camera[] = {
- { .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
- { .supply = "gp2", .min_uV = 2850000, .max_uV = 2850000 },
- { .supply = "usb2", .min_uV = 1800000, .max_uV = 1800000 },
-};
-
-static void __init msm_camera_vreg_init(void)
-{
- int rc;
-
- rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
- if (rc) {
- pr_err("%s: could not get regulators: %d\n", __func__, rc);
- return;
- }
-
- rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_camera), regs_camera);
- if (rc) {
- pr_err("%s: could not set voltages: %d\n", __func__, rc);
- return;
- }
-}
-
-static void msm_camera_vreg_config(int vreg_en)
-{
- int rc = vreg_en ?
- regulator_bulk_enable(ARRAY_SIZE(regs_camera), regs_camera) :
- regulator_bulk_disable(ARRAY_SIZE(regs_camera), regs_camera);
-
- if (rc)
- pr_err("%s: could not %sable regulators: %d\n",
- __func__, vreg_en ? "en" : "dis", rc);
-}
-static int config_gpio_table(uint32_t *table, int len)
-{
- int rc = 0, i = 0;
-
- for (i = 0; i < len; i++) {
- rc = gpio_tlmm_config(table[i], GPIO_CFG_ENABLE);
- if (rc) {
- pr_err("%s not able to get gpio\n", __func__);
- for (i--; i >= 0; i--)
- gpio_tlmm_config(camera_off_gpio_table[i],
- GPIO_CFG_ENABLE);
- break;
- }
- }
- return rc;
-}
-
-static int config_camera_on_gpios_rear(void)
-{
- int rc = 0;
-
- msm_camera_vreg_config(1);
-
- rc = config_gpio_table(camera_on_gpio_table,
- ARRAY_SIZE(camera_on_gpio_table));
- if (rc < 0) {
- pr_err("%s: CAMSENSOR gpio table request"
- "failed\n", __func__);
- return rc;
- }
-
- return rc;
-}
-
-static void config_camera_off_gpios_rear(void)
-{
- msm_camera_vreg_config(0);
- config_gpio_table(camera_off_gpio_table,
- ARRAY_SIZE(camera_off_gpio_table));
-}
-
-static int config_camera_on_gpios_front(void)
-{
- int rc = 0;
-
- msm_camera_vreg_config(1);
-
- rc = config_gpio_table(camera_on_gpio_table,
- ARRAY_SIZE(camera_on_gpio_table));
- if (rc < 0) {
- pr_err("%s: CAMSENSOR gpio table request"
- "failed\n", __func__);
- return rc;
- }
-
- return rc;
-}
-
-static void config_camera_off_gpios_front(void)
-{
- msm_camera_vreg_config(0);
-
- config_gpio_table(camera_off_gpio_table,
- ARRAY_SIZE(camera_off_gpio_table));
-}
-
-struct msm_camera_device_platform_data msm_camera_data_rear = {
- .camera_gpio_on = config_camera_on_gpios_rear,
- .camera_gpio_off = config_camera_off_gpios_rear,
- .ioext.csiphy = 0xA1000000,
- .ioext.csisz = 0x00100000,
- .ioext.csiirq = INT_CSI_IRQ_1,
- .ioclk.mclk_clk_rate = 24000000,
- .ioclk.vfe_clk_rate = 192000000,
- .ioext.appphy = MSM_CLK_CTL_PHYS,
- .ioext.appsz = MSM_CLK_CTL_SIZE,
-};
-
-struct msm_camera_device_platform_data msm_camera_data_front = {
- .camera_gpio_on = config_camera_on_gpios_front,
- .camera_gpio_off = config_camera_off_gpios_front,
- .ioext.csiphy = 0xA0F00000,
- .ioext.csisz = 0x00100000,
- .ioext.csiirq = INT_CSI_IRQ_0,
- .ioclk.mclk_clk_rate = 24000000,
- .ioclk.vfe_clk_rate = 192000000,
- .ioext.appphy = MSM_CLK_CTL_PHYS,
- .ioext.appsz = MSM_CLK_CTL_SIZE,
-};
-
-#ifdef CONFIG_OV5640
-static struct msm_camera_sensor_platform_info ov5640_sensor_info = {
- .mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_src msm_flash_src_ov5640 = {
- .flash_sr_type = MSM_CAMERA_FLASH_SRC_LED,
- ._fsrc.led_src.led_name = "flashlight",
- ._fsrc.led_src.led_name_len = 10,
-};
-
-static struct msm_camera_sensor_flash_data flash_ov5640 = {
- .flash_type = MSM_CAMERA_FLASH_LED,
- .flash_src = &msm_flash_src_ov5640,
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_ov5640_data = {
- .sensor_name = "ov5640",
- .sensor_reset_enable = 1,
- .sensor_reset = GPIO_CAM_5MP_RESET,
- .sensor_pwd = GPIO_CAM_5MP_SHDN_EN,
- .vcm_pwd = 0,
- .vcm_enable = 0,
- .pdata = &msm_camera_data_rear,
- .flash_data = &flash_ov5640,
- .sensor_platform_info = &ov5640_sensor_info,
- .csi_if = 1,
-};
-
-static struct platform_device msm_camera_sensor_ov5640 = {
- .name = "msm_camera_ov5640",
- .dev = {
- .platform_data = &msm_camera_sensor_ov5640_data,
- },
-};
-#endif
-
-#ifdef CONFIG_WEBCAM_OV7692_QRD
-static struct msm_camera_sensor_platform_info ov7692_sensor_7627a_info = {
- .mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_ov7692 = {
- .flash_type = MSM_CAMERA_FLASH_NONE,
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
- .sensor_name = "ov7692",
- .sensor_reset_enable = 0,
- .sensor_reset = 0,
- .sensor_pwd = GPIO_CAM_3MP_PWDN,
- .vcm_pwd = 0,
- .vcm_enable = 0,
- .pdata = &msm_camera_data_front,
- .flash_data = &flash_ov7692,
- .sensor_platform_info = &ov7692_sensor_7627a_info,
- .csi_if = 1,
-};
-
-static struct platform_device msm_camera_sensor_ov7692 = {
- .name = "msm_camera_ov7692",
- .dev = {
- .platform_data = &msm_camera_sensor_ov7692_data,
- },
-};
-#endif
-
-static struct i2c_board_info i2c_camera_devices[] = {
- #ifdef CONFIG_OV5640
- {
- I2C_BOARD_INFO("ov5640", 0x78 >> 1),
- },
- #endif
- #ifdef CONFIG_WEBCAM_OV7692_QRD
- {
- I2C_BOARD_INFO("ov7692", 0x78),
- },
- #endif
-};
static struct platform_device *qrd1_devices[] __initdata = {
&msm_device_dmov,
&msm_device_smd,
@@ -1025,12 +742,6 @@
&msm_device_snd,
&msm_device_adspdec,
&msm_batt_device,
-#ifdef CONFIG_OV5640
- &msm_camera_sensor_ov5640,
-#endif
-#ifdef CONFIG_WEBCAM_OV7692_QRD
- &msm_camera_sensor_ov7692,
-#endif
&msm_kgsl_3d0,
#ifdef CONFIG_BT
&msm_bt_power_device,
@@ -1183,11 +894,11 @@
int rc = 0;
if (!dsi_gpio_initialized) {
- rc = gpio_request(GPIO_BACKLIGHT_EN, "gpio_bkl_en");
+ rc = gpio_request(QRD_GPIO_BACKLIGHT_EN, "gpio_bkl_en");
if (rc < 0)
return rc;
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_BACKLIGHT_EN, 0,
+ rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_BACKLIGHT_EN, 0,
GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
GPIO_CFG_ENABLE);
if (rc < 0) {
@@ -1195,16 +906,16 @@
return rc;
}
- rc = gpio_direction_output(GPIO_BACKLIGHT_EN, 1);
+ rc = gpio_direction_output(QRD_GPIO_BACKLIGHT_EN, 1);
if (rc < 0) {
pr_err("failed to enable backlight\n");
- gpio_free(GPIO_BACKLIGHT_EN);
+ gpio_free(QRD_GPIO_BACKLIGHT_EN);
return rc;
}
dsi_gpio_initialized = 1;
}
- gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, !!on);
+ gpio_set_value_cansleep(QRD_GPIO_BACKLIGHT_EN, !!on);
if (!on) {
gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 1);
@@ -1331,7 +1042,6 @@
msm7x2x_misc_init();
msm7627a_init_regulators();
msm_device_i2c_init();
- qrd1_camera_gpio_cfg();
#ifdef CONFIG_SERIAL_MSM_HS
msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
@@ -1361,9 +1071,7 @@
msm7627a_bt_power_init();
#endif
- msm_camera_vreg_init();
- i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID, i2c_camera_devices,
- ARRAY_SIZE(i2c_camera_devices));
+ msm7627a_camera_init();
#if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C) || \
defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_MODULE)
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index eec6b8a..09f70f1 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -91,22 +91,6 @@
#define BB_PLL14_STATUS_REG REG(0x31D8)
#define PLLTEST_PAD_CFG_REG REG(0x2FA4)
#define PMEM_ACLK_CTL_REG REG(0x25A0)
-#define QDSS_AT_CLK_SRC0_NS_REG REG(0x2180)
-#define QDSS_AT_CLK_SRC1_NS_REG REG(0x2184)
-#define QDSS_AT_CLK_SRC_CTL_REG REG(0x2188)
-#define QDSS_AT_CLK_NS_REG REG(0x218C)
-#define QDSS_HCLK_CTL_REG REG(0x22A0)
-#define QDSS_RESETS_REG REG(0x2260)
-#define QDSS_STM_CLK_CTL_REG REG(0x2060)
-#define QDSS_TRACECLKIN_CLK_SRC0_NS_REG REG(0x21A0)
-#define QDSS_TRACECLKIN_CLK_SRC1_NS_REG REG(0x21A4)
-#define QDSS_TRACECLKIN_CLK_SRC_CTL_REG REG(0x21A8)
-#define QDSS_TRACECLKIN_CTL_REG REG(0x21AC)
-#define QDSS_TSCTR_CLK_SRC0_NS_REG REG(0x21C0)
-#define QDSS_TSCTR_CLK_SRC1_NS_REG REG(0x21C4)
-#define QDSS_TSCTR_CLK_SRC_CTL_REG REG(0x21C8)
-#define QDSS_TSCTR_CLK_SRC_CTL_REG REG(0x21C8)
-#define QDSS_TSCTR_CTL_REG REG(0x21CC)
#define RINGOSC_NS_REG REG(0x2DC0)
#define RINGOSC_STATUS_REG REG(0x2DCC)
#define RINGOSC_TCXO_CTL_REG REG(0x2DC4)
@@ -1435,279 +1419,6 @@
static CLK_GSBI_QUP(gsbi11_qup, 11, CLK_HALT_CFPB_STATEC_REG, 15);
static CLK_GSBI_QUP(gsbi12_qup, 12, CLK_HALT_CFPB_STATEC_REG, 11);
-#define F_QDSS(f, s, d) \
- { \
- .freq_hz = f, \
- .src_clk = &s##_clk.c, \
- .ns_val = NS_DIVSRC(6, 3, d, 2, 0, s##_to_bb_mux), \
- }
-static struct clk_freq_tbl clk_tbl_qdss[] = {
- F_QDSS( 27000000, pxo, 1),
- F_QDSS(128000000, pll8, 3),
- F_QDSS(300000000, pll3, 4),
- F_END
-};
-
-struct qdss_bank {
- const u32 bank_sel_mask;
- void __iomem *const ns_reg;
- const u32 ns_mask;
-};
-
-#define QDSS_CLK_ROOT_ENA BIT(1)
-
-static int qdss_clk_handoff(struct clk *c)
-{
- struct rcg_clk *clk = to_rcg_clk(c);
- const struct qdss_bank *bank = clk->bank_info;
- u32 reg, ns_val, bank_sel;
- struct clk_freq_tbl *freq;
-
- reg = readl_relaxed(clk->ns_reg);
- if (!(reg & QDSS_CLK_ROOT_ENA))
- return 0;
-
- bank_sel = reg & bank->bank_sel_mask;
- /* Force bank 1 to PXO if bank 0 is in use */
- if (bank_sel == 0)
- writel_relaxed(0, bank->ns_reg);
- ns_val = readl_relaxed(bank->ns_reg) & bank->ns_mask;
- for (freq = clk->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
- if ((freq->ns_val & bank->ns_mask) == ns_val) {
- pr_info("%s rate=%d\n", clk->c.dbg_name, freq->freq_hz);
- break;
- }
- }
- if (freq->freq_hz == FREQ_END)
- return 0;
-
- clk->current_freq = freq;
-
- return 1;
-}
-
-static void set_rate_qdss(struct rcg_clk *clk, struct clk_freq_tbl *nf)
-{
- const struct qdss_bank *bank = clk->bank_info;
- u32 reg, bank_sel_mask = bank->bank_sel_mask;
-
- /* Switch to bank 0 (always sourced from PXO) */
- reg = readl_relaxed(clk->ns_reg);
- reg &= ~bank_sel_mask;
- writel_relaxed(reg, clk->ns_reg);
- /*
- * Wait at least 6 cycles of slowest bank's clock for the glitch-free
- * MUX to fully switch sources.
- */
- mb();
- udelay(1);
-
- /* Set source and divider */
- reg = readl_relaxed(bank->ns_reg);
- reg &= ~bank->ns_mask;
- reg |= nf->ns_val;
- writel_relaxed(reg, bank->ns_reg);
-
- /* Switch to reprogrammed bank */
- reg = readl_relaxed(clk->ns_reg);
- reg |= bank_sel_mask;
- writel_relaxed(reg, clk->ns_reg);
- /*
- * Wait at least 6 cycles of slowest bank's clock for the glitch-free
- * MUX to fully switch sources.
- */
- mb();
- udelay(1);
-}
-
-static int qdss_clk_enable(struct clk *c)
-{
- struct rcg_clk *clk = to_rcg_clk(c);
- const struct qdss_bank *bank = clk->bank_info;
- u32 reg, bank_sel_mask = bank->bank_sel_mask;
- int ret;
-
- /* Switch to bank 1 */
- reg = readl_relaxed(clk->ns_reg);
- reg |= bank_sel_mask;
- writel_relaxed(reg, clk->ns_reg);
-
- ret = rcg_clk_enable(c);
- if (ret) {
- /* Switch to bank 0 */
- reg &= ~bank_sel_mask;
- writel_relaxed(reg, clk->ns_reg);
- }
- return ret;
-}
-
-static void qdss_clk_disable(struct clk *c)
-{
- struct rcg_clk *clk = to_rcg_clk(c);
- const struct qdss_bank *bank = clk->bank_info;
- u32 reg, bank_sel_mask = bank->bank_sel_mask;
-
- rcg_clk_disable(c);
- /* Switch to bank 0 */
- reg = readl_relaxed(clk->ns_reg);
- reg &= ~bank_sel_mask;
- writel_relaxed(reg, clk->ns_reg);
-}
-
-static void qdss_clk_auto_off(struct clk *c)
-{
- struct rcg_clk *clk = to_rcg_clk(c);
- const struct qdss_bank *bank = clk->bank_info;
- u32 reg, bank_sel_mask = bank->bank_sel_mask;
-
- rcg_clk_disable(c);
- /* Switch to bank 0 */
- reg = readl_relaxed(clk->ns_reg);
- reg &= ~bank_sel_mask;
- writel_relaxed(reg, clk->ns_reg);
-}
-
-static struct clk_ops clk_ops_qdss = {
- .enable = qdss_clk_enable,
- .disable = qdss_clk_disable,
- .auto_off = qdss_clk_auto_off,
- .handoff = qdss_clk_handoff,
- .set_rate = rcg_clk_set_rate,
- .get_rate = rcg_clk_get_rate,
- .list_rate = rcg_clk_list_rate,
- .is_enabled = rcg_clk_is_enabled,
- .round_rate = rcg_clk_round_rate,
- .reset = rcg_clk_reset,
- .is_local = local_clk_is_local,
- .get_parent = rcg_clk_get_parent,
-};
-
-static struct qdss_bank bdiv_info_qdss = {
- .bank_sel_mask = BIT(0),
- .ns_reg = QDSS_AT_CLK_SRC1_NS_REG,
- .ns_mask = BM(6, 0),
-};
-
-static struct rcg_clk qdss_at_clk = {
- .b = {
- .ctl_reg = QDSS_AT_CLK_NS_REG,
- .reset_reg = QDSS_RESETS_REG,
- .reset_mask = BIT(0),
- .halt_check = NOCHECK,
- },
- .ns_reg = QDSS_AT_CLK_SRC_CTL_REG,
- .set_rate = set_rate_qdss,
- .freq_tbl = clk_tbl_qdss,
- .bank_info = &bdiv_info_qdss,
- .current_freq = &rcg_dummy_freq,
- .c = {
- .dbg_name = "qdss_at_clk",
- .ops = &clk_ops_qdss,
- VDD_DIG_FMAX_MAP2(LOW, 150000000, NOMINAL, 300000000),
- CLK_INIT(qdss_at_clk.c),
- },
-};
-
-static struct branch_clk qdss_pclkdbg_clk = {
- .b = {
- .ctl_reg = QDSS_AT_CLK_NS_REG,
- .en_mask = BIT(4),
- .reset_reg = QDSS_RESETS_REG,
- .reset_mask = BIT(0),
- .halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
- .halt_bit = 9,
- .halt_check = HALT_VOTED
- },
- .parent = &qdss_at_clk.c,
- .c = {
- .dbg_name = "qdss_pclkdbg_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(qdss_pclkdbg_clk.c),
- },
-};
-
-static struct qdss_bank bdiv_info_qdss_trace = {
- .bank_sel_mask = BIT(0),
- .ns_reg = QDSS_TRACECLKIN_CLK_SRC1_NS_REG,
- .ns_mask = BM(6, 0),
-};
-
-static struct rcg_clk qdss_traceclkin_clk = {
- .b = {
- .ctl_reg = QDSS_TRACECLKIN_CTL_REG,
- .en_mask = BIT(4),
- .reset_reg = QDSS_RESETS_REG,
- .reset_mask = BIT(0),
- .halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
- .halt_bit = 8,
- .halt_check = HALT_VOTED,
- },
- .ns_reg = QDSS_TRACECLKIN_CLK_SRC_CTL_REG,
- .set_rate = set_rate_qdss,
- .freq_tbl = clk_tbl_qdss,
- .bank_info = &bdiv_info_qdss_trace,
- .current_freq = &rcg_dummy_freq,
- .c = {
- .dbg_name = "qdss_traceclkin_clk",
- .ops = &clk_ops_qdss,
- VDD_DIG_FMAX_MAP2(LOW, 150000000, NOMINAL, 300000000),
- CLK_INIT(qdss_traceclkin_clk.c),
- },
-};
-
-static struct clk_freq_tbl clk_tbl_qdss_tsctr[] = {
- F_QDSS( 27000000, pxo, 1),
- F_QDSS(200000000, pll3, 6),
- F_QDSS(400000000, pll3, 3),
- F_END
-};
-
-static struct qdss_bank bdiv_info_qdss_tsctr = {
- .bank_sel_mask = BIT(0),
- .ns_reg = QDSS_TSCTR_CLK_SRC1_NS_REG,
- .ns_mask = BM(6, 0),
-};
-
-static struct rcg_clk qdss_tsctr_clk = {
- .b = {
- .ctl_reg = QDSS_TSCTR_CTL_REG,
- .en_mask = BIT(4),
- .reset_reg = QDSS_RESETS_REG,
- .reset_mask = BIT(3),
- .halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
- .halt_bit = 7,
- .halt_check = HALT_VOTED,
- },
- .ns_reg = QDSS_TSCTR_CLK_SRC_CTL_REG,
- .set_rate = set_rate_qdss,
- .freq_tbl = clk_tbl_qdss_tsctr,
- .bank_info = &bdiv_info_qdss_tsctr,
- .current_freq = &rcg_dummy_freq,
- .c = {
- .dbg_name = "qdss_tsctr_clk",
- .ops = &clk_ops_qdss,
- VDD_DIG_FMAX_MAP2(LOW, 200000000, NOMINAL, 400000000),
- CLK_INIT(qdss_tsctr_clk.c),
- },
-};
-
-static struct branch_clk qdss_stm_clk = {
- .b = {
- .ctl_reg = QDSS_STM_CLK_CTL_REG,
- .en_mask = BIT(4),
- .reset_reg = QDSS_RESETS_REG,
- .reset_mask = BIT(1),
- .halt_reg = CLK_HALT_AFAB_SFAB_STATEB_REG,
- .halt_bit = 20,
- .halt_check = HALT_VOTED,
- },
- .c = {
- .dbg_name = "qdss_stm_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(qdss_stm_clk.c),
- },
-};
-
#define F_PDM(f, s, d) \
{ \
.freq_hz = f, \
@@ -2505,23 +2216,6 @@
},
};
-static struct branch_clk qdss_p_clk = {
- .b = {
- .ctl_reg = QDSS_HCLK_CTL_REG,
- .en_mask = BIT(4),
- .halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
- .halt_bit = 11,
- .halt_check = HALT_VOTED,
- .reset_reg = QDSS_RESETS_REG,
- .reset_mask = BIT(2),
- },
- .c = {
- .dbg_name = "qdss_p_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(qdss_p_clk.c),
- }
-};
-
static struct branch_clk sata_phy_cfg_clk = {
.b = {
.ctl_reg = SATA_PHY_CFG_CLK_CTL_REG,
@@ -4756,11 +4450,7 @@
static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
-/*
- * TODO: replace dummy_clk below with ebi1_clk.c once the
- * bus driver starts voting on ebi1 rates.
- */
-static DEFINE_CLK_VOTER(ebi1_adm_clk, &dummy_clk);
+static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c);
#ifdef CONFIG_DEBUG_FS
struct measure_sel {
@@ -4776,7 +4466,6 @@
static DEFINE_CLK_MEASURE(q6_func_clk);
static struct measure_sel measure_mux[] = {
- { TEST_PER_LS(0x05), &qdss_p_clk.c },
{ TEST_PER_LS(0x08), &slimbus_xo_src_clk.c },
{ TEST_PER_LS(0x12), &sdc1_p_clk.c },
{ TEST_PER_LS(0x13), &sdc1_clk.c },
@@ -4877,11 +4566,6 @@
{ TEST_PER_HS(0x2A), &adm0_clk.c },
{ TEST_PER_HS(0x34), &ebi1_clk.c },
{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
- { TEST_PER_HS(0x48), &qdss_at_clk.c },
- { TEST_PER_HS(0x49), &qdss_pclkdbg_clk.c },
- { TEST_PER_HS(0x4A), &qdss_traceclkin_clk.c },
- { TEST_PER_HS(0x4B), &qdss_tsctr_clk.c },
- { TEST_PER_HS(0x4F), &qdss_stm_clk.c },
{ TEST_PER_HS(0x50), &usb_hsic_hsic_clk.c },
{ TEST_MM_LS(0x00), &dsi1_byte_clk.c },
@@ -5545,12 +5229,6 @@
CLK_LOOKUP("vsync_clk", mdp_vsync_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("lut_mdp", lut_mdp_clk.c, NULL),
CLK_LOOKUP("lut_clk", lut_mdp_clk.c, "footswitch-8x60.4"),
- CLK_LOOKUP("qdss_pclk", qdss_p_clk.c, NULL),
- CLK_LOOKUP("qdss_at_clk", qdss_at_clk.c, NULL),
- CLK_LOOKUP("qdss_pclkdbg_clk", qdss_pclkdbg_clk.c, NULL),
- CLK_LOOKUP("qdss_traceclkin_clk", qdss_traceclkin_clk.c, NULL),
- CLK_LOOKUP("qdss_tsctr_clk", qdss_tsctr_clk.c, NULL),
- CLK_LOOKUP("qdss_stm_clk", qdss_stm_clk.c, NULL),
CLK_LOOKUP("core_clk", rot_clk.c, "msm_rotator.0"),
CLK_LOOKUP("core_clk", rot_clk.c, "footswitch-8x60.6"),
CLK_LOOKUP("tv_src_clk", tv_src_clk.c, NULL),
@@ -5631,6 +5309,13 @@
CLK_LOOKUP("core_clk", gfx3d_clk.c, "msm_iommu.9"),
CLK_LOOKUP("core_clk", gfx2d0_clk.c, "msm_iommu.10"),
CLK_LOOKUP("core_clk", gfx2d1_clk.c, "msm_iommu.11"),
+
+ CLK_LOOKUP("mdp_iommu_clk", mdp_axi_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("rot_iommu_clk", rot_axi_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("vcodec_iommu0_clk", vcodec_axi_a_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_b_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c, "msm_vidc.0"),
+
CLK_LOOKUP("dfab_dsps_clk", dfab_dsps_clk.c, NULL),
CLK_LOOKUP("core_clk", dfab_usb_hs_clk.c, "msm_otg"),
CLK_LOOKUP("bus_clk", dfab_sdc1_clk.c, "msm_sdcc.1"),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index c33daf7..3e57ebc 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1671,6 +1671,11 @@
CLK_LOOKUP("core_clk", usb_hsic_sys_clk.c, "msm_hsic_host"),
CLK_LOOKUP("iface_clk", usb_hsic_p_clk.c, "msm_hsic_host"),
CLK_LOOKUP("phy_clk", usb_hsic_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("alt_core_clk", usb_hsic_xcvr_clk.c, "msm_hsic_peripheral"),
+ CLK_LOOKUP("cal_clk", usb_hsic_hsio_cal_clk.c, "msm_hsic_peripheral"),
+ CLK_LOOKUP("core_clk", usb_hsic_sys_clk.c, "msm_hsic_peripheral"),
+ CLK_LOOKUP("iface_clk", usb_hsic_p_clk.c, "msm_hsic_peripheral"),
+ CLK_LOOKUP("phy_clk", usb_hsic_clk.c, "msm_hsic_peripheral"),
CLK_LOOKUP("iface_clk", sdc1_p_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("iface_clk", sdc2_p_clk.c, "msm_sdcc.2"),
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 12a00e6..9c77f3d 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -24,6 +24,7 @@
#include <mach/dma.h>
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
+#include <mach/msm_bus_board.h>
#include "clock.h"
#include "devices.h"
#include "msm_watchdog.h"
@@ -694,6 +695,27 @@
},
};
+struct platform_device msm_bus_8064_sys_fabric = {
+ .name = "msm_bus_fabric",
+ .id = MSM_BUS_FAB_SYSTEM,
+};
+struct platform_device msm_bus_8064_apps_fabric = {
+ .name = "msm_bus_fabric",
+ .id = MSM_BUS_FAB_APPSS,
+};
+struct platform_device msm_bus_8064_mm_fabric = {
+ .name = "msm_bus_fabric",
+ .id = MSM_BUS_FAB_MMSS,
+};
+struct platform_device msm_bus_8064_sys_fpb = {
+ .name = "msm_bus_fabric",
+ .id = MSM_BUS_FAB_SYSTEM_FPB,
+};
+struct platform_device msm_bus_8064_cpss_fpb = {
+ .name = "msm_bus_fabric",
+ .id = MSM_BUS_FAB_CPSS_FPB,
+};
+
static struct msm_sps_platform_data msm_sps_pdata = {
.bamdma_restricted_pipes = 0x06,
};
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 0c46c9d..314d064 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -170,6 +170,29 @@
},
};
+static struct resource resources_hsic_peripheral[] = {
+ {
+ .start = MSM9615_HSIC_PHYS,
+ .end = MSM9615_HSIC_PHYS + MSM9615_HSIC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = USB_HSIC_IRQ,
+ .end = USB_HSIC_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm_device_hsic_peripheral = {
+ .name = "msm_hsic_peripheral",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_hsic_peripheral),
+ .resource = resources_hsic_peripheral,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
static struct resource resources_hsusb_host[] = {
{
.start = MSM9615_HSUSB_PHYS,
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 917dfc7..97cb263 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -595,12 +595,16 @@
.bus_freq = 200000000,
},
{
+ .gpu_freq = 192000000,
+ .bus_freq = 160000000,
+ },
+ {
.gpu_freq = 133330000,
.bus_freq = 0,
},
},
.init_level = 0,
- .num_levels = 2,
+ .num_levels = 3,
.set_grp_async = set_grp_xbar_async,
.idle_timeout = HZ/5,
.nap_allowed = false,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 6d8d393..5d28fa9 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -94,7 +94,7 @@
extern struct platform_device msm_device_hsic_host;
extern struct platform_device msm_device_otg;
-
+extern struct platform_device msm_device_hsic_peripheral;
extern struct platform_device msm8960_device_otg;
extern struct platform_device msm8960_device_gadget_peripheral;
@@ -264,3 +264,9 @@
extern struct platform_device msm_funnel_device;
extern struct platform_device msm_ptm_device;
#endif
+
+extern struct platform_device msm_bus_8064_apps_fabric;
+extern struct platform_device msm_bus_8064_sys_fabric;
+extern struct platform_device msm_bus_8064_mm_fabric;
+extern struct platform_device msm_bus_8064_sys_fpb;
+extern struct platform_device msm_bus_8064_cpss_fpb;
diff --git a/arch/arm/mach-msm/idle_stats_device.c b/arch/arm/mach-msm/idle_stats_device.c
index 5c4b6a3..c28cf94 100644
--- a/arch/arm/mach-msm/idle_stats_device.c
+++ b/arch/arm/mach-msm/idle_stats_device.c
@@ -137,8 +137,7 @@
device->stats = &device->stats_vector[1];
else
device->stats = &device->stats_vector[0];
- device->stats->event = (stats->event &
- MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED);
+ device->stats->event = 0;
device->stats->nr_collected = 0;
spin_unlock(&device->lock);
if (stats->nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS) {
@@ -217,7 +216,7 @@
device->remaining_time =
hrtimer_get_remaining(&device->busy_timer);
if (ktime_to_us(device->remaining_time) <= 0)
- device->remaining_time = us_to_ktime(1);
+ device->remaining_time = us_to_ktime(0);
} else {
device->remaining_time = us_to_ktime(0);
}
@@ -228,8 +227,11 @@
void msm_idle_stats_idle_end(struct msm_idle_stats_device *device,
struct msm_idle_pulse *pulse)
{
+ u32 idle_time = 0;
spin_lock(&device->lock);
if (ktime_to_us(device->idle_start) != 0) {
+ idle_time = ktime_to_us(ktime_get())
+ - ktime_to_us(device->idle_start);
device->idle_start = us_to_ktime(0);
msm_idle_stats_add_sample(device, pulse);
if (device->stats->event &
@@ -240,7 +242,10 @@
MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED_RESET);
} else if (ktime_to_us(device->busy_timer_interval) > 0) {
ktime_t busy_timer = device->busy_timer_interval;
- if ((pulse->wait_interval > 0) &&
+ /* if it is serialized, it would be full busy,
+ * checking 80%
+ */
+ if ((pulse->wait_interval*5 >= idle_time*4) &&
(ktime_to_us(device->remaining_time) > 0) &&
(ktime_to_us(device->remaining_time) <
ktime_to_us(busy_timer)))
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index fd282d5..8961c79 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -155,8 +155,12 @@
struct msm_vpe_phy_info {
uint32_t sbuf_phy;
- uint32_t y_phy;
- uint32_t cbcr_phy;
+ uint32_t planar0_off;
+ uint32_t planar1_off;
+ uint32_t planar2_off;
+ uint32_t p0_phy;
+ uint32_t p1_phy;
+ uint32_t p2_phy;
uint8_t output_id; /* VFE31_OUTPUT_MODE_PT/S/V */
uint32_t frame_id;
};
@@ -193,6 +197,7 @@
#define VFE31_OUTPUT_MODE_V (0x1 << 2)
#define VFE31_OUTPUT_MODE_P (0x1 << 3)
#define VFE31_OUTPUT_MODE_T (0x1 << 4)
+#define VFE31_OUTPUT_MODE_P_ALL_CHNLS (0x1 << 5)
#define CSI_EMBED_DATA 0x12
#define CSI_YUV422_8 0x1E
@@ -206,8 +211,12 @@
struct msm_vfe_phy_info {
uint32_t sbuf_phy;
- uint32_t y_phy;
- uint32_t cbcr_phy;
+ uint32_t planar0_off;
+ uint32_t planar1_off;
+ uint32_t planar2_off;
+ uint32_t p0_phy;
+ uint32_t p1_phy;
+ uint32_t p2_phy;
uint8_t output_id; /* VFE31_OUTPUT_MODE_PT/S/V */
uint32_t frame_id;
};
@@ -238,8 +247,8 @@
};
struct msm_vpe_buf_info {
- uint32_t y_phy;
- uint32_t cbcr_phy;
+ uint32_t p0_phy;
+ uint32_t p1_phy;
struct timespec ts;
uint32_t frame_id;
struct video_crop_t vpe_crop;
@@ -303,7 +312,7 @@
struct msm_camvpe_fn {
int (*vpe_reg)(struct msm_vpe_callback *);
int (*vpe_cfg_update) (void *);
- void (*send_frame_to_vpe) (uint32_t y_phy, uint32_t cbcr_phy,
+ void (*send_frame_to_vpe) (uint32_t planar0_off, uint32_t planar1_off,
struct timespec *ts, int output_id);
int (*vpe_config)(struct msm_vpe_cfg_cmd *, void *);
void (*vpe_cfg_offset)(int frame_pack, uint32_t pyaddr,
diff --git a/arch/arm/mach-msm/include/mach/ion.h b/arch/arm/mach-msm/include/mach/ion.h
index 4d12249..9fbc720 100644
--- a/arch/arm/mach-msm/include/mach/ion.h
+++ b/arch/arm/mach-msm/include/mach/ion.h
@@ -1,6 +1,6 @@
/**
*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,4 +20,10 @@
ION_SMI_TYPE,
};
+enum ion_permission_type {
+ IPT_TYPE_MM_CARVEOUT = 0,
+ IPT_TYPE_MFC_SHAREDMEM = 1,
+ IPT_TYPE_MDP_WRITEBACK = 2,
+};
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-9615.h b/arch/arm/mach-msm/include/mach/irqs-9615.h
index 74e5847..5fba24e 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9615.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9615.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -179,8 +179,9 @@
#define TLMM_MSM_DIR_CONN_IRQ_21 (GIC_SPI_START + 224)
#define MSM_SPARE0_IRQ (GIC_SPI_START + 225)
#define PMIC_SEC_IRQ_N (GIC_SPI_START + 226)
+#define USB_HSIC_IRQ (GIC_SPI_START + 232)
-#define NR_MSM_IRQS 256
+#define NR_MSM_IRQS 288
#define NR_GPIO_IRQS 88
#define NR_PM8018_IRQS 256
#define NR_BOARD_IRQS NR_PM8018_IRQS
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index 9cd73db..e1fc054 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/include/mach/memory.h
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, 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
@@ -23,8 +23,13 @@
#define MAX_PHYSMEM_BITS 32
#define SECTION_SIZE_BITS 28
-/* Maximum number of Memory Regions */
-#define MAX_NR_REGIONS 4
+/* Maximum number of Memory Regions
+* The largest system can have 4 memory banks, each divided into 8 regions
+*/
+#define MAX_NR_REGIONS 32
+
+/* The number of regions each memory bank is divided into */
+#define NR_REGIONS_PER_BANK 8
/* Certain configurations of MSM7x30 have multiple memory banks.
* One or more of these banks can contain holes in the memory map as well.
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8064.h b/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
index 7f5bd75..15b2856 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
@@ -77,4 +77,25 @@
#define APQ8064_IMEM_PHYS 0x2A03F000
#define APQ8064_IMEM_SIZE SZ_4K
+#define APQ8064_RPM_PHYS 0x00108000
+#define APQ8064_RPM_SIZE SZ_4K
+
+#define APQ8064_RPM_MPM_PHYS 0x00200000
+#define APQ8064_RPM_MPM_SIZE SZ_4K
+
+#define APQ8064_SAW0_PHYS 0x02089000
+#define APQ8064_SAW0_SIZE SZ_4K
+
+#define APQ8064_SAW1_PHYS 0x02099000
+#define APQ8064_SAW1_SIZE SZ_4K
+
+#define APQ8064_SAW2_PHYS 0x020A9000
+#define APQ8064_SAW2_SIZE SZ_4K
+
+#define APQ8064_SAW3_PHYS 0x020B9000
+#define APQ8064_SAW3_SIZE SZ_4K
+
+#define APQ8064_SAW_L2_PHYS 0x02012000
+#define APQ8064_SAW_L2_SIZE SZ_4K
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9615.h b/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
index dda5f50..fc9b198 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -77,6 +77,9 @@
#define MSM9615_HSUSB_PHYS 0x12500000
#define MSM9615_HSUSB_SIZE SZ_4K
+#define MSM9615_HSIC_PHYS 0x12540000
+#define MSM9615_HSIC_SIZE SZ_4K
+
#define MSM9615_QFPROM_PHYS 0x00700000
#define MSM9615_QFPROM_SIZE SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index dd01c62..ff0b368 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -75,8 +75,10 @@
#define MSM_RPM_BASE IOMEM(0xFA801000) /* 4K */
#define MSM_RPM_MPM_BASE IOMEM(0xFA802000) /* 4K */
#define MSM_QFPROM_BASE IOMEM(0xFA700000) /* 4K */
-#define MSM_L2CC_BASE IOMEM(0xFA701000) /* 4K */
-#define MSM_APCS_GLB_BASE IOMEM(0xFA702000) /* 4K */
+#define MSM_L2CC_BASE IOMEM(0xFA701000) /* 4K */
+#define MSM_APCS_GLB_BASE IOMEM(0xFA702000) /* 4K */
+#define MSM_SAW2_BASE IOMEM(0xFA703000) /* 4k */
+#define MSM_SAW3_BASE IOMEM(0xFA704000) /* 4k */
#if defined(CONFIG_ARCH_MSM9615)
#define MSM_SHARED_RAM_SIZE SZ_1M
diff --git a/arch/arm/mach-msm/include/mach/pm.h b/arch/arm/mach-msm/include/mach/pm.h
index 813ece1..689cd17 100644
--- a/arch/arm/mach-msm/include/mach/pm.h
+++ b/arch/arm/mach-msm/include/mach/pm.h
@@ -51,11 +51,19 @@
staying in the low power mode saves power */
};
+struct msm_pm_sleep_status_data {
+ void *base_addr;
+ uint32_t cpu_offset;
+ uint32_t mask;
+};
+
void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
int msm_pm_idle_prepare(struct cpuidle_device *dev);
int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
+void __init msm_pm_init_sleep_status_data(
+ struct msm_pm_sleep_status_data *sleep_data);
#ifdef CONFIG_PM
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
#else
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index a332b67..6aa944f 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -21,6 +21,7 @@
#define SCM_SVC_SSD 0x7
#define SCM_SVC_FUSE 0x8
#define SCM_SVC_PWR 0x9
+#define SCM_SVC_CP 0xC
#define SCM_SVC_TZSCHEDULER 0xFC
#ifdef CONFIG_MSM_SCM
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 2d5b0a4..9622a4c 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -265,6 +265,13 @@
MSM_CHIP_DEVICE(MMSS_CLK_CTL, APQ8064),
MSM_CHIP_DEVICE(LPASS_CLK_CTL, APQ8064),
MSM_CHIP_DEVICE(APCS_GCC, APQ8064),
+ MSM_CHIP_DEVICE(RPM, APQ8064),
+ MSM_CHIP_DEVICE(RPM_MPM, APQ8064),
+ MSM_CHIP_DEVICE(SAW0, APQ8064),
+ MSM_CHIP_DEVICE(SAW1, APQ8064),
+ MSM_CHIP_DEVICE(SAW2, APQ8064),
+ MSM_CHIP_DEVICE(SAW3, APQ8064),
+ MSM_CHIP_DEVICE(SAW_L2, APQ8064),
MSM_CHIP_DEVICE(IMEM, APQ8064),
{
.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
index 5854a23..6208a0d 100644
--- a/arch/arm/mach-msm/memory_topology.c
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,11 +31,11 @@
/* reserved for future use */
u64 num_partitions;
int state;
- int mask;
- struct mutex state_mutex;
} mem_regions[MAX_NR_REGIONS];
+static struct mutex mem_regions_mutex;
static unsigned int nr_mem_regions;
+static int mem_regions_mask;
enum {
STATE_POWER_DOWN = 0x0,
@@ -43,14 +43,6 @@
STATE_DEFAULT = STATE_ACTIVE
};
-enum {
- MEM_NO_CHANGE = 0x0,
- MEM_DEEP_POWER_DOWN,
- MEM_SELF_REFRESH,
-};
-
-static unsigned int dmm_mode;
-
static int default_mask = ~0x0;
/* Return the number of chipselects populated with a memory bank */
@@ -111,50 +103,55 @@
}
}
-static int switch_memory_state(int id, int new_state)
+static int switch_memory_state(int mask, int new_state, int start_region,
+ int end_region)
{
- int mask = 0;
- int power_down_masks[MAX_NR_REGIONS] = { 0xFFFFFF00, 0xFFFF00FF,
- 0xFF00FFFF, 0x00FFFFFF };
- int self_refresh_masks[MAX_NR_REGIONS] = { 0xFFFFFFF0, 0xFFFFFF0F,
- 0xFFFFF0FF, 0xFFFF0FFF };
- mutex_lock(&mem_regions[id].state_mutex);
+ int final_mask = 0;
+ int i;
- if (new_state == mem_regions[id].state)
- goto no_change;
+ mutex_lock(&mem_regions_mutex);
- pr_info("request memory %d state switch (%d->%d) mode %d\n", id,
- mem_regions[id].state, new_state, dmm_mode);
- if (new_state == STATE_POWER_DOWN) {
- if (dmm_mode == MEM_DEEP_POWER_DOWN)
- mask = mem_regions[id].mask & power_down_masks[id];
- else
- mask = mem_regions[id].mask & self_refresh_masks[id];
- } else if (new_state == STATE_ACTIVE) {
- if (dmm_mode == MEM_DEEP_POWER_DOWN)
- mask = mem_regions[id].mask | (~power_down_masks[id]);
- else
- mask = mem_regions[id].mask | (~self_refresh_masks[id]);
+ for (i = start_region; i <= end_region; i++) {
+ if (new_state == mem_regions[i].state)
+ goto no_change;
+ /* All region states must be the same to change them */
+ if (mem_regions[i].state != mem_regions[start_region].state)
+ goto no_change;
}
- if (rpm_change_memory_state(mask, mask) == 0) {
- mem_regions[id].state = new_state;
- mem_regions[id].mask = mask;
- pr_info("completed memory %d state switch to %d mode %d\n",
- id, new_state, dmm_mode);
- mutex_unlock(&mem_regions[id].state_mutex);
+ if (new_state == STATE_POWER_DOWN)
+ final_mask = mem_regions_mask & mask;
+ else if (new_state == STATE_ACTIVE)
+ final_mask = mem_regions_mask | ~mask;
+ else
+ goto no_change;
+
+ pr_info("request memory %d to %d state switch (%d->%d)\n",
+ start_region, end_region, mem_regions[start_region].state,
+ new_state);
+ if (rpm_change_memory_state(final_mask, final_mask) == 0) {
+ for (i = start_region; i <= end_region; i++)
+ mem_regions[i].state = new_state;
+ mem_regions_mask = final_mask;
+
+ pr_info("completed memory %d to %d state switch to %d\n",
+ start_region, end_region, new_state);
+ mutex_unlock(&mem_regions_mutex);
return 0;
}
- pr_err("failed memory %d state switch (%d->%d) mode %d\n", id,
- mem_regions[id].state, new_state, dmm_mode);
+ pr_err("failed memory %d to %d state switch (%d->%d)\n",
+ start_region, end_region, mem_regions[start_region].state,
+ new_state);
+
no_change:
- mutex_unlock(&mem_regions[id].state_mutex);
+ mutex_unlock(&mem_regions_mutex);
return -EINVAL;
}
#else
-static int switch_memory_state(int id, int new_state)
+static int switch_memory_state(int mask, int new_state, int start_region,
+ int end_region)
{
return -EINVAL;
}
@@ -165,29 +162,34 @@
*/
int soc_change_memory_power(u64 start, u64 size, int change)
{
-
int i = 0;
- int match = 0;
-
- /* Find the memory region starting just below start */
- for (i = 0; i < nr_mem_regions; i++) {
- if (mem_regions[i].start <= start &&
- mem_regions[i].start >= mem_regions[match].start) {
- match = i;
- }
- }
-
- if (start + size > mem_regions[match].start + mem_regions[match].size) {
- pr_info("passed size exceeds size of memory bank\n");
- return 0;
- }
+ int mask = default_mask;
+ u64 end = start + size;
+ int start_region = 0;
+ int end_region = 0;
if (change != STATE_ACTIVE && change != STATE_POWER_DOWN) {
pr_info("requested state transition invalid\n");
return 0;
}
+ /* Find the memory regions that fall within the range */
+ for (i = 0; i < nr_mem_regions; i++) {
+ if (mem_regions[i].start <= start &&
+ mem_regions[i].start >=
+ mem_regions[start_region].start) {
+ start_region = i;
+ }
+ if (end <= mem_regions[i].start + mem_regions[i].size) {
+ end_region = i;
+ break;
+ }
+ }
- if (!switch_memory_state(match, change))
+ /* Set the bitmask for each region in the range */
+ for (i = start_region; i <= end_region; i++)
+ mask &= ~(0x1 << i);
+
+ if (!switch_memory_state(mask, change, start_region, end_region))
return size;
else
return 0;
@@ -212,9 +214,10 @@
int __init meminfo_init(unsigned int type, unsigned int min_bank_size)
{
- unsigned int i;
+ unsigned int i, j;
unsigned long bank_size;
unsigned long bank_start;
+ unsigned long region_size;
struct smem_ram_ptable *ram_ptable;
/* physical memory banks */
unsigned int nr_mem_banks = 0;
@@ -229,40 +232,35 @@
return -EINVAL;
}
- /* Determine power control mode based on the hw version */
- /* This check will be removed when PASR is fully supported */
- if (cpu_is_msm8960() &&
- SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 2)
- dmm_mode = MEM_DEEP_POWER_DOWN;
- else
- dmm_mode = MEM_SELF_REFRESH;
-
pr_info("meminfo_init: smem ram ptable found: ver: %d len: %d\n",
ram_ptable->version, ram_ptable->len);
for (i = 0; i < ram_ptable->len; i++) {
+ /* A bank is valid only if is greater than min_bank_size. If
+ * non-valid memory (e.g. modem memory) became greater than
+ * min_bank_size, there is currently no way to differentiate.
+ */
if (ram_ptable->parts[i].type == type &&
ram_ptable->parts[i].size >= min_bank_size) {
bank_start = ram_ptable->parts[i].start;
bank_size = ram_ptable->parts[i].size;
- /* Divide into logical memory regions of same size */
- while (bank_size) {
+ region_size = bank_size / NR_REGIONS_PER_BANK;
+
+ for (j = 0; j < NR_REGIONS_PER_BANK; j++) {
mem_regions[nr_mem_regions].start =
bank_start;
mem_regions[nr_mem_regions].size =
- MIN_MEMORY_BLOCK_SIZE;
- mutex_init(&mem_regions[nr_mem_regions]
- .state_mutex);
+ region_size;
mem_regions[nr_mem_regions].state =
STATE_DEFAULT;
- mem_regions[nr_mem_regions].mask = default_mask;
- bank_start += MIN_MEMORY_BLOCK_SIZE;
- bank_size -= MIN_MEMORY_BLOCK_SIZE;
+ bank_start += region_size;
nr_mem_regions++;
}
nr_mem_banks++;
}
}
+ mutex_init(&mem_regions_mutex);
+ mem_regions_mask = default_mask;
pr_info("Found %d memory banks grouped into %d memory regions\n",
nr_mem_banks, nr_mem_regions);
return 0;
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 4e487a7..efb2bf6 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -39,8 +39,10 @@
#include <mach/subsystem_restart.h>
#include <mach/subsystem_notif.h>
+#include <timer.h>
+
#define DRV_NAME "msm_dsps"
-#define DRV_VERSION "3.01"
+#define DRV_VERSION "3.02"
#define PPSS_PAUSE_REG 0x1804
@@ -146,9 +148,9 @@
{
u32 val;
- val = readl_relaxed(drv->ppss_base + PPSS_TIMER0_32KHZ_REG);
- rmb(); /* order reads from the user output buffer */
-
+ /* Read the timer value from the MSM sclk. The MSM slow clock & DSPS
+ * timers are in sync, so these are the same value */
+ val = msm_timer_get_sclk_ticks();
pr_debug("%s.count=%d.\n", __func__, val);
return val;
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index de61041..6848c59 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,10 @@
#define RIVA_PMU_CFG_IRIS_XO_MODE 0x6
#define RIVA_PMU_CFG_IRIS_XO_MODE_48 (3 << 1)
+#define RIVA_PMU_OVRD_EN 0x2C
+#define RIVA_PMU_OVRD_EN_CCPU_RESET BIT(0)
+#define RIVA_PMU_OVRD_EN_CCPU_CLK BIT(1)
+
#define RIVA_PMU_OVRD_VAL 0x30
#define RIVA_PMU_OVRD_VAL_CCPU_RESET BIT(0)
#define RIVA_PMU_OVRD_VAL_CCPU_CLK BIT(1)
@@ -57,6 +61,7 @@
#define RIVA_PLL_N_VAL (MSM_CLK_CTL_BASE + 0x31Ac)
#define RIVA_PLL_CONFIG (MSM_CLK_CTL_BASE + 0x31B4)
#define RIVA_PLL_STATUS (MSM_CLK_CTL_BASE + 0x31B8)
+#define RIVA_RESET (MSM_CLK_CTL_BASE + 0x35E0)
#define RIVA_PMU_ROOT_CLK_SEL 0xC8
#define RIVA_PMU_ROOT_CLK_SEL_3 BIT(2)
@@ -230,9 +235,23 @@
struct riva_data *drv = dev_get_drvdata(pil->dev);
u32 reg;
+ /* Put cCPU and cCPU clock into reset */
reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_VAL);
+ reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_EN);
+ reg |= RIVA_PMU_OVRD_EN_CCPU_RESET | RIVA_PMU_OVRD_EN_CCPU_CLK;
+ writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_EN);
+ mb();
+
+ /* Assert reset to Riva */
+ writel_relaxed(1, RIVA_RESET);
+ mb();
+ usleep_range(1000, 2000);
+
+ /* Deassert reset to Riva */
+ writel_relaxed(0, RIVA_RESET);
+ mb();
pil_riva_remove_xo_proxy_votes_now(pil->dev);
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index d73d4a0..f1c6c48 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -31,13 +31,8 @@
int pen_release = -1;
-/* Initialize the present map (cpu_set(i, cpu_present_map)). */
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- int i;
-
- for (i = 0; i < max_cpus; i++)
- cpu_set(i, cpu_present_map);
}
void __init smp_init_cpus(void)
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index a6644d6..754d76f 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -27,6 +27,7 @@
#include <linux/tick.h>
#include <linux/uaccess.h>
#include <linux/wakelock.h>
+#include <linux/delay.h>
#include <mach/msm_iomap.h>
#include <mach/system.h>
#include <asm/cacheflush.h>
@@ -55,6 +56,7 @@
* Debug Definitions
*****************************************************************************/
+
enum {
MSM_PM_DEBUG_SUSPEND = BIT(0),
MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
@@ -953,6 +955,23 @@
return 0;
}
+static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(enum msm_pm_sleep_mode,
+ msm_pm_last_slp_mode);
+
+bool msm_pm_verify_cpu_pc(unsigned int cpu)
+{
+ enum msm_pm_sleep_mode mode = per_cpu(msm_pm_last_slp_mode, cpu);
+
+ if (msm_pm_slp_sts)
+ if ((mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) ||
+ (mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE))
+ return true;
+
+ return false;
+}
+
void msm_pm_cpu_enter_lowpower(unsigned int cpu)
{
int i;
@@ -968,14 +987,50 @@
if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
- if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
+ if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) {
+ per_cpu(msm_pm_last_slp_mode, cpu)
+ = MSM_PM_SLEEP_MODE_POWER_COLLAPSE;
msm_pm_power_collapse(false);
- else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
+ } else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
+ per_cpu(msm_pm_last_slp_mode, cpu)
+ = MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
msm_pm_power_collapse_standalone(false);
- else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT])
+ } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+ per_cpu(msm_pm_last_slp_mode, cpu)
+ = MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
msm_pm_swfi();
+ } else
+ per_cpu(msm_pm_last_slp_mode, cpu) = MSM_PM_SLEEP_MODE_NR;
+}
+int msm_pm_wait_cpu_shutdown(unsigned int cpu)
+{
+ int timeout = 10;
+
+ if (!msm_pm_slp_sts)
+ return 0;
+
+ while (timeout--) {
+
+ /*
+ * Check for the SPM of the core being hotplugged to set
+ * its sleep state.The SPM sleep state indicates that the
+ * core has been power collapsed.
+ */
+
+ int acc_sts = __raw_readl(msm_pm_slp_sts->base_addr
+ + cpu * msm_pm_slp_sts->cpu_offset);
+ mb();
+
+ if (acc_sts & msm_pm_slp_sts->mask)
+ return 0;
+
+ usleep(100);
+ }
+ pr_warn("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
+ __func__, cpu);
+ return -EBUSY;
}
static int msm_pm_enter(suspend_state_t state)
@@ -1085,10 +1140,14 @@
.valid = suspend_valid_only_mem,
};
-
/******************************************************************************
* Initialization routine
*****************************************************************************/
+void __init msm_pm_init_sleep_status_data(
+ struct msm_pm_sleep_status_data *data)
+{
+ msm_pm_slp_sts = data;
+}
static int __init msm_pm_init(void)
{
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 0a9b27c..747b585 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -94,7 +94,7 @@
{
int ret = 0;
- if (!scm_perf_client || scm_bus_clk)
+ if (!scm_perf_client || !scm_bus_clk)
return -EINVAL;
mutex_lock(&scm_pas_bw_mutex);
diff --git a/arch/arm/mach-msm/sdio_al_test.c b/arch/arm/mach-msm/sdio_al_test.c
index a71aae3..c97588f 100644
--- a/arch/arm/mach-msm/sdio_al_test.c
+++ b/arch/arm/mach-msm/sdio_al_test.c
@@ -146,7 +146,6 @@
SDIO_DIAG,
SDIO_DUN,
SDIO_SMEM,
- SDIO_CIQ,
SDIO_CSVT,
SDIO_MAX_CHANNELS
};
@@ -250,7 +249,7 @@
struct dentry *rpc_sender_rmnet_a2_perf_test;
struct dentry *all_channels_test;
struct dentry *host_sender_no_lp_diag_test;
- struct dentry *host_sender_no_lp_diag_rpc_ciq_test;
+ struct dentry *host_sender_no_lp_diag_rpc_test;
struct dentry *rmnet_small_packets_test;
struct dentry *rmnet_rtt_test;
struct dentry *csvt_rtt_test;
@@ -297,7 +296,6 @@
u8 *smem_buf;
uint32_t smem_counter;
- struct platform_device *ciq_app_pdev;
struct platform_device *csvt_app_pdev;
wait_queue_head_t wait_q;
@@ -1181,7 +1179,6 @@
set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_CIQ]);
set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
ret = test_start();
@@ -1284,8 +1281,8 @@
.read = host_sender_no_lp_diag_test_read,
};
-/* HOST SENDER NO LP DIAG, RPC, CIQ TEST */
-static ssize_t host_sender_no_lp_diag_rpc_ciq_test_write(
+/* HOST SENDER NO LP DIAG, RPC TEST */
+static ssize_t host_sender_no_lp_diag_rpc_test_write(
struct file *file,
const char __user *buf,
size_t count,
@@ -1295,8 +1292,8 @@
int i = 0;
int number = -1;
- pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG, RPC, "
- "CIQ TEST --");
+ pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG, RPC "
+ "TEST --");
number = sdio_al_test_extract_number(buf, count);
@@ -1313,7 +1310,6 @@
sdio_al_test_initial_dev_and_chan(test_ctx);
set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]);
- set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_CIQ]);
set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_RPC]);
ret = test_start();
@@ -1325,7 +1321,7 @@
return count;
}
-static ssize_t host_sender_no_lp_diag_rpc_ciq_test_read(
+static ssize_t host_sender_no_lp_diag_rpc_test_read(
struct file *file,
char __user *buffer,
size_t count,
@@ -1334,7 +1330,7 @@
memset((void *)buffer, 0, count);
snprintf(buffer, count,
- "\nHOST_SENDER_NO_LP_DIAG_RPC_CIQ_TEST\n"
+ "\nHOST_SENDER_NO_LP_DIAG_RPC_TEST\n"
"===================================\n"
"Description:\n"
"TBD\n");
@@ -1347,10 +1343,10 @@
}
}
-const struct file_operations host_sender_no_lp_diag_rpc_ciq_test_ops = {
+const struct file_operations host_sender_no_lp_diag_rpc_test_ops = {
.open = sdio_al_test_open,
- .write = host_sender_no_lp_diag_rpc_ciq_test_write,
- .read = host_sender_no_lp_diag_rpc_ciq_test_read,
+ .write = host_sender_no_lp_diag_rpc_test_write,
+ .read = host_sender_no_lp_diag_rpc_test_read,
};
/* RMNET SMALL PACKETS TEST */
@@ -1774,7 +1770,6 @@
set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_CIQ]);
ret = test_start();
@@ -1844,7 +1839,6 @@
set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]);
set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_CIQ]);
ret = test_start();
@@ -1910,7 +1904,6 @@
sdio_al_test_initial_dev_and_chan(test_ctx);
set_params_loopback_9k_close(ch_arr[SDIO_DIAG]);
- set_params_loopback_9k_close(ch_arr[SDIO_CIQ]);
set_params_loopback_9k_close(ch_arr[SDIO_RPC]);
set_params_loopback_9k_close(ch_arr[SDIO_SMEM]);
set_params_loopback_9k_close(ch_arr[SDIO_QMI]);
@@ -1924,9 +1917,8 @@
break;
pr_info(TEST_MODULE_NAME " -- correctness test for"
- "DIAG, CIQ ");
+ "DIAG ");
set_params_loopback_9k(ch_arr[SDIO_DIAG]);
- set_params_loopback_9k(ch_arr[SDIO_CIQ]);
ret = test_start();
@@ -1950,7 +1942,7 @@
"Description:\n"
"In this test the host sends 5k packets to the modem in the "
"following sequence: Send a random burst of packets on "
- "Diag, CIQ and Rmnet channels, read 0 or a random number "
+ "Diag and Rmnet channels, read 0 or a random number "
"of packets, close and re-open the channel. At the end of the "
"test, the channel is verified by running a loopback test\n\n"
"END OF DESCRIPTION\n");
@@ -2373,8 +2365,6 @@
set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
SDIO_TEST_LPM_RANDOM, 0);
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_CIQ],
- SDIO_TEST_LPM_RANDOM, 0);
set_params_lpm_test(test_ctx->test_ch_arr[SDIO_DIAG],
SDIO_TEST_LPM_RANDOM, 0);
set_params_lpm_test(test_ctx->test_ch_arr[SDIO_QMI],
@@ -2403,7 +2393,7 @@
"Description:\n"
"In this test, the HOST and CLIENT "
"send messages to each other,\n"
- "random in time, over RPC, QMI, DIAG AND CIQ channels\n"
+ "random in time, over RPC, QMI AND DIAG channels\n"
"(i.e, on both SDIO devices).\n"
"All events are being recorded, and later on,\n"
"they are being analysed by the HOST and by the CLIENT,\n"
@@ -2545,12 +2535,12 @@
NULL,
&host_sender_no_lp_diag_test_ops);
- test_ctx->debug.host_sender_no_lp_diag_rpc_ciq_test =
- debugfs_create_file("170_host_sender_no_lp_diag_rpc_ciq_test",
+ test_ctx->debug.host_sender_no_lp_diag_rpc_test =
+ debugfs_create_file("170_host_sender_no_lp_diag_rpc_test",
S_IRUGO | S_IWUGO,
test_ctx->debug.debug_root,
NULL,
- &host_sender_no_lp_diag_rpc_ciq_test_ops);
+ &host_sender_no_lp_diag_rpc_test_ops);
test_ctx->debug.rmnet_small_packets_test =
debugfs_create_file("180_rmnet_small_packets_test",
@@ -2697,9 +2687,6 @@
else if (!strncmp(name, "SDIO_SMEM_TEST",
strnlen("SDIO_SMEM_TEST", TEST_CH_NAME_SIZE)))
return SDIO_SMEM;
- else if (!strncmp(name, "SDIO_CIQ_TEST",
- strnlen("SDIO_CIQ_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_CIQ;
else if (!strncmp(name, "SDIO_CSVT_TEST",
strnlen("SDIO_CSVT_TEST", TEST_CH_NAME_SIZE)))
return SDIO_CSVT;
@@ -5829,7 +5816,6 @@
case SDIO_RPC:
tch->packet_length = 128; /* max is 2K*/
break;
- case SDIO_CIQ:
case SDIO_DIAG:
case SDIO_RMNT:
default:
@@ -6297,34 +6283,6 @@
}
-static int sdio_test_channel_ciq_probe(struct platform_device *pdev)
-{
- int ret = 0;
-
- if (!pdev)
- return -ENODEV;
-
- test_ctx->ciq_app_pdev = platform_device_alloc("SDIO_CIQ_TEST_APP", -1);
- ret = platform_device_add(test_ctx->ciq_app_pdev);
- if (ret) {
- pr_err(MODULE_NAME ":platform_device_add failed, "
- "ret=%d\n", ret);
- return ret;
- }
-
- return sdio_test_channel_probe(pdev);
-}
-
-static int sdio_test_channel_ciq_remove(struct platform_device *pdev)
-{
- if (!pdev)
- return -ENODEV;
-
- platform_device_unregister(test_ctx->ciq_app_pdev);
-
- return sdio_test_channel_remove(pdev);
-}
-
static int sdio_test_channel_csvt_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -6408,15 +6366,6 @@
},
};
-static struct platform_driver sdio_ciq_drv = {
- .probe = sdio_test_channel_ciq_probe,
- .remove = sdio_test_channel_ciq_remove,
- .driver = {
- .name = "SDIO_CIQ_TEST",
- .owner = THIS_MODULE,
- },
-};
-
static struct platform_driver sdio_csvt_drv = {
.probe = sdio_test_channel_csvt_probe,
.remove = sdio_test_channel_csvt_remove,
@@ -6494,7 +6443,6 @@
platform_driver_register(&sdio_smem_drv);
platform_driver_register(&sdio_rmnt_drv);
platform_driver_register(&sdio_dun_drv);
- platform_driver_register(&sdio_ciq_drv);
platform_driver_register(&sdio_csvt_drv);
return ret;
@@ -6523,7 +6471,6 @@
platform_driver_unregister(&sdio_smem_drv);
platform_driver_unregister(&sdio_rmnt_drv);
platform_driver_unregister(&sdio_dun_drv);
- platform_driver_unregister(&sdio_ciq_drv);
platform_driver_unregister(&sdio_csvt_drv);
for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
diff --git a/arch/arm/mach-msm/sdio_tty.c b/arch/arm/mach-msm/sdio_tty.c
index 2aaa41e..41bc270 100644
--- a/arch/arm/mach-msm/sdio_tty.c
+++ b/arch/arm/mach-msm/sdio_tty.c
@@ -30,11 +30,6 @@
#define MAX_SDIO_TTY_DEV_NAME_SIZE 25
/* Configurations per channel device */
-/* CIQ */
-#define SDIO_TTY_CIQ_DEV "sdio_tty_ciq_0"
-#define SDIO_TTY_CIQ_TEST_DEV "sdio_tty_ciq_test_0"
-#define SDIO_TTY_CH_CIQ "SDIO_CIQ"
-
/* CSVT */
#define SDIO_TTY_CSVT_DEV "sdio_tty_csvt_0"
#define SDIO_TTY_CSVT_TEST_DEV "sdio_tty_csvt_test_0"
@@ -48,15 +43,11 @@
};
enum sdio_tty_devices {
- SDIO_CIQ,
- SDIO_CIQ_TEST_APP,
SDIO_CSVT,
SDIO_CSVT_TEST_APP,
};
static const struct platform_device_id sdio_tty_id_table[] = {
- { "SDIO_CIQ", SDIO_CIQ },
- { "SDIO_CIQ_TEST_APP", SDIO_CIQ_TEST_APP },
{ "SDIO_CSVT", SDIO_CSVT },
{ "SDIO_CSVT_TEST_APP", SDIO_CSVT_TEST_APP },
{ },
@@ -95,8 +86,6 @@
* Enable sdio_tty debug messages
* By default the sdio_tty debug messages are turned off
*/
-static int ciq_debug_msg_on;
-module_param(ciq_debug_msg_on, int, 0);
static int csvt_debug_msg_on;
module_param(csvt_debug_msg_on, int, 0);
@@ -677,16 +666,6 @@
pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
switch (device_id) {
- case SDIO_CIQ:
- device_name = SDIO_TTY_CIQ_DEV;
- channel_name = SDIO_TTY_CH_CIQ;
- debug_msg_on = ciq_debug_msg_on;
- break;
- case SDIO_CIQ_TEST_APP:
- device_name = SDIO_TTY_CIQ_TEST_DEV;
- channel_name = SDIO_TTY_CH_CIQ;
- debug_msg_on = ciq_debug_msg_on;
- break;
case SDIO_CSVT:
device_name = SDIO_TTY_CSVT_DEV;
channel_name = SDIO_TTY_CH_CSVT;
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 61e65d2..67b1f7b 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -405,11 +405,7 @@
*/
static void (*msm_timer_sync_timeout)(void);
#if defined(CONFIG_MSM_DIRECT_SCLK_ACCESS)
-static uint32_t msm_timer_do_sync_to_sclk(
- void (*time_start)(struct msm_timer_sync_data_t *data),
- bool (*time_expired)(struct msm_timer_sync_data_t *data),
- void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t),
- struct msm_timer_sync_data_t *data)
+uint32_t msm_timer_get_sclk_ticks(void)
{
uint32_t t1, t2;
int loop_count = 10;
@@ -442,7 +438,18 @@
return 0;
}
- if (update != NULL)
+ return t1;
+}
+
+static uint32_t msm_timer_do_sync_to_sclk(
+ void (*time_start)(struct msm_timer_sync_data_t *data),
+ bool (*time_expired)(struct msm_timer_sync_data_t *data),
+ void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t),
+ struct msm_timer_sync_data_t *data)
+{
+ unsigned t1 = msm_timer_get_sclk_ticks();
+
+ if (t1 && update != NULL)
update(data, t1, sclk_hz);
return t1;
}
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
index 545675c..caef19d 100644
--- a/arch/arm/mach-msm/timer.h
+++ b/arch/arm/mach-msm/timer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,5 +20,6 @@
int64_t msm_timer_enter_idle(void);
void msm_timer_exit_idle(int low_power);
int64_t msm_timer_get_sclk_time(int64_t *period);
+uint32_t msm_timer_get_sclk_ticks(void);
int msm_timer_init_time_sync(void (*timeout)(void));
#endif
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index ecfe93c..ce65e93 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -125,14 +125,6 @@
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- int i;
-
- /*
- * Initialise the present map, which describes the set of CPUs
- * actually populated at the present time.
- */
- for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
/*
* Initialise the SCU and wake up the secondary core using
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index 963bf0d..4ae943b 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -68,14 +68,6 @@
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- int i;
-
- /*
- * Initialise the present map, which describes the set of CPUs
- * actually populated at the present time.
- */
- for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
scu_enable(scu_base_addr());
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index f3888fe..66f9806 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -64,10 +64,5 @@
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- int i;
-
- for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
-
shmobile_smp_prepare_cpus();
}
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index b8ae3c9..1a594dc 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -129,14 +129,6 @@
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- int i;
-
- /*
- * Initialise the present map, which describes the set of CPUs
- * actually populated at the present time.
- */
- for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
scu_enable(scu_base);
}
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index 0c527fe..a33df5f 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -172,14 +172,6 @@
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- int i;
-
- /*
- * Initialise the present map, which describes the set of CPUs
- * actually populated at the present time.
- */
- for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
scu_enable(scu_base_addr());
wakeup_secondary();
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 765a71f..bfd32f5 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -229,10 +229,6 @@
static void ct_ca9x4_smp_enable(unsigned int max_cpus)
{
- int i;
- for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
-
scu_enable(MMIO_P2V(A9_MPCORE_SCU));
}
#endif
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index e048367..a9faff0 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -50,9 +50,6 @@
#define USER_SPACE_DATA 8000
#define PKT_SIZE 4096
#define MAX_EQUIP_ID 12
-#define DIAG_CTRL_MSG_LOG_MASK 9
-#define DIAG_CTRL_MSG_EVENT_MASK 10
-#define DIAG_CTRL_MSG_F3_MASK 11
/* Maximum number of pkt reg supported at initialization*/
extern unsigned int diag_max_registration;
@@ -150,10 +147,7 @@
int count_hdlc_pool;
int count_write_struct_pool;
int used;
- /* Buffers for masks */
- struct diag_ctrl_event_mask *event_mask;
- struct diag_ctrl_log_mask *log_mask;
- struct diag_ctrl_msg_mask *msg_mask;
+
/* State for diag forwarding */
unsigned char *buf_in_1;
unsigned char *buf_in_2;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 8d914dd..6853654 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -43,15 +43,8 @@
static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
struct diag_master_table entry;
smd_channel_t *ch_temp, *chqdsp_temp, *ch_wcnss_temp;
-int diag_event_num_bytes;
-int diag_event_config;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
-struct mask_info {
- int equip_id;
- int num_items;
- int index;
-};
#define ENCODE_RSP_AND_SEND(buf_length) \
do { \
@@ -98,7 +91,7 @@
}
/*
- * This will return TRUE for targets which support apps only mode and hence SSR.
+ * This will return TRUE for targets which support apps only mode.
* This applies to 8960 and newer targets.
*/
int chk_apps_only(void)
@@ -388,6 +381,7 @@
mutex_lock(&driver->diagchar_mutex);
/* First SSID can be zero : So check that last is non-zero */
+
while (*(uint32_t *)(ptr + 4)) {
first = *(uint32_t *)ptr;
ptr += 4;
@@ -407,6 +401,7 @@
else
printk(KERN_INFO "Unable to copy"
" mask change\n");
+
found = 1;
break;
} else {
@@ -428,9 +423,10 @@
}
mutex_unlock(&driver->diagchar_mutex);
diag_print_mask_table();
+
}
-static void diag_update_event_mask(uint8_t *buf, int toggle)
+static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bits)
{
uint8_t *ptr = driver->event_masks;
uint8_t *temp = buf + 2;
@@ -441,8 +437,8 @@
else
if (CHK_OVERFLOW(ptr, ptr,
ptr+EVENT_MASK_SIZE,
- diag_event_num_bytes))
- memcpy(ptr, temp , diag_event_num_bytes);
+ num_bits/8 + 1))
+ memcpy(ptr, temp , num_bits/8 + 1);
else
printk(KERN_CRIT "Not enough buffer space "
"for EVENT_MASK\n");
@@ -452,6 +448,10 @@
static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
{
uint8_t *temp = buf;
+ struct mask_info {
+ int equip_id;
+ int index;
+ };
int i = 0;
unsigned char *ptr_data;
int offset = 8*MAX_EQUIP_ID;
@@ -465,9 +465,8 @@
break;
}
if ((ptr->equip_id == 0) && (ptr->index == 0)) {
- /* Reached a null entry */
+ /*Reached a null entry */
ptr->equip_id = equip_id;
- ptr->num_items = num_items;
ptr->index = driver->log_masks_length;
offset = driver->log_masks_length;
driver->log_masks_length += ((num_items+7)/8);
@@ -553,88 +552,6 @@
}
}
-void diag_send_log_mask_update(smd_channel_t *ch)
-{
- unsigned char buf[1000];
- int header_size = sizeof(struct diag_ctrl_log_mask);
- struct mask_info *ptr = (struct mask_info *)driver->log_masks;
- int i, size = (driver->log_mask->num_items+7)/8;
-
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- /* reached null entry */
- if ((ptr->equip_id == 0) && (ptr->index == 0))
- break;
- driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
- driver->log_mask->num_items = ptr->num_items;
- driver->log_mask->data_len = 11 + size;
- driver->log_mask->stream_id = 1; /* 2, if dual stream */
- driver->log_mask->status = 3; /* status for valid mask */
- driver->log_mask->equip_id = ptr->equip_id;
- driver->log_mask->log_mask_size = size;
- memcpy(buf, driver->log_mask, header_size);
- memcpy(buf+header_size, driver->log_masks+ptr->index, size);
- if (ch)
- smd_write(ch, buf, header_size + size);
- else
- pr_info("diag: invalid SMD channel\n");
- ptr++;
- }
-}
-
-void diag_send_event_mask_update(smd_channel_t *ch)
-{
- unsigned char buf[EVENT_MASK_SIZE];
- int header_size = sizeof(struct diag_ctrl_event_mask);
-
- /* send event mask update */
- driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
- driver->event_mask->data_len = 7 + diag_event_num_bytes;
- driver->event_mask->stream_id = 1; /* 2, if dual stream */
- driver->event_mask->status = 3; /* status for valid mask */
- driver->event_mask->event_config = diag_event_config; /* event config */
- driver->event_mask->event_mask_size = diag_event_num_bytes;
- memcpy(buf, driver->event_mask, header_size);
- memcpy(buf+header_size, driver->event_masks, diag_event_num_bytes);
- if (ch)
- smd_write(ch, buf, header_size + diag_event_num_bytes);
- else
- pr_info("diag: invalid SMD channel\n");
-}
-
-void diag_send_msg_mask_update(smd_channel_t *ch)
-{
- unsigned char buf[1000];
- int first, last;
- int header_size = sizeof(struct diag_ctrl_msg_mask);
- uint8_t *ptr = driver->msg_masks;
-
- while (*(uint32_t *)(ptr + 4)) {
- first = *(uint32_t *)ptr;
- ptr += 4;
- last = *(uint32_t *)ptr;
- ptr += 4;
- /* send event mask update */
- driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
- driver->msg_mask->msg_mask_size = last - first + 1;
- driver->msg_mask->data_len = 11 +
- 4 * (driver->msg_mask->msg_mask_size);
- driver->msg_mask->stream_id = 1; /* 2, if dual stream */
- driver->msg_mask->status = 3; /* status for valid mask */
- driver->msg_mask->msg_mode = 0; /* Legcay mode */
- driver->msg_mask->ssid_first = first;
- driver->msg_mask->ssid_last = last;
- memcpy(buf, driver->msg_mask, header_size);
- memcpy(buf+header_size, ptr,
- 4 * (driver->msg_mask->msg_mask_size));
- if (ch)
- smd_write(ch, buf,
- header_size + 4*(driver->msg_mask->msg_mask_size));
- else
- pr_info("diag: invalid SMD channel\n");
- ptr += ((last - first) + 1)*4;
- }
-}
-
static int diag_process_apps_pkt(unsigned char *buf, int len)
{
uint16_t subsys_cmd_code;
@@ -647,100 +564,6 @@
unsigned char *ptr;
#endif
- /* Set log masks */
- if (*buf == 0x73 && *(int *)(buf+4) == 3) {
- buf += 8;
- /* Read Equip ID and pass as first param below*/
- diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
- diag_update_userspace_clients(LOG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (chk_apps_only()) {
- driver->apps_rsp_buf[0] = 0x73;
- *(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
- *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
- payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
- for (i = 0; i < payload_length; i++)
- *(int *)(driver->apps_rsp_buf+12+i) =
- *(buf+8+i);
- ENCODE_RSP_AND_SEND(12 + payload_length - 1);
- if (driver->ch_cntl) {
- diag_send_log_mask_update(driver->ch_cntl);
- diag_send_log_mask_update(driver->chqdsp_cntl);
- diag_send_log_mask_update(
- driver->ch_wcnss_cntl);
- }
- return 0;
- } else
- buf = temp;
-#endif
- } /* Check for set message mask */
- else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
- ssid_first = *(uint16_t *)(buf + 2);
- ssid_last = *(uint16_t *)(buf + 4);
- ssid_range = 4 * (ssid_last - ssid_first + 1);
- diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
- diag_update_userspace_clients(MSG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (chk_apps_only()) {
- for (i = 0; i < 8 + ssid_range; i++)
- *(driver->apps_rsp_buf + i) = *(buf+i);
- ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
- if (driver->ch_cntl) {
- diag_send_msg_mask_update(driver->ch_cntl);
- diag_send_msg_mask_update(driver->chqdsp_cntl);
- diag_send_msg_mask_update(
- driver->ch_wcnss_cntl);
- }
- return 0;
- } else
- buf = temp;
-#endif
- } else if (*buf == 0x82) { /* event mask change */
- buf += 4;
- diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
- diag_update_event_mask(buf, 1);
- diag_update_userspace_clients(EVENT_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (chk_apps_only()) {
- driver->apps_rsp_buf[0] = 0x82;
- driver->apps_rsp_buf[1] = 0x0;
- *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
- *(uint16_t *)(driver->apps_rsp_buf + 4) =
- EVENT_LAST_ID + 1;
- for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
- *(unsigned char *)(driver->apps_rsp_buf + 6 + i)
- = 0x0;
- ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
- if (driver->ch_cntl) {
- diag_send_event_mask_update(driver->ch_cntl);
- diag_send_event_mask_update(
- driver->chqdsp_cntl);
- diag_send_event_mask_update(
- driver->ch_wcnss_cntl);
- }
- return 0;
- } else
- buf = temp;
-#endif
- } else if (*buf == 0x60) {
- diag_event_config = *(buf+1);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (chk_apps_only()) {
- driver->apps_rsp_buf[0] = 0x60;
- driver->apps_rsp_buf[1] = 0x0;
- driver->apps_rsp_buf[2] = 0x0;
- ENCODE_RSP_AND_SEND(2);
- if (driver->ch_cntl) {
- diag_send_event_mask_update(driver->ch_cntl);
- diag_send_event_mask_update(
- driver->chqdsp_cntl);
- diag_send_event_mask_update(
- driver->ch_wcnss_cntl);
- }
- return 0;
- }
-#endif
- }
/* Check for registered clients and forward packet to apropriate proc */
cmd_code = (int)(*(char *)buf);
temp++;
@@ -791,9 +614,70 @@
}
}
}
+ /* set event mask */
+ if (*buf == 0x82) {
+ buf += 4;
+ diag_update_event_mask(buf, 1, *(uint16_t *)buf);
+ diag_update_userspace_clients(EVENT_MASKS_TYPE);
+ }
+ /* event mask change */
+ else if ((*buf == 0x60) && (*(buf+1) == 0x0)) {
+ diag_update_event_mask(buf+1, 0, 0);
+ diag_update_userspace_clients(EVENT_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ /* Check for Apps Only */
+ if (!(driver->ch) && chk_apps_only()) {
+ /* echo response back for apps only DIAG */
+ driver->apps_rsp_buf[0] = 0x60;
+ driver->apps_rsp_buf[1] = 0x0;
+ driver->apps_rsp_buf[2] = 0x0;
+ ENCODE_RSP_AND_SEND(2);
+ return 0;
+ }
+#endif
+ }
+ /* Set log masks */
+ else if (*buf == 0x73 && *(int *)(buf+4) == 3) {
+ buf += 8;
+ /* Read Equip ID and pass as first param below*/
+ diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
+ diag_update_userspace_clients(LOG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ /* Check for Apps Only */
+ if (!(driver->ch) && chk_apps_only()) {
+ /* echo response back for Apps only DIAG */
+ driver->apps_rsp_buf[0] = 0x73;
+ *(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
+ *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
+ payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
+ for (i = 0; i < payload_length; i++)
+ *(int *)(driver->apps_rsp_buf+12+i) =
+ *(buf+8+i);
+ ENCODE_RSP_AND_SEND(12 + payload_length - 1);
+ return 0;
+ }
+#endif
+ }
+ /* Check for set message mask */
+ else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
+ ssid_first = *(uint16_t *)(buf + 2);
+ ssid_last = *(uint16_t *)(buf + 4);
+ ssid_range = 4 * (ssid_last - ssid_first + 1);
+ diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
+ diag_update_userspace_clients(MSG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (!(driver->ch) && chk_apps_only()) {
+ /* echo response back for apps only DIAG */
+ for (i = 0; i < 8 + ssid_range; i++)
+ *(driver->apps_rsp_buf + i) = *(buf+i);
+ ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
+ return 0;
+ }
+#endif
+ }
#if defined(CONFIG_DIAG_OVER_USB)
/* Check for Apps Only & get event mask request */
- if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
+ else if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
driver->apps_rsp_buf[0] = 0x81;
driver->apps_rsp_buf[1] = 0x0;
*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
@@ -1406,25 +1290,6 @@
{
diag_debug_buf_idx = 0;
driver->read_len_legacy = 0;
-
- if (driver->event_mask == NULL) {
- driver->event_mask = kzalloc(sizeof(
- struct diag_ctrl_event_mask), GFP_KERNEL);
- if (driver->event_mask == NULL)
- goto err;
- }
- if (driver->msg_mask == NULL) {
- driver->msg_mask = kzalloc(sizeof(
- struct diag_ctrl_msg_mask), GFP_KERNEL);
- if (driver->msg_mask == NULL)
- goto err;
- }
- if (driver->log_mask == NULL) {
- driver->log_mask = kzalloc(sizeof(
- struct diag_ctrl_log_mask), GFP_KERNEL);
- if (driver->log_mask == NULL)
- goto err;
- }
if (driver->buf_in_1 == NULL) {
driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
if (driver->buf_in_1 == NULL)
@@ -1554,9 +1419,6 @@
return;
err:
pr_err("diag: Could not initialize diag buffers");
- kfree(driver->event_mask);
- kfree(driver->log_mask);
- kfree(driver->msg_mask);
kfree(driver->buf_in_1);
kfree(driver->buf_in_2);
kfree(driver->buf_in_qdsp_1);
@@ -1599,9 +1461,6 @@
#endif
platform_driver_unregister(&msm_smd_ch1_driver);
platform_driver_unregister(&diag_smd_lite_driver);
- kfree(driver->event_mask);
- kfree(driver->log_mask);
- kfree(driver->msg_mask);
kfree(driver->buf_in_1);
kfree(driver->buf_in_2);
kfree(driver->buf_in_qdsp_1);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index d33343e..6dacab7 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,9 +28,6 @@
int mask_request_validate(unsigned char mask_buf[]);
void diag_clear_reg(int);
int chk_apps_only(void);
-void diag_send_event_mask_update(smd_channel_t *);
-void diag_send_msg_mask_update(smd_channel_t *);
-void diag_send_log_mask_update(smd_channel_t *);
/* State for diag forwarding */
#ifdef CONFIG_DIAG_OVER_USB
int diagfwd_connect(void);
@@ -38,5 +35,5 @@
#endif
extern int diag_debug_buf_idx;
extern unsigned char diag_debug_buf[1024];
-extern int diag_event_num_bytes;
+
#endif
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 2c58772..9730d4f 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -118,31 +118,16 @@
static void diag_smd_cntl_notify(void *ctxt, unsigned event)
{
- if (event == SMD_EVENT_OPEN) {
- diag_send_event_mask_update(driver->ch_cntl);
- diag_send_msg_mask_update(driver->ch_cntl);
- diag_send_log_mask_update(driver->ch_cntl);
- }
queue_work(driver->diag_wq, &(driver->diag_read_smd_cntl_work));
}
static void diag_smd_qdsp_cntl_notify(void *ctxt, unsigned event)
{
- if (event == SMD_EVENT_OPEN) {
- diag_send_event_mask_update(driver->chqdsp_cntl);
- diag_send_msg_mask_update(driver->chqdsp_cntl);
- diag_send_log_mask_update(driver->chqdsp_cntl);
- }
queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_cntl_work));
}
static void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event)
{
- if (event == SMD_EVENT_OPEN) {
- diag_send_event_mask_update(driver->ch_wcnss_cntl);
- diag_send_msg_mask_update(driver->ch_wcnss_cntl);
- diag_send_log_mask_update(driver->ch_wcnss_cntl);
- }
queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_cntl_work));
}
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index b567c5f..542138d 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -29,39 +29,6 @@
uint16_t port;
};
-struct diag_ctrl_event_mask {
- uint32_t cmd_type;
- uint32_t data_len;
- uint8_t stream_id;
- uint8_t status;
- uint8_t event_config;
- uint32_t event_mask_size;
- /* Copy event mask here */
-} __packed;
-
-struct diag_ctrl_log_mask {
- uint32_t cmd_type;
- uint32_t data_len;
- uint8_t stream_id;
- uint8_t status;
- uint8_t equip_id;
- uint32_t num_items; /* Last log code for this equip_id */
- uint32_t log_mask_size; /* Size of log mask stored in log_mask[] */
- /* Copy log mask here */
-} __packed;
-
-struct diag_ctrl_msg_mask {
- uint32_t cmd_type;
- uint32_t data_len;
- uint8_t stream_id;
- uint8_t status;
- uint8_t msg_mode;
- uint16_t ssid_first; /* Start of range of supported SSIDs */
- uint16_t ssid_last; /* Last SSID in range */
- uint32_t msg_mask_size; /* ssid_last - ssid_first + 1 */
- /* Copy msg mask here */
-} __packed;
-
void diagfwd_cntl_init(void);
void diagfwd_cntl_exit(void);
void diag_read_smd_cntl_work_fn(struct work_struct *);
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 529d9dd..bd48925 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -569,11 +569,18 @@
unsigned int in_paddr,
unsigned int out_paddr,
unsigned int use_imem,
- int new_session)
+ int new_session,
+ unsigned int out_chroma_paddr)
{
int bpp;
+ uint32_t dst_format;
- if (info->src.format != info->dst.format)
+ if (info->src.format == MDP_YCRYCB_H2V1)
+ dst_format = MDP_Y_CRCB_H2V1;
+ else
+ return -EINVAL;
+
+ if (info->dst.format != dst_format)
return -EINVAL;
bpp = get_bpp(info->src.format);
@@ -584,15 +591,25 @@
iowrite32(out_paddr +
((info->dst_y * info->dst.width) + info->dst_x),
MSM_ROTATOR_OUTP0_ADDR);
+ iowrite32(out_chroma_paddr +
+ ((info->dst_y * info->dst.width)/2 + info->dst_x),
+ MSM_ROTATOR_OUTP1_ADDR);
if (new_session) {
- iowrite32(info->src.width,
+ iowrite32(info->src.width * bpp,
MSM_ROTATOR_SRC_YSTRIDE1);
- iowrite32(info->dst.width,
- MSM_ROTATOR_OUT_YSTRIDE1);
+ if (info->rotations & MDP_ROT_90)
+ iowrite32(info->dst.width |
+ (info->dst.width*2) << 16,
+ MSM_ROTATOR_OUT_YSTRIDE1);
+ else
+ iowrite32(info->dst.width |
+ (info->dst.width) << 16,
+ MSM_ROTATOR_OUT_YSTRIDE1);
+
iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
MSM_ROTATOR_SRC_UNPACK_PATTERN1);
- iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
+ iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
MSM_ROTATOR_OUT_PACK_PATTERN1);
iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
(ROTATIONS_TO_BITMASK(info->rotations) << 9) |
@@ -1036,7 +1053,8 @@
case MDP_YCRYCB_H2V1:
rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
in_paddr, out_paddr, use_imem,
- msm_rotator_dev->last_session_idx != s);
+ msm_rotator_dev->last_session_idx != s,
+ out_chroma_paddr);
break;
default:
rc = -EINVAL;
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..c44cde8 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
config CLKDEV_LOOKUP
bool
select HAVE_CLK
+
+config HAVE_CLK_PREPARE
+ bool
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index 3911950..c9e8a94 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,3 +1,3 @@
-obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o
+obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o ion_cp_heap.o
obj-$(CONFIG_ION_TEGRA) += tegra/
obj-$(CONFIG_ION_MSM) += msm/
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 1428315..386593f5 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -2,6 +2,7 @@
* drivers/gpu/ion/ion.c
*
* Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2012, 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
@@ -76,7 +77,7 @@
struct rb_root handles;
struct mutex lock;
unsigned int heap_mask;
- const char *name;
+ char *name;
struct task_struct *task;
pid_t pid;
struct dentry *debug_root;
@@ -363,6 +364,12 @@
struct ion_handle *handle;
struct ion_device *dev = client->dev;
struct ion_buffer *buffer = NULL;
+ unsigned long secure_allocation = flags & ION_SECURE;
+ const unsigned int MAX_DBG_STR_LEN = 64;
+ char dbg_str[MAX_DBG_STR_LEN];
+ unsigned int dbg_str_idx = 0;
+
+ dbg_str[0] = '\0';
/*
* traverse the list of heaps available in this system in priority
@@ -379,14 +386,37 @@
/* if the caller didn't specify this heap type */
if (!((1 << heap->id) & flags))
continue;
+ /* Do not allow un-secure heap if secure is specified */
+ if (secure_allocation && (heap->type != ION_HEAP_TYPE_CP))
+ continue;
buffer = ion_buffer_create(heap, dev, len, align, flags);
if (!IS_ERR_OR_NULL(buffer))
break;
+ if (dbg_str_idx < MAX_DBG_STR_LEN) {
+ unsigned int len_left = MAX_DBG_STR_LEN-dbg_str_idx-1;
+ int ret_value = snprintf(&dbg_str[dbg_str_idx],
+ len_left, "%s ", heap->name);
+ if (ret_value >= len_left) {
+ /* overflow */
+ dbg_str[MAX_DBG_STR_LEN-1] = '\0';
+ dbg_str_idx = MAX_DBG_STR_LEN;
+ } else if (ret_value >= 0) {
+ dbg_str_idx += ret_value;
+ } else {
+ /* error */
+ dbg_str[MAX_DBG_STR_LEN-1] = '\0';
+ }
+ }
}
mutex_unlock(&dev->lock);
- if (IS_ERR_OR_NULL(buffer))
+ if (IS_ERR_OR_NULL(buffer)) {
+ pr_debug("ION is unable to allocate 0x%x bytes (alignment: "
+ "0x%x) from heap(s) %sfor client %s with heap "
+ "mask 0x%x\n",
+ len, align, dbg_str, client->name, client->heap_mask);
return ERR_PTR(PTR_ERR(buffer));
+ }
handle = ion_handle_create(client, buffer);
@@ -979,6 +1009,7 @@
struct rb_node *parent = NULL;
struct ion_client *entry;
pid_t pid;
+ unsigned int name_len = strnlen(name, 64);
get_task_struct(current->group_leader);
task_lock(current->group_leader);
@@ -1012,7 +1043,17 @@
client->dev = dev;
client->handles = RB_ROOT;
mutex_init(&client->lock);
- client->name = name;
+
+ client->name = kzalloc(sizeof(name_len+1), GFP_KERNEL);
+ if (!client->name) {
+ put_task_struct(current->group_leader);
+ kfree(client);
+ return ERR_PTR(-ENOMEM);
+ } else {
+ strncpy(client->name, name, name_len);
+ client->name[name_len] = '\0';
+ }
+
client->heap_mask = heap_mask;
client->task = task;
client->pid = pid;
@@ -1078,6 +1119,7 @@
debugfs_remove_recursive(client->debug_root);
mutex_unlock(&dev->lock);
+ kfree(client->name);
kfree(client);
}
@@ -1273,12 +1315,14 @@
/* now map it to userspace */
ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma,
flags);
- mutex_unlock(&buffer->lock);
+
+ buffer->umap_cnt++;
if (ret) {
pr_err("%s: failure mapping buffer to userspace\n",
__func__);
goto err2;
}
+ mutex_unlock(&buffer->lock);
vma->vm_ops = &ion_vm_ops;
/* move the handle into the vm_private_data so we can access it from
@@ -1293,6 +1337,7 @@
err2:
buffer->umap_cnt--;
+ mutex_unlock(&buffer->lock);
/* drop the reference to the handle */
err1:
ion_handle_put(handle);
@@ -1350,7 +1395,7 @@
data.flags);
if (IS_ERR_OR_NULL(data.handle))
- return PTR_ERR(data.handle);
+ return -ENOMEM;
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
@@ -1563,14 +1608,8 @@
seq_printf(s, "%16.s %16u %16x\n", client->name, client->pid,
size);
}
- if (heap->ops->get_allocated) {
- seq_printf(s, "total bytes currently allocated: %lx\n",
- heap->ops->get_allocated(heap));
- }
- if (heap->ops->get_total) {
- seq_printf(s, "total heap size: %lx\n",
- heap->ops->get_total(heap));
- }
+ if (heap->ops->print_debug)
+ heap->ops->print_debug(heap, s);
return 0;
}
@@ -1617,6 +1656,60 @@
mutex_unlock(&dev->lock);
}
+int ion_secure_heap(struct ion_device *dev, int heap_id)
+{
+ struct rb_node *n;
+ int ret_val = 0;
+
+ /*
+ * traverse the list of heaps available in this system
+ * and find the heap that is specified.
+ */
+ mutex_lock(&dev->lock);
+ for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
+ struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
+ if (heap->type != ION_HEAP_TYPE_CP)
+ continue;
+ if (ION_HEAP(heap->id) != heap_id)
+ continue;
+ if (heap->ops->secure_heap)
+ ret_val = heap->ops->secure_heap(heap);
+ else
+ ret_val = -EINVAL;
+ break;
+ }
+ mutex_unlock(&dev->lock);
+ return ret_val;
+}
+EXPORT_SYMBOL(ion_secure_heap);
+
+int ion_unsecure_heap(struct ion_device *dev, int heap_id)
+{
+ struct rb_node *n;
+ int ret_val = 0;
+
+ /*
+ * traverse the list of heaps available in this system
+ * and find the heap that is specified.
+ */
+ mutex_lock(&dev->lock);
+ for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
+ struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
+ if (heap->type != ION_HEAP_TYPE_CP)
+ continue;
+ if (ION_HEAP(heap->id) != heap_id)
+ continue;
+ if (heap->ops->secure_heap)
+ ret_val = heap->ops->unsecure_heap(heap);
+ else
+ ret_val = -EINVAL;
+ break;
+ }
+ mutex_unlock(&dev->lock);
+ return ret_val;
+}
+EXPORT_SYMBOL(ion_unsecure_heap);
+
static int ion_debug_leak_show(struct seq_file *s, void *unused)
{
struct ion_device *dev = s->private;
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index c13abff..ad0c7b1 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/iommu.h>
+#include <linux/seq_file.h>
#include "ion_priv.h"
#include <mach/iommu_domains.h>
@@ -131,28 +132,55 @@
vfree(buffer->sglist);
}
+static int ion_carveout_request_region(struct ion_carveout_heap *carveout_heap)
+{
+ int ret_value = 0;
+ if (atomic_inc_return(&carveout_heap->map_count) == 1) {
+ if (carveout_heap->request_region) {
+ ret_value = carveout_heap->request_region(
+ carveout_heap->bus_id);
+ if (ret_value) {
+ pr_err("Unable to request SMI region");
+ atomic_dec(&carveout_heap->map_count);
+ }
+ }
+ }
+ return ret_value;
+}
+
+static int ion_carveout_release_region(struct ion_carveout_heap *carveout_heap)
+{
+ int ret_value = 0;
+ if (atomic_dec_and_test(&carveout_heap->map_count)) {
+ if (carveout_heap->release_region) {
+ ret_value = carveout_heap->release_region(
+ carveout_heap->bus_id);
+ if (ret_value)
+ pr_err("Unable to release SMI region");
+ }
+ }
+ return ret_value;
+}
+
void *ion_carveout_heap_map_kernel(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long flags)
{
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
+ void *ret_value;
- if (atomic_inc_return(&carveout_heap->map_count) == 1) {
- if (carveout_heap->request_region) {
- int ret = carveout_heap->request_region(
- carveout_heap->bus_id);
- if (ret) {
- pr_err("Unable to request SMI region");
- atomic_dec(&carveout_heap->map_count);
- return NULL;
- }
- }
- }
+ if (ion_carveout_request_region(carveout_heap))
+ return NULL;
+
if (ION_IS_CACHED(flags))
- return ioremap_cached(buffer->priv_phys, buffer->size);
+ ret_value = ioremap_cached(buffer->priv_phys, buffer->size);
else
- return ioremap(buffer->priv_phys, buffer->size);
+ ret_value = ioremap(buffer->priv_phys, buffer->size);
+
+ if (!ret_value)
+ ion_carveout_release_region(carveout_heap);
+ return ret_value;
}
void ion_carveout_heap_unmap_kernel(struct ion_heap *heap,
@@ -164,15 +192,7 @@
__arch_iounmap(buffer->vaddr);
buffer->vaddr = NULL;
- if (atomic_dec_and_test(&carveout_heap->map_count)) {
- if (carveout_heap->release_region) {
- int ret = carveout_heap->release_region(
- carveout_heap->bus_id);
- if (ret)
- pr_err("Unable to release SMI region");
- }
- }
-
+ ion_carveout_release_region(carveout_heap);
return;
}
@@ -181,29 +201,25 @@
{
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
+ int ret_value = 0;
- if (atomic_inc_return(&carveout_heap->map_count) == 1) {
- if (carveout_heap->request_region) {
- int ret = carveout_heap->request_region(
- carveout_heap->bus_id);
- if (ret) {
- pr_err("Unable to request SMI region");
- atomic_dec(&carveout_heap->map_count);
- return -EINVAL;
- }
- }
- }
+ if (ion_carveout_request_region(carveout_heap))
+ return -EINVAL;
if (ION_IS_CACHED(flags))
- return remap_pfn_range(vma, vma->vm_start,
+ ret_value = remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
else
- return remap_pfn_range(vma, vma->vm_start,
+ ret_value = remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
pgprot_noncached(vma->vm_page_prot));
+
+ if (ret_value)
+ ion_carveout_release_region(carveout_heap);
+ return ret_value;
}
void ion_carveout_heap_unmap_user(struct ion_heap *heap,
@@ -211,15 +227,7 @@
{
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
-
- if (atomic_dec_and_test(&carveout_heap->map_count)) {
- if (carveout_heap->release_region) {
- int ret = carveout_heap->release_region(
- carveout_heap->bus_id);
- if (ret)
- pr_err("Unable to release SMI region");
- }
- }
+ ion_carveout_release_region(carveout_heap);
}
int ion_carveout_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
@@ -248,20 +256,16 @@
return 0;
}
-static unsigned long ion_carveout_get_allocated(struct ion_heap *heap)
+static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s)
{
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
- return carveout_heap->allocated_bytes;
-}
+ seq_printf(s, "total bytes currently allocated: %lx\n",
+ carveout_heap->allocated_bytes);
+ seq_printf(s, "total heap size: %lx\n", carveout_heap->total_size);
-static unsigned long ion_carveout_get_total(struct ion_heap *heap)
-{
- struct ion_carveout_heap *carveout_heap =
- container_of(heap, struct ion_carveout_heap, heap);
-
- return carveout_heap->total_size;
+ return 0;
}
int ion_carveout_heap_map_iommu(struct ion_buffer *buffer,
@@ -377,8 +381,7 @@
.map_dma = ion_carveout_heap_map_dma,
.unmap_dma = ion_carveout_heap_unmap_dma,
.cache_op = ion_carveout_cache_ops,
- .get_allocated = ion_carveout_get_allocated,
- .get_total = ion_carveout_get_total,
+ .print_debug = ion_carveout_print_debug,
.map_iommu = ion_carveout_heap_map_iommu,
.unmap_iommu = ion_carveout_heap_unmap_iommu,
};
@@ -409,13 +412,20 @@
carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
carveout_heap->allocated_bytes = 0;
carveout_heap->total_size = heap_data->size;
- if (heap_data->setup_region)
- carveout_heap->bus_id = heap_data->setup_region();
- if (heap_data->request_region)
- carveout_heap->request_region = heap_data->request_region;
- if (heap_data->release_region)
- carveout_heap->release_region = heap_data->release_region;
+ if (heap_data->extra_data) {
+ struct ion_co_heap_pdata *extra_data =
+ heap_data->extra_data;
+
+ if (extra_data->setup_region)
+ carveout_heap->bus_id = extra_data->setup_region();
+ if (extra_data->request_region)
+ carveout_heap->request_region =
+ extra_data->request_region;
+ if (extra_data->release_region)
+ carveout_heap->release_region =
+ extra_data->release_region;
+ }
return &carveout_heap->heap;
}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
new file mode 100644
index 0000000..16ace6f
--- /dev/null
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -0,0 +1,632 @@
+/*
+ * drivers/gpu/ion/ion_cp_heap.c
+ *
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/spinlock.h>
+
+#include <linux/err.h>
+#include <linux/genalloc.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/memory_alloc.h>
+#include <linux/seq_file.h>
+#include <mach/msm_memtypes.h>
+#include <mach/scm.h>
+#include "ion_priv.h"
+
+#include <asm/mach/map.h>
+
+/**
+ * struct ion_cp_heap - container for the heap and shared heap data
+
+ * @heap: the heap information structure
+ * @pool: memory pool to allocate from.
+ * @base: the base address of the memory pool.
+ * @permission_type: Identifier for the memory used by SCM for protecting
+ * and unprotecting memory.
+ * @secure_base: Base address used when securing a heap that is shared.
+ * @secure_size: Size used when securing a heap that is shared.
+ * @lock: mutex to protect shared access.
+ * @heap_secured: Identifies the heap_id as secure or not.
+ * @allocated_bytes: the total number of allocated bytes from the pool.
+ * @total_size: the total size of the memory pool.
+ * @request_region: function pointer to call when first mapping of memory
+ * occurs.
+ * @release_region: function pointer to call when last mapping of memory
+ * unmapped.
+ * @bus_id: token used with request/release region.
+ * @kmap_count: the total number of times this heap has been mapped in
+ * kernel space.
+ * @umap_count: the total number of times this heap has been mapped in
+ * user space.
+ * @alloc_count:the total number of times this heap has been allocated
+ */
+struct ion_cp_heap {
+ struct ion_heap heap;
+ struct gen_pool *pool;
+ ion_phys_addr_t base;
+ unsigned int permission_type;
+ ion_phys_addr_t secure_base;
+ size_t secure_size;
+ struct mutex lock;
+ unsigned int heap_secured;
+ unsigned long allocated_bytes;
+ unsigned long total_size;
+ int (*request_region)(void *);
+ int (*release_region)(void *);
+ void *bus_id;
+ unsigned long kmap_count;
+ unsigned long umap_count;
+ unsigned long alloc_count;
+};
+
+enum {
+ NON_SECURED_HEAP = 0,
+ SECURED_HEAP = 1,
+};
+
+static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
+ unsigned int permission_type);
+
+static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size,
+ unsigned int permission_type);
+
+
+/**
+ * Protects memory if heap is unsecured heap.
+ * Must be called with heap->lock locked.
+ */
+static int ion_cp_protect(struct ion_heap *heap)
+{
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+ int ret_value = 0;
+
+ if (cp_heap->heap_secured == NON_SECURED_HEAP) {
+ int ret_value = ion_cp_protect_mem(cp_heap->secure_base,
+ cp_heap->secure_size, cp_heap->permission_type);
+ if (ret_value) {
+ pr_err("Failed to protect memory for heap %s - "
+ "error code: %d\n", heap->name, ret_value);
+ } else {
+ cp_heap->heap_secured = SECURED_HEAP;
+ pr_debug("Protected heap %s @ 0x%x\n",
+ heap->name, (unsigned int) cp_heap->base);
+ }
+ }
+ return ret_value;
+}
+
+/**
+ * Unprotects memory if heap is secure heap.
+ * Must be called with heap->lock locked.
+ */
+static void ion_cp_unprotect(struct ion_heap *heap)
+{
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+
+ if (cp_heap->heap_secured == SECURED_HEAP) {
+ int error_code = ion_cp_unprotect_mem(
+ cp_heap->secure_base, cp_heap->secure_size,
+ cp_heap->permission_type);
+ if (error_code) {
+ pr_err("Failed to un-protect memory for heap %s - "
+ "error code: %d\n", heap->name, error_code);
+ } else {
+ cp_heap->heap_secured = NON_SECURED_HEAP;
+ pr_debug("Un-protected heap %s @ 0x%x\n", heap->name,
+ (unsigned int) cp_heap->base);
+ }
+ }
+}
+
+ion_phys_addr_t ion_cp_allocate(struct ion_heap *heap,
+ unsigned long size,
+ unsigned long align,
+ unsigned long flags)
+{
+ unsigned long offset;
+ unsigned long secure_allocation = flags & ION_SECURE;
+
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+
+ mutex_lock(&cp_heap->lock);
+
+ if (!secure_allocation && cp_heap->heap_secured == SECURED_HEAP) {
+ mutex_unlock(&cp_heap->lock);
+ pr_err("ION cannot allocate un-secure memory from protected"
+ " heap %s\n", heap->name);
+ return ION_CP_ALLOCATE_FAIL;
+ }
+
+ if (secure_allocation && cp_heap->umap_count > 0) {
+ mutex_unlock(&cp_heap->lock);
+ pr_err("ION cannot allocate secure memory from heap with "
+ "outstanding user space mappings for heap %s\n",
+ heap->name);
+ return ION_CP_ALLOCATE_FAIL;
+ }
+
+ if (secure_allocation && ion_cp_protect(heap)) {
+ mutex_unlock(&cp_heap->lock);
+ return ION_CP_ALLOCATE_FAIL;
+ }
+
+ cp_heap->allocated_bytes += size;
+ ++cp_heap->alloc_count;
+ mutex_unlock(&cp_heap->lock);
+
+ offset = gen_pool_alloc_aligned(cp_heap->pool,
+ size, ilog2(align));
+
+ if (!offset) {
+ mutex_lock(&cp_heap->lock);
+ if ((cp_heap->total_size -
+ cp_heap->allocated_bytes) > size)
+ pr_debug("%s: heap %s has enough memory (%lx) but"
+ " the allocation of size %lx still failed."
+ " Memory is probably fragmented.\n",
+ __func__, heap->name,
+ cp_heap->total_size -
+ cp_heap->allocated_bytes, size);
+
+ cp_heap->allocated_bytes -= size;
+ --cp_heap->alloc_count;
+
+ if (cp_heap->alloc_count == 0)
+ ion_cp_unprotect(heap);
+
+ mutex_unlock(&cp_heap->lock);
+
+ return ION_CP_ALLOCATE_FAIL;
+ }
+
+ return offset;
+}
+
+void ion_cp_free(struct ion_heap *heap, ion_phys_addr_t addr,
+ unsigned long size)
+{
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+
+ if (addr == ION_CP_ALLOCATE_FAIL)
+ return;
+ gen_pool_free(cp_heap->pool, addr, size);
+
+ mutex_lock(&cp_heap->lock);
+
+ cp_heap->allocated_bytes -= size;
+ --cp_heap->alloc_count;
+
+ if (cp_heap->alloc_count == 0)
+ ion_cp_unprotect(heap);
+ mutex_unlock(&cp_heap->lock);
+}
+
+static int ion_cp_heap_phys(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ ion_phys_addr_t *addr, size_t *len)
+{
+ *addr = buffer->priv_phys;
+ *len = buffer->size;
+ return 0;
+}
+
+static int ion_cp_heap_allocate(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ unsigned long size, unsigned long align,
+ unsigned long flags)
+{
+ buffer->priv_phys = ion_cp_allocate(heap, size, align, flags);
+ return buffer->priv_phys == ION_CP_ALLOCATE_FAIL ? -ENOMEM : 0;
+}
+
+static void ion_cp_heap_free(struct ion_buffer *buffer)
+{
+ struct ion_heap *heap = buffer->heap;
+
+ ion_cp_free(heap, buffer->priv_phys, buffer->size);
+ buffer->priv_phys = ION_CP_ALLOCATE_FAIL;
+}
+
+
+/**
+ * Checks if user space mapping is allowed.
+ * NOTE: Will increment the mapping count if
+ * mapping is allowed.
+ * Will fail mapping if heap is secured.
+ */
+static unsigned int is_user_mapping_allowed(struct ion_heap *heap)
+{
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+
+ mutex_lock(&cp_heap->lock);
+
+ if (cp_heap->heap_secured == SECURED_HEAP) {
+ mutex_unlock(&cp_heap->lock);
+ return 0;
+ }
+ ++cp_heap->umap_count;
+
+ mutex_unlock(&cp_heap->lock);
+ return 1;
+}
+
+struct scatterlist *ion_cp_heap_map_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ struct scatterlist *sglist;
+ struct page *page = phys_to_page(buffer->priv_phys);
+
+ if (page == NULL)
+ return NULL;
+
+ sglist = vmalloc(sizeof(*sglist));
+ if (!sglist)
+ return ERR_PTR(-ENOMEM);
+
+ sg_init_table(sglist, 1);
+ sg_set_page(sglist, page, buffer->size, 0);
+
+ return sglist;
+}
+
+void ion_cp_heap_unmap_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ if (buffer->sglist)
+ vfree(buffer->sglist);
+}
+
+/**
+ * Call request region for SMI memory of this is the first mapping.
+ */
+static int ion_cp_request_region(struct ion_cp_heap *cp_heap)
+{
+ int ret_value = 0;
+ if ((cp_heap->umap_count+cp_heap->kmap_count) == 1)
+ if (cp_heap->request_region)
+ ret_value = cp_heap->request_region(cp_heap->bus_id);
+ return ret_value;
+}
+
+/**
+ * Call release region for SMI memory of this is the last un-mapping.
+ */
+static int ion_cp_release_region(struct ion_cp_heap *cp_heap)
+{
+ int ret_value = 0;
+ if ((cp_heap->umap_count + cp_heap->kmap_count) == 0)
+ if (cp_heap->release_region)
+ ret_value = cp_heap->release_region(cp_heap->bus_id);
+ return ret_value;
+}
+
+void *ion_cp_heap_map_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ unsigned long flags)
+{
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+ void *ret_value;
+
+ mutex_lock(&cp_heap->lock);
+
+ if (cp_heap->heap_secured == SECURED_HEAP && ION_IS_CACHED(flags)) {
+ pr_err("Unable to map secured heap %s as cached\n", heap->name);
+ mutex_unlock(&cp_heap->lock);
+ return NULL;
+ }
+
+ ++cp_heap->kmap_count;
+
+ if (ion_cp_request_region(cp_heap)) {
+ --cp_heap->kmap_count;
+ mutex_unlock(&cp_heap->lock);
+ return NULL;
+ }
+ mutex_unlock(&cp_heap->lock);
+
+ if (ION_IS_CACHED(flags))
+ ret_value = ioremap_cached(buffer->priv_phys, buffer->size);
+ else
+ ret_value = ioremap(buffer->priv_phys, buffer->size);
+
+ if (!ret_value) {
+ mutex_lock(&cp_heap->lock);
+ --cp_heap->kmap_count;
+ ion_cp_release_region(cp_heap);
+ mutex_unlock(&cp_heap->lock);
+ }
+ return ret_value;
+}
+
+void ion_cp_heap_unmap_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+
+ __arch_iounmap(buffer->vaddr);
+ buffer->vaddr = NULL;
+
+ mutex_lock(&cp_heap->lock);
+ --cp_heap->kmap_count;
+ ion_cp_release_region(cp_heap);
+ mutex_unlock(&cp_heap->lock);
+
+ return;
+}
+
+int ion_cp_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
+ struct vm_area_struct *vma, unsigned long flags)
+{
+ int ret_value = -EAGAIN;
+ if (is_user_mapping_allowed(heap)) {
+
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+
+ mutex_lock(&cp_heap->lock);
+ if (ion_cp_request_region(cp_heap)) {
+ mutex_unlock(&cp_heap->lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&cp_heap->lock);
+
+ if (ION_IS_CACHED(flags))
+ ret_value = remap_pfn_range(vma, vma->vm_start,
+ __phys_to_pfn(buffer->priv_phys) +
+ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+ else
+ ret_value = remap_pfn_range(vma, vma->vm_start,
+ __phys_to_pfn(buffer->priv_phys) +
+ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ pgprot_noncached(vma->vm_page_prot));
+
+ if (ret_value) {
+ mutex_lock(&cp_heap->lock);
+ --cp_heap->umap_count;
+ ion_cp_release_region(cp_heap);
+ mutex_unlock(&cp_heap->lock);
+ }
+ }
+ return ret_value;
+}
+
+void ion_cp_heap_unmap_user(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+
+ mutex_lock(&cp_heap->lock);
+ --cp_heap->umap_count;
+ ion_cp_release_region(cp_heap);
+ mutex_unlock(&cp_heap->lock);
+}
+
+int ion_cp_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
+ void *vaddr, unsigned int offset, unsigned int length,
+ unsigned int cmd)
+{
+ unsigned long vstart, pstart;
+
+ pstart = buffer->priv_phys + offset;
+ vstart = (unsigned long)vaddr;
+
+ switch (cmd) {
+ case ION_IOC_CLEAN_CACHES:
+ clean_caches(vstart, length, pstart);
+ break;
+ case ION_IOC_INV_CACHES:
+ invalidate_caches(vstart, length, pstart);
+ break;
+ case ION_IOC_CLEAN_INV_CACHES:
+ clean_and_invalidate_caches(vstart, length, pstart);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s)
+{
+ unsigned long total_alloc;
+ unsigned long total_size;
+ unsigned long alloc_count;
+ unsigned long umap_count;
+ unsigned long kmap_count;
+ unsigned long heap_secured;
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+
+ mutex_lock(&cp_heap->lock);
+ total_alloc = cp_heap->allocated_bytes;
+ total_size = cp_heap->total_size;
+ alloc_count = cp_heap->alloc_count;
+ umap_count = cp_heap->umap_count;
+ kmap_count = cp_heap->kmap_count;
+ heap_secured = cp_heap->heap_secured == SECURED_HEAP;
+ mutex_unlock(&cp_heap->lock);
+
+ seq_printf(s, "total bytes currently allocated: %lx\n", total_alloc);
+ seq_printf(s, "total heap size: %lx\n", total_size);
+ seq_printf(s, "allocation count: %lx\n", alloc_count);
+ seq_printf(s, "umapping count: %lx\n", umap_count);
+ seq_printf(s, "kmapping count: %lx\n", kmap_count);
+ seq_printf(s, "secured heap: %s\n", heap_secured ? "Yes" : "No");
+
+ return 0;
+}
+
+int ion_cp_secure_heap(struct ion_heap *heap)
+{
+ int ret_value;
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+ mutex_lock(&cp_heap->lock);
+ ret_value = ion_cp_protect(heap);
+ mutex_unlock(&cp_heap->lock);
+ return ret_value;
+}
+
+int ion_cp_unsecure_heap(struct ion_heap *heap)
+{
+ int ret_value = 0;
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+ mutex_lock(&cp_heap->lock);
+ ion_cp_unprotect(heap);
+ mutex_unlock(&cp_heap->lock);
+ return ret_value;
+}
+
+
+static struct ion_heap_ops cp_heap_ops = {
+ .allocate = ion_cp_heap_allocate,
+ .free = ion_cp_heap_free,
+ .phys = ion_cp_heap_phys,
+ .map_user = ion_cp_heap_map_user,
+ .unmap_user = ion_cp_heap_unmap_user,
+ .map_kernel = ion_cp_heap_map_kernel,
+ .unmap_kernel = ion_cp_heap_unmap_kernel,
+ .map_dma = ion_cp_heap_map_dma,
+ .unmap_dma = ion_cp_heap_unmap_dma,
+ .cache_op = ion_cp_cache_ops,
+ .print_debug = ion_cp_print_debug,
+ .secure_heap = ion_cp_secure_heap,
+ .unsecure_heap = ion_cp_unsecure_heap,
+};
+
+struct ion_heap *ion_cp_heap_create(struct ion_platform_heap *heap_data)
+{
+ struct ion_cp_heap *cp_heap;
+ int ret;
+
+ cp_heap = kzalloc(sizeof(*cp_heap), GFP_KERNEL);
+ if (!cp_heap)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&cp_heap->lock);
+
+ cp_heap->pool = gen_pool_create(12, -1);
+ if (!cp_heap->pool)
+ goto free_heap;
+
+ cp_heap->base = heap_data->base;
+ ret = gen_pool_add(cp_heap->pool, cp_heap->base, heap_data->size, -1);
+ if (ret < 0)
+ goto destroy_pool;
+
+ cp_heap->allocated_bytes = 0;
+ cp_heap->alloc_count = 0;
+ cp_heap->umap_count = 0;
+ cp_heap->kmap_count = 0;
+ cp_heap->total_size = heap_data->size;
+ cp_heap->heap.ops = &cp_heap_ops;
+ cp_heap->heap.type = ION_HEAP_TYPE_CP;
+ cp_heap->heap_secured = NON_SECURED_HEAP;
+ cp_heap->secure_base = cp_heap->base;
+ cp_heap->secure_size = heap_data->size;
+ if (heap_data->extra_data) {
+ struct ion_cp_heap_pdata *extra_data =
+ heap_data->extra_data;
+ cp_heap->permission_type = extra_data->permission_type;
+ if (extra_data->secure_size) {
+ cp_heap->secure_base = extra_data->secure_base;
+ cp_heap->secure_size = extra_data->secure_size;
+ }
+ if (extra_data->setup_region)
+ cp_heap->bus_id = extra_data->setup_region();
+ if (extra_data->request_region)
+ cp_heap->request_region = extra_data->request_region;
+ if (extra_data->release_region)
+ cp_heap->release_region = extra_data->release_region;
+ }
+ return &cp_heap->heap;
+
+destroy_pool:
+ gen_pool_destroy(cp_heap->pool);
+
+free_heap:
+ kfree(cp_heap);
+
+ return ERR_PTR(-ENOMEM);
+}
+
+void ion_cp_heap_destroy(struct ion_heap *heap)
+{
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+
+ gen_pool_destroy(cp_heap->pool);
+ kfree(cp_heap);
+ cp_heap = NULL;
+}
+
+
+/* SCM related code for locking down memory for content protection */
+
+#define SCM_CP_LOCK_CMD_ID 0x1
+#define SCM_CP_PROTECT 0x1
+#define SCM_CP_UNPROTECT 0x0
+
+struct cp_lock_msg {
+ unsigned int start;
+ unsigned int end;
+ unsigned int permission_type;
+ unsigned char lock;
+} __attribute__ ((__packed__));
+
+
+static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
+ unsigned int permission_type)
+{
+ struct cp_lock_msg cmd;
+ cmd.start = phy_base;
+ cmd.end = phy_base + size;
+ cmd.permission_type = permission_type;
+ cmd.lock = SCM_CP_PROTECT;
+
+ return scm_call(SCM_SVC_CP, SCM_CP_LOCK_CMD_ID,
+ &cmd, sizeof(cmd), NULL, 0);
+}
+
+static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size,
+ unsigned int permission_type)
+{
+ struct cp_lock_msg cmd;
+ cmd.start = phy_base;
+ cmd.end = phy_base + size;
+ cmd.permission_type = permission_type;
+ cmd.lock = SCM_CP_UNPROTECT;
+
+ return scm_call(SCM_SVC_CP, SCM_CP_LOCK_CMD_ID,
+ &cmd, sizeof(cmd), NULL, 0);
+}
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 900f445..6ea49db 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -2,6 +2,7 @@
* drivers/gpu/ion/ion_heap.c
*
* Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2012, 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
@@ -35,6 +36,9 @@
case ION_HEAP_TYPE_IOMMU:
heap = ion_iommu_heap_create(heap_data);
break;
+ case ION_HEAP_TYPE_CP:
+ heap = ion_cp_heap_create(heap_data);
+ break;
default:
pr_err("%s: Invalid heap type %d\n", __func__,
heap_data->type);
@@ -68,6 +72,12 @@
case ION_HEAP_TYPE_CARVEOUT:
ion_carveout_heap_destroy(heap);
break;
+ case ION_HEAP_TYPE_IOMMU:
+ ion_iommu_heap_destroy(heap);
+ break;
+ case ION_HEAP_TYPE_CP:
+ ion_cp_heap_destroy(heap);
+ break;
default:
pr_err("%s: Invalid heap type %d\n", __func__,
heap->type);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 77b73e2..78dfe6e 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -2,6 +2,7 @@
* drivers/gpu/ion/ion_priv.h
*
* Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2012, 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
@@ -138,8 +139,6 @@
int (*cache_op)(struct ion_heap *heap, struct ion_buffer *buffer,
void *vaddr, unsigned int offset,
unsigned int length, unsigned int cmd);
- unsigned long (*get_allocated)(struct ion_heap *heap);
- unsigned long (*get_total)(struct ion_heap *heap);
int (*map_iommu)(struct ion_buffer *buffer,
struct ion_iommu_map *map_data,
unsigned int domain_num,
@@ -148,7 +147,9 @@
unsigned long iova_length,
unsigned long flags);
void (*unmap_iommu)(struct ion_iommu_map *data);
-
+ int (*print_debug)(struct ion_heap *heap, struct seq_file *s);
+ int (*secure_heap)(struct ion_heap *heap);
+ int (*unsecure_heap)(struct ion_heap *heap);
};
/**
@@ -226,6 +227,9 @@
struct ion_heap *ion_iommu_heap_create(struct ion_platform_heap *);
void ion_iommu_heap_destroy(struct ion_heap *);
+struct ion_heap *ion_cp_heap_create(struct ion_platform_heap *);
+void ion_cp_heap_destroy(struct ion_heap *);
+
/**
* kernel api to allocate/free from carveout -- used when carveout is
* used to back an architecture specific custom heap
@@ -238,9 +242,10 @@
struct ion_heap *msm_get_contiguous_heap(void);
/**
- * The carveout heap returns physical addresses, since 0 may be a valid
+ * The carveout/cp heap returns physical addresses, since 0 may be a valid
* physical address, this is used to indicate allocation failed
*/
#define ION_CARVEOUT_ALLOCATE_FAIL -1
+#define ION_CP_ALLOCATE_FAIL -1
#endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 5957658..316740e 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -2,7 +2,7 @@
* drivers/gpu/ion/ion_system_heap.c
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, 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
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/iommu.h>
+#include <linux/seq_file.h>
#include <mach/iommu_domains.h>
#include "ion_priv.h"
#include <mach/memory.h>
@@ -189,9 +190,12 @@
return 0;
}
-static unsigned long ion_system_heap_get_allocated(struct ion_heap *heap)
+static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s)
{
- return atomic_read(&system_heap_allocated);
+ seq_printf(s, "total bytes currently allocated: %lx\n",
+ (unsigned long) atomic_read(&system_heap_allocated));
+
+ return 0;
}
int ion_system_heap_map_iommu(struct ion_buffer *buffer,
@@ -274,7 +278,7 @@
.unmap_kernel = ion_system_heap_unmap_kernel,
.map_user = ion_system_heap_map_user,
.cache_op = ion_system_heap_cache_ops,
- .get_allocated = ion_system_heap_get_allocated,
+ .print_debug = ion_system_print_debug,
.map_iommu = ion_system_heap_map_iommu,
.unmap_iommu = ion_system_heap_unmap_iommu,
};
@@ -387,9 +391,13 @@
return 0;
}
-static unsigned long ion_system_contig_heap_get_allocated(struct ion_heap *heap)
+static int ion_system_contig_print_debug(struct ion_heap *heap,
+ struct seq_file *s)
{
- return atomic_read(&system_contig_heap_allocated);
+ seq_printf(s, "total bytes currently allocated: %lx\n",
+ (unsigned long) atomic_read(&system_contig_heap_allocated));
+
+ return 0;
}
int ion_system_contig_heap_map_iommu(struct ion_buffer *buffer,
@@ -470,7 +478,7 @@
.unmap_kernel = ion_system_heap_unmap_kernel,
.map_user = ion_system_contig_heap_map_user,
.cache_op = ion_system_contig_heap_cache_ops,
- .get_allocated = ion_system_contig_heap_get_allocated,
+ .print_debug = ion_system_contig_print_debug,
.map_iommu = ion_system_contig_heap_map_iommu,
.unmap_iommu = ion_system_heap_unmap_iommu,
};
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 0c96eaf..f71f514 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -30,21 +30,131 @@
}
EXPORT_SYMBOL(msm_ion_client_create);
-static unsigned long msm_ion_get_base(unsigned long size, int memory_type)
+int msm_ion_secure_heap(int heap_id)
+{
+ return ion_secure_heap(idev, heap_id);
+}
+EXPORT_SYMBOL(msm_ion_secure_heap);
+
+int msm_ion_unsecure_heap(int heap_id)
+{
+ return ion_unsecure_heap(idev, heap_id);
+}
+EXPORT_SYMBOL(msm_ion_unsecure_heap);
+
+static unsigned long msm_ion_get_base(unsigned long size, int memory_type,
+ unsigned int align)
{
switch (memory_type) {
case ION_EBI_TYPE:
- return allocate_contiguous_ebi_nomap(size, PAGE_SIZE);
+ return allocate_contiguous_ebi_nomap(size, align);
break;
case ION_SMI_TYPE:
return allocate_contiguous_memory_nomap(size, MEMTYPE_SMI,
- PAGE_SIZE);
+ align);
break;
default:
+ pr_err("%s: Unknown memory type %d\n", __func__, memory_type);
return 0;
}
}
+static struct ion_platform_heap *find_heap(const struct ion_platform_heap
+ heap_data[],
+ unsigned int nr_heaps,
+ int heap_id)
+{
+ unsigned int i;
+ for (i = 0; i < nr_heaps; ++i) {
+ const struct ion_platform_heap *heap = &heap_data[i];
+ if (heap->id == heap_id)
+ return (struct ion_platform_heap *) heap;
+ }
+ return 0;
+}
+
+static void allocate_co_memory(struct ion_platform_heap *heap,
+ struct ion_platform_heap heap_data[],
+ unsigned int nr_heaps)
+{
+ struct ion_co_heap_pdata *co_heap_data =
+ (struct ion_co_heap_pdata *) heap->extra_data;
+ if (co_heap_data->adjacent_mem_id != INVALID_HEAP_ID) {
+ struct ion_platform_heap *shared_heap =
+ find_heap(heap_data, nr_heaps,
+ co_heap_data->adjacent_mem_id);
+ if (shared_heap) {
+ struct ion_cp_heap_pdata *cp_data =
+ (struct ion_cp_heap_pdata *) shared_heap->extra_data;
+ heap->base = msm_ion_get_base(
+ heap->size + shared_heap->size,
+ shared_heap->memory_type,
+ co_heap_data->align);
+ if (heap->base) {
+ shared_heap->base = heap->base + heap->size;
+ cp_data->secure_base = heap->base;
+ cp_data->secure_size =
+ heap->size + shared_heap->size;
+ } else {
+ pr_err("%s: could not get memory for heap %s "
+ "(id %x)\n", __func__, heap->name, heap->id);
+ }
+
+ }
+ }
+}
+
+/* Fixup heaps in board file to support two heaps being adjacent to each other.
+ * A flag (adjacent_mem_id) in the platform data tells us that the heap phy
+ * memory location must be adjacent to the specified heap. We do this by
+ * carving out memory for both heaps and then splitting up the memory to the
+ * two heaps. The heap specifying the "adjacent_mem_id" get the base of the
+ * memory while heap specified in "adjacent_mem_id" get base+size as its
+ * base address.
+ * Note: Modifies platform data and allocates memory.
+ */
+static void msm_ion_heap_fixup(struct ion_platform_heap heap_data[],
+ unsigned int nr_heaps)
+{
+ unsigned int i;
+
+ for (i = 0; i < nr_heaps; i++) {
+ struct ion_platform_heap *heap = &heap_data[i];
+ if (!heap->base && heap->type == ION_HEAP_TYPE_CARVEOUT) {
+ if (heap->extra_data)
+ allocate_co_memory(heap, heap_data, nr_heaps);
+ }
+ }
+}
+
+static void msm_ion_allocate(struct ion_platform_heap *heap)
+{
+
+ if (!heap->base && heap->extra_data) {
+ unsigned int align = 0;
+ switch (heap->type) {
+ case ION_HEAP_TYPE_CARVEOUT:
+ align =
+ ((struct ion_co_heap_pdata *) heap->extra_data)->align;
+ break;
+ case ION_HEAP_TYPE_CP:
+ align =
+ ((struct ion_cp_heap_pdata *) heap->extra_data)->align;
+ break;
+ default:
+ break;
+ }
+ if (align) {
+ heap->base = msm_ion_get_base(heap->size,
+ heap->memory_type,
+ align);
+ if (!heap->base)
+ pr_err("%s: could not get memory for heap %s "
+ "(id %x)\n", __func__, heap->name, heap->id);
+ }
+ }
+}
+
static int msm_ion_probe(struct platform_device *pdev)
{
struct ion_platform_data *pdata = pdev->dev.platform_data;
@@ -66,28 +176,26 @@
goto freeheaps;
}
+ msm_ion_heap_fixup(pdata->heaps, num_heaps);
+
/* create the heaps as specified in the board file */
for (i = 0; i < num_heaps; i++) {
struct ion_platform_heap *heap_data = &pdata->heaps[i];
-
- if (heap_data->type == ION_HEAP_TYPE_CARVEOUT) {
- heap_data->base = msm_ion_get_base(heap_data->size,
- heap_data->memory_type);
- if (!heap_data->base) {
- pr_err("%s: could not get memory for heap %s"
- " (id %x)\n", __func__, heap_data->name,
- heap_data->id);
- continue;
- }
- }
+ msm_ion_allocate(heap_data);
heaps[i] = ion_heap_create(heap_data);
if (IS_ERR_OR_NULL(heaps[i])) {
- pr_err("%s: could not create ion heap %s"
- " (id %x)\n", __func__, heap_data->name,
- heap_data->id);
heaps[i] = 0;
continue;
+ } else {
+ if (heap_data->size)
+ pr_info("ION heap %s created at %lx "
+ "with size %x\n", heap_data->name,
+ heap_data->base,
+ heap_data->size);
+ else
+ pr_info("ION heap %s created\n",
+ heap_data->name);
}
ion_device_add_heap(idev, heaps[i]);
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index 39a7b04..908b63d 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -14,7 +14,7 @@
msm_kgsl_core-$(CONFIG_MSM_KGSL_CFF_DUMP) += kgsl_cffdump.o
msm_kgsl_core-$(CONFIG_MSM_KGSL_DRM) += kgsl_drm.o
msm_kgsl_core-$(CONFIG_MSM_SCM) += kgsl_pwrscale_trustzone.o
-msm_kgsl_core-$(CONFIG_MSM_SLEEP_STATS) += kgsl_pwrscale_idlestats.o
+msm_kgsl_core-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += kgsl_pwrscale_idlestats.o
msm_adreno-y += \
adreno_ringbuffer.o \
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index c29da39..6ab9534 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -631,9 +631,33 @@
void kgsl_pre_hwaccess(struct kgsl_device *device)
{
BUG_ON(!mutex_is_locked(&device->mutex));
- if (device->state & (KGSL_STATE_SLEEP | KGSL_STATE_NAP |
- KGSL_STATE_SLUMBER))
+ switch (device->state) {
+ case KGSL_STATE_ACTIVE:
+ return;
+ case KGSL_STATE_NAP:
+ case KGSL_STATE_SLEEP:
+ case KGSL_STATE_SLUMBER:
kgsl_pwrctrl_wake(device);
+ break;
+ case KGSL_STATE_SUSPEND:
+ kgsl_check_suspended(device);
+ break;
+ case KGSL_STATE_INIT:
+ case KGSL_STATE_HUNG:
+ case KGSL_STATE_DUMP_AND_RECOVER:
+ if (test_bit(KGSL_PWRFLAGS_CLK_ON,
+ &device->pwrctrl.power_flags))
+ break;
+ else
+ KGSL_PWR_ERR(device,
+ "hw access while clocks off from state %d\n",
+ device->state);
+ break;
+ default:
+ KGSL_PWR_ERR(device, "hw access while in unknown state %d\n",
+ device->state);
+ break;
+ }
}
EXPORT_SYMBOL(kgsl_pre_hwaccess);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 55e5383..4c9a239 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -42,7 +42,7 @@
#ifdef CONFIG_MSM_SCM
&kgsl_pwrscale_policy_tz,
#endif
-#ifdef CONFIG_MSM_SLEEP_STATS
+#ifdef CONFIG_MSM_SLEEP_STATS_DEVICE
&kgsl_pwrscale_policy_idlestats,
#endif
NULL
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c954260..2453b6b 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -306,6 +306,12 @@
u8 t7_data[T7_DATA_SIZE];
u16 t7_start_addr;
u8 t9_ctrl;
+ u32 keyarray_old;
+ u32 keyarray_new;
+ u8 t9_max_reportid;
+ u8 t9_min_reportid;
+ u8 t15_max_reportid;
+ u8 t15_min_reportid;
};
static bool mxt_object_readable(unsigned int type)
@@ -670,16 +676,48 @@
mxt_input_report(data, id);
}
+static void mxt_handle_key_array(struct mxt_data *data,
+ struct mxt_message *message)
+{
+ u32 keys_changed;
+ int i;
+
+ if (!data->pdata->key_codes) {
+ dev_err(&data->client->dev, "keyarray is not supported\n");
+ return;
+ }
+
+ data->keyarray_new = message->message[1] |
+ (message->message[2] << 8) |
+ (message->message[3] << 16) |
+ (message->message[4] << 24);
+
+ keys_changed = data->keyarray_old ^ data->keyarray_new;
+
+ if (!keys_changed) {
+ dev_dbg(&data->client->dev, "no keys changed\n");
+ return;
+ }
+
+ for (i = 0; i < MXT_KEYARRAY_MAX_KEYS; i++) {
+ if (!(keys_changed & (1 << i)))
+ continue;
+
+ input_report_key(data->input_dev, data->pdata->key_codes[i],
+ (data->keyarray_new & (1 << i)));
+ input_sync(data->input_dev);
+ }
+
+ data->keyarray_old = data->keyarray_new;
+}
+
static irqreturn_t mxt_interrupt(int irq, void *dev_id)
{
struct mxt_data *data = dev_id;
struct mxt_message message;
- struct mxt_object *object;
struct device *dev = &data->client->dev;
int id;
u8 reportid;
- u8 max_reportid;
- u8 min_reportid;
do {
if (mxt_read_message(data, &message)) {
@@ -688,16 +726,20 @@
}
reportid = message.reportid;
- /* whether reportid is thing of MXT_TOUCH_MULTI_T9 */
- object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
- if (!object)
- goto end;
- max_reportid = object->max_reportid;
- min_reportid = max_reportid - object->num_report_ids + 1;
- id = reportid - min_reportid;
+ if (!reportid) {
+ dev_dbg(dev, "Report id 0 is reserved\n");
+ continue;
+ }
- if (reportid >= min_reportid && reportid <= max_reportid)
+ /* check whether report id is part of T9 or T15 */
+ id = reportid - data->t9_min_reportid;
+
+ if (reportid >= data->t9_min_reportid &&
+ reportid <= data->t9_max_reportid)
mxt_input_touchevent(data, &message, id);
+ else if (reportid >= data->t15_min_reportid &&
+ reportid <= data->t15_max_reportid)
+ mxt_handle_key_array(data, &message);
else
mxt_dump_message(dev, &message);
} while (reportid != 0xff);
@@ -857,6 +899,8 @@
u8 val;
u8 command_register;
struct mxt_object *t7_object;
+ struct mxt_object *t9_object;
+ struct mxt_object *t15_object;
error = mxt_get_info(data);
if (error)
@@ -903,6 +947,28 @@
goto free_object_table;
}
+ /* Store T9, T15's min and max report ids */
+ t9_object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
+ if (!t9_object) {
+ dev_err(&client->dev, "Failed to get T9 object\n");
+ error = -EINVAL;
+ goto free_object_table;
+ }
+ data->t9_max_reportid = t9_object->max_reportid;
+ data->t9_min_reportid = t9_object->max_reportid -
+ t9_object->num_report_ids + 1;
+
+ if (data->pdata->key_codes) {
+ t15_object = mxt_get_object(data, MXT_TOUCH_KEYARRAY_T15);
+ if (!t15_object)
+ dev_dbg(&client->dev, "T15 object is not available\n");
+ else {
+ data->t15_max_reportid = t15_object->max_reportid;
+ data->t15_min_reportid = t15_object->max_reportid -
+ t15_object->num_report_ids + 1;
+ }
+ }
+
/* Backup to memory */
mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_BACKUPNV,
@@ -1562,7 +1628,7 @@
const struct mxt_platform_data *pdata = client->dev.platform_data;
struct mxt_data *data;
struct input_dev *input_dev;
- int error;
+ int error, i;
if (!pdata)
return -EINVAL;
@@ -1608,6 +1674,15 @@
input_set_abs_params(input_dev, ABS_MT_PRESSURE,
0, 255, 0, 0);
+ /* set key array supported keys */
+ if (pdata->key_codes) {
+ for (i = 0; i < MXT_KEYARRAY_MAX_KEYS; i++) {
+ if (pdata->key_codes[i])
+ input_set_capability(input_dev, EV_KEY,
+ pdata->key_codes[i]);
+ }
+ }
+
input_set_drvdata(input_dev, data);
i2c_set_clientdata(client, data);
@@ -1750,6 +1825,12 @@
else
mxt_regulator_configure(data, false);
+ if (gpio_is_valid(data->pdata->reset_gpio))
+ gpio_free(data->pdata->reset_gpio);
+
+ if (gpio_is_valid(data->pdata->irq_gpio))
+ gpio_free(data->pdata->irq_gpio);
+
kfree(data->object_table);
kfree(data);
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 59f915e..ff0e00d 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -97,6 +97,7 @@
struct hci_fm_riva_poke riva_data_req;
struct hci_fm_ssbi_req ssbi_data_accs;
struct hci_fm_ssbi_peek ssbi_peek_reg;
+ struct hci_fm_sig_threshold_rsp sig_th;
};
static struct video_device *priv_videodev;
@@ -419,6 +420,13 @@
.minimum = 0,
.maximum = 1,
},
+ {
+ .id = V4L2_CID_PRIVATE_IRIS_GET_SINR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "GET SINR",
+ .minimum = -128,
+ .maximum = 127,
+ },
};
static void iris_q_event(struct iris_device *radio,
@@ -1580,13 +1588,11 @@
{
struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
struct iris_device *radio = video_get_drvdata(video_get_dev());
- struct v4l2_control *v4l_ctl = radio->g_ctl;
if (rsp->status)
return;
- v4l_ctl->value = rsp->sig_threshold;
-
+ memcpy(&radio->sig_th, rsp, sizeof(struct hci_fm_sig_threshold_rsp));
radio_hci_req_complete(hdev, rsp->status);
}
@@ -1908,7 +1914,7 @@
if (i >= IRIS_BUF_RT_RDS)
kfifo_reset(&radio->data_buf[i]);
}
- if (radio->fm_st_rsp.station_rsp.rssi)
+ if (radio->fm_st_rsp.station_rsp.serv_avble)
iris_q_event(radio, IRIS_EVT_ABOVE_TH);
else
iris_q_event(radio, IRIS_EVT_BELOW_TH);
@@ -2027,10 +2033,8 @@
iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
- while (skb->data[len+RDS_OFFSET] != 0x0d)
+ while ((skb->data[len+RDS_OFFSET] != 0x0d) && (len < RX_RT_DATA_LENGTH))
len++;
- len++;
-
data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
if (!data) {
FMDERR("Failed to allocate memory");
@@ -2081,7 +2085,8 @@
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- if (radio->fm_st_rsp.station_rsp.serv_avble)
+ u8 serv_avble = skb->data[0];
+ if (serv_avble)
iris_q_event(radio, IRIS_EVT_ABOVE_TH);
else
iris_q_event(radio, IRIS_EVT_BELOW_TH);
@@ -2427,6 +2432,11 @@
break;
case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("Error in get signal threshold %d\n", retval);
+ return retval;
+ }
+ ctrl->value = radio->sig_th.sig_threshold;
break;
case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
ctrl->value = radio->srch_rds.srch_pty;
@@ -2499,6 +2509,20 @@
case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
retval = iris_do_calibration(radio);
break;
+ case V4L2_CID_PRIVATE_IRIS_GET_SINR:
+ if (radio->mode == FM_RECV) {
+ retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD,
+ radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("Get SINR Failed");
+ return retval;
+ }
+ ctrl->value = radio->fm_st_rsp.station_rsp.sinr;
+
+ } else
+ retval = -EINVAL;
+
+ break;
default:
retval = -EINVAL;
}
@@ -2609,9 +2633,8 @@
hci_fm_set_cal_req_proc,
(unsigned long)&proc_cal_req,
RADIO_HCI_TIMEOUT);
- if (retval < 0) {
+ if (retval < 0)
FMDERR("Set Process calibration failed %d", retval);
- }
break;
default:
FMDBG("Shouldn't reach here\n");
@@ -3235,7 +3258,7 @@
if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
rds_buf*3, GFP_KERNEL);
- else if (i == IRIS_BUF_CAL_DATA)
+ else if ((i == IRIS_BUF_CAL_DATA) || (i == IRIS_BUF_RT_RDS))
kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
STD_BUF_SIZE*2, GFP_KERNEL);
else
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 393e30e..8f09b6a 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -2107,7 +2107,7 @@
1, internal_vreg_ctl[index][0]);
if (retval < 0) {
printk(KERN_ERR "%s:0xF0 write failed\n", __func__);
- return retval;
+ goto exit;
}
/* actual value itself used as mask*/
retval = marimba_write_bit_mask(radio->marimba,
@@ -2115,7 +2115,7 @@
1, internal_vreg_ctl[index][1]);
if (retval < 0) {
printk(KERN_ERR "%s:0xF4 write failed\n", __func__);
- return retval;
+ goto exit;
}
} else {
/* disable fm core */
@@ -2127,8 +2127,9 @@
&value, 1, FM_ENABLE);
if (retval < 0) {
printk(KERN_ERR "%s:XO_BUFF_CNTRL write failed\n", __func__);
- return retval;
+ goto exit;
}
+exit:
FMDBG("%s, Calling fm_shutdown\n", __func__);
/* teardown gpio and pmic */
@@ -2139,7 +2140,7 @@
radio->handle_irq = 1;
atomic_inc(&radio->users);
radio->marimba->mod_id = SLAVE_ID_BAHAMA;
- return 0;
+ return retval;
}
/*
@@ -2864,6 +2865,7 @@
unsigned char value;
unsigned char xfr_buf[XFR_REG_NUM];
unsigned char tx_data[XFR_REG_NUM];
+ unsigned char dis_buf[XFR_REG_NUM];
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
@@ -2915,20 +2917,26 @@
/* check if off */
else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
FMDBG("turning off...\n");
- retval = tavarua_write_register(radio, RDCTRL,
- ctrl->value);
- /*Make it synchronous
- Block it till READY interrupt
- Wait for interrupt i.e.
- complete(&radio->sync_req_done)
- */
+ tavarua_write_register(radio, RDCTRL, ctrl->value);
+ /* flush the event and work queues */
+ kfifo_reset(&radio->data_buf[TAVARUA_BUF_EVENTS]);
+ flush_workqueue(radio->wqueue);
+ /*
+ * queue the READY event from the host side
+ * in case of FM off
+ */
+ tavarua_q_event(radio, TAVARUA_EVT_RADIO_READY);
- if (retval >= 0) {
-
- if (!wait_for_completion_timeout(
- &radio->sync_req_done,
- msecs_to_jiffies(wait_timeout)))
- FMDBG("turning off timedout...\n");
+ FMDBG("%s, Disable All Interrupts\n", __func__);
+ /* disable irq */
+ dis_buf[STATUS_REG1] = 0x00;
+ dis_buf[STATUS_REG2] = 0x00;
+ dis_buf[STATUS_REG3] = TRANSFER;
+ retval = sync_write_xfr(radio, INT_CTRL, dis_buf);
+ if (retval < 0) {
+ pr_err("%s: failed to disable"
+ "Interrupts\n", __func__);
+ return retval;
}
}
break;
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 8df6243..363e437 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -674,14 +674,12 @@
static int msm_camera_v4l2_querycap(struct file *f, void *pctx,
struct v4l2_capability *pcaps)
{
- struct msm_cam_v4l2_device *pcam = video_drvdata(f);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
/* some other day, some other time */
/*cap->version = LINUX_VERSION_CODE; */
- strlcpy(pcaps->driver, pcam->pdev->name, sizeof(pcaps->driver));
pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
return 0;
}
diff --git a/drivers/media/video/msm/msm_camera.c b/drivers/media/video/msm/msm_camera.c
index e401a7a..dbf0eae 100644
--- a/drivers/media/video/msm/msm_camera.c
+++ b/drivers/media/video/msm/msm_camera.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -279,16 +279,18 @@
{
if (info->offset < len &&
info->offset + info->len <= len &&
- info->y_off < len &&
- info->cbcr_off < len)
+ info->planar0_off < len &&
+ info->planar1_off < len &&
+ info->planar2_off < len)
return 0;
- pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
+ pr_err("%s: check failed: off %d len %d y 0x%x cbcr_p1 0x%x p2_add 0x%x(total len %d)\n",
__func__,
info->offset,
info->len,
- info->y_off,
- info->cbcr_off,
+ info->planar0_off,
+ info->planar1_off,
+ info->planar2_off,
len);
return -EINVAL;
}
@@ -352,8 +354,10 @@
hlist_add_head(&(region->list), ptype);
spin_unlock_irqrestore(pmem_spinlock, flags);
- CDBG("%s: type %d, paddr 0x%lx, vaddr 0x%lx\n",
- __func__, info->type, paddr, (unsigned long)info->vaddr);
+ CDBG("%s: type %d, paddr 0x%lx, vaddr 0x%lx p0_add = 0x%x"
+ "p1_addr = 0x%x p2_addr = 0x%x\n",
+ __func__, info->type, paddr, (unsigned long)info->vaddr,
+ info->planar0_off, info->planar1_off, info->planar2_off);
return 0;
out2:
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -439,8 +443,9 @@
}
static int msm_pmem_frame_ptov_lookup(struct msm_sync *sync,
- unsigned long pyaddr,
- unsigned long pcbcraddr,
+ unsigned long p0addr,
+ unsigned long p1addr,
+ unsigned long p2addr,
struct msm_pmem_info *pmem_info,
int clear_active)
{
@@ -450,10 +455,10 @@
spin_lock_irqsave(&sync->pmem_frame_spinlock, flags);
hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) {
- if (pyaddr == (region->paddr + region->info.y_off) &&
- pcbcraddr == (region->paddr +
- region->info.cbcr_off) &&
- region->info.active) {
+ if (p0addr == (region->paddr + region->info.planar0_off) &&
+ p1addr == (region->paddr + region->info.planar1_off) &&
+ p2addr == (region->paddr + region->info.planar2_off) &&
+ region->info.active) {
/* offset since we could pass vaddr inside
* a registerd pmem buffer
*/
@@ -466,12 +471,13 @@
}
}
/* After lookup failure, dump all the list entries... */
- pr_err("%s, for pyaddr 0x%lx, pcbcraddr 0x%lx\n",
- __func__, pyaddr, pcbcraddr);
+ pr_err("%s, for plane0 addr = 0x%lx, plane1 addr = 0x%lx plane2 addr = 0x%lx\n",
+ __func__, p0addr, p1addr, p2addr);
hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) {
- pr_err("listed pyaddr 0x%lx, pcbcraddr 0x%lx, active = %d",
- (region->paddr + region->info.y_off),
- (region->paddr + region->info.cbcr_off),
+ pr_err("listed p0addr 0x%lx, p1addr 0x%lx, p2addr 0x%lx, active = %d",
+ (region->paddr + region->info.planar0_off),
+ (region->paddr + region->info.planar1_off),
+ (region->paddr + region->info.planar2_off),
region->info.active);
}
@@ -480,7 +486,7 @@
}
static int msm_pmem_frame_ptov_lookup2(struct msm_sync *sync,
- unsigned long pyaddr,
+ unsigned long p0_phy,
struct msm_pmem_info *pmem_info,
int clear_active)
{
@@ -490,7 +496,7 @@
spin_lock_irqsave(&sync->pmem_frame_spinlock, flags);
hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) {
- if (pyaddr == (region->paddr + region->info.y_off) &&
+ if (p0_phy == (region->paddr + region->info.planar0_off) &&
region->info.active) {
/* offset since we could pass vaddr inside
* a registerd pmem buffer
@@ -541,8 +547,8 @@
}
static unsigned long msm_pmem_frame_vtop_lookup(struct msm_sync *sync,
- unsigned long buffer,
- uint32_t yoff, uint32_t cbcroff, int fd, int change_flag)
+ unsigned long buffer, uint32_t p0_off, uint32_t p1_off,
+ uint32_t p2_off, int fd, int change_flag)
{
struct msm_pmem_region *region;
struct hlist_node *node, *n;
@@ -552,8 +558,9 @@
hlist_for_each_entry_safe(region,
node, n, &sync->pmem_frames, list) {
if (((unsigned long)(region->info.vaddr) == buffer) &&
- (region->info.y_off == yoff) &&
- (region->info.cbcr_off == cbcroff) &&
+ (region->info.planar0_off == p0_off) &&
+ (region->info.planar1_off == p1_off) &&
+ (region->info.planar2_off == p2_off) &&
(region->info.fd == fd) &&
(region->info.active == 0)) {
if (change_flag)
@@ -564,13 +571,16 @@
}
}
/* After lookup failure, dump all the list entries... */
- pr_err("%s, failed for vaddr 0x%lx, yoff %d cbcroff %d\n",
- __func__, buffer, yoff, cbcroff);
+ pr_err("%s, failed for vaddr 0x%lx, p0_off %d p1_off %d\n",
+ __func__, buffer, p0_off, p1_off);
hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) {
- pr_err("listed vaddr 0x%p, cbcroff %d, active = %d",
- (region->info.vaddr),
- (region->info.cbcr_off),
- region->info.active);
+ pr_err("%s, listed vaddr 0x%lx, r_p0 = 0x%x p0_off 0x%x"
+ "r_p1 = 0x%x, p1_off 0x%x, r_p2 = 0x%x, p2_off = 0x%x"
+ " active = %d\n", __func__, buffer,
+ region->info.planar0_off,
+ p0_off, region->info.planar1_off,
+ p1_off, region->info.planar2_off, p2_off,
+ region->info.active);
}
spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags);
@@ -741,33 +751,36 @@
vdata = (struct msm_vfe_resp *)(qcmd->command);
pphy = &vdata->phy;
+ CDBG("%s, pphy->p2_phy = 0x%x\n", __func__, pphy->p2_phy);
rc = msm_pmem_frame_ptov_lookup(sync,
- pphy->y_phy,
- pphy->cbcr_phy,
+ pphy->p0_phy,
+ pphy->p1_phy,
+ pphy->p2_phy,
&pmem_info,
1); /* Clear the active flag */
if (rc < 0) {
- pr_err("%s: cannot get frame, invalid lookup address "
- "y %x cbcr %x\n",
- __func__,
- pphy->y_phy,
- pphy->cbcr_phy);
+ pr_err("%s: cannot get frame, invalid lookup address"
+ "plane0 add %x plane1 add %x plane2 add%x\n",
+ __func__,
+ pphy->p0_phy,
+ pphy->p1_phy,
+ pphy->p2_phy);
goto err;
}
frame->ts = qcmd->ts;
frame->buffer = (unsigned long)pmem_info.vaddr;
- frame->y_off = pmem_info.y_off;
- frame->cbcr_off = pmem_info.cbcr_off;
+ frame->planar0_off = pmem_info.planar0_off;
+ frame->planar1_off = pmem_info.planar1_off;
+ frame->planar2_off = pmem_info.planar2_off;
frame->fd = pmem_info.fd;
frame->path = vdata->phy.output_id;
frame->frame_id = vdata->phy.frame_id;
-
- CDBG("%s: y %x, cbcr %x, qcmd %x, virt_addr %x\n",
- __func__,
- pphy->y_phy, pphy->cbcr_phy, (int) qcmd, (int) frame->buffer);
+ CDBG("%s: plane0 %x, plane1 %x, plane2 %x,qcmd %x, virt_addr %x\n",
+ __func__, pphy->p0_phy, pphy->p1_phy, pphy->p2_phy,
+ (int) qcmd, (int) frame->buffer);
err:
free_qcmd(qcmd);
@@ -1010,7 +1023,7 @@
qcmd_resp = __msm_control_nb(sync, qcmd);
goto end;
}
-
+ msm_queue_drain(&ctrl_pmsm->ctrl_q, list_control);
qcmd_resp = __msm_control(sync,
&ctrl_pmsm->ctrl_q,
qcmd, msecs_to_jiffies(10000));
@@ -1078,8 +1091,8 @@
return -EINVAL;
}
- rc = msm_pmem_frame_ptov_lookup(sync, data->phy.y_phy,
- data->phy.cbcr_phy, &pinfo,
+ rc = msm_pmem_frame_ptov_lookup(sync, data->phy.p0_phy,
+ data->phy.p1_phy, data->phy.p2_phy, &pinfo,
0); /* do not clear the active flag */
if (rc < 0) {
@@ -1088,8 +1101,8 @@
}
buf.fmain.buffer = (unsigned long)pinfo.vaddr;
- buf.fmain.y_off = pinfo.y_off;
- buf.fmain.cbcr_off = pinfo.cbcr_off;
+ buf.fmain.planar0_off = pinfo.planar0_off;
+ buf.fmain.planar1_off = pinfo.planar1_off;
buf.fmain.fd = pinfo.fd;
CDBG("%s: buf 0x%x fd %d\n", __func__, (unsigned int)buf.fmain.buffer,
@@ -1119,14 +1132,14 @@
buf.type = OUTPUT_TYPE_ST_R;
} else {
if (se->resptype == MSM_CAM_RESP_STEREO_OP_1) {
- rc = msm_pmem_frame_ptov_lookup(sync, data->phy.y_phy,
- data->phy.cbcr_phy, &pinfo,
- 1); /* do clear the active flag */
+ rc = msm_pmem_frame_ptov_lookup(sync, data->phy.p0_phy,
+ data->phy.p1_phy, data->phy.p2_phy, &pinfo,
+ 1); /* do clear the active flag */
buf.buf_info.path = path;
} else if (se->resptype == MSM_CAM_RESP_STEREO_OP_2) {
- rc = msm_pmem_frame_ptov_lookup(sync, data->phy.y_phy,
- data->phy.cbcr_phy, &pinfo,
- 0); /* do not clear the active flag */
+ rc = msm_pmem_frame_ptov_lookup(sync, data->phy.p0_phy,
+ data->phy.p1_phy, data->phy.p2_phy, &pinfo,
+ 0); /* do not clear the active flag */
buf.buf_info.path = path;
} else
CDBG("%s: Invalid resptype = %d\n", __func__,
@@ -1184,8 +1197,9 @@
buf.buf_info.buffer = (unsigned long)pinfo.vaddr;
buf.buf_info.phy_offset = pinfo.offset;
- buf.buf_info.y_off = pinfo.y_off;
- buf.buf_info.cbcr_off = pinfo.cbcr_off;
+ buf.buf_info.planar0_off = pinfo.planar0_off;
+ buf.buf_info.planar1_off = pinfo.planar1_off;
+ buf.buf_info.planar2_off = pinfo.planar2_off;
buf.buf_info.fd = pinfo.fd;
CDBG("%s: buf 0x%x fd %d\n", __func__,
@@ -1837,6 +1851,7 @@
}
break;
+ case CMD_AXI_CFG_VIDEO_ALL_CHNLS:
case CMD_AXI_CFG_VIDEO:
pmem_type = MSM_PMEM_PREVIEW;
axi_data.bufnum1 =
@@ -1889,6 +1904,7 @@
}
break;
+ case CMD_AXI_CFG_ZSL_ALL_CHNLS:
case CMD_AXI_CFG_ZSL:
CDBG("%s, CMD_AXI_CFG_ZSL, type = %d\n", __func__,
cfgcmd->cmd_type);
@@ -2044,7 +2060,7 @@
/* Change the active flag. */
pphy = msm_pmem_frame_vtop_lookup(sync,
pb->buffer,
- pb->y_off, pb->cbcr_off, pb->fd, 1);
+ pb->planar0_off, pb->planar1_off, pb->planar2_off, pb->fd, 1);
if (pphy != 0) {
CDBG("%s: rel: vaddr %lx, paddr %lx\n",
@@ -2072,7 +2088,7 @@
pphy = msm_pmem_frame_vtop_lookup(sync,
pb->buffer,
- pb->y_off, pb->cbcr_off, pb->fd, 1);
+ pb->planar0_off, pb->planar1_off, pb->planar2_off, pb->fd, 1);
if (pphy != 0) {
CDBG("%s: rel: vaddr %lx, paddr %lx\n",
@@ -2295,6 +2311,8 @@
case CMD_AXI_CFG_SNAP:
case CMD_RAW_PICT_AXI_CFG:
case CMD_AXI_CFG_ZSL:
+ case CMD_AXI_CFG_VIDEO_ALL_CHNLS:
+ case CMD_AXI_CFG_ZSL_ALL_CHNLS:
CDBG("%s, cfgcmd.cmd_type = %d\n", __func__, cfgcmd.cmd_type);
return msm_frame_axi_cfg(sync, &cfgcmd);
@@ -2340,21 +2358,21 @@
pphy = &vdata->phy;
rc = msm_pmem_frame_ptov_lookup2(sync,
- pphy->y_phy,
+ pphy->p0_phy,
&pmem_info,
1); /* mark pic frame in use */
if (rc < 0) {
pr_err("%s: cannot get pic frame, invalid lookup"
- " address y %x cbcr %x\n",
- __func__, pphy->y_phy, pphy->cbcr_phy);
+ " address p0_phy add %x p1_phy add%x\n",
+ __func__, pphy->p0_phy, pphy->p1_phy);
goto err;
}
frame->ts = qcmd->ts;
frame->buffer = (unsigned long)pmem_info.vaddr;
- frame->y_off = pmem_info.y_off;
- frame->cbcr_off = pmem_info.cbcr_off;
+ frame->planar0_off = pmem_info.planar0_off;
+ frame->planar1_off = pmem_info.planar1_off;
frame->fd = pmem_info.fd;
if (sync->stereocam_enabled &&
sync->stereo_state != STEREO_RAW_SNAP_STARTED) {
@@ -2365,20 +2383,20 @@
} else
frame->path = vdata->phy.output_id;
- CDBG("%s: y %x, cbcr %x, qcmd %x, virt_addr %x\n",
- __func__, pphy->y_phy,
- pphy->cbcr_phy, (int) qcmd, (int) frame->buffer);
+ CDBG("%s:p0_phy add %x, p0_phy add %x, qcmd %x, virt_addr %x\n",
+ __func__, pphy->p0_phy,
+ pphy->p1_phy, (int) qcmd, (int) frame->buffer);
} else { /* PP */
pframe = (struct msm_frame *)(qcmd->command);
frame->ts = qcmd->ts;
frame->buffer = pframe->buffer;
- frame->y_off = pframe->y_off;
- frame->cbcr_off = pframe->cbcr_off;
+ frame->planar0_off = pframe->planar0_off;
+ frame->planar1_off = pframe->planar1_off;
frame->fd = pframe->fd;
frame->path = pframe->path;
CDBG("%s: PP y_off %x, cbcr_off %x, path %d vaddr 0x%x\n",
- __func__, frame->y_off, frame->cbcr_off, frame->path,
- (int) frame->buffer);
+ __func__, frame->planar0_off, frame->planar1_off, frame->path,
+ (int) frame->buffer);
}
err:
@@ -2604,13 +2622,13 @@
vfe_rp = (struct msm_vfe_resp *)qcmd->command;
CDBG("%s: Left Py = 0x%x y_off = %d cbcr_off = %d\n",
- __func__, vfe_rp->phy.y_phy,
- stereo_frame_half.L.buf_y_off,
- stereo_frame_half.L.buf_cbcr_off);
+ __func__, vfe_rp->phy.p0_phy,
+ stereo_frame_half.L.buf_p0_off,
+ stereo_frame_half.L.buf_p1_off);
sync->vpefn.vpe_cfg_offset(stereo_frame_half.packing,
- vfe_rp->phy.y_phy + stereo_frame_half.L.buf_y_off,
- vfe_rp->phy.y_phy + stereo_frame_half.L.buf_cbcr_off,
+ vfe_rp->phy.p0_phy + stereo_frame_half.L.buf_p0_off,
+ vfe_rp->phy.p1_phy + stereo_frame_half.L.buf_p1_off,
&(qcmd->ts), OUTPUT_TYPE_ST_L, stereo_frame_half.L,
stereo_frame_half.frame_id);
@@ -2626,14 +2644,15 @@
st_pphy = msm_pmem_frame_vtop_lookup(sync,
stereo_frame_half.buf_info.buffer,
- stereo_frame_half.buf_info.y_off,
- stereo_frame_half.buf_info.cbcr_off,
+ stereo_frame_half.buf_info.planar0_off,
+ stereo_frame_half.buf_info.planar1_off,
+ stereo_frame_half.buf_info.planar2_off,
stereo_frame_half.buf_info.fd,
0); /* Do not change the active flag. */
sync->vpefn.vpe_cfg_offset(stereo_frame_half.packing,
- st_pphy + stereo_frame_half.R.buf_y_off,
- st_pphy + stereo_frame_half.R.buf_cbcr_off,
+ st_pphy + stereo_frame_half.R.buf_p0_off,
+ st_pphy + stereo_frame_half.R.buf_p1_off,
NULL, OUTPUT_TYPE_ST_R, stereo_frame_half.R,
stereo_frame_half.frame_id);
@@ -3332,10 +3351,10 @@
switch (vdata->type) {
case VFE_MSG_OUTPUT_P:
if (sync->pp_mask & PP_PREV) {
- CDBG("%s: PP_PREV in progress: phy_y %x phy_cbcr %x\n",
+ CDBG("%s: PP_PREV in progress: p0_add %x p1_add %x\n",
__func__,
- vdata->phy.y_phy,
- vdata->phy.cbcr_phy);
+ vdata->phy.p0_phy,
+ vdata->phy.p1_phy);
spin_lock_irqsave(&pp_prev_spinlock, flags);
if (sync->pp_prev)
CDBG("%s: overwriting pp_prev!\n",
@@ -3493,8 +3512,8 @@
vdata->vpe_bf.vpe_crop =
*(struct video_crop_t *)(sync->cropinfo);
- vdata->vpe_bf.y_phy = vdata->phy.y_phy;
- vdata->vpe_bf.cbcr_phy = vdata->phy.cbcr_phy;
+ vdata->vpe_bf.p0_phy = vdata->phy.p0_phy;
+ vdata->vpe_bf.p1_phy = vdata->phy.p1_phy;
vdata->vpe_bf.ts = (qcmd->ts);
vdata->vpe_bf.frame_id = vdata->phy.frame_id;
qcmd->command = vdata;
@@ -3506,8 +3525,8 @@
"= %ld\n", __func__, qcmd->ts.tv_nsec);
sync->vpefn.send_frame_to_vpe(
- vdata->phy.y_phy,
- vdata->phy.cbcr_phy,
+ vdata->phy.p0_phy,
+ vdata->phy.p1_phy,
&(qcmd->ts), OUTPUT_TYPE_V);
free_qcmd(qcmd);
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 759ac47..e13dd62 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -76,6 +76,22 @@
.colorspace = V4L2_COLORSPACE_JPEG,
},
{
+ .name = "NV16BAYER",
+ .depth = 8,
+ .bitsperpxl = 8,
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
+ .name = "NV61BAYER",
+ .depth = 8,
+ .bitsperpxl = 8,
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
.name = "YU12BAYER",
.depth = 8,
.bitsperpxl = 8,
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index c13e7e5..b631981 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -84,16 +84,16 @@
{
if (info->offset < len &&
info->offset + info->len <= len &&
- info->y_off < len &&
- info->cbcr_off < len)
+ info->planar0_off < len &&
+ info->planar1_off < len)
return 0;
pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
__func__,
info->offset,
info->len,
- info->y_off,
- info->cbcr_off,
+ info->planar0_off,
+ info->planar1_off,
len);
return -EINVAL;
}
diff --git a/drivers/media/video/msm/msm_vfe31.c b/drivers/media/video/msm/msm_vfe31.c
index b22b6c5..2b3732c 100644
--- a/drivers/media/video/msm/msm_vfe31.c
+++ b/drivers/media/video/msm/msm_vfe31.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -337,10 +337,12 @@
break;
}
pinfo->output_id = outid;
- pinfo->y_phy =
- ((struct vfe_message *)data)->_u.msgOut.yBuffer;
- pinfo->cbcr_phy =
- ((struct vfe_message *)data)->_u.msgOut.cbcrBuffer;
+ pinfo->p0_phy =
+ ((struct vfe_message *)data)->_u.msgOut.p0_addr;
+ pinfo->p1_phy =
+ ((struct vfe_message *)data)->_u.msgOut.p1_addr;
+ pinfo->p2_phy =
+ ((struct vfe_message *)data)->_u.msgOut.p2_addr;
pinfo->frame_id =
((struct vfe_message *)data)->_u.msgOut.frameCounter;
@@ -458,8 +460,8 @@
GFP_ATOMIC);
}
-static void vfe_send_outmsg(uint8_t msgid, uint32_t pyaddr,
- uint32_t pcbcraddr)
+static void vfe_send_outmsg(uint8_t msgid, uint32_t p0_addr,
+ uint32_t p1_addr, uint32_t p2_addr)
{
struct vfe_message msg;
uint8_t outid;
@@ -485,9 +487,10 @@
break;
}
msg._u.msgOut.output_id = msgid;
- msg._u.msgOut.yBuffer = pyaddr;
- msg._u.msgOut.cbcrBuffer = pcbcraddr;
-
+ msg._u.msgOut.p0_addr = p0_addr;
+ msg._u.msgOut.p1_addr = p1_addr;
+ msg._u.msgOut.p2_addr = p2_addr;
+ CDBG("%s p2_addr = 0x%x\n", __func__, p2_addr);
vfe31_proc_ops(msgid, &msg, sizeof(struct vfe_message));
return;
}
@@ -542,7 +545,7 @@
}
static int vfe31_add_free_buf2(struct vfe31_output_ch *outch,
- uint32_t paddr, uint32_t y_off, uint32_t cbcr_off)
+ uint32_t paddr, uint32_t p0_off, uint32_t p1_off, uint32_t p2_off)
{
struct vfe31_free_buf *free_buf = NULL;
unsigned long flags = 0;
@@ -552,20 +555,23 @@
spin_lock_irqsave(&outch->free_buf_lock, flags);
free_buf->paddr = paddr;
- free_buf->y_off = y_off;
- free_buf->cbcr_off = cbcr_off;
+ free_buf->planar0_off = p0_off;
+ free_buf->planar1_off = p1_off;
+ free_buf->planar2_off = p2_off;
list_add_tail(&free_buf->node, &outch->free_buf_head);
CDBG("%s: free_buf paddr = 0x%x, y_off = %d, cbcr_off = %d\n",
- __func__, free_buf->paddr, free_buf->y_off,
- free_buf->cbcr_off);
+ __func__, free_buf->paddr, free_buf->planar0_off,
+ free_buf->planar1_off);
spin_unlock_irqrestore(&outch->free_buf_lock, flags);
return 0;
}
#define vfe31_add_free_buf(outch, regptr) \
- vfe31_add_free_buf2(outch, regptr->paddr, regptr->info.y_off, \
- regptr->info.cbcr_off)
+ vfe31_add_free_buf2(outch, regptr->paddr, \
+ regptr->info.planar0_off, \
+ regptr->info.planar1_off, \
+ regptr->info.planar2_off)
#define vfe31_free_buf_available(outch) \
(!list_empty(&outch.free_buf_head))
@@ -662,10 +668,10 @@
for (i = 0; i < 2; i++) {
p1 = ao + 6 + i; /* wm0 for y */
- *p1 = (regp1->paddr + regp1->info.y_off);
+ *p1 = (regp1->paddr + regp1->info.planar0_off);
p1 = ao + 12 + i; /* wm1 for cbcr */
- *p1 = (regp1->paddr + regp1->info.cbcr_off);
+ *p1 = (regp1->paddr + regp1->info.planar1_off);
regp1++;
}
ret = vfe31_add_free_buf(outp1, regp1);
@@ -694,47 +700,47 @@
/* Parse the buffers!!! */
if (ad->bufnum2 == 1) { /* assuming bufnum1 = bufnum2 */
p1 = ao + 6; /* wm0 ping */
- *p1++ = (regp1->paddr + regp1->info.y_off);
+ *p1++ = (regp1->paddr + regp1->info.planar0_off);
/* this is to duplicate ping address to pong.*/
- *p1 = (regp1->paddr + regp1->info.y_off);
+ *p1 = (regp1->paddr + regp1->info.planar0_off);
p1 = ao + 30; /* wm4 ping */
- *p1++ = (regp1->paddr + regp1->info.cbcr_off);
+ *p1++ = (regp1->paddr + regp1->info.planar1_off);
CDBG("%s: regp1->info.cbcr_off = 0x%x\n", __func__,
- regp1->info.cbcr_off);
+ regp1->info.planar1_off);
/* this is to duplicate ping address to pong.*/
- *p1 = (regp1->paddr + regp1->info.cbcr_off);
+ *p1 = (regp1->paddr + regp1->info.planar1_off);
p1 = ao + 12; /* wm1 ping */
- *p1++ = (regp2->paddr + regp2->info.y_off);
+ *p1++ = (regp2->paddr + regp2->info.planar0_off);
/* pong = ping,*/
- *p1 = (regp2->paddr + regp2->info.y_off);
+ *p1 = (regp2->paddr + regp2->info.planar0_off);
p1 = ao + 36; /* wm5 */
- *p1++ = (regp2->paddr + regp2->info.cbcr_off);
+ *p1++ = (regp2->paddr + regp2->info.planar1_off);
CDBG("%s: regp2->info.cbcr_off = 0x%x\n", __func__,
- regp2->info.cbcr_off);
+ regp2->info.planar1_off);
/* pong = ping,*/
- *p1 = (regp2->paddr + regp2->info.cbcr_off);
+ *p1 = (regp2->paddr + regp2->info.planar1_off);
} else { /* more than one snapshot */
/* first fill ping & pong */
for (i = 0; i < 2; i++) {
p1 = ao + 6 + i; /* wm0 for y */
- *p1 = (regp1->paddr + regp1->info.y_off);
+ *p1 = (regp1->paddr + regp1->info.planar0_off);
p1 = ao + 30 + i; /* wm4 for cbcr */
- *p1 = (regp1->paddr + regp1->info.cbcr_off);
+ *p1 = (regp1->paddr + regp1->info.planar1_off);
regp1--;
}
for (i = 0; i < 2; i++) {
p2 = ao + 12 + i; /* wm1 for y */
- *p2 = (regp2->paddr + regp2->info.y_off);
+ *p2 = (regp2->paddr + regp2->info.planar0_off);
p2 = ao + 36 + i; /* wm5 for cbcr */
- *p2 = (regp2->paddr + regp2->info.cbcr_off);
+ *p2 = (regp2->paddr + regp2->info.planar1_off);
regp2--;
}
@@ -783,25 +789,25 @@
/* first fill ping & pong */
for (i = 0; i < 2; i++) {
p1 = ao + 6 + i; /* wm0 for y */
- *p1 = (regp1->paddr + regp1->info.y_off);
+ *p1 = (regp1->paddr + regp1->info.planar0_off);
p1 = ao + 30 + i; /* wm4 for cbcr */
- *p1 = (regp1->paddr + regp1->info.cbcr_off);
+ *p1 = (regp1->paddr + regp1->info.planar1_off);
regp1++;
}
for (i = 0; i < 2; i++) {
p2 = ao + 12 + i; /* wm1 for y */
- *p2 = (regp2->paddr + regp2->info.y_off);
+ *p2 = (regp2->paddr + regp2->info.planar0_off);
p2 = ao + 36 + i; /* wm5 for cbcr */
- *p2 = (regp2->paddr + regp2->info.cbcr_off);
+ *p2 = (regp2->paddr + regp2->info.planar1_off);
regp2++;
}
for (i = 0; i < 2; i++) {
p3 = ao + 18 + i; /* wm2 for y */
- *p3 = (regp3->paddr + regp3->info.y_off);
+ *p3 = (regp3->paddr + regp3->info.planar0_off);
p3 = ao + 42 + i; /* wm6 for cbcr */
- *p3 = (regp3->paddr + regp3->info.cbcr_off);
+ *p3 = (regp3->paddr + regp3->info.planar1_off);
regp3++;
}
@@ -827,6 +833,80 @@
}
break;
+ case OUTPUT_ZSL_ALL_CHNLS:
+ CDBG("%s: OUTPUT_ZSL_ALL_CHNLS", __func__);
+ CDBG("%s: %d %d %d", __func__, ad->bufnum1, ad->bufnum2,
+ ad->bufnum3);
+ /* use wm0& 4 for postview, wm1&5 for preview.*/
+ /* use wm2& 6 for main img */
+ if ((ad->bufnum1 < 1) || (ad->bufnum2 < 1) || (ad->bufnum3 < 1))
+ return -EINVAL;
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_S; /* main image.*/
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_P_ALL_CHNLS; /* preview. */
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_T; /* thumbnail. */
+
+ /* this is preview buffer. */
+ regp1 = &(ad->region[0]);
+ /* this is thumbnail buffer. */
+ regp2 = &(ad->region[ad->bufnum1]);
+ /* this is main image buffer. */
+ regp3 = &(ad->region[ad->bufnum1+ad->bufnum2]);
+ outp1 = &(vfe31_ctrl->outpath.out0);
+ outp2 = &(vfe31_ctrl->outpath.out1);
+ outp3 = &(vfe31_ctrl->outpath.out2);
+
+ /* Parse the buffers!!! */
+ /* first fill ping & pong */
+ for (i = 0; i < 2; i++) {
+ p1 = ao + 6 + i; /* wm0 for y */
+ *p1 = (regp2->paddr + regp2->info.planar0_off);
+ p1 = ao + 12 + i; /* wm1 for cbcr */
+ *p1 = (regp2->paddr + regp2->info.planar1_off);
+ regp2++;
+ }
+
+ for (i = 0; i < 2; i++) {
+ p2 = ao + 30 + i; /* wm4 for y */
+ *p2 = (regp1->paddr + regp1->info.planar0_off);
+ p2 = ao + 36 + i; /* wm5 for cbcr */
+ *p2 = (regp1->paddr + regp1->info.planar1_off);
+ p2 = ao + 42 + i; /* wm5 for cbcr */
+ *p2 = (regp1->paddr + regp1->info.planar2_off);
+ regp1++;
+ }
+
+ for (i = 0; i < 2; i++) {
+ p3 = ao + 18 + i; /* wm2 for y */
+ *p3 = (regp3->paddr + regp3->info.planar0_off);
+ p3 = ao + 24 + i; /* wm3 for cbcr */
+ *p3 = (regp3->paddr + regp3->info.planar1_off);
+ regp3++;
+ }
+ for (i = 2; i < ad->bufnum1; i++) {
+ ret = vfe31_add_free_buf(outp1, regp1);
+ if (ret < 0)
+ return ret;
+ regp1++;
+ }
+
+ for (i = 2; i < ad->bufnum2; i++) {
+ ret = vfe31_add_free_buf(outp2, regp2);
+ if (ret < 0)
+ return ret;
+ regp2++;
+ }
+
+ for (i = 2; i < ad->bufnum3; i++) {
+ ret = vfe31_add_free_buf(outp3, regp3);
+ if (ret < 0)
+ return ret;
+ regp3++;
+ }
+ break;
+
case OUTPUT_1_AND_3: {
/* use wm0&4 for preview, wm1&5 for video.*/
if ((ad->bufnum1 < 2) || (ad->bufnum2 < 2))
@@ -849,19 +929,19 @@
for (i = 0; i < 2; i++) {
p1 = ao + 6 + i; /* wm0 for y */
- *p1 = (regp1->paddr + regp1->info.y_off);
+ *p1 = (regp1->paddr + regp1->info.planar0_off);
p1 = ao + 30 + i; /* wm4 for cbcr */
- *p1 = (regp1->paddr + regp1->info.cbcr_off);
+ *p1 = (regp1->paddr + regp1->info.planar1_off);
regp1++;
}
for (i = 0; i < 2; i++) {
p2 = ao + 12 + i; /* wm1 for y */
- *p2 = (regp2->paddr + regp2->info.y_off);
+ *p2 = (regp2->paddr + regp2->info.planar0_off);
p2 = ao + 36 + i; /* wm5 for cbcr */
- *p2 = (regp2->paddr + regp2->info.cbcr_off);
+ *p2 = (regp2->paddr + regp2->info.planar1_off);
regp2++;
}
for (i = 2; i < ad->bufnum1; i++) {
@@ -879,6 +959,52 @@
}
}
break;
+
+ case OUTPUT_VIDEO_ALL_CHNLS: {
+ /* use wm0&4 for preview, wm1&5 for video.*/
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_V; /* video*/
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_P_ALL_CHNLS;
+ regp1 = &(ad->region[0]);
+ regp2 = &(ad->region[ad->bufnum1]);
+ outp1 = &(vfe31_ctrl->outpath.out0);
+ outp2 = &(vfe31_ctrl->outpath.out2);
+
+ for (i = 0; i < 2; i++) {
+ p1 = ao + 6 + i; /* wm0 for y */
+ *p1 = (regp1->paddr + regp1->info.planar0_off);
+
+ p1 = ao + 12 + i; /* wm1 for cbcr */
+ *p1 = (regp1->paddr + regp1->info.planar1_off);
+
+ p1 = ao + 18 + i; /* wm2 for cbcr */
+ *p1 = (regp1->paddr + regp1->info.planar2_off);
+ regp1++;
+ }
+ for (i = 0; i < 2; i++) {
+ p2 = ao + 30 + i; /* wm4 for y */
+ *p2 = (regp2->paddr + regp2->info.planar0_off);
+
+ p2 = ao + 36 + i; /* wm5 for cbcr */
+ *p2 = (regp2->paddr + regp2->info.planar1_off);
+ regp2++;
+ }
+ for (i = 2; i < ad->bufnum1; i++) {
+ ret = vfe31_add_free_buf(outp1, regp1);
+ if (ret < 0)
+ return ret;
+ regp1++;
+ }
+ for (i = 2; i < ad->bufnum2; i++) {
+ ret = vfe31_add_free_buf(outp2, regp2);
+ if (ret < 0)
+ return ret;
+ regp2++;
+ }
+ }
+ break;
+
case CAMIF_TO_AXI_VIA_OUTPUT_2: { /* use wm0 only */
if (ad->bufnum2 < 1)
return -EINVAL;
@@ -887,7 +1013,7 @@
regp1 = &(ad->region[ad->bufnum1]);
vfe31_ctrl->outpath.output_mode |= VFE31_OUTPUT_MODE_S;
p1 = ao + 6; /* wm0 for y */
- *p1 = (regp1->paddr + regp1->info.y_off);
+ *p1 = (regp1->paddr + regp1->info.planar0_off);
if (p_sync->stereocam_enabled)
p_sync->stereo_state = STEREO_RAW_SNAP_IDLE;
}
@@ -1193,6 +1319,11 @@
irq_comp_mask |=
((0x1 << (vfe31_ctrl->outpath.out0.ch0)) |
(0x1 << (vfe31_ctrl->outpath.out0.ch1)));
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_P_ALL_CHNLS) {
+ irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch1 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch2);
}
if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_T) {
irq_comp_mask |=
@@ -1209,6 +1340,14 @@
vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
msm_io_w(1, vfe31_ctrl->vfebase +
vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_P_ALL_CHNLS) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
}
if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_T) {
msm_io_w(1, vfe31_ctrl->vfebase +
@@ -1302,12 +1441,22 @@
if ((vfe31_ctrl->operation_mode != VFE_MODE_OF_OPERATION_CONTINUOUS) &&
(vfe31_ctrl->operation_mode != VFE_MODE_OF_OPERATION_VIDEO))
return 0;
- irq_comp_mask =
+ irq_comp_mask =
msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) {
irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
0x1 << vfe31_ctrl->outpath.out0.ch1);
+ if (vfe31_ctrl->outpath.out0.ch2 >= 0)
+ irq_comp_mask |=
+ (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch1 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch2);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_P_ALL_CHNLS) {
+ irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch1 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch2);
}
if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_V) {
@@ -1323,7 +1472,19 @@
vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
msm_io_w(1, vfe31_ctrl->vfebase +
vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ if (vfe31_ctrl->outpath.out0.ch2 >= 0)
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_P_ALL_CHNLS) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
}
+
if (p_sync->stereocam_enabled)
msm_camio_set_perf_lvl(S_STEREO_VIDEO);
else
@@ -2240,7 +2401,8 @@
break;
}
- ret = vfe31_add_free_buf2(outch, p, b->y_off, b->cbcr_off);
+ ret = vfe31_add_free_buf2(outch, p, b->planar0_off,
+ b->planar1_off, b->planar2_off);
if (ret < 0)
return ret;
break;
@@ -2267,7 +2429,8 @@
} else
return -EFAULT;
- ret = vfe31_add_free_buf2(outch, p, b->y_off, b->cbcr_off);
+ ret = vfe31_add_free_buf2(outch, p, b->planar0_off,
+ b->planar1_off, b->planar2_off);
if (ret < 0)
return ret;
break;
@@ -2403,6 +2566,32 @@
}
break;
+ case CMD_AXI_CFG_ZSL_ALL_CHNLS: {
+ struct axidata *axid;
+ uint32_t *axio;
+ CDBG("%s, CMD_AXI_CFG_ZSL\n", __func__);
+ axid = data;
+ if (!axid)
+ return -EFAULT;
+ axio =
+ kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_ZSL_ALL_CHNLS, axid, axio);
+ kfree(axio);
+ }
+ break;
+
case CMD_AXI_CFG_VIDEO: {
struct axidata *axid;
uint32_t *axio = NULL;
@@ -2431,6 +2620,34 @@
break;
}
+ case CMD_AXI_CFG_VIDEO_ALL_CHNLS: {
+ struct axidata *axid;
+ uint32_t *axio = NULL;
+ axid = data;
+ if (!axid) {
+ rc = -EFAULT;
+ break;
+ }
+
+ axio =
+ kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_VIDEO_ALL_CHNLS, axid, axio);
+ kfree(axio);
+ break;
+ }
+
default:
break;
}
@@ -2804,7 +3021,7 @@
static void vfe31_process_output_path_irq_0(uint32_t ping_pong)
{
- uint32_t pyaddr, pcbcraddr;
+ uint32_t p0_addr, p1_addr, p2_addr;
#ifdef CONFIG_MSM_CAMERA_V4L2
uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong;
#endif
@@ -2816,26 +3033,37 @@
if (free_buf) {
/* Y channel */
- pyaddr = vfe31_get_ch_addr(ping_pong,
+ p0_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out0.ch0);
/* Chroma channel */
- pcbcraddr = vfe31_get_ch_addr(ping_pong,
+ p1_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out0.ch1);
-
- CDBG("output path 0, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
- pyaddr, pcbcraddr);
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_P_ALL_CHNLS) {
+ p2_addr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch2);
+ } else {
+ p2_addr = p0_addr;
+ }
+ CDBG("Output path 0, p0_addr = 0x%x, p1_addr = 0x%x,"
+ "p2_addr = 0x%x\n", p0_addr, p1_addr, p2_addr);
/* Y channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out0.ch0,
- free_buf->paddr + free_buf->y_off);
+ free_buf->paddr + free_buf->planar0_off);
/* Chroma channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out0.ch1,
- free_buf->paddr + free_buf->cbcr_off);
-
- kfree(free_buf);
- /* if continuous mode, for display. (preview) */
- vfe_send_outmsg(MSG_ID_OUTPUT_P, pyaddr, pcbcraddr);
+ free_buf->paddr + free_buf->planar1_off);
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_P_ALL_CHNLS)
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch2,
+ free_buf->paddr + free_buf->planar2_off);
+ kfree(free_buf);
+ /* if continuous mode, for display. (preview) */
+ vfe_send_outmsg(MSG_ID_OUTPUT_P, p0_addr, p1_addr,
+ p2_addr);
} else {
vfe31_ctrl->outpath.out0.frame_drop_cnt++;
pr_warning("path_irq_0 - no free buffer!\n");
@@ -2880,54 +3108,54 @@
static void vfe31_process_snapshot_frame(uint32_t ping_pong)
{
- uint32_t pyaddr, pcbcraddr;
+ uint32_t p0_addr, p1_addr;
struct vfe31_free_buf *free_buf = NULL;
/* Y channel- Main Image */
- pyaddr = vfe31_get_ch_addr(ping_pong,
+ p0_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out1.ch0);
/* Chroma channel - TN Image */
- pcbcraddr = vfe31_get_ch_addr(ping_pong,
+ p1_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out1.ch1);
free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out1);
- CDBG("%s: snapshot main, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
- __func__, pyaddr, pcbcraddr);
+ CDBG("%s: snapshot main, p0_addr = 0x%x, p1_addr = 0x%x\n",
+ __func__, p0_addr, p1_addr);
if (free_buf) {
/* Y channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out1.ch0,
- free_buf->paddr + free_buf->y_off);
+ free_buf->paddr + free_buf->planar0_off);
/* Chroma channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out1.ch1,
- free_buf->paddr + free_buf->cbcr_off);
+ free_buf->paddr + free_buf->planar1_off);
kfree(free_buf);
}
- vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr, pcbcraddr);
+ vfe_send_outmsg(MSG_ID_OUTPUT_S, p0_addr, p1_addr, p0_addr);
/* Y channel- TN Image */
- pyaddr = vfe31_get_ch_addr(ping_pong,
+ p0_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out0.ch0);
/* Chroma channel - TN Image */
- pcbcraddr = vfe31_get_ch_addr(ping_pong,
+ p1_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out0.ch1);
free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out0);
- CDBG("%s: snapshot TN, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
- __func__, pyaddr, pcbcraddr);
+ CDBG("%s: snapshot TN, p0_addr = 0x%x, p1_addr = 0x%x\n",
+ __func__, p0_addr, p1_addr);
if (free_buf) {
/* Y channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out0.ch0,
- free_buf->paddr + free_buf->y_off);
+ free_buf->paddr + free_buf->planar0_off);
/* Chroma channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out0.ch1,
- free_buf->paddr + free_buf->cbcr_off);
+ free_buf->paddr + free_buf->planar1_off);
kfree(free_buf);
}
- vfe_send_outmsg(MSG_ID_OUTPUT_T, pyaddr, pcbcraddr);
+ vfe_send_outmsg(MSG_ID_OUTPUT_T, p0_addr, p1_addr, p0_addr);
/* in snapshot mode if done then send
snapshot done message */
@@ -2964,14 +3192,14 @@
/* Y channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out1.ch0,
- free_buf->paddr + free_buf->y_off);
+ free_buf->paddr + free_buf->planar0_off);
/* Chroma channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out1.ch1,
- free_buf->paddr + free_buf->cbcr_off);
+ free_buf->paddr + free_buf->planar1_off);
kfree(free_buf);
}
- vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr, pcbcraddr);
+ vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr, pcbcraddr, 0);
/* in snapshot mode if done then send
snapshot done message */
@@ -2986,54 +3214,54 @@
}
static void vfe31_process_zsl_frame(uint32_t ping_pong)
{
- uint32_t pyaddr, pcbcraddr;
+ uint32_t p0_addr, p1_addr;
struct vfe31_free_buf *free_buf = NULL;
/* Y channel- Main Image */
- pyaddr = vfe31_get_ch_addr(ping_pong,
+ p0_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out2.ch0);
/* Chroma channel - Main Image */
- pcbcraddr = vfe31_get_ch_addr(ping_pong,
+ p1_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out2.ch1);
free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out2);
CDBG("%s: snapshot main, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
- __func__, pyaddr, pcbcraddr);
+ __func__, p0_addr, p1_addr);
if (free_buf) {
/* Y channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out2.ch0,
- free_buf->paddr + free_buf->y_off);
+ free_buf->paddr + free_buf->planar0_off);
/* Chroma channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out2.ch1,
- free_buf->paddr + free_buf->cbcr_off);
+ free_buf->paddr + free_buf->planar1_off);
kfree(free_buf);
}
- vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr, pcbcraddr);
+ vfe_send_outmsg(MSG_ID_OUTPUT_S, p0_addr, p1_addr, p0_addr);
/* Y channel- TN Image */
- pyaddr = vfe31_get_ch_addr(ping_pong,
+ p0_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out1.ch0);
/* Chroma channel - TN Image */
- pcbcraddr = vfe31_get_ch_addr(ping_pong,
+ p1_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out1.ch1);
free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out1);
CDBG("%s: snapshot TN, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
- __func__, pyaddr, pcbcraddr);
+ __func__, p0_addr, p1_addr);
if (free_buf) {
/* Y channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out1.ch0,
- free_buf->paddr + free_buf->y_off);
+ free_buf->paddr + free_buf->planar0_off);
/* Chroma channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out1.ch1,
- free_buf->paddr + free_buf->cbcr_off);
+ free_buf->paddr + free_buf->planar1_off);
kfree(free_buf);
}
- vfe_send_outmsg(MSG_ID_OUTPUT_T, pyaddr, pcbcraddr);
+ vfe_send_outmsg(MSG_ID_OUTPUT_T, p0_addr, p1_addr, p0_addr);
}
static void vfe31_process_output_path_irq_1(uint32_t ping_pong)
@@ -3105,7 +3333,7 @@
static void vfe31_process_output_path_irq_2(uint32_t ping_pong)
{
- uint32_t pyaddr, pcbcraddr;
+ uint32_t p0_addr, p1_addr, p2_addr;
struct vfe31_free_buf *free_buf = NULL;
#ifdef CONFIG_MSM_CAMERA_V4L2
@@ -3135,25 +3363,25 @@
if (free_buf) {
/* Y channel */
- pyaddr = vfe31_get_ch_addr(ping_pong,
+ p0_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out2.ch0);
/* Chroma channel */
- pcbcraddr = vfe31_get_ch_addr(ping_pong,
+ p1_addr = vfe31_get_ch_addr(ping_pong,
vfe31_ctrl->outpath.out2.ch1);
-
+ p2_addr = p0_addr;
CDBG("video output, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
- pyaddr, pcbcraddr);
+ p0_addr, p1_addr);
/* Y channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out2.ch0,
- free_buf->paddr + free_buf->y_off);
+ free_buf->paddr + free_buf->planar0_off);
/* Chroma channel */
vfe31_put_ch_addr(ping_pong,
vfe31_ctrl->outpath.out2.ch1,
- free_buf->paddr + free_buf->cbcr_off);
+ free_buf->paddr + free_buf->planar1_off);
kfree(free_buf);
- vfe_send_outmsg(MSG_ID_OUTPUT_V, pyaddr, pcbcraddr);
+ vfe_send_outmsg(MSG_ID_OUTPUT_V, p0_addr, p1_addr, p2_addr);
} else {
vfe31_ctrl->outpath.out2.frame_drop_cnt++;
pr_warning("path_irq_2 - no free buffer!\n");
diff --git a/drivers/media/video/msm/msm_vfe31.h b/drivers/media/video/msm/msm_vfe31.h
index c47c7de..d1df2dd 100644
--- a/drivers/media/video/msm/msm_vfe31.h
+++ b/drivers/media/video/msm/msm_vfe31.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -842,8 +842,9 @@
struct vfe_msg_output {
uint8_t output_id;
- uint32_t yBuffer;
- uint32_t cbcrBuffer;
+ uint32_t p0_addr;
+ uint32_t p1_addr;
+ uint32_t p2_addr;
struct vfe_frame_bpc_info bpcInfo;
struct vfe_frame_asf_info asfInfo;
uint32_t frameCounter;
@@ -878,7 +879,9 @@
struct vfe31_free_buf {
struct list_head node;
uint32_t paddr;
- uint32_t y_off;
+ uint32_t planar0_off;
+ uint32_t planar1_off;
+ uint32_t planar2_off;
uint32_t cbcr_off;
};
diff --git a/drivers/media/video/msm/msm_vfe7x.c b/drivers/media/video/msm/msm_vfe7x.c
index 316aacf..d74bebc 100644
--- a/drivers/media/video/msm/msm_vfe7x.c
+++ b/drivers/media/video/msm/msm_vfe7x.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -72,14 +72,14 @@
{
switch (type) {
case VFE_MSG_OUTPUT_P: {
- pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
- pinfo->cbcr_phy =
+ pinfo->p0_phy = ((struct vfe_endframe *)data)->y_address;
+ pinfo->p1_phy =
((struct vfe_endframe *)data)->cbcr_address;
-
+ pinfo->p2_phy = pinfo->p0_phy;
pinfo->output_id = OUTPUT_TYPE_P;
CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
- pinfo->y_phy, pinfo->cbcr_phy);
+ pinfo->p0_phy, pinfo->p1_phy);
((struct vfe_frame_extra *)extdata)->bl_evencol =
((struct vfe_endframe *)data)->blacklevelevencolumn;
@@ -99,20 +99,22 @@
break;
case VFE_MSG_OUTPUT_S: {
- pinfo->y_phy = paddr_s_y;
- pinfo->cbcr_phy = paddr_s_cbcr;
+ pinfo->p0_phy = paddr_s_y;
+ pinfo->p1_phy = paddr_s_cbcr;
+ pinfo->p2_phy = pinfo->p0_phy;
pinfo->output_id = OUTPUT_TYPE_S;
CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n",
- pinfo->y_phy, pinfo->cbcr_phy);
+ pinfo->p0_phy, pinfo->p1_phy);
}
break;
case VFE_MSG_OUTPUT_T: {
- pinfo->y_phy = paddr_t_y;
- pinfo->cbcr_phy = paddr_t_cbcr;
+ pinfo->p0_phy = paddr_t_y;
+ pinfo->p1_phy = paddr_t_cbcr;
+ pinfo->p2_phy = pinfo->p0_phy;
pinfo->output_id = OUTPUT_TYPE_T;
CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n",
- pinfo->y_phy, pinfo->cbcr_phy);
+ pinfo->p0_phy, pinfo->p1_phy);
}
break;
@@ -372,19 +374,19 @@
CDBG("bufnum1 = %d\n", ad->bufnum1);
if (mode == OUTPUT_1_AND_2) {
- paddr_t_y = regptr->paddr + regptr->info.y_off;
- paddr_t_cbcr = regptr->paddr + regptr->info.cbcr_off;
+ paddr_t_y = regptr->paddr + regptr->info.planar0_off;
+ paddr_t_cbcr = regptr->paddr + regptr->info.planar1_off;
}
CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
- regptr->paddr, regptr->info.y_off,
- regptr->info.cbcr_off);
+ regptr->paddr, regptr->info.planar0_off,
+ regptr->info.planar1_off);
bptr = &ao->output1buffer1_y_phy;
for (cnt = 0; cnt < ad->bufnum1; cnt++) {
- *bptr = regptr->paddr + regptr->info.y_off;
+ *bptr = regptr->paddr + regptr->info.planar0_off;
bptr++;
- *bptr = regptr->paddr + regptr->info.cbcr_off;
+ *bptr = regptr->paddr + regptr->info.planar1_off;
bptr++;
regptr++;
@@ -392,9 +394,9 @@
regptr--;
for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) {
- *bptr = regptr->paddr + regptr->info.y_off;
+ *bptr = regptr->paddr + regptr->info.planar0_off;
bptr++;
- *bptr = regptr->paddr + regptr->info.cbcr_off;
+ *bptr = regptr->paddr + regptr->info.planar1_off;
bptr++;
}
} /* if OUTPUT1 or Both */
@@ -403,16 +405,17 @@
regptr = &(ad->region[ad->bufnum1]);
CDBG("bufnum2 = %d\n", ad->bufnum2);
- paddr_s_y = regptr->paddr + regptr->info.y_off;
- paddr_s_cbcr = regptr->paddr + regptr->info.cbcr_off;
+ paddr_s_y = regptr->paddr + regptr->info.planar0_off;
+ paddr_s_cbcr = regptr->paddr + regptr->info.planar1_off;
CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
- regptr->paddr, regptr->info.y_off, regptr->info.cbcr_off);
+ regptr->paddr, regptr->info.planar0_off,
+ regptr->info.planar1_off);
bptr = &ao->output2buffer1_y_phy;
for (cnt = 0; cnt < ad->bufnum2; cnt++) {
- *bptr = regptr->paddr + regptr->info.y_off;
+ *bptr = regptr->paddr + regptr->info.planar0_off;
bptr++;
- *bptr = regptr->paddr + regptr->info.cbcr_off;
+ *bptr = regptr->paddr + regptr->info.planar1_off;
bptr++;
regptr++;
@@ -420,9 +423,9 @@
regptr--;
for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) {
- *bptr = regptr->paddr + regptr->info.y_off;
+ *bptr = regptr->paddr + regptr->info.planar0_off;
bptr++;
- *bptr = regptr->paddr + regptr->info.cbcr_off;
+ *bptr = regptr->paddr + regptr->info.planar1_off;
bptr++;
}
}
@@ -584,10 +587,10 @@
fack.header = VFE_FRAME_ACK;
fack.output2newybufferaddress =
- (void *)(p + b->y_off);
+ (void *)(p + b->planar0_off);
fack.output2newcbcrbufferaddress =
- (void *)(p + b->cbcr_off);
+ (void *)(p + b->planar1_off);
vfecmd->queue = QDSP_CMDQUEUE;
vfecmd->length = sizeof(struct vfe_outputack);
diff --git a/drivers/media/video/msm/msm_vfe7x27a.c b/drivers/media/video/msm/msm_vfe7x27a.c
index 9f7dff7..337085d 100644
--- a/drivers/media/video/msm/msm_vfe7x27a.c
+++ b/drivers/media/video/msm/msm_vfe7x27a.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -72,14 +72,14 @@
{
switch (type) {
case VFE_MSG_OUTPUT_P: {
- pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
- pinfo->cbcr_phy =
+ pinfo->p0_phy = ((struct vfe_endframe *)data)->y_address;
+ pinfo->p1_phy =
((struct vfe_endframe *)data)->cbcr_address;
-
+ pinfo->p2_phy = pinfo->p0_phy;
pinfo->output_id = OUTPUT_TYPE_P;
CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
- pinfo->y_phy, pinfo->cbcr_phy);
+ pinfo->p0_phy, pinfo->p1_phy);
memcpy(((struct vfe_frame_extra *)extdata),
&((struct vfe_endframe *)data)->extra,
@@ -92,19 +92,21 @@
}
break;
case VFE_MSG_OUTPUT_S: {
- pinfo->y_phy = paddr_s_y;
- pinfo->cbcr_phy = paddr_s_cbcr;
+ pinfo->p0_phy = paddr_s_y;
+ pinfo->p1_phy = paddr_s_cbcr;
+ pinfo->p2_phy = pinfo->p0_phy;
pinfo->output_id = OUTPUT_TYPE_S;
CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n",
- pinfo->y_phy, pinfo->cbcr_phy);
+ pinfo->p0_phy, pinfo->p1_phy);
}
break;
case VFE_MSG_OUTPUT_T: {
- pinfo->y_phy = paddr_t_y;
- pinfo->cbcr_phy = paddr_t_cbcr;
+ pinfo->p0_phy = paddr_t_y;
+ pinfo->p1_phy = paddr_t_cbcr;
+ pinfo->p2_phy = pinfo->p0_phy;
pinfo->output_id = OUTPUT_TYPE_T;
CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n",
- pinfo->y_phy, pinfo->cbcr_phy);
+ pinfo->p0_phy, pinfo->p1_phy);
}
break;
case VFE_MSG_STATS_AF:
@@ -354,19 +356,20 @@
CDBG("bufnum1 = %d\n", ad->bufnum1);
if (mode == OUTPUT_1_AND_2) {
- paddr_t_y = regptr->paddr + regptr->info.y_off;
- paddr_t_cbcr = regptr->paddr + regptr->info.cbcr_off;
+ paddr_t_y = regptr->paddr + regptr->info.planar0_off;
+ paddr_t_cbcr = regptr->paddr +
+ regptr->info.planar1_off;
}
CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
- regptr->paddr, regptr->info.y_off,
- regptr->info.cbcr_off);
+ regptr->paddr, regptr->info.planar0_off,
+ regptr->info.planar1_off);
bptr = &ao->output1buffer1_y_phy;
for (cnt = 0; cnt < ad->bufnum1; cnt++) {
- *bptr = regptr->paddr + regptr->info.y_off;
+ *bptr = regptr->paddr + regptr->info.planar0_off;
bptr++;
- *bptr = regptr->paddr + regptr->info.cbcr_off;
+ *bptr = regptr->paddr + regptr->info.planar1_off;
bptr++;
regptr++;
@@ -374,9 +377,9 @@
regptr--;
for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) {
- *bptr = regptr->paddr + regptr->info.y_off;
+ *bptr = regptr->paddr + regptr->info.planar0_off;
bptr++;
- *bptr = regptr->paddr + regptr->info.cbcr_off;
+ *bptr = regptr->paddr + regptr->info.planar1_off;
bptr++;
}
}
@@ -385,17 +388,18 @@
regptr = &(ad->region[ad->bufnum1]);
CDBG("bufnum2 = %d\n", ad->bufnum2);
- paddr_s_y = regptr->paddr + regptr->info.y_off;
- paddr_s_cbcr = regptr->paddr + regptr->info.cbcr_off;
+ paddr_s_y = regptr->paddr + regptr->info.planar0_off;
+ paddr_s_cbcr = regptr->paddr + regptr->info.planar1_off;
CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
- regptr->paddr, regptr->info.y_off, regptr->info.cbcr_off);
+ regptr->paddr, regptr->info.planar0_off,
+ regptr->info.planar1_off);
bptr = &ao->output2buffer1_y_phy;
for (cnt = 0; cnt < ad->bufnum2; cnt++) {
- *bptr = regptr->paddr + regptr->info.y_off;
+ *bptr = regptr->paddr + regptr->info.planar0_off;
bptr++;
- *bptr = regptr->paddr + regptr->info.cbcr_off;
+ *bptr = regptr->paddr + regptr->info.planar1_off;
bptr++;
regptr++;
@@ -403,9 +407,9 @@
regptr--;
for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) {
- *bptr = regptr->paddr + regptr->info.y_off;
+ *bptr = regptr->paddr + regptr->info.planar0_off;
bptr++;
- *bptr = regptr->paddr + regptr->info.cbcr_off;
+ *bptr = regptr->paddr + regptr->info.planar1_off;
bptr++;
}
}
@@ -563,10 +567,10 @@
fack.header = VFE_FRAME_ACK;
fack.output2newybufferaddress =
- (void *)(p + b->y_off);
+ (void *)(p + b->planar0_off);
fack.output2newcbcrbufferaddress =
- (void *)(p + b->cbcr_off);
+ (void *)(p + b->planar1_off);
vfecmd->queue = QDSP_CMDQUEUE;
vfecmd->length = sizeof(struct vfe_outputack);
diff --git a/drivers/media/video/msm/msm_vfe8x.c b/drivers/media/video/msm/msm_vfe8x.c
index 0bf1785..a99c6f1 100644
--- a/drivers/media/video/msm/msm_vfe8x.c
+++ b/drivers/media/video/msm/msm_vfe8x.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009, 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -122,10 +122,10 @@
for (j = 0; j < ao->output1.fragmentCount; j++) {
- *p1 = regptr->paddr + regptr->info.y_off;
+ *p1 = regptr->paddr + regptr->info.planar0_off;
p1++;
- *p2 = regptr->paddr + regptr->info.cbcr_off;
+ *p2 = regptr->paddr + regptr->info.planar1_off;
p2++;
}
regptr++;
@@ -144,15 +144,16 @@
CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, "\
"cbcr_off = %d\n", regptr->paddr,
- regptr->info.y_off, regptr->info.cbcr_off);
+ regptr->info.planar0_off,
+ regptr->info.planar1_off);
for (j = 0; j < ao->output2.fragmentCount; j++) {
- *p1 = regptr->paddr + regptr->info.y_off;
+ *p1 = regptr->paddr + regptr->info.planar0_off;
CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
p1++;
- *p2 = regptr->paddr + regptr->info.cbcr_off;
+ *p2 = regptr->paddr + regptr->info.planar1_off;
CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
p2++;
}
@@ -174,15 +175,15 @@
CDBG("config_axi: O1, phy = 0x%lx, y_off = %d, "\
"cbcr_off = %d\n", regptr->paddr,
- regptr->info.y_off, regptr->info.cbcr_off);
+ regptr->info.planar0_off, regptr->info.planar1_off);
for (j = 0; j < ao->output1.fragmentCount; j++) {
- *p1 = regptr->paddr + regptr->info.y_off;
+ *p1 = regptr->paddr + regptr->info.planar0_off;
CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
p1++;
- *p2 = regptr->paddr + regptr->info.cbcr_off;
+ *p2 = regptr->paddr + regptr->info.planar1_off;
CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
p2++;
}
@@ -194,15 +195,15 @@
CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, "\
"cbcr_off = %d\n", regptr1->paddr,
- regptr1->info.y_off, regptr1->info.cbcr_off);
+ regptr1->info.planar0_off, regptr1->info.planar1_off);
for (j = 0; j < ao->output2.fragmentCount; j++) {
-
- *p1 = regptr1->paddr + regptr1->info.y_off;
+ *p1 = regptr1->paddr +
+ regptr1->info.planar0_off;
CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
p1++;
-
- *p2 = regptr1->paddr + regptr1->info.cbcr_off;
+ *p2 = regptr1->paddr +
+ r1->info.planar1_off;
CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
p2++;
}
@@ -689,9 +690,9 @@
b = (struct msm_frame *)(cmd->value);
p = *(unsigned long *)data;
- fack.ybufaddr[0] = (uint32_t) (p + b->y_off);
+ fack.ybufaddr[0] = (uint32_t) (p + b->planar0_off);
- fack.chromabufaddr[0] = (uint32_t) (p + b->cbcr_off);
+ fack.chromabufaddr[0] = (uint32_t) (p + b->planar1_off);
if (b->path == OUTPUT_TYPE_P)
vfe_output_p_ack(&fack);
diff --git a/drivers/media/video/msm/msm_vfe8x_proc.c b/drivers/media/video/msm/msm_vfe8x_proc.c
index 9764557..055b244 100644
--- a/drivers/media/video/msm/msm_vfe8x_proc.c
+++ b/drivers/media/video/msm/msm_vfe8x_proc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -608,11 +608,12 @@
switch (type) {
case VFE_MSG_OUTPUT_P:
case VFE_MSG_OUTPUT_V:{
- pinfo->y_phy =
+ pinfo->planar0_off =
((struct vfe_message *)data)->_u.msgOutput2.yBuffer;
- pinfo->cbcr_phy =
+ pinfo->planar1_off =
((struct vfe_message *)data)->_u.msgOutput2.
cbcrBuffer;
+ pinfo->planar2_off = pinfo->planar0_off;
ctrl->extdata.bpcInfo =
((struct vfe_message *)data)->_u.msgOutput2.bpcInfo;
ctrl->extdata.asfInfo =
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 3a7faa2..fcf2495 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -466,6 +466,11 @@
struct msm_vpe_resp rp;
memset(&rp, 0, sizeof(rp));
spin_lock_irqsave(&vpe_ctrl->lock, flags);
+ if (vpe_ctrl->state == VPE_STATE_IDLE) {
+ pr_err("%s VPE is in IDLE state. Ignore the ack msg", __func__);
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+ return;
+ }
rp.type = vpe_ctrl->pp_frame_info->pp_frame_cmd.path;
rp.extdata = (void *)vpe_ctrl->pp_frame_info;
rp.extlen = sizeof(*vpe_ctrl->pp_frame_info);
@@ -558,7 +563,6 @@
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
return rc;
}
- vpe_ctrl->state = VPE_STATE_IDLE;
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
msm_cam_clk_enable(&vpe_ctrl->pdev->dev, vpe_clk_info,
@@ -569,6 +573,9 @@
vpe_ctrl->fs_vpe = NULL;
disable_irq(vpe_ctrl->vpeirq->start);
tasklet_kill(&vpe_tasklet);
+ spin_lock_irqsave(&vpe_ctrl->lock, flags);
+ vpe_ctrl->state = VPE_STATE_IDLE;
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
return rc;
}
diff --git a/drivers/media/video/msm/msm_vpe1.c b/drivers/media/video/msm/msm_vpe1.c
index 891816f..5f128e1 100644
--- a/drivers/media/video/msm/msm_vpe1.c
+++ b/drivers/media/video/msm/msm_vpe1.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -709,15 +709,15 @@
return 1;
}
-void msm_send_frame_to_vpe(uint32_t pyaddr, uint32_t pcbcraddr,
+void msm_send_frame_to_vpe(uint32_t p0_phy_add, uint32_t p1_phy_add,
struct timespec *ts, int output_type)
{
uint32_t temp_pyaddr = 0, temp_pcbcraddr = 0;
- CDBG("vpe input, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
- pyaddr, pcbcraddr);
- msm_io_w(pyaddr, vpe_device->vpebase + VPE_SRCP0_ADDR_OFFSET);
- msm_io_w(pcbcraddr, vpe_device->vpebase + VPE_SRCP1_ADDR_OFFSET);
+ CDBG("vpe input, p0_phy_add = 0x%x, p1_phy_add = 0x%x\n",
+ p0_phy_add, p1_phy_add);
+ msm_io_w(p0_phy_add, vpe_device->vpebase + VPE_SRCP0_ADDR_OFFSET);
+ msm_io_w(p1_phy_add, vpe_device->vpebase + VPE_SRCP1_ADDR_OFFSET);
if (vpe_ctrl->state == VPE_STATE_ACTIVE)
CDBG(" =====VPE is busy!!! Wrong!========\n");
@@ -881,7 +881,7 @@
vpe_update_scaler_with_dis(&(vpe_buf->vpe_crop),
&(vpe_ctrl->dis_offset));
- msm_send_frame_to_vpe(vpe_buf->y_phy, vpe_buf->cbcr_phy,
+ msm_send_frame_to_vpe(vpe_buf->p0_phy, vpe_buf->p1_phy,
&(vpe_buf->ts), OUTPUT_TYPE_V);
if (!qcmd || !atomic_read(&qcmd->on_heap)) {
@@ -919,10 +919,10 @@
CDBG("In vpe_addr_convert output_id = %d\n", pinfo->output_id);
- pinfo->y_phy =
- ((struct vpe_message *)data)->_u.msgOut.yBuffer;
- pinfo->cbcr_phy =
- ((struct vpe_message *)data)->_u.msgOut.cbcrBuffer;
+ pinfo->p0_phy =
+ ((struct vpe_message *)data)->_u.msgOut.p0_Buffer;
+ pinfo->p1_phy =
+ ((struct vpe_message *)data)->_u.msgOut.p1_Buffer;
*ext = vpe_ctrl->extdata;
*elen = vpe_ctrl->extlen;
}
@@ -987,10 +987,10 @@
regp1 = &(ad->region[0]);
/* for video Y address */
- p1 = (regp1->paddr + regp1->info.y_off);
+ p1 = (regp1->paddr + regp1->info.planar0_off);
msm_io_w(p1, vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
/* for video CbCr address */
- p1 = (regp1->paddr + regp1->info.cbcr_off);
+ p1 = (regp1->paddr + regp1->info.planar1_off);
msm_io_w(p1, vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET);
return 0;
@@ -1048,8 +1048,8 @@
vpe_ctrl->frame_pack = frame_pack;
vpe_ctrl->output_type = output_id;
- input_stride = (st_half.buf_cbcr_stride * (1<<16)) +
- st_half.buf_y_stride;
+ input_stride = (st_half.buf_p1_stride * (1<<16)) +
+ st_half.buf_p0_stride;
msm_io_w(input_stride, vpe_device->vpebase + VPE_SRC_YSTRIDE1_OFFSET);
@@ -1059,15 +1059,16 @@
msm_send_frame_to_vpe(pyaddr, pcbcraddr, ts, output_id);
}
-static void vpe_send_outmsg(uint8_t msgid, uint32_t pyaddr,
- uint32_t pcbcraddr)
+static void vpe_send_outmsg(uint8_t msgid, uint32_t p0_addr,
+ uint32_t p1_addr, uint32_t p2_addr)
{
struct vpe_message msg;
uint8_t outid;
msg._d = outid = msgid;
msg._u.msgOut.output_id = msgid;
- msg._u.msgOut.yBuffer = pyaddr;
- msg._u.msgOut.cbcrBuffer = pcbcraddr;
+ msg._u.msgOut.p0_Buffer = p0_addr;
+ msg._u.msgOut.p1_Buffer = p1_addr;
+ msg._u.msgOut.p2_Buffer = p2_addr;
vpe_proc_ops(outid, &msg, sizeof(struct vpe_message));
return;
}
@@ -1203,10 +1204,11 @@
if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_R) {
CDBG("vpe send out R msg.\n");
vpe_send_outmsg(MSG_ID_VPE_OUTPUT_ST_R, pyaddr,
- pcbcraddr);
+ pcbcraddr, pyaddr);
} else if (vpe_ctrl->output_type == OUTPUT_TYPE_V) {
CDBG("vpe send out V msg.\n");
- vpe_send_outmsg(MSG_ID_VPE_OUTPUT_V, pyaddr, pcbcraddr);
+ vpe_send_outmsg(MSG_ID_VPE_OUTPUT_V, pyaddr,
+ pcbcraddr, pyaddr);
}
vpe_ctrl->output_type = 0;
diff --git a/drivers/media/video/msm/msm_vpe1.h b/drivers/media/video/msm/msm_vpe1.h
index ed7112e..f4d328d 100644
--- a/drivers/media/video/msm/msm_vpe1.h
+++ b/drivers/media/video/msm/msm_vpe1.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010, 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -212,8 +212,9 @@
struct vpe_msg_output {
uint8_t output_id;
- uint32_t yBuffer;
- uint32_t cbcrBuffer;
+ uint32_t p0_Buffer;
+ uint32_t p1_Buffer;
+ uint32_t p2_Buffer;
uint32_t frameCounter;
};
diff --git a/drivers/media/video/msm/wfd/Makefile b/drivers/media/video/msm/wfd/Makefile
index e1484aa..7ea9db3 100644
--- a/drivers/media/video/msm/wfd/Makefile
+++ b/drivers/media/video/msm/wfd/Makefile
@@ -1,4 +1,5 @@
#obj-$(CONFIG_MSM_WFD_V4L2) += wfd-ioctl.o
#obj-$(CONFIG_MSM_WFD_V4L2) += enc-subdev.o
obj-y += mdp-subdev.o
+obj-y += enc-subdev.o
obj-y += wfd-ioctl.o
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
new file mode 100644
index 0000000..abba5d4
--- /dev/null
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -0,0 +1,1355 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#include <media/v4l2-subdev.h>
+
+#include "enc-subdev.h"
+#include "wfd-util.h"
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
+#include <media/msm/vcd_property.h>
+#include <linux/time.h>
+#include <linux/ktime.h>
+
+#define VID_ENC_MAX_ENCODER_CLIENTS 1
+#define MAX_NUM_CTRLS 20
+
+struct venc_inst {
+ struct video_client_ctx venc_client;
+ void *cbdata;
+ void (*op_buffer_done)(void *cookie, u32 status,
+ struct vb2_buffer *buf);
+ void (*ip_buffer_done)(void *cookie, u32 status,
+ struct mem_region *mregion);
+ u32 width;
+ u32 height;
+};
+
+struct venc {
+ s32 device_handle;
+ void *virt_base;
+ struct venc_inst venc_clients[VID_ENC_MAX_ENCODER_CLIENTS];
+ struct mutex lock;
+ struct ion_client *iclient;
+};
+
+static struct venc venc_p;
+
+static void *venc_map_dev_base_addr(void *device_name)
+{
+ return venc_p.virt_base;
+}
+
+static void venc_interrupt_deregister(void)
+{
+}
+
+static void venc_interrupt_register(void *device_name)
+{
+}
+
+static void venc_interrupt_clear(void)
+{
+}
+
+int venc_load_fw(struct v4l2_subdev *sd)
+{
+ return !vidc_load_firmware();
+}
+
+static u32 venc_get_empty_client_index(void)
+{
+ u32 i;
+ u32 found = false;
+
+ for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
+ if (!venc_p.venc_clients[i].venc_client.vcd_handle) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ WFD_MSG_ERR("%s():ERROR No space for new client\n",
+ __func__);
+ return -ENOMEM;
+ }
+ WFD_MSG_INFO("%s(): available client index = %u\n",
+ __func__, i);
+ return i;
+}
+
+int venc_init(struct v4l2_subdev *sd, u32 val)
+{
+ struct vcd_init_config vcd_init_config;
+ mutex_init(&venc_p.lock);
+ venc_p.virt_base = vidc_get_ioaddr();
+ vcd_init_config.device_name = "VIDC";
+ vcd_init_config.map_dev_base_addr = venc_map_dev_base_addr;
+ vcd_init_config.interrupt_clr = venc_interrupt_clear;
+ vcd_init_config.register_isr = venc_interrupt_register;
+ vcd_init_config.deregister_isr = venc_interrupt_deregister;
+ vcd_init(&vcd_init_config, &venc_p.device_handle);
+ return 0;
+}
+
+static void venc_notify_client(struct video_client_ctx *client_ctx)
+{
+ if (client_ctx)
+ complete(&client_ctx->event);
+}
+
+static void venc_open_done(struct video_client_ctx *client_ctx,
+ struct vcd_handle_container *handle_container)
+{
+ if (client_ctx) {
+ if (handle_container)
+ client_ctx->vcd_handle = handle_container->handle;
+ else
+ WFD_MSG_ERR("handle_container is NULL\n");
+ venc_notify_client(client_ctx);
+ } else
+ WFD_MSG_ERR("ERROR. client_ctx is NULL");
+}
+
+static void venc_start_done(struct video_client_ctx *client_ctx, u32 status)
+{
+ if (client_ctx)
+ venc_notify_client(client_ctx);
+ else
+ WFD_MSG_ERR("ERROR. client_ctx is NULL");
+}
+
+static void venc_stop_done(struct video_client_ctx *client_ctx, u32 status)
+{
+ WFD_MSG_DBG("Inside venc_stop_done: E\n");
+ if (client_ctx)
+ venc_notify_client(client_ctx);
+ else
+ WFD_MSG_ERR("ERROR. client_ctx is NULL");
+ WFD_MSG_DBG("Inside venc_stop_done: X\n");
+}
+
+static void venc_cb(u32 event, u32 status, void *info, u32 size, void *handle,
+ void *const client_data)
+{
+ struct venc_inst *inst = client_data;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ struct vb2_buffer *vbuf;
+ struct mem_region *mregion;
+ struct vcd_frame_data *frame_data = (struct vcd_frame_data *)info;
+ struct timespec ts;
+
+ if (!client_ctx) {
+ WFD_MSG_ERR("Client context is NULL\n");
+ return;
+ }
+ client_ctx->event_status = status;
+ switch (event) {
+ case VCD_EVT_RESP_OPEN:
+ WFD_MSG_DBG("EVENT: open done = %d\n", event);
+ venc_open_done(client_ctx,
+ (struct vcd_handle_container *)info);
+ break;
+ case VCD_EVT_RESP_INPUT_DONE:
+ case VCD_EVT_RESP_INPUT_FLUSHED:
+ WFD_MSG_DBG("EVENT: input done = %d\n", event);
+ mregion = (struct mem_region *)
+ frame_data->frm_clnt_data;
+ inst->ip_buffer_done(inst->cbdata, status, mregion);
+ break;
+ case VCD_EVT_RESP_OUTPUT_DONE:
+ case VCD_EVT_RESP_OUTPUT_FLUSHED:
+ WFD_MSG_DBG("EVENT: output done = %d\n", event);
+ vbuf = (struct vb2_buffer *)
+ frame_data->frm_clnt_data;
+ vbuf->v4l2_planes[0].bytesused =
+ frame_data->data_len;
+
+ switch (frame_data->frame) {
+ case VCD_FRAME_I:
+ case VCD_FRAME_IDR:
+ vbuf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case VCD_FRAME_P:
+ vbuf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+ break;
+ case VCD_FRAME_B:
+ vbuf->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME;
+ break;
+ default:
+ break;
+ }
+
+ ktime_get_ts(&ts);
+ vbuf->v4l2_buf.timestamp.tv_sec = ts.tv_sec;
+ vbuf->v4l2_buf.timestamp.tv_usec = ts.tv_nsec/1000;
+
+ WFD_MSG_DBG("bytes used %d, ts: %d.%d, frame type is %d\n",
+ frame_data->data_len,
+ (int)vbuf->v4l2_buf.timestamp.tv_sec,
+ (int)vbuf->v4l2_buf.timestamp.tv_usec,
+ frame_data->frame);
+
+ inst->op_buffer_done(inst->cbdata, status, vbuf);
+ break;
+ case VCD_EVT_RESP_START:
+ WFD_MSG_DBG("EVENT: start done = %d\n", event);
+ venc_start_done(client_ctx, status);
+ /*TODO: should wait for this event*/
+ break;
+ case VCD_EVT_RESP_STOP:
+ WFD_MSG_DBG("EVENT: not expected = %d\n", event);
+ venc_stop_done(client_ctx, status);
+ break;
+ case VCD_EVT_RESP_PAUSE:
+ case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+ case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+ case VCD_EVT_IND_OUTPUT_RECONFIG:
+ WFD_MSG_DBG("EVENT: not expected = %d\n", event);
+ break;
+ case VCD_EVT_IND_HWERRFATAL:
+ case VCD_EVT_IND_RESOURCES_LOST:
+ WFD_MSG_DBG("EVENT: error = %d\n", event);
+ break;
+ default:
+ WFD_MSG_ERR("Invalid event type = %u\n", event);
+ break;
+ }
+}
+
+static long venc_open(struct v4l2_subdev *sd, void *arg)
+{
+ u32 client_index;
+ int rc = 0;
+ struct venc_inst *inst;
+ struct video_client_ctx *client_ctx;
+ struct venc_msg_ops *vmops = arg;
+ mutex_lock(&venc_p.lock);
+ client_index = venc_get_empty_client_index();
+ if (client_index < 0) {
+ WFD_MSG_ERR("No free clients, client_index = %d\n",
+ client_index);
+ rc = -ENODEV;
+ goto no_free_client;
+ }
+ inst = &venc_p.venc_clients[client_index];
+ client_ctx = &inst->venc_client;
+ init_completion(&client_ctx->event);
+ mutex_init(&client_ctx->msg_queue_lock);
+ mutex_init(&client_ctx->enrty_queue_lock);
+ INIT_LIST_HEAD(&client_ctx->msg_queue);
+ init_waitqueue_head(&client_ctx->msg_wait);
+ inst->op_buffer_done = vmops->op_buffer_done;
+ inst->ip_buffer_done = vmops->ip_buffer_done;
+ inst->cbdata = vmops->cbdata;
+
+ if (vcd_get_ion_status()) {
+ client_ctx->user_ion_client = vcd_get_ion_client();
+ if (!client_ctx->user_ion_client) {
+ WFD_MSG_ERR("vcd_open ion get client failed");
+ return -EFAULT;
+ }
+ }
+
+ rc = vcd_open(venc_p.device_handle, false, venc_cb,
+ inst);
+ if (rc) {
+ WFD_MSG_ERR("vcd_open failed, rc = %d\n", rc);
+ goto no_free_client;
+ }
+ wait_for_completion(&client_ctx->event);
+ if (client_ctx->event_status) {
+ WFD_MSG_ERR("callback for vcd_open returned error: %u",
+ client_ctx->event_status);
+ goto no_free_client;
+ }
+ WFD_MSG_ERR("NOTE: client_ctx = %p\n", client_ctx);
+ vmops->cookie = inst;
+ sd->dev_priv = inst;
+no_free_client:
+ mutex_unlock(&venc_p.lock);
+ return rc;
+}
+
+static long venc_close(struct v4l2_subdev *sd, void *arg)
+{
+ long rc = 0;
+ struct venc_inst *inst;
+ struct video_client_ctx *client_ctx = NULL;
+ mutex_lock(&venc_p.lock);
+ inst = sd->dev_priv;
+ client_ctx = &inst->venc_client;
+ if (!client_ctx || !client_ctx->vcd_handle) {
+ WFD_MSG_ERR("Invalid client context in close\n");
+ rc = -ENODEV;
+ goto end;
+ }
+ rc = vcd_close(client_ctx->vcd_handle);
+ if (rc) {
+ WFD_MSG_ERR("Failed to close encoder subdevice\n");
+ goto end;
+ }
+ memset((void *)client_ctx, 0,
+ sizeof(struct video_client_ctx));
+end:
+ mutex_unlock(&venc_p.lock);
+ return rc;
+}
+
+static long venc_get_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct v4l2_requestbuffers *b = arg;
+ struct vcd_buffer_requirement buf_req;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ if (!client_ctx) {
+ WFD_MSG_ERR("Invalid client context");
+ rc = -EINVAL;
+ goto err;
+ }
+ rc = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_OUTPUT, &buf_req);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get out buf reqs rc = %d", rc);
+ goto err;
+ }
+ b->count = buf_req.actual_count;
+err:
+ return rc;
+}
+
+static long venc_set_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct bufreq *b = arg;
+ struct vcd_buffer_requirement buf_req;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ if (!client_ctx) {
+ WFD_MSG_ERR("Invalid client context");
+ rc = -EINVAL;
+ goto err;
+ }
+ buf_req.actual_count = b->count;
+ buf_req.min_count = b->count;
+ buf_req.max_count = b->count;
+ buf_req.sz = (((b->height * b->width) + 2047) & (~2047))
+ + (((b->height * b->width * 1/2) + 2047) & (~2047));
+ buf_req.align = 0;
+ inst->width = b->width;
+ inst->height = b->height;
+ rc = vcd_set_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_INPUT, &buf_req);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get out buf reqs rc = %d", rc);
+ goto err;
+ }
+ b->size = buf_req.sz;
+err:
+ return rc;
+}
+
+static long venc_start(struct v4l2_subdev *sd)
+{
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ int rc;
+ if (!client_ctx) {
+ WFD_MSG_ERR("Client context is NULL");
+ return -EINVAL;
+ }
+ rc = vcd_encode_start(client_ctx->vcd_handle);
+ if (rc) {
+ WFD_MSG_ERR("vcd_encode_start failed, rc = %d\n", rc);
+ goto err;
+ }
+ wait_for_completion(&client_ctx->event);
+ if (client_ctx->event_status)
+ WFD_MSG_ERR("callback for vcd_encode_start returned error: %u",
+ client_ctx->event_status);
+err:
+ return rc;
+}
+
+static long venc_stop(struct v4l2_subdev *sd)
+{
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ int rc;
+ if (!client_ctx) {
+ WFD_MSG_ERR("Client context is NULL");
+ return -EINVAL;
+ }
+ rc = vcd_stop(client_ctx->vcd_handle);
+ wait_for_completion(&client_ctx->event);
+ return rc;
+}
+
+static long venc_set_codec(struct video_client_ctx *client_ctx, __s32 codec)
+{
+ struct vcd_property_codec vcd_property_codec;
+ struct vcd_property_hdr vcd_property_hdr;
+ vcd_property_hdr.prop_id = VCD_I_CODEC;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+ vcd_property_codec.codec = VCD_CODEC_H264;
+ switch (codec) {
+ case V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC:
+ vcd_property_codec.codec = VCD_CODEC_H264;
+ break;
+ case V4L2_MPEG_VIDEO_ENCODING_MPEG_1:
+ vcd_property_codec.codec = VCD_CODEC_MPEG4;
+ break;
+ default:
+ WFD_MSG_ERR("Codec not supported, defaulting to h264\n");
+ break;
+ }
+ return vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_codec);
+}
+
+static long venc_get_codec(struct video_client_ctx *client_ctx, __s32 *codec)
+{
+ struct vcd_property_codec vcd_property_codec;
+ struct vcd_property_hdr vcd_property_hdr;
+ int rc = 0;
+
+ vcd_property_hdr.prop_id = VCD_I_CODEC;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_codec);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Failed to get codec property");
+ return rc;
+ }
+
+ switch (vcd_property_codec.codec) {
+ case VCD_CODEC_H264:
+ *codec = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
+ break;
+ case VCD_CODEC_MPEG4:
+ *codec = V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ break;
+ default:
+ WFD_MSG_ERR("Unrecognized codec");
+ return -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+static long venc_set_codec_level(struct video_client_ctx *client_ctx,
+ __s32 codec, __s32 level)
+{
+ struct vcd_property_level vcd_property_level;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_codec vcd_property_codec;
+
+ int rc = 0;
+ int mpeg4_base = VCD_LEVEL_MPEG4_0;
+ int h264_base = VCD_LEVEL_H264_1;
+
+ /* Validate params */
+ vcd_property_hdr.prop_id = VCD_I_CODEC;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_codec);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Error getting codec property");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ if (!((vcd_property_codec.codec == VCD_CODEC_H264
+ && codec == V4L2_CID_MPEG_VIDEO_H264_LEVEL) ||
+ (vcd_property_codec.codec == VCD_CODEC_MPEG4
+ && codec == V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL))) {
+ WFD_MSG_ERR("Attempting to set %d for codec type %d",
+ codec, vcd_property_codec.codec);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ /* Set property */
+ vcd_property_hdr.prop_id = VCD_I_LEVEL;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_level);
+
+ if (codec == V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL) {
+ vcd_property_level.level = mpeg4_base + level;
+
+ if (vcd_property_level.level < VCD_LEVEL_MPEG4_0
+ || vcd_property_level.level > VCD_LEVEL_MPEG4_X) {
+ WFD_MSG_ERR("Level (%d) out of range"
+ "for codec (%d)\n", level, codec);
+
+ rc = -EINVAL;
+ goto err;
+ }
+ } else if (codec == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
+ vcd_property_level.level = h264_base + level;
+
+ if (vcd_property_level.level < VCD_LEVEL_H264_1
+ || vcd_property_level.level > VCD_LEVEL_H264_5p1) {
+ WFD_MSG_ERR("Level (%d) out of range"
+ "for codec (%d)\n", level, codec);
+
+ rc = -EINVAL;
+ goto err;
+ }
+ } else {
+ WFD_MSG_ERR("Codec (%d) not supported, not setting level (%d)",
+ codec, level);
+ rc = -ENOTSUPP;
+ goto err;
+ }
+
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_level);
+err:
+ return rc;
+}
+
+static long venc_get_codec_level(struct video_client_ctx *client_ctx,
+ __s32 codec, __s32 *level)
+{
+ struct vcd_property_level vcd_property_level;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_codec vcd_property_codec;
+
+ int rc = 0;
+ int mpeg4_base = VCD_LEVEL_MPEG4_0;
+ int h264_base = VCD_LEVEL_H264_1;
+
+ /* Validate params */
+ vcd_property_hdr.prop_id = VCD_I_CODEC;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_codec);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Error getting codec property");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ if (!((vcd_property_codec.codec == VCD_CODEC_H264
+ && codec == V4L2_CID_MPEG_VIDEO_H264_LEVEL) ||
+ (vcd_property_codec.codec == VCD_CODEC_MPEG4
+ && codec == V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL))) {
+ WFD_MSG_ERR("Attempting to get %d for codec type %d",
+ codec, vcd_property_codec.codec);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_LEVEL;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_level);
+
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_level);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ if (codec == V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL) {
+ *level = vcd_property_level.level - mpeg4_base;
+ } else if (codec == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
+ *level = vcd_property_level.level - h264_base;
+ } else {
+ WFD_MSG_ERR("Codec (%d) not supported", codec);
+ rc = -ENOTSUPP;
+ goto err;
+ }
+
+err:
+ return rc;
+}
+
+static long venc_set_codec_profile(struct video_client_ctx *client_ctx,
+ __s32 codec, __s32 profile)
+{
+ struct vcd_property_profile vcd_property_profile;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_codec vcd_property_codec;
+ int rc = 0;
+
+ /* Validate params */
+ vcd_property_hdr.prop_id = VCD_I_CODEC;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_codec);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Error getting codec property");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ if (!((vcd_property_codec.codec == VCD_CODEC_H264
+ && codec == V4L2_CID_MPEG_VIDEO_H264_PROFILE) ||
+ (vcd_property_codec.codec == VCD_CODEC_MPEG4
+ && codec == V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE))) {
+ WFD_MSG_ERR("Attempting to set %d for codec type %d",
+ codec, vcd_property_codec.codec);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ /* Set property */
+ vcd_property_hdr.prop_id = VCD_I_PROFILE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_profile);
+
+ if (codec == V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE) {
+ switch (profile) {
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+ vcd_property_profile.profile = VCD_PROFILE_MPEG4_SP;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+ vcd_property_profile.profile = VCD_PROFILE_MPEG4_ASP;
+ break;
+ default:
+ WFD_MSG_ERR("Profile %d not supported,"
+ "defaulting to simple (%d)",
+ profile, VCD_PROFILE_MPEG4_SP);
+ vcd_property_profile.profile = VCD_PROFILE_MPEG4_SP;
+ break;
+ }
+ } else if (codec == V4L2_CID_MPEG_VIDEO_H264_PROFILE) {
+ switch (profile) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ vcd_property_profile.profile =
+ VCD_PROFILE_H264_BASELINE;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ vcd_property_profile.profile = VCD_PROFILE_H264_MAIN;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ vcd_property_profile.profile = VCD_PROFILE_H264_HIGH;
+ break;
+ default:
+ WFD_MSG_ERR("Profile %d not supported,"
+ "defaulting to baseline (%d)",
+ profile, VCD_PROFILE_H264_BASELINE);
+ vcd_property_profile.profile =
+ VCD_PROFILE_H264_BASELINE;
+ break;
+ }
+ } else {
+ WFD_MSG_ERR("Codec (%d) not supported,"
+ "not setting profile (%d)",
+ codec, profile);
+ rc = -ENOTSUPP;
+ goto err;
+ }
+
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_profile);
+err:
+ return rc;
+}
+
+static long venc_get_codec_profile(struct video_client_ctx *client_ctx,
+ __s32 codec, __s32 *profile)
+{
+ struct vcd_property_profile vcd_property_profile;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_codec vcd_property_codec;
+ int rc = 0;
+
+ /* Validate params */
+ vcd_property_hdr.prop_id = VCD_I_CODEC;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_codec);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Error getting codec property");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ if (!((vcd_property_codec.codec == VCD_CODEC_H264
+ && codec == V4L2_CID_MPEG_VIDEO_H264_PROFILE) ||
+ (vcd_property_codec.codec == VCD_CODEC_MPEG4
+ && codec == V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE))) {
+ WFD_MSG_ERR("Attempting to set %d for codec type %d",
+ codec, vcd_property_codec.codec);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ /* Set property */
+ vcd_property_hdr.prop_id = VCD_I_PROFILE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_profile);
+
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_profile);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Unable to get property");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ switch (vcd_property_profile.profile) {
+ case VCD_PROFILE_MPEG4_SP:
+ *profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE;
+ break;
+ case VCD_PROFILE_MPEG4_ASP:
+ *profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE;
+ break;
+ case VCD_PROFILE_H264_BASELINE:
+ *profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
+ break;
+ case VCD_PROFILE_H264_MAIN:
+ *profile = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
+ break;
+ case VCD_PROFILE_H264_HIGH:
+ *profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
+ break;
+ default:
+ WFD_MSG_ERR("Unexpected profile");
+ rc = -EINVAL;
+ goto err;
+ break;
+ }
+err:
+ return rc;
+}
+
+static long venc_set_h264_intra_period(struct video_client_ctx *client_ctx,
+ __s32 period) {
+ struct vcd_property_i_period vcd_property_i_period;
+ struct vcd_property_codec vcd_property_codec;
+ struct vcd_property_hdr vcd_property_hdr;
+ int rc = 0;
+
+ vcd_property_hdr.prop_id = VCD_I_CODEC;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_codec);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Error getting codec property\n");
+ goto err;
+ }
+
+ if (vcd_property_codec.codec != VCD_CODEC_H264) {
+ rc = -ENOTSUPP;
+ WFD_MSG_ERR("Control not supported for non H264 codec\n");
+ goto err;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_INTRA_PERIOD;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_i_period);
+
+ vcd_property_i_period.p_frames = period - 1;
+ vcd_property_i_period.b_frames = 1;
+
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_i_period);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Error setting intra period\n");
+ goto err;
+ }
+
+err:
+ return rc;
+}
+
+static long venc_request_frame(struct video_client_ctx *client_ctx, __s32 type)
+{
+ struct vcd_property_req_i_frame vcd_property_req_i_frame;
+ struct vcd_property_hdr vcd_property_hdr;
+
+ int rc = 0;
+ switch (type) {
+ case V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED:
+ /*So...nothing to do?*/
+ break;
+ case V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME:
+ vcd_property_hdr.prop_id = VCD_I_REQ_IFRAME;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_req_i_frame);
+ vcd_property_req_i_frame.req_i_frame = 1;
+
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_req_i_frame);
+ break;
+ case V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED:
+ default:
+ rc = -ENOTSUPP;
+ }
+
+ return rc;
+}
+
+static long venc_set_bitrate(struct video_client_ctx *client_ctx,
+ __s32 bitrate)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_target_bitrate bit_rate;
+ if (!client_ctx || !bitrate)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_TARGET_BITRATE;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_target_bitrate);
+ bit_rate.target_bitrate = bitrate;
+ return vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &bit_rate);
+}
+
+static long venc_get_bitrate(struct video_client_ctx *client_ctx,
+ __s32 *bitrate)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_target_bitrate bit_rate;
+ int rc = 0;
+
+ if (!client_ctx || !bitrate)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_TARGET_BITRATE;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_target_bitrate);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &bit_rate);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Failed getting property for bitrate");
+ return rc;
+ }
+
+ *bitrate = bit_rate.target_bitrate;
+ return rc;
+}
+
+static long venc_set_bitrate_mode(struct video_client_ctx *client_ctx,
+ __s32 mode)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_rate_control rate_control;
+ int rc = 0;
+
+ if (!client_ctx) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_RATE_CONTROL;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_rate_control);
+ /*
+ * XXX: V4L doesn't seem have a control to toggle between CFR
+ * and VFR, so assuming worse case VFR.
+ */
+ switch (mode) {
+ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
+ rate_control.rate_control = VCD_RATE_CONTROL_VBR_VFR;
+ break;
+ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
+ rate_control.rate_control = VCD_RATE_CONTROL_CBR_VFR;
+ break;
+ default:
+ WFD_MSG_ERR("unknown bitrate mode %d", mode);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &rate_control);
+err:
+ return rc;
+}
+
+static long venc_get_bitrate_mode(struct video_client_ctx *client_ctx,
+ __s32 *mode)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_rate_control rate_control;
+ int rc = 0;
+
+ if (!client_ctx)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_RATE_CONTROL;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_rate_control);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &rate_control);
+
+ switch (rate_control.rate_control) {
+ case VCD_RATE_CONTROL_CBR_VFR:
+ case VCD_RATE_CONTROL_CBR_CFR:
+ *mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ break;
+ case VCD_RATE_CONTROL_VBR_VFR:
+ case VCD_RATE_CONTROL_VBR_CFR:
+ *mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+ break;
+ default:
+ WFD_MSG_ERR("unknown bitrate mode %d",
+ rate_control.rate_control);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static long venc_set_frame_size(struct video_client_ctx *client_ctx,
+ u32 height, u32 width)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_frame_size frame_size;
+ vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_frame_size);
+ frame_size.height = height;
+ frame_size.width = width;
+ return vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &frame_size);
+}
+
+static long venc_set_format(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst;
+ struct video_client_ctx *client_ctx;
+ struct v4l2_format *fmt = arg;
+ struct vcd_buffer_requirement buf_req;
+ int rc = 0;
+
+ inst = sd->dev_priv;
+ client_ctx = &inst->venc_client;
+ if (!inst || !client_ctx || !fmt) {
+ WFD_MSG_ERR("Invalid parameters\n");
+ return -EINVAL;
+ }
+ rc = venc_set_frame_size(client_ctx, fmt->fmt.pix.height,
+ fmt->fmt.pix.width);
+ if (rc) {
+ WFD_MSG_ERR("Failed to set frame size, rc = %d\n", rc);
+ goto err;
+ }
+ rc = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_OUTPUT, &buf_req);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get buf requrements, rc = %d\n", rc);
+ goto err;
+ }
+ fmt->fmt.pix.sizeimage = buf_req.sz;
+err:
+ return rc;
+}
+
+static long venc_set_framerate(struct v4l2_subdev *sd,
+ void *arg)
+{
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ struct v4l2_fract *frate = arg;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_frame_rate vcd_frame_rate;
+ int rc;
+ vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_frame_rate);
+ vcd_frame_rate.fps_denominator = frate->denominator;
+ vcd_frame_rate.fps_numerator = frate->numerator;
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_frame_rate);
+ if (rc)
+ WFD_MSG_ERR("Failed to set frame rate, rc = %d\n", rc);
+ return rc;
+}
+
+static long venc_alloc_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ struct mem_region *mregion = arg;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ int rc = 0;
+ if (!client_ctx || !mregion) {
+ WFD_MSG_ERR("Invalid input\n");
+ return -EINVAL;
+ }
+ rc = vcd_allocate_buffer(client_ctx->vcd_handle,
+ VCD_BUFFER_INPUT, mregion->size,
+ &mregion->kvaddr, &mregion->paddr);
+ if (rc)
+ WFD_MSG_ERR("Failed to allocate input buffer\n");
+ return rc;
+}
+
+static long venc_set_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ struct mem_region *mregion = arg;
+ if (!client_ctx || !mregion) {
+ WFD_MSG_ERR("Invalid input\n");
+ return -EINVAL;
+ }
+ WFD_MSG_DBG("size = %u, offset = %u fd = %d\n", mregion->size,
+ mregion->offset, mregion->fd);
+ rc = vidc_insert_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+ mregion->cookie,
+ (unsigned long *)&mregion->kvaddr,
+ mregion->fd,
+ mregion->offset,
+ 32,
+ mregion->size);
+ if (!rc) {
+ WFD_MSG_ERR("Failed to insert outbuf in table\n");
+ goto err;
+ }
+ WFD_MSG_DBG("size = %u, %p\n", mregion->size, mregion->kvaddr);
+
+ rc = vcd_set_buffer(client_ctx->vcd_handle,
+ VCD_BUFFER_OUTPUT, (u8 *) mregion->kvaddr,
+ mregion->size);
+ if (rc)
+ WFD_MSG_ERR("Failed to set outbuf on encoder\n");
+err:
+ return rc;
+}
+
+static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ struct mem_region *mregion = arg;
+ struct vcd_frame_data vcd_frame = {0};
+ unsigned long kernel_vaddr, phy_addr, user_vaddr;
+ int pmem_fd;
+ struct file *file;
+ s32 buffer_index = -1;
+
+ user_vaddr = mregion->cookie;
+ rc = vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+ true, &user_vaddr,
+ &kernel_vaddr, &phy_addr, &pmem_fd, &file,
+ &buffer_index);
+ if (!rc) {
+ WFD_MSG_ERR("Address lookup failed\n");
+ goto err;
+ }
+ vcd_frame.virtual = (u8 *) kernel_vaddr;
+ vcd_frame.frm_clnt_data = mregion->cookie;
+ vcd_frame.alloc_len = mregion->size;
+
+ rc = vcd_fill_output_buffer(client_ctx->vcd_handle, &vcd_frame);
+ if (rc)
+ WFD_MSG_ERR("Failed to fill output buffer on encoder");
+err:
+ return rc;
+}
+
+static long venc_encode_frame(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ struct mem_region *mregion = arg;
+ struct vcd_frame_data vcd_input_buffer = {0};
+
+ vcd_input_buffer.virtual = mregion->kvaddr;
+ vcd_input_buffer.frm_clnt_data = (u32)mregion;
+ vcd_input_buffer.ip_frm_tag = (u32)mregion;
+ vcd_input_buffer.data_len = mregion->size;
+ vcd_input_buffer.time_stamp = 0; /*TODO: Need to fix this*/
+ vcd_input_buffer.offset = 0;
+
+ rc = vcd_encode_frame(client_ctx->vcd_handle,
+ &vcd_input_buffer);
+
+ if (rc)
+ WFD_MSG_ERR("encode frame failed\n");
+ return rc;
+}
+
+static long venc_alloc_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_buffer_size control;
+ struct vcd_property_enc_recon_buffer *ctrl = NULL;
+ unsigned long phy_addr;
+ int i = 0;
+ u32 len;
+ control.width = inst->width;
+ control.height = inst->height;
+ vcd_property_hdr.prop_id = VCD_I_GET_RECON_BUFFER_SIZE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &control);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get recon buf size\n");
+ goto err;
+ }
+
+ if (vcd_get_ion_status()) {
+ for (i = 0; i < 4; ++i) {
+ ctrl = &client_ctx->recon_buffer[i];
+ ctrl->buffer_size = control.size;
+ ctrl->pmem_fd = 0;
+ ctrl->offset = 0;
+ ctrl->user_virtual_addr = (void *)i;
+ client_ctx->recon_buffer_ion_handle[i]
+ = ion_alloc(client_ctx->user_ion_client,
+ control.size, SZ_8K, (0x1<<ION_CP_MM_HEAP_ID));
+ ctrl->kernel_virtual_addr = ion_map_kernel(
+ client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i], 0);
+
+ rc = ion_phys(client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i],
+ &phy_addr, &len);
+ if (rc) {
+ WFD_MSG_ERR("Failed to allo recon buffers\n");
+ break;
+ }
+ ctrl->physical_addr = (u8 *) phy_addr;
+ ctrl->dev_addr = ctrl->physical_addr;
+ vcd_property_hdr.prop_id = VCD_I_RECON_BUFFERS;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_enc_recon_buffer);
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, ctrl);
+ if (rc) {
+ WFD_MSG_ERR("Failed to set recon buffers\n");
+ break;
+ }
+ }
+ } else {
+ WFD_MSG_ERR("PMEM not suported\n");
+ return -ENOMEM;
+ }
+err:
+ return rc;
+}
+
+static long venc_free_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ struct mem_region *mregion = arg;
+ unsigned long kernel_vaddr, user_vaddr;
+
+ if (!client_ctx || !mregion) {
+ WFD_MSG_ERR("Invalid input\n");
+ return -EINVAL;
+ }
+
+ user_vaddr = mregion->cookie;
+ rc = vidc_delete_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+ user_vaddr,
+ &kernel_vaddr);
+ if (!rc) {
+ WFD_MSG_ERR("Failed to delete buf from address table\n");
+ return -EINVAL;
+ }
+ return vcd_free_buffer(client_ctx->vcd_handle, VCD_BUFFER_OUTPUT,
+ (u8 *)kernel_vaddr);
+}
+
+static long venc_free_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ struct mem_region *mregion = arg;
+ if (!client_ctx || !mregion) {
+ WFD_MSG_ERR("Invalid input\n");
+ return -EINVAL;
+ }
+ rc = vcd_free_buffer(client_ctx->vcd_handle, VCD_BUFFER_INPUT,
+ mregion->kvaddr);
+ if (rc)
+ WFD_MSG_ERR("Failed to free input buffer\n");
+ return rc;
+}
+
+static long venc_free_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ struct vcd_property_hdr vcd_property_hdr;
+ int i;
+
+ if (vcd_get_ion_status()) {
+ for (i = 0; i < 4; i++) {
+ vcd_property_hdr.prop_id = VCD_I_FREE_RECON_BUFFERS;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_buffer_size);
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &client_ctx->recon_buffer[i]);
+ if (rc)
+ WFD_MSG_ERR("Failed to free recon buffer\n");
+
+ if (client_ctx->recon_buffer_ion_handle[i]) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i]);
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i]);
+ client_ctx->recon_buffer_ion_handle[i] = NULL;
+ }
+ }
+ }
+ return rc;
+}
+
+static long venc_set_property(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = sd->dev_priv;
+ struct v4l2_control *ctrl = arg;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ rc = venc_set_bitrate(client_ctx, ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ rc = venc_set_bitrate_mode(client_ctx, ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ rc = venc_set_codec(client_ctx, ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+ rc = venc_set_h264_intra_period(client_ctx, ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ rc = venc_set_codec_level(client_ctx, ctrl->id, ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ rc = venc_set_codec_profile(client_ctx, ctrl->id, ctrl->value);
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+ rc = venc_request_frame(client_ctx, ctrl->value);
+ break;
+ default:
+ WFD_MSG_ERR("Set property not suported: %d\n", ctrl->id);
+ rc = -ENOTSUPP;
+ break;
+ }
+ return rc;
+}
+
+static long venc_get_property(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = sd->dev_priv;
+ struct v4l2_control *ctrl = arg;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ rc = venc_get_bitrate(client_ctx, &ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ rc = venc_get_bitrate_mode(client_ctx, &ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ rc = venc_get_codec(client_ctx, &ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ rc = venc_get_codec_level(client_ctx, ctrl->id, &ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ rc = venc_get_codec_profile(client_ctx, ctrl->id, &ctrl->value);
+ break;
+ default:
+ WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
+ rc = -ENOTSUPP;
+ break;
+ }
+ return rc;
+}
+
+long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ long rc = 0;
+ switch (cmd) {
+ case OPEN:
+ rc = venc_open(sd, arg);
+ break;
+ case CLOSE:
+ rc = venc_close(sd, arg);
+ break;
+ case ENCODE_START:
+ rc = venc_start(sd);
+ break;
+ case ENCODE_FRAME:
+ venc_encode_frame(sd, arg);
+ break;
+ case ENCODE_STOP:
+ rc = venc_stop(sd);
+ break;
+ case SET_PROP:
+ rc = venc_set_property(sd, arg);
+ break;
+ case GET_PROP:
+ rc = venc_get_property(sd, arg);
+ break;
+ case GET_BUFFER_REQ:
+ rc = venc_get_buffer_req(sd, arg);
+ break;
+ case SET_BUFFER_REQ:
+ rc = venc_set_buffer_req(sd, arg);
+ break;
+ case FREE_BUFFER:
+ break;
+ case FILL_OUTPUT_BUFFER:
+ rc = venc_fill_outbuf(sd, arg);
+ break;
+ case SET_FORMAT:
+ rc = venc_set_format(sd, arg);
+ break;
+ case SET_FRAMERATE:
+ rc = venc_set_framerate(sd, arg);
+ break;
+ case ALLOC_INPUT_BUFFER:
+ rc = venc_alloc_input_buffer(sd, arg);
+ break;
+ case SET_OUTPUT_BUFFER:
+ rc = venc_set_output_buffer(sd, arg);
+ break;
+ case ALLOC_RECON_BUFFERS:
+ rc = venc_alloc_recon_buffers(sd, arg);
+ break;
+ case FREE_OUTPUT_BUFFER:
+ rc = venc_free_output_buffer(sd, arg);
+ break;
+ case FREE_INPUT_BUFFER:
+ rc = venc_free_input_buffer(sd, arg);
+ break;
+ case FREE_RECON_BUFFERS:
+ rc = venc_free_recon_buffers(sd, arg);
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+ return rc;
+}
diff --git a/drivers/media/video/msm/wfd/enc-subdev.h b/drivers/media/video/msm/wfd/enc-subdev.h
new file mode 100644
index 0000000..890c973
--- /dev/null
+++ b/drivers/media/video/msm/wfd/enc-subdev.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-core.h>
+#define VENC_MAGIC_IOCTL 'V'
+
+struct mem_region {
+ struct list_head list;
+ u8 *kvaddr;
+ u8 *paddr;
+ u32 size;
+ u32 offset;
+ u32 fd;
+ u32 cookie;
+};
+struct bufreq {
+ u32 count;
+ u32 height;
+ u32 width;
+ u32 size;
+};
+struct venc_msg_ops {
+ void *cookie;
+ void *cbdata;
+ void (*op_buffer_done)(void *cookie, u32 status,
+ struct vb2_buffer *buf);
+ void (*ip_buffer_done)(void *cookie, u32 status,
+ struct mem_region *mregion);
+};
+
+#define OPEN _IOR('V', 1, void *)
+#define CLOSE _IO('V', 2)
+#define ENCODE_START _IO('V', 3)
+#define ENCODE_FRAME _IO('V', 4)
+#define PAUSE _IO('V', 5)
+#define RESUME _IO('V', 6)
+#define FLUSH _IO('V', 7)
+#define ENCODE_STOP _IO('V', 8)
+#define SET_PROP _IO('V', 9)
+#define GET_PROP _IO('V', 10)
+#define SET_BUFFER_REQ _IOWR('V', 11, struct v4l2_requestbuffers *)
+#define GET_BUFFER_REQ _IOWR('V', 12, struct v4l2_requestbuffers *)
+#define ALLOCATE_BUFFER _IO('V', 13)
+#define FREE_BUFFER _IO('V', 14)
+#define FILL_OUTPUT_BUFFER _IO('V', 15)
+#define SET_FORMAT _IOW('V', 16, struct v4l2_format *)
+#define SET_FRAMERATE _IOW('V', 17, struct v4l2_fract *)
+#define ALLOC_INPUT_BUFFER _IOWR('V', 18, struct mem_region *)
+#define SET_OUTPUT_BUFFER _IOWR('V', 19, struct mem_region *)
+#define ALLOC_RECON_BUFFERS _IO('V', 20)
+#define FREE_OUTPUT_BUFFER _IOWR('V', 21, struct mem_region *)
+#define FREE_INPUT_BUFFER _IOWR('V', 22, struct mem_region *)
+#define FREE_RECON_BUFFERS _IO('V', 23)
+
+extern int venc_init(struct v4l2_subdev *sd, u32 val);
+extern int venc_load_fw(struct v4l2_subdev *sd);
+extern long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/msm/wfd/mdp-subdev.c b/drivers/media/video/msm/wfd/mdp-subdev.c
index ed72ca8..9fd8a8e 100644
--- a/drivers/media/video/msm/wfd/mdp-subdev.c
+++ b/drivers/media/video/msm/wfd/mdp-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -67,6 +67,11 @@
int rc = 0;
struct fb_info *fbi = NULL;
if (inst) {
+ rc = msm_fb_writeback_start(inst->mdp);
+ if (rc) {
+ WFD_MSG_ERR("Failed to start MDP mode\n");
+ goto exit;
+ }
fbi = msm_fb_get_writeback_fb();
if (!fbi) {
WFD_MSG_ERR("Failed to acquire mdp instance\n");
@@ -86,6 +91,11 @@
int rc = 0;
struct fb_info *fbi = NULL;
if (inst) {
+ rc = msm_fb_writeback_stop(inst->mdp);
+ if (rc) {
+ WFD_MSG_ERR("Failed to stop writeback mode\n");
+ return rc;
+ }
fbi = (struct fb_info *)inst->mdp;
rc = kobject_uevent(&fbi->dev->kobj, KOBJ_OFFLINE);
if (rc) {
@@ -112,16 +122,17 @@
struct mdp_buf_info *binfo = arg;
struct msmfb_data fbdata;
struct mdp_instance *inst;
- if (!binfo || !binfo->inst || !binfo->b) {
+ if (!binfo || !binfo->inst || !binfo->cookie) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
inst = binfo->inst;
fbdata.offset = binfo->offset;
fbdata.memory_id = binfo->fd;
+ fbdata.iova = binfo->paddr;
fbdata.id = 0;
fbdata.flags = 0;
- fbdata.priv = (uint32_t)binfo->b;
+ fbdata.priv = (uint32_t)binfo->cookie;
WFD_MSG_INFO("queue buffer to mdp with offset = %u,"
"fd = %u, priv = %u\n",
@@ -150,45 +161,9 @@
WFD_MSG_ERR("Failed to dequeue buffer\n");
return rc;
}
- WFD_MSG_INFO("dequeue buffer from mdp with offset = %u,"
- "fd = %u, priv = %u\n",
- fbdata.offset, fbdata.memory_id, fbdata.priv);
- obuf->b = (struct vb2_buffer *)fbdata.priv;
- return rc;
-}
-int mdp_prepare_buffer(struct v4l2_subdev *sd, void *arg)
-{
- int rc = 0;
- struct mdp_buf_info *binfo = arg;
- struct msmfb_writeback_data wbdata;
- struct mdp_instance *inst;
-
- if (!binfo || !binfo->inst || !binfo->b) {
- WFD_MSG_ERR("Invalid argument\n");
- return -EINVAL;
- }
-
- inst = binfo->inst;
- wbdata.buf_info.offset = binfo->offset;
- wbdata.buf_info.memory_id = binfo->fd;
- wbdata.buf_info.id = 0;
- wbdata.buf_info.flags = 0;
- wbdata.buf_info.priv = (uint32_t)binfo->b;
-
- wbdata.img.width = inst->width;
- wbdata.img.height = inst->height;
- wbdata.img.format = MDP_RGB_565;
- WFD_MSG_DBG("offset = %u, fd = %u, width = %u, height = %u,"
- "uaddr = %u\n", wbdata.buf_info.offset,
- wbdata.buf_info.memory_id,
- wbdata.img.width, wbdata.img.height,
- wbdata.buf_info.priv);
-
- rc = msm_fb_writeback_register_buffer(inst->mdp, &wbdata);
- if (rc) {
- WFD_MSG_ERR("Failed to register buffer\n");
- return -EIO;
- }
+ WFD_MSG_DBG("dequeue buf from mdp with priv = %u\n",
+ fbdata.priv);
+ obuf->cookie = (void *)fbdata.priv;
return rc;
}
int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
@@ -203,34 +178,6 @@
inst->width = prop->width;
return 0;
}
-int mdp_release_buffer(struct v4l2_subdev *sd, void *arg)
-{
- int rc = 0;
- struct mdp_buf_info *binfo = arg;
- struct msmfb_writeback_data wbdata;
- struct mdp_instance *inst;
- if (!binfo || !binfo->inst || !binfo->b) {
- WFD_MSG_ERR("Invalid argument\n");
- return -EINVAL;
- }
- inst = binfo->inst;
-
- wbdata.buf_info.offset = binfo->offset;
- wbdata.buf_info.memory_id = binfo->fd;
- wbdata.buf_info.id = 0;
- wbdata.buf_info.flags = 0;
- wbdata.buf_info.priv = (uint32_t)binfo->b;
-
- wbdata.img.width = inst->width;
- wbdata.img.height = inst->height;
- wbdata.img.format = MDP_RGB_565;
-
- rc = msm_fb_writeback_unregister_buffer(inst->mdp, &wbdata);
-
- if (rc)
- WFD_MSG_ERR("Failed to unregister buffer\n");
- return rc;
-}
long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
int rc = 0;
@@ -245,9 +192,6 @@
case MDP_DQ_BUFFER:
rc = mdp_dq_buffer(sd, arg);
break;
- case MDP_PREPARE_BUF:
- rc = mdp_prepare_buffer(sd, arg);
- break;
case MDP_OPEN:
rc = mdp_open(sd, arg);
break;
@@ -260,9 +204,6 @@
case MDP_SET_PROP:
rc = mdp_set_prop(sd, arg);
break;
- case MDP_RELEASE_BUF:
- rc = mdp_release_buffer(sd, arg);
- break;
case MDP_CLOSE:
rc = mdp_close(sd, arg);
break;
diff --git a/drivers/media/video/msm/wfd/mdp-subdev.h b/drivers/media/video/msm/wfd/mdp-subdev.h
index fe8963a..a6b3bc4 100644
--- a/drivers/media/video/msm/wfd/mdp-subdev.h
+++ b/drivers/media/video/msm/wfd/mdp-subdev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,9 +18,11 @@
struct mdp_buf_info {
void *inst;
- struct vb2_buffer *b;
+ void *cookie;
u32 fd;
u32 offset;
+ u32 kvaddr;
+ u32 paddr;
};
struct mdp_prop {
@@ -30,12 +32,10 @@
};
#define MDP_Q_BUFFER _IOW(MDP_MAGIC_IOCTL, 1, struct mdp_buf_info *)
#define MDP_DQ_BUFFER _IOR(MDP_MAGIC_IOCTL, 2, struct mdp_out_buf *)
-#define MDP_PREPARE_BUF _IOW(MDP_MAGIC_IOCTL, 3, struct mdp_buf_info *)
-#define MDP_OPEN _IOR(MDP_MAGIC_IOCTL, 4, void **)
-#define MDP_SET_PROP _IOW(MDP_MAGIC_IOCTL, 5, struct mdp_prop *)
-#define MDP_RELEASE_BUF _IOW(MDP_MAGIC_IOCTL, 6, struct mdp_buf_info *)
-#define MDP_CLOSE _IOR(MDP_MAGIC_IOCTL, 7, void *)
-#define MDP_START _IOR(MDP_MAGIC_IOCTL, 8, void *)
-#define MDP_STOP _IOR(MDP_MAGIC_IOCTL, 9, void *)
+#define MDP_OPEN _IOR(MDP_MAGIC_IOCTL, 3, void **)
+#define MDP_SET_PROP _IOW(MDP_MAGIC_IOCTL, 4, struct mdp_prop *)
+#define MDP_CLOSE _IOR(MDP_MAGIC_IOCTL, 5, void *)
+#define MDP_START _IOR(MDP_MAGIC_IOCTL, 6, void *)
+#define MDP_STOP _IOR(MDP_MAGIC_IOCTL, 7, void *)
extern int mdp_init(struct v4l2_subdev *sd, u32 val);
extern long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 9db5b54..27a8888 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -30,17 +30,20 @@
#include <media/videobuf2-msm-mem.h>
#include "wfd-util.h"
#include "mdp-subdev.h"
+#include "enc-subdev.h"
#define WFD_VERSION KERNEL_VERSION(0, 0, 1)
#define DEFAULT_WFD_WIDTH 640
#define DEFAULT_WFD_HEIGHT 480
#define MIN_BUF_COUNT 2
+#define VENC_INPUT_BUFFERS 3
struct wfd_device {
struct platform_device *pdev;
struct v4l2_device v4l2_dev;
struct video_device *pvdev;
struct v4l2_subdev mdp_sdev;
+ struct v4l2_subdev enc_sdev;
};
struct mem_info {
@@ -48,18 +51,27 @@
u32 offset;
};
+struct mem_info_entry {
+ struct list_head list;
+ unsigned long userptr;
+ struct mem_info minfo;
+};
struct wfd_inst {
struct vb2_queue vid_bufq;
- spinlock_t buflock;
spinlock_t inst_lock;
u32 buf_count;
struct task_struct *mdp_task;
void *mdp_inst;
+ void *venc_inst;
u32 height;
u32 width;
u32 pixelformat;
- struct mem_info **minfo;
+ struct list_head minfo_list;
bool streamoff;
+ u32 input_bufs_allocated;
+ u32 input_buf_size;
+ u32 out_buf_size;
+ struct list_head input_mem_list;
};
struct wfd_vid_buffer {
@@ -70,15 +82,22 @@
unsigned int *num_buffers, unsigned int *num_planes,
unsigned long sizes[], void *alloc_ctxs[])
{
- WFD_MSG_DBG("In %s\n", __func__);
+ struct file *priv_data = (struct file *)(q->drv_priv);
+ struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ unsigned long flags;
+ int i;
+ WFD_MSG_DBG("In %s\n", __func__);
if (num_buffers == NULL || num_planes == NULL)
return -EINVAL;
*num_planes = 1;
- /*MDP outputs in RGB for now;i
- * make sure it's smaller than VIDEO_MAX_PLANES*/
- sizes[0] = 800*480*2;
+ spin_lock_irqsave(&inst->inst_lock, flags);
+ for (i = 0; i < *num_planes; ++i) {
+ sizes[i] = inst->out_buf_size;
+ alloc_ctxs[i] = inst;
+ }
+ spin_unlock_irqrestore(&inst->inst_lock, flags);
return 0;
}
@@ -90,6 +109,135 @@
{
}
+int wfd_allocate_input_buffers(struct wfd_device *wfd_dev,
+ struct wfd_inst *inst)
+{
+ int i;
+ struct mem_region *mregion;
+ int rc;
+ unsigned long flags;
+ struct mdp_buf_info buf = {0};
+ spin_lock_irqsave(&inst->inst_lock, flags);
+ if (inst->input_bufs_allocated) {
+ spin_unlock_irqrestore(&inst->inst_lock, flags);
+ return 0;
+ }
+ inst->input_bufs_allocated = true;
+ spin_unlock_irqrestore(&inst->inst_lock, flags);
+
+ for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
+ mregion = kzalloc(sizeof(struct mem_region), GFP_KERNEL);
+ mregion->size = inst->input_buf_size;
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ALLOC_INPUT_BUFFER, (void *)mregion);
+ if (rc) {
+ WFD_MSG_ERR("Failed to allocate input memory."
+ " This error causes memory leak!!!\n");
+ break;
+ }
+ WFD_MSG_DBG("NOTE: paddr = %p, kvaddr = %p\n", mregion->paddr,
+ mregion->kvaddr);
+ list_add_tail(&mregion->list, &inst->input_mem_list);
+ buf.inst = inst->mdp_inst;
+ buf.cookie = mregion;
+ buf.kvaddr = (u32) mregion->kvaddr;
+ buf.paddr = (u32) mregion->paddr;
+ rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+ MDP_Q_BUFFER, (void *)&buf);
+ if (rc) {
+ WFD_MSG_ERR("Unable to queue the buffer to mdp\n");
+ break;
+ }
+ }
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ALLOC_RECON_BUFFERS, NULL);
+ if (rc)
+ WFD_MSG_ERR("Failed to allocate recon buffers\n");
+
+ return rc;
+}
+void wfd_free_input_buffers(struct wfd_device *wfd_dev,
+ struct wfd_inst *inst)
+{
+ struct list_head *ptr, *next;
+ struct mem_region *mregion;
+ unsigned long flags;
+ int rc = 0;
+ spin_lock_irqsave(&inst->inst_lock, flags);
+ if (!inst->input_bufs_allocated) {
+ spin_unlock_irqrestore(&inst->inst_lock, flags);
+ return;
+ }
+ inst->input_bufs_allocated = false;
+ spin_unlock_irqrestore(&inst->inst_lock, flags);
+ if (!list_empty(&inst->input_mem_list)) {
+ list_for_each_safe(ptr, next,
+ &inst->input_mem_list) {
+ mregion = list_entry(ptr, struct mem_region,
+ list);
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev,
+ core, ioctl, FREE_INPUT_BUFFER,
+ (void *)mregion);
+ if (rc)
+ WFD_MSG_ERR("TODO: SOMETHING IS WRONG!!!\n");
+
+ list_del(&mregion->list);
+ kfree(mregion);
+ }
+ }
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ FREE_RECON_BUFFERS, NULL);
+ if (rc)
+ WFD_MSG_ERR("Failed to free recon buffers\n");
+}
+
+struct mem_info *wfd_get_mem_info(struct wfd_inst *inst,
+ unsigned long userptr)
+{
+ struct mem_info_entry *temp;
+ struct mem_info *ret = NULL;
+ unsigned long flags;
+ spin_lock_irqsave(&inst->inst_lock, flags);
+ if (!list_empty(&inst->minfo_list)) {
+ list_for_each_entry(temp, &inst->minfo_list, list) {
+ if (temp && temp->userptr == userptr) {
+ ret = &temp->minfo;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&inst->inst_lock, flags);
+ return ret;
+}
+void wfd_put_mem_info(struct wfd_inst *inst,
+ struct mem_info *minfo)
+{
+ struct list_head *ptr, *next;
+ struct mem_info_entry *temp;
+ unsigned long flags;
+ spin_lock_irqsave(&inst->inst_lock, flags);
+ if (!list_empty(&inst->minfo_list)) {
+ list_for_each_safe(ptr, next,
+ &inst->minfo_list) {
+ temp = list_entry(ptr, struct mem_info_entry,
+ list);
+ if (temp && (&temp->minfo == minfo)) {
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&inst->inst_lock, flags);
+}
+static void wfd_unregister_out_buf(struct wfd_inst *inst,
+ struct mem_info *minfo)
+{
+ if (!minfo || !inst) {
+ WFD_MSG_ERR("Invalid arguments\n");
+ return;
+ }
+ wfd_put_mem_info(inst, minfo);
+}
int wfd_vidbuf_buf_init(struct vb2_buffer *vb)
{
int rc = 0;
@@ -98,20 +246,32 @@
struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
- struct mdp_buf_info buf = {
- inst->mdp_inst,
- vb,
- inst->minfo[vb->v4l2_buf.index]->fd,
- inst->minfo[vb->v4l2_buf.index]->offset
- };
+ struct mem_info *minfo = vb2_plane_cookie(vb, 0);
+ struct mem_region mregion;
+ mregion.fd = minfo->fd;
+ mregion.offset = minfo->offset;
+ mregion.cookie = (u32)vb;
+ /*TODO: should be fixed in kernel 3.2*/
+ mregion.size = inst->out_buf_size;
if (inst && !inst->vid_bufq.streaming) {
- rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
- ioctl, MDP_PREPARE_BUF, (void *)&buf);
- if (rc)
- WFD_MSG_ERR("Unable to prepare/register the buffer\n");
+ rc = wfd_allocate_input_buffers(wfd_dev, inst);
+ if (rc) {
+ WFD_MSG_ERR("Failed to allocate input buffers\n");
+ goto err;
+ }
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ SET_OUTPUT_BUFFER, (void *)&mregion);
+ if (rc) {
+ WFD_MSG_ERR("Failed to set output buffer\n");
+ goto free_input_bufs;
+ }
}
return rc;
+free_input_bufs:
+ wfd_free_input_buffers(wfd_dev, inst);
+err:
+ return rc;
}
int wfd_vidbuf_buf_prepare(struct vb2_buffer *vb)
@@ -132,17 +292,48 @@
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
- struct mdp_buf_info buf = {
- inst->mdp_inst,
- vb,
- inst->minfo[vb->v4l2_buf.index]->fd,
- inst->minfo[vb->v4l2_buf.index]->offset
- };
- WFD_MSG_DBG("Releasing buffer\n");
- rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
- MDP_RELEASE_BUF, (void *)&buf);
+ struct mem_info *minfo = vb2_plane_cookie(vb, 0);
+ struct mem_region mregion;
+ mregion.fd = minfo->fd;
+ mregion.offset = minfo->offset;
+ mregion.cookie = (u32)vb;
+ mregion.size = inst->out_buf_size;
+
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ FREE_OUTPUT_BUFFER, (void *)&mregion);
if (rc)
- WFD_MSG_ERR("Failed to release the buffer\n");
+ WFD_MSG_ERR("Failed to free output buffer\n");
+ wfd_unregister_out_buf(inst, minfo);
+ wfd_free_input_buffers(wfd_dev, inst);
+}
+static int mdp_output_thread(void *data)
+{
+ int rc = 0;
+ struct file *filp = (struct file *)data;
+ struct wfd_inst *inst = filp->private_data;
+ struct wfd_device *wfd_dev =
+ (struct wfd_device *)video_drvdata(filp);
+ struct mdp_buf_info obuf = {inst->mdp_inst, 0, 0, 0};
+ while (!kthread_should_stop()) {
+ WFD_MSG_DBG("waiting for mdp output\n");
+ rc = v4l2_subdev_call(&wfd_dev->mdp_sdev,
+ core, ioctl, MDP_DQ_BUFFER, (void *)&obuf);
+
+ if (rc) {
+ WFD_MSG_ERR("Either streamoff called or"
+ " MDP REPORTED ERROR\n");
+ break;
+ }
+
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ENCODE_FRAME, obuf.cookie);
+ if (rc) {
+ WFD_MSG_ERR("Failed to encode frame\n");
+ break;
+ }
+ }
+ WFD_MSG_DBG("Exiting the thread\n");
+ return rc;
}
int wfd_vidbuf_start_streaming(struct vb2_queue *q)
@@ -152,11 +343,25 @@
(struct wfd_device *)video_drvdata(priv_data);
struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
int rc = 0;
+
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ENCODE_START, (void *)inst->venc_inst);
+ if (rc) {
+ WFD_MSG_ERR("Failed to start encoder\n");
+ goto err;
+ }
+
+ inst->mdp_task = kthread_run(mdp_output_thread, priv_data,
+ "mdp_output_thread");
+ if (IS_ERR(inst->mdp_task)) {
+ rc = PTR_ERR(inst->mdp_task);
+ goto err;
+ }
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_START, (void *)inst->mdp_inst);
if (rc)
WFD_MSG_ERR("Failed to start MDP\n");
-
+err:
return rc;
}
@@ -172,6 +377,12 @@
if (rc)
WFD_MSG_ERR("Failed to stop MDP\n");
+ kthread_stop(inst->mdp_task);
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ENCODE_STOP, (void *)inst->venc_inst);
+ if (rc)
+ WFD_MSG_ERR("Failed to stop encoder\n");
+
return rc;
}
@@ -183,18 +394,17 @@
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
- struct mdp_buf_info buf = {
- inst->mdp_inst,
- vb,
- inst->minfo[vb->v4l2_buf.index]->fd,
- inst->minfo[vb->v4l2_buf.index]->offset
- };
-
- WFD_MSG_DBG("Inside wfd_vidbuf_queue\n");
- rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
- MDP_Q_BUFFER, (void *)&buf);
- if (rc)
- WFD_MSG_ERR("Failed to call fill this buffer\n");
+ struct mem_region mregion;
+ struct mem_info *minfo = vb2_plane_cookie(vb, 0);
+ mregion.fd = minfo->fd;
+ mregion.offset = minfo->offset;
+ mregion.cookie = (u32)vb;
+ mregion.size = inst->out_buf_size;
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ FILL_OUTPUT_BUFFER, (void *)&mregion);
+ if (rc) {
+ WFD_MSG_ERR("Failed to fill output buffer\n");
+ }
}
static struct vb2_ops wfd_vidbuf_ops = {
@@ -212,16 +422,27 @@
.stop_streaming = wfd_vidbuf_stop_streaming,
.buf_queue = wfd_vidbuf_buf_queue,
-
};
static const struct v4l2_subdev_core_ops mdp_subdev_core_ops = {
.init = mdp_init,
.ioctl = mdp_ioctl,
};
+
static const struct v4l2_subdev_ops mdp_subdev_ops = {
.core = &mdp_subdev_core_ops,
};
+
+static const struct v4l2_subdev_core_ops enc_subdev_core_ops = {
+ .init = venc_init,
+ .load_fw = venc_load_fw,
+ .ioctl = venc_ioctl,
+};
+
+static const struct v4l2_subdev_ops enc_subdev_ops = {
+ .core = &enc_subdev_core_ops,
+}
+;
static int wfdioc_querycap(struct file *filp, void *fh,
struct v4l2_capability *cap) {
WFD_MSG_DBG("wfdioc_querycap: E\n");
@@ -250,12 +471,7 @@
fmt->fmt.pix.width = inst->width;
fmt->fmt.pix.height = inst->height;
fmt->fmt.pix.pixelformat = inst->pixelformat;
- fmt->fmt.pix.sizeimage = inst->width * inst->height * 2;
- fmt->fmt.pix.bytesperline = inst->width * 2; /*TODO: Needs
- discussion */
- fmt->fmt.pix.field = V4L2_FIELD_NONE;
- fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; /*TODO: Needs
- discussion*/
+ fmt->fmt.pix.sizeimage = inst->out_buf_size;
fmt->fmt.pix.priv = 0;
spin_unlock_irqrestore(&inst->inst_lock, flags);
return 0;
@@ -268,126 +484,124 @@
struct wfd_device *wfd_dev = video_drvdata(filp);
struct mdp_prop prop;
unsigned long flags;
+ struct bufreq breq;
if (!fmt) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
-
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_RGB565) {
+ fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_NV12) {
WFD_MSG_ERR("Only V4L2_BUF_TYPE_VIDEO_CAPTURE and "
- "V4L2_PIX_FMT_RGB565 are supported\n");
+ "V4L2_PIX_FMT_NV12 are supported\n");
return -EINVAL;
}
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, SET_FORMAT,
+ (void *)fmt);
+ if (rc) {
+ WFD_MSG_ERR("Failed to set format on encoder, rc = %d\n", rc);
+ goto err;
+ }
+ breq.count = VENC_INPUT_BUFFERS;
+ breq.height = fmt->fmt.pix.height;
+ breq.width = fmt->fmt.pix.width;
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ SET_BUFFER_REQ, (void *)&breq);
+ if (rc) {
+ WFD_MSG_ERR("Failed to set buffer reqs on encoder\n");
+ goto err;
+ }
spin_lock_irqsave(&inst->inst_lock, flags);
+ inst->input_buf_size = breq.size;
+ inst->out_buf_size = fmt->fmt.pix.sizeimage;
prop.height = inst->height = fmt->fmt.pix.height;
prop.width = inst->width = fmt->fmt.pix.width;
prop.inst = inst->mdp_inst;
- fmt->fmt.pix.sizeimage = inst->height * inst->width * 2;
- fmt->fmt.pix.field = V4L2_FIELD_NONE;
- fmt->fmt.pix.bytesperline = inst->width * 2; /*TODO: Needs
- discussion */
- fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; /*TODO: Needs
- discussion*/
spin_unlock_irqrestore(&inst->inst_lock, flags);
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_SET_PROP,
(void *)&prop);
if (rc)
WFD_MSG_ERR("Failed to set height/width property on mdp\n");
+err:
return rc;
}
static int wfdioc_reqbufs(struct file *filp, void *fh,
struct v4l2_requestbuffers *b)
{
- int rc = 0;
struct wfd_inst *inst = filp->private_data;
+ struct wfd_device *wfd_dev = video_drvdata(filp);
unsigned long flags;
- int i;
+ int rc = 0;
+
if (b->type != V4L2_CAP_VIDEO_CAPTURE ||
b->memory != V4L2_MEMORY_USERPTR) {
WFD_MSG_ERR("Only V4L2_CAP_VIDEO_CAPTURE and "
- "V4L2_CAP_VIDEO_CAPTURE are supported\n");
+ "V4L2_MEMORY_USERPTR are supported\n");
return -EINVAL;
}
- if (b->count < MIN_BUF_COUNT)
- b->count = MIN_BUF_COUNT;
- spin_lock_irqsave(&inst->inst_lock, flags);
- if (inst->minfo) {
- for (i = 0; i < inst->buf_count; ++i)
- kfree(inst->minfo[i]);
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ GET_BUFFER_REQ, (void *)b);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get buf reqs from encoder\n");
+ goto err;
}
- kfree(inst->minfo);
+ spin_lock_irqsave(&inst->inst_lock, flags);
inst->buf_count = b->count;
- inst->minfo = kzalloc(sizeof(struct mem_info *) * inst->buf_count,
- GFP_KERNEL);
- for (i = 0; i < inst->buf_count; ++i)
- inst->minfo[i] = kzalloc(sizeof(struct mem_info), GFP_KERNEL);
spin_unlock_irqrestore(&inst->inst_lock, flags);
rc = vb2_reqbufs(&inst->vid_bufq, b);
- if (rc) {
- WFD_MSG_ERR("Failed in videobuf_reqbufs, rc = %d\n", rc);
- spin_lock_irqsave(&inst->inst_lock, flags);
- if (inst->minfo) {
- for (i = 0; i < inst->buf_count; ++i)
- kfree(inst->minfo[i]);
- }
- kfree(inst->minfo);
- inst->minfo = NULL;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
- }
+err:
return rc;
}
+static int wfd_register_out_buf(struct wfd_inst *inst,
+ struct v4l2_buffer *b)
+{
+ struct mem_info_entry *minfo_entry;
+ struct mem_info *minfo;
+ unsigned long flags;
+ if (!b || !inst || !b->reserved) {
+ WFD_MSG_ERR("Invalid arguments\n");
+ return -EINVAL;
+ }
+ minfo = wfd_get_mem_info(inst, b->m.userptr);
+ if (!minfo) {
+ minfo_entry = kzalloc(sizeof(struct mem_info_entry),
+ GFP_KERNEL);
+ if (copy_from_user(&minfo_entry->minfo, (void *)b->reserved,
+ sizeof(struct mem_info))) {
+ WFD_MSG_ERR(" copy_from_user failed. Populate"
+ " v4l2_buffer->reserved with meminfo\n");
+ return -EINVAL;
+ }
+ minfo_entry->userptr = b->m.userptr;
+ spin_lock_irqsave(&inst->inst_lock, flags);
+ list_add_tail(&minfo_entry->list, &inst->minfo_list);
+ spin_unlock_irqrestore(&inst->inst_lock, flags);
+ } else
+ WFD_MSG_INFO("Buffer already registered\n");
+
+ return 0;
+}
static int wfdioc_qbuf(struct file *filp, void *fh,
struct v4l2_buffer *b)
{
int rc = 0;
struct wfd_inst *inst = filp->private_data;
-
- if (!inst || !b || !b->reserved ||
+ if (!inst || !b ||
(b->index < 0 || b->index >= inst->buf_count)) {
WFD_MSG_ERR("Invalid input parameters to QBUF IOCTL\n");
return -EINVAL;
}
- if (!inst->vid_bufq.streaming) {
- if (copy_from_user(inst->minfo[b->index], (void *)b->reserved,
- sizeof(struct mem_info))) {
- WFD_MSG_ERR(" copy_from_user failed. Populate"
- " v4l2_buffer->reserved with meminfo\n");
- return -EINVAL;
- }
+ rc = wfd_register_out_buf(inst, b);
+ if (rc) {
+ WFD_MSG_ERR("Failed to register buffer\n");
+ goto err;
}
rc = vb2_qbuf(&inst->vid_bufq, b);
if (rc)
WFD_MSG_ERR("Failed to queue buffer\n");
+err:
return rc;
}
-static int mdp_output_thread(void *data)
-{
- int rc = 0;
- struct file *filp = (struct file *)data;
- struct wfd_inst *inst = filp->private_data;
- struct wfd_device *wfd_dev =
- (struct wfd_device *)video_drvdata(filp);
- struct vb2_buffer *vbuf = NULL;
- struct mdp_buf_info obuf = {inst->mdp_inst, vbuf, 0, 0};
- while (!kthread_should_stop()) {
- rc = v4l2_subdev_call(&wfd_dev->mdp_sdev,
- core, ioctl, MDP_DQ_BUFFER, (void *)&obuf);
- if (rc) {
- WFD_MSG_ERR("Either streamoff called or"
- " MDP REPORTED ERROR\n");
- break;
- } else
- WFD_MSG_DBG("Dequeued buffer successfully\n");
-
- vbuf = obuf.b;
- vb2_buffer_done(vbuf,
- rc ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
- }
- WFD_MSG_DBG("Exiting the thread\n");
- return rc;
-}
static int wfdioc_streamon(struct file *filp, void *fh,
enum v4l2_buf_type i)
{
@@ -403,22 +617,16 @@
spin_lock_irqsave(&inst->inst_lock, flags);
inst->streamoff = false;
spin_unlock_irqrestore(&inst->inst_lock, flags);
- /*TODO: Do we need to lock the instance here*/
+
rc = vb2_streamon(&inst->vid_bufq, i);
if (rc) {
WFD_MSG_ERR("videobuf_streamon failed with err = %d\n", rc);
goto vidbuf_streamon_failed;
}
- inst->mdp_task = kthread_run(mdp_output_thread, filp,
- "mdp_output_thread");
- if (IS_ERR(inst->mdp_task)) {
- rc = PTR_ERR(inst->mdp_task);
- goto mdp_task_failed;
- }
return rc;
-mdp_task_failed:
- vb2_streamoff(&inst->vid_bufq, i);
+
vidbuf_streamon_failed:
+ vb2_streamoff(&inst->vid_bufq, i);
return rc;
}
static int wfdioc_streamoff(struct file *filp, void *fh,
@@ -441,8 +649,6 @@
}
WFD_MSG_DBG("Calling videobuf_streamoff\n");
vb2_streamoff(&inst->vid_bufq, i);
- vb2_queue_release(&inst->vid_bufq);
- kthread_stop(inst->mdp_task);
return 0;
}
static int wfdioc_dqbuf(struct file *filp, void *fh,
@@ -452,6 +658,28 @@
WFD_MSG_INFO("Waiting to dequeue buffer\n");
return vb2_dqbuf(&inst->vid_bufq, b, 0);
}
+static int wfdioc_g_ctrl(struct file *filp, void *fh,
+ struct v4l2_control *a)
+{
+ int rc = 0;
+ struct wfd_device *wfd_dev = video_drvdata(filp);
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+ ioctl, GET_PROP, a);
+ if (rc)
+ WFD_MSG_ERR("Failed to get encoder property\n");
+ return rc;
+}
+static int wfdioc_s_ctrl(struct file *filp, void *fh,
+ struct v4l2_control *a)
+{
+ int rc = 0;
+ struct wfd_device *wfd_dev = video_drvdata(filp);
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+ ioctl, SET_PROP, a);
+ if (rc)
+ WFD_MSG_ERR("Failed to set encoder property\n");
+ return rc;
+}
static const struct v4l2_ioctl_ops g_wfd_ioctl_ops = {
.vidioc_querycap = wfdioc_querycap,
.vidioc_s_fmt_vid_cap = wfdioc_s_fmt,
@@ -461,36 +689,106 @@
.vidioc_streamon = wfdioc_streamon,
.vidioc_streamoff = wfdioc_streamoff,
.vidioc_dqbuf = wfdioc_dqbuf,
+ .vidioc_g_ctrl = wfdioc_g_ctrl,
+ .vidioc_s_ctrl = wfdioc_s_ctrl,
+
};
-static int wfd_set_default_properties(struct wfd_inst *inst)
+static int wfd_set_default_properties(struct file *filp)
{
unsigned long flags;
+ struct v4l2_format fmt;
+ struct wfd_inst *inst = filp->private_data;
if (!inst) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
spin_lock_irqsave(&inst->inst_lock, flags);
- inst->height = DEFAULT_WFD_HEIGHT;
- inst->width = DEFAULT_WFD_WIDTH;
- inst->pixelformat = V4L2_PIX_FMT_RGB565;
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.height = inst->height = DEFAULT_WFD_HEIGHT;
+ fmt.fmt.pix.width = inst->width = DEFAULT_WFD_WIDTH;
+ fmt.fmt.pix.pixelformat = inst->pixelformat
+ = V4L2_PIX_FMT_NV12;
spin_unlock_irqrestore(&inst->inst_lock, flags);
+ wfdioc_s_fmt(filp, filp->private_data, &fmt);
return 0;
}
+void venc_op_buffer_done(void *cookie, u32 status,
+ struct vb2_buffer *buf)
+{
+ WFD_MSG_DBG("yay!! got callback\n");
+ vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
+}
+void venc_ip_buffer_done(void *cookie, u32 status,
+ struct mem_region *mregion)
+{
+ struct file *filp = cookie;
+ struct wfd_inst *inst = filp->private_data;
+ struct mdp_buf_info buf = {0};
+ struct wfd_device *wfd_dev =
+ (struct wfd_device *)video_drvdata(filp);
+ int rc = 0;
+ WFD_MSG_DBG("yay!! got ip callback\n");
+ buf.inst = inst->mdp_inst;
+ buf.cookie = mregion;
+ buf.kvaddr = (u32) mregion->kvaddr;
+ buf.paddr = (u32) mregion->paddr;
+ rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
+ ioctl, MDP_Q_BUFFER, (void *)&buf);
+ if (rc)
+ WFD_MSG_ERR("Failed to Q buffer to mdp\n");
+
+}
+void *wfd_vb2_mem_ops_get_userptr(void *alloc_ctx, unsigned long vaddr,
+ unsigned long size, int write)
+{
+ return wfd_get_mem_info(alloc_ctx, vaddr);
+}
+
+void wfd_vb2_mem_ops_put_userptr(void *buf_priv)
+{
+ /*TODO: Free the list*/
+}
+
+void *wfd_vb2_mem_ops_cookie(void *buf_priv)
+{
+ return buf_priv;
+}
+
+
+static struct vb2_mem_ops wfd_vb2_mem_ops = {
+ .get_userptr = wfd_vb2_mem_ops_get_userptr,
+ .put_userptr = wfd_vb2_mem_ops_put_userptr,
+ .cookie = wfd_vb2_mem_ops_cookie,
+};
+
+int wfd_initialize_vb2_queue(struct vb2_queue *q, void *priv)
+{
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_USERPTR;
+ q->ops = &wfd_vidbuf_ops;
+ q->mem_ops = &wfd_vb2_mem_ops;
+ q->drv_priv = priv;
+ return vb2_queue_init(q);
+}
+
static int wfd_open(struct file *filp)
{
int rc = 0;
struct wfd_inst *inst;
struct wfd_device *wfd_dev;
+ struct venc_msg_ops vmops;
WFD_MSG_DBG("wfd_open: E\n");
+ wfd_dev = video_drvdata(filp);
inst = kzalloc(sizeof(struct wfd_inst), GFP_KERNEL);
- if (!inst) {
+ if (!inst || !wfd_dev) {
WFD_MSG_ERR("Could not allocate memory for "
"wfd instance\n");
return -ENOMEM;
}
+ filp->private_data = inst;
spin_lock_init(&inst->inst_lock);
- spin_lock_init(&inst->buflock);
- wfd_dev = video_drvdata(filp);
+ INIT_LIST_HEAD(&inst->input_mem_list);
+ INIT_LIST_HEAD(&inst->minfo_list);
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
(void *)&inst->mdp_inst);
if (rc) {
@@ -498,43 +796,55 @@
goto err_mdp_open;
}
- videobuf2_queue_pmem_contig_init(&inst->vid_bufq,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- &wfd_vidbuf_ops,
- sizeof(struct wfd_vid_buffer),
- filp); /*TODO: Check if it needs to be freed*/
- wfd_set_default_properties(inst);
- filp->private_data = inst;
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, load_fw);
+ if (rc) {
+ WFD_MSG_ERR("Failed to load video encoder firmware: %d\n", rc);
+ goto err_venc;
+ }
+ vmops.op_buffer_done = venc_op_buffer_done;
+ vmops.ip_buffer_done = venc_ip_buffer_done;
+ vmops.cbdata = filp;
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, OPEN,
+ (void *)&vmops);
+ if (rc || !vmops.cookie) {
+ WFD_MSG_ERR("Failed to open encoder subdevice: %d\n", rc);
+ goto err_venc;
+ }
+ inst->venc_inst = vmops.cookie;
+
+ wfd_initialize_vb2_queue(&inst->vid_bufq, filp);
+ wfd_set_default_properties(filp);
WFD_MSG_DBG("wfd_open: X\n");
return rc;
+err_venc:
+ v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+ MDP_CLOSE, (void *)inst->mdp_inst);
err_mdp_open:
kfree(inst);
return rc;
}
+
static int wfd_close(struct file *filp)
{
struct wfd_inst *inst;
struct wfd_device *wfd_dev;
int rc = 0;
- int k;
- unsigned long flags;
wfd_dev = video_drvdata(filp);
WFD_MSG_DBG("wfd_close: E\n");
inst = filp->private_data;
if (inst) {
wfdioc_streamoff(filp, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ vb2_queue_release(&inst->vid_bufq);
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_CLOSE, (void *)inst->mdp_inst);
if (rc)
WFD_MSG_ERR("Failed to CLOSE mdp subdevice: %d\n", rc);
- spin_lock_irqsave(&inst->inst_lock, flags);
- if (inst->minfo) {
- for (k = 0; k < inst->buf_count; ++k)
- kfree(inst->minfo[k]);
- }
- kfree(inst->minfo);
- inst->minfo = NULL;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ CLOSE, (void *)inst->venc_inst);
+ if (rc)
+ WFD_MSG_ERR("Failed to CLOSE enc subdev: %d\n", rc);
+
kfree(inst);
}
WFD_MSG_DBG("wfd_close: X\n");
@@ -555,7 +865,7 @@
int rc = 0;
struct wfd_device *wfd_dev;
WFD_MSG_DBG("__wfd_probe: E\n");
- wfd_dev = kzalloc(sizeof(*wfd_dev), GFP_KERNEL); /*TODO: Free it*/
+ wfd_dev = kzalloc(sizeof(*wfd_dev), GFP_KERNEL);
if (!wfd_dev) {
WFD_MSG_ERR("Could not allocate memory for "
"wfd device\n");
@@ -592,8 +902,28 @@
WFD_MSG_ERR("Failed to register mdp subdevice: %d\n", rc);
goto err_mdp_register_subdev;
}
+
+ v4l2_subdev_init(&wfd_dev->enc_sdev, &enc_subdev_ops);
+ strncpy(wfd_dev->enc_sdev.name, "wfd-venc", V4L2_SUBDEV_NAME_SIZE);
+ rc = v4l2_device_register_subdev(&wfd_dev->v4l2_dev,
+ &wfd_dev->enc_sdev);
+ if (rc) {
+ WFD_MSG_ERR("Failed to register encoder subdevice: %d\n", rc);
+ goto err_venc_register_subdev;
+ }
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, init, 0);
+ if (rc) {
+ WFD_MSG_ERR("Failed to initiate encoder device %d\n", rc);
+ goto err_venc_init;
+ }
+
WFD_MSG_DBG("__wfd_probe: X\n");
return rc;
+
+err_venc_init:
+ v4l2_device_unregister_subdev(&wfd_dev->enc_sdev);
+err_venc_register_subdev:
+ v4l2_device_unregister_subdev(&wfd_dev->mdp_sdev);
err_mdp_register_subdev:
video_unregister_device(wfd_dev->pvdev);
err_video_register_device:
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index fa7e3fd..37b935b 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Based on videobuf-dma-contig.c,
* (c) 2008 Magnus Damm
@@ -45,17 +45,51 @@
#define D(fmt, args...) do {} while (0)
#endif
-static int32_t msm_mem_allocate(const size_t size)
+static int32_t msm_mem_allocate(struct videobuf2_contig_pmem *mem)
{
int32_t phyaddr;
- phyaddr = allocate_contiguous_ebi_nomap(size, SZ_4K);
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ int rc, len;
+ mem->client = msm_ion_client_create(-1, "camera");
+ if (IS_ERR((void *)mem->client)) {
+ pr_err("%s Could not create client\n", __func__);
+ goto client_failed;
+ }
+ mem->ion_handle = ion_alloc(mem->client, mem->size, SZ_4K,
+ (0x1 << ION_CP_MM_HEAP_ID | 0x1 << ION_IOMMU_HEAP_ID));
+ if (IS_ERR((void *)mem->ion_handle)) {
+ pr_err("%s Could not allocate\n", __func__);
+ goto alloc_failed;
+ }
+ rc = ion_phys(mem->client, mem->ion_handle, (ion_phys_addr_t *)&phyaddr,
+ (size_t *)&len);
+ if (rc < 0) {
+ pr_err("%s Could not get physical address\n", __func__);
+ goto phys_failed;
+ }
+#else
+ phyaddr = allocate_contiguous_ebi_nomap(mem->size, SZ_4K);
+#endif
return phyaddr;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+phys_failed:
+ ion_free(mem->client, mem->ion_handle);
+alloc_failed:
+ ion_client_destroy(mem->client);
+client_failed:
+ return 0;
+#endif
}
-static int32_t msm_mem_free(const int32_t phyaddr)
+static int32_t msm_mem_free(struct videobuf2_contig_pmem *mem)
{
int32_t rc = 0;
- free_contiguous_memory_by_paddr(phyaddr);
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_free(mem->client, mem->ion_handle);
+ ion_client_destroy(mem->client);
+#else
+ free_contiguous_memory_by_paddr(mem->phyaddr);
+#endif
return rc;
}
@@ -92,7 +126,7 @@
mem->size = PAGE_ALIGN(size);
mem->alloc_ctx = alloc_ctx;
mem->is_userptr = 0;
- mem->phyaddr = msm_mem_allocate(mem->size);
+ mem->phyaddr = msm_mem_allocate(mem);
if (!mem->phyaddr) {
pr_err("%s : pmem memory allocation failed\n", __func__);
kfree(mem);
@@ -105,7 +139,7 @@
if (IS_ERR((void *)mem->msm_buffer)) {
pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
rc = PTR_ERR((void *)mem->msm_buffer);
- msm_mem_free(mem->phyaddr);
+ msm_mem_free(mem);
kfree(mem);
return ERR_PTR(-ENOMEM);
}
@@ -119,7 +153,7 @@
D("%s Freeing memory ", __func__);
if (msm_subsystem_unmap_buffer(mem->msm_buffer) < 0)
D("%s unmapped memory\n", __func__);
- msm_mem_free(mem->phyaddr);
+ msm_mem_free(mem);
}
kfree(mem);
}
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index c90ea16..8a9d289 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -21,6 +21,7 @@
#include <linux/msm_ssbi.h>
#include <linux/mfd/core.h>
#include <linux/mfd/pm8xxx/pm8038.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/regulator.h>
@@ -155,6 +156,63 @@
.num_resources = ARRAY_SIZE(adc_cell_resources),
};
+static const struct resource charger_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("USBIN_VALID_IRQ", PM8921_USBIN_VALID_IRQ),
+ SINGLE_IRQ_RESOURCE("USBIN_OV_IRQ", PM8921_USBIN_OV_IRQ),
+ SINGLE_IRQ_RESOURCE("BATT_INSERTED_IRQ", PM8921_BATT_INSERTED_IRQ),
+ SINGLE_IRQ_RESOURCE("VBATDET_LOW_IRQ", PM8921_VBATDET_LOW_IRQ),
+ SINGLE_IRQ_RESOURCE("USBIN_UV_IRQ", PM8921_USBIN_UV_IRQ),
+ SINGLE_IRQ_RESOURCE("VBAT_OV_IRQ", PM8921_VBAT_OV_IRQ),
+ SINGLE_IRQ_RESOURCE("CHGWDOG_IRQ", PM8921_CHGWDOG_IRQ),
+ SINGLE_IRQ_RESOURCE("VCP_IRQ", PM8921_VCP_IRQ),
+ SINGLE_IRQ_RESOURCE("ATCDONE_IRQ", PM8921_ATCDONE_IRQ),
+ SINGLE_IRQ_RESOURCE("ATCFAIL_IRQ", PM8921_ATCFAIL_IRQ),
+ SINGLE_IRQ_RESOURCE("CHGDONE_IRQ", PM8921_CHGDONE_IRQ),
+ SINGLE_IRQ_RESOURCE("CHGFAIL_IRQ", PM8921_CHGFAIL_IRQ),
+ SINGLE_IRQ_RESOURCE("CHGSTATE_IRQ", PM8921_CHGSTATE_IRQ),
+ SINGLE_IRQ_RESOURCE("LOOP_CHANGE_IRQ", PM8921_LOOP_CHANGE_IRQ),
+ SINGLE_IRQ_RESOURCE("FASTCHG_IRQ", PM8921_FASTCHG_IRQ),
+ SINGLE_IRQ_RESOURCE("TRKLCHG_IRQ", PM8921_TRKLCHG_IRQ),
+ SINGLE_IRQ_RESOURCE("BATT_REMOVED_IRQ", PM8921_BATT_REMOVED_IRQ),
+ SINGLE_IRQ_RESOURCE("BATTTEMP_HOT_IRQ", PM8921_BATTTEMP_HOT_IRQ),
+ SINGLE_IRQ_RESOURCE("CHGHOT_IRQ", PM8921_CHGHOT_IRQ),
+ SINGLE_IRQ_RESOURCE("BATTTEMP_COLD_IRQ", PM8921_BATTTEMP_COLD_IRQ),
+ SINGLE_IRQ_RESOURCE("CHG_GONE_IRQ", PM8921_CHG_GONE_IRQ),
+ SINGLE_IRQ_RESOURCE("BAT_TEMP_OK_IRQ", PM8921_BAT_TEMP_OK_IRQ),
+ SINGLE_IRQ_RESOURCE("COARSE_DET_LOW_IRQ", PM8921_COARSE_DET_LOW_IRQ),
+ SINGLE_IRQ_RESOURCE("VDD_LOOP_IRQ", PM8921_VDD_LOOP_IRQ),
+ SINGLE_IRQ_RESOURCE("VREG_OV_IRQ", PM8921_VREG_OV_IRQ),
+ SINGLE_IRQ_RESOURCE("VBATDET_IRQ", PM8921_VBATDET_IRQ),
+ SINGLE_IRQ_RESOURCE("BATFET_IRQ", PM8921_BATFET_IRQ),
+ SINGLE_IRQ_RESOURCE("PSI_IRQ", PM8921_PSI_IRQ),
+ SINGLE_IRQ_RESOURCE("DCIN_VALID_IRQ", PM8921_DCIN_VALID_IRQ),
+ SINGLE_IRQ_RESOURCE("DCIN_OV_IRQ", PM8921_DCIN_OV_IRQ),
+ SINGLE_IRQ_RESOURCE("DCIN_UV_IRQ", PM8921_DCIN_UV_IRQ),
+};
+
+static const struct resource bms_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("PM8921_BMS_SBI_WRITE_OK", PM8921_BMS_SBI_WRITE_OK),
+ SINGLE_IRQ_RESOURCE("PM8921_BMS_CC_THR", PM8921_BMS_CC_THR),
+ SINGLE_IRQ_RESOURCE("PM8921_BMS_VSENSE_THR", PM8921_BMS_VSENSE_THR),
+ SINGLE_IRQ_RESOURCE("PM8921_BMS_VSENSE_FOR_R", PM8921_BMS_VSENSE_FOR_R),
+ SINGLE_IRQ_RESOURCE("PM8921_BMS_OCV_FOR_R", PM8921_BMS_OCV_FOR_R),
+ SINGLE_IRQ_RESOURCE("PM8921_BMS_GOOD_OCV", PM8921_BMS_GOOD_OCV),
+ SINGLE_IRQ_RESOURCE("PM8921_BMS_VSENSE_AVG", PM8921_BMS_VSENSE_AVG),
+};
+
+static struct mfd_cell charger_cell __devinitdata = {
+ .name = PM8921_CHARGER_DEV_NAME,
+ .id = -1,
+ .resources = charger_cell_resources,
+ .num_resources = ARRAY_SIZE(charger_cell_resources),
+};
+
+static struct mfd_cell bms_cell __devinitdata = {
+ .name = PM8921_BMS_DEV_NAME,
+ .id = -1,
+ .resources = bms_cell_resources,
+ .num_resources = ARRAY_SIZE(bms_cell_resources),
+};
static const struct resource mpp_cell_resources[] __devinitconst = {
{
.start = PM8038_IRQ_BLOCK_BIT(PM8038_MPP_BLOCK_START, 0),
@@ -470,6 +528,39 @@
}
}
+ if (pdata->charger_pdata) {
+ pdata->charger_pdata->charger_cdata.vbat_channel = CHANNEL_VBAT;
+ pdata->charger_pdata->charger_cdata.batt_temp_channel
+ = CHANNEL_BATT_THERM;
+ pdata->charger_pdata->charger_cdata.batt_id_channel
+ = CHANNEL_BATT_ID;
+ charger_cell.platform_data = pdata->charger_pdata;
+ charger_cell.pdata_size =
+ sizeof(struct pm8921_charger_platform_data);
+ ret = mfd_add_devices(pmic->dev, 0, &charger_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add charger subdevice ret=%d\n", ret);
+ goto bail;
+ }
+ }
+
+ if (pdata->bms_pdata) {
+ pdata->bms_pdata->bms_cdata.batt_temp_channel
+ = CHANNEL_BATT_THERM;
+ pdata->bms_pdata->bms_cdata.vbat_channel = CHANNEL_VBAT;
+ pdata->bms_pdata->bms_cdata.ref625mv_channel = CHANNEL_625MV;
+ pdata->bms_pdata->bms_cdata.ref1p25v_channel = CHANNEL_125V;
+ pdata->bms_pdata->bms_cdata.batt_id_channel = CHANNEL_BATT_ID;
+ bms_cell.platform_data = pdata->bms_pdata;
+ bms_cell.pdata_size = sizeof(struct pm8921_bms_platform_data);
+ ret = mfd_add_devices(pmic->dev, 0, &bms_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add bms subdevice ret=%d\n", ret);
+ goto bail;
+ }
+ }
return 0;
bail:
if (pmic->irq_chip) {
diff --git a/drivers/mfd/timpani-codec.c b/drivers/mfd/timpani-codec.c
index d2c2eb4..4b9aef2 100644
--- a/drivers/mfd/timpani-codec.c
+++ b/drivers/mfd/timpani-codec.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -2819,7 +2819,7 @@
u8 reg_mask = 0;
int rc = 0;
- for (i = 0; i < 0xEF; i++) {
+ for (i = 0; i < ARRAY_SIZE(timpani_regset); i++) {
if (timpani_regset[i].reg_addr == reg) {
for (j = 0; j < TIMPANI_MAX_FIELDS; j++) {
fld_mask = timpani_regset[i].fld_ref_cnt[j].mask
diff --git a/drivers/misc/tzcom.c b/drivers/misc/tzcom.c
index ba03064..e662f43 100644
--- a/drivers/misc/tzcom.c
+++ b/drivers/misc/tzcom.c
@@ -1,6 +1,6 @@
/* Qualcomm TrustZone communicator driver
*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,7 @@
#include <linux/mutex.h>
#include <linux/android_pmem.h>
#include <linux/io.h>
+#include <linux/ion.h>
#include <mach/scm.h>
#include <mach/peripheral-loader.h>
#include <linux/tzcom.h>
@@ -53,7 +54,7 @@
static struct class *driver_class;
static dev_t tzcom_device_no;
static struct cdev tzcom_cdev;
-
+struct ion_client *ion_clnt;
static u8 *sb_in_virt;
static s32 sb_in_phys;
static size_t sb_in_length = 20 * SZ_1K;
@@ -280,13 +281,13 @@
* _________________________________________________________
* OUTPUT SHARED BUFFER
*/
-static int tzcom_send_cmd(struct tzcom_data_t *data, void __user *argp)
+static int __tzcom_send_cmd(struct tzcom_data_t *data,
+ struct tzcom_send_cmd_op_req *req)
{
int ret = 0;
unsigned long flags;
u32 reqd_len_sb_in = 0;
u32 reqd_len_sb_out = 0;
- struct tzcom_send_cmd_op_req req;
struct tzcom_command cmd;
struct tzcom_response resp;
struct tzcom_callback *next_callback;
@@ -296,30 +297,24 @@
size_t new_entry_len = 0;
struct tzcom_registered_svc_list *ptr_svc;
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- PERR("copy_from_user failed");
- return ret;
- }
-
- if (req.cmd_buf == NULL || req.resp_buf == NULL) {
+ if (req->cmd_buf == NULL || req->resp_buf == NULL) {
PERR("cmd buffer or response buffer is null");
return -EINVAL;
}
- if (req.cmd_len <= 0 || req.resp_len <= 0 ||
- req.cmd_len > sb_in_length || req.resp_len > sb_in_length) {
+ if (req->cmd_len <= 0 || req->resp_len <= 0 ||
+ req->cmd_len > sb_in_length || req->resp_len > sb_in_length) {
PERR("cmd buffer length or "
"response buffer length not valid");
return -EINVAL;
}
PDEBUG("received cmd_req.req: 0x%p",
- req.cmd_buf);
+ req->cmd_buf);
PDEBUG("received cmd_req.rsp size: %u, ptr: 0x%p",
- req.resp_len,
- req.resp_buf);
+ req->resp_len,
+ req->resp_buf);
- reqd_len_sb_in = req.cmd_len + req.resp_len;
+ reqd_len_sb_in = req->cmd_len + req->resp_len;
if (reqd_len_sb_in > sb_in_length) {
PDEBUG("Not enough memory to fit cmd_buf and "
"resp_buf. Required: %u, Available: %u",
@@ -327,23 +322,25 @@
return -ENOMEM;
}
- /* Copy req.cmd_buf to SB in and set req.resp_buf to SB in + cmd_len */
+ /* Copy req->cmd_buf to SB in and set
+ * req->resp_buf to SB in + cmd_len
+ */
mutex_lock(&sb_in_lock);
PDEBUG("Before memcpy on sb_in");
- memcpy(sb_in_virt, req.cmd_buf, req.cmd_len);
+ memcpy(sb_in_virt, req->cmd_buf, req->cmd_len);
PDEBUG("After memcpy on sb_in");
/* cmd_type will always be a new here */
cmd.cmd_type = TZ_SCHED_CMD_NEW;
cmd.sb_in_cmd_addr = (u8 *) tzcom_virt_to_phys(sb_in_virt);
- cmd.sb_in_cmd_len = req.cmd_len;
+ cmd.sb_in_cmd_len = req->cmd_len;
resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
resp.sb_in_rsp_addr = (u8 *) tzcom_virt_to_phys(sb_in_virt +
- req.cmd_len);
- resp.sb_in_rsp_len = req.resp_len;
+ req->cmd_len);
+ resp.sb_in_rsp_len = req->resp_len;
- PDEBUG("before call tzcom_scm_call, cmd_id = : %u", req.cmd_id);
+ PDEBUG("before call tzcom_scm_call, cmd_id = : %u", req->cmd_id);
PDEBUG("before call tzcom_scm_call, sizeof(cmd) = : %u", sizeof(cmd));
ret = tzcom_scm_call((const void *) &cmd, sizeof(cmd),
@@ -442,13 +439,31 @@
mutex_lock(&sb_in_lock);
resp.sb_in_rsp_addr = sb_in_virt + cmd.sb_in_cmd_len;
- resp.sb_in_rsp_len = req.resp_len;
- memcpy(req.resp_buf, resp.sb_in_rsp_addr, resp.sb_in_rsp_len);
+ resp.sb_in_rsp_len = req->resp_len;
+ memcpy(req->resp_buf, resp.sb_in_rsp_addr, resp.sb_in_rsp_len);
/* Zero out memory for security purpose */
memset(sb_in_virt, 0, reqd_len_sb_in);
mutex_unlock(&sb_in_lock);
- PDEBUG("sending cmd_req.rsp "
+ return ret;
+}
+
+
+static int tzcom_send_cmd(struct tzcom_data_t *data, void __user *argp)
+{
+ int ret = 0;
+ struct tzcom_send_cmd_op_req req;
+
+ ret = copy_from_user(&req, argp, sizeof(req));
+ if (ret) {
+ PERR("copy_from_user failed");
+ return ret;
+ }
+ ret = __tzcom_send_cmd(data, &req);
+ if (ret)
+ return ret;
+
+ PDEBUG("sending cmd_req->rsp "
"size: %u, ptr: 0x%p", req.resp_len,
req.resp_buf);
ret = copy_to_user(argp, &req, sizeof(req));
@@ -456,7 +471,99 @@
PDEBUG("copy_to_user failed");
return ret;
}
+ return ret;
+}
+static int __tzcom_send_cmd_req_clean_up(
+ struct tzcom_send_cmd_fd_op_req *req)
+{
+ char *field;
+ uint32_t *update;
+ int ret = 0;
+ int i = 0;
+
+ for (i = 0; i < MAX_ION_FD; i++) {
+ if (req->ifd_data[i].fd != 0) {
+ field = (char *)req->cmd_buf +
+ req->ifd_data[i].cmd_buf_offset;
+ update = (uint32_t *) field;
+ *update = 0;
+ }
+ }
+ return ret;
+}
+
+static int __tzcom_update_with_phy_addr(
+ struct tzcom_send_cmd_fd_op_req *req)
+{
+ struct ion_handle *ihandle;
+ char *field;
+ uint32_t *update;
+ ion_phys_addr_t pa;
+ int ret = 0;
+ int i = 0;
+ uint32_t length;
+
+ for (i = 0; i < MAX_ION_FD; i++) {
+ if (req->ifd_data[i].fd != 0) {
+ /* Get the handle of the shared fd */
+ ihandle = ion_import_fd(ion_clnt, req->ifd_data[i].fd);
+ if (ihandle == NULL) {
+ PERR("Ion client can't retrieve the handle\n");
+ return -ENOMEM;
+ }
+ field = (char *) req->cmd_buf +
+ req->ifd_data[i].cmd_buf_offset;
+ update = (uint32_t *) field;
+
+ /* Populate the cmd data structure with the phys_addr */
+ ret = ion_phys(ion_clnt, ihandle, &pa, &length);
+ if (ret)
+ return -ENOMEM;
+
+ *update = (uint32_t)pa;
+ ion_free(ion_clnt, ihandle);
+ }
+ }
+ return ret;
+}
+
+static int tzcom_send_cmd_with_fd(struct tzcom_data_t *data,
+ void __user *argp)
+{
+ int ret = 0;
+ struct tzcom_send_cmd_fd_op_req req;
+ struct tzcom_send_cmd_op_req send_cmd_req;
+
+ ret = copy_from_user(&req, argp, sizeof(req));
+ if (ret) {
+ PERR("copy_from_user failed");
+ return ret;
+ }
+
+ send_cmd_req.cmd_id = req.cmd_id;
+ send_cmd_req.cmd_buf = req.cmd_buf;
+ send_cmd_req.cmd_len = req.cmd_len;
+ send_cmd_req.resp_buf = req.resp_buf;
+ send_cmd_req.resp_len = req.resp_len;
+
+ ret = __tzcom_update_with_phy_addr(&req);
+ if (ret)
+ return ret;
+ ret = __tzcom_send_cmd(data, &send_cmd_req);
+ __tzcom_send_cmd_req_clean_up(&req);
+
+ if (ret)
+ return ret;
+
+ PDEBUG("sending cmd_req->rsp "
+ "size: %u, ptr: 0x%p", req.resp_len,
+ req.resp_buf);
+ ret = copy_to_user(argp, &req, sizeof(req));
+ if (ret) {
+ PDEBUG("copy_to_user failed");
+ return ret;
+ }
return ret;
}
@@ -713,6 +820,19 @@
PERR("failed tzcom_send_cmd: %d", ret);
break;
}
+ case TZCOM_IOCTL_SEND_CMD_FD_REQ: {
+ PDEBUG("ioctl send_cmd_req()");
+ /* Only one client allowed here at a time */
+ mutex_lock(&send_cmd_lock);
+ atomic_inc(&tzcom_data->ioctl_count);
+ ret = tzcom_send_cmd_with_fd(tzcom_data, argp);
+ atomic_dec(&tzcom_data->ioctl_count);
+ wake_up_interruptible(&tzcom_data->abort_wq);
+ mutex_unlock(&send_cmd_lock);
+ if (ret)
+ PERR("failed tzcom_send_cmd: %d", ret);
+ break;
+ }
case TZCOM_IOCTL_READ_NEXT_CMD_REQ: {
PDEBUG("ioctl read_next_cmd_req()");
atomic_inc(&tzcom_data->ioctl_count);
@@ -971,7 +1091,7 @@
}
PDEBUG("sb_out virt address: %p, phys address: 0x%x",
sb_out_virt, tzcom_virt_to_phys(sb_out_virt));
-
+ ion_clnt = msm_ion_client_create(0x03, "tzcom");
/* Initialized in tzcom_open */
pil = NULL;
@@ -1012,6 +1132,7 @@
device_destroy(driver_class, tzcom_device_no);
class_destroy(driver_class);
unregister_chrdev_region(tzcom_device_no, 1);
+ ion_client_destroy(ion_clnt);
}
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 3cffd65..57e5696 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -477,11 +477,7 @@
goto out;
}
msmsdcc_stop_data(host);
-
- if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
- || !mrq->sbc)) {
- msmsdcc_start_command(host, mrq->data->stop, 0);
- } else if (!mrq->data->stop || mrq->cmd->error ||
+ if (!mrq->data->stop || mrq->cmd->error ||
(mrq->sbc && !mrq->data->error)) {
host->curr.mrq = NULL;
host->curr.cmd = NULL;
@@ -491,6 +487,9 @@
mmc_request_done(host->mmc, mrq);
return;
+ } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+ || !mrq->sbc)) {
+ msmsdcc_start_command(host, mrq->data->stop, 0);
}
}
@@ -635,10 +634,7 @@
return;
}
msmsdcc_stop_data(host);
- if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
- || !mrq->sbc)) {
- msmsdcc_start_command(host, mrq->data->stop, 0);
- } else if (!mrq->data->stop || mrq->cmd->error ||
+ if (!mrq->data->stop || mrq->cmd->error ||
(mrq->sbc && !mrq->data->error)) {
host->curr.mrq = NULL;
host->curr.cmd = NULL;
@@ -648,6 +644,9 @@
mmc_request_done(host->mmc, mrq);
return;
+ } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+ || !mrq->sbc)) {
+ msmsdcc_start_command(host, mrq->data->stop, 0);
}
}
spin_unlock_irqrestore(&host->lock, flags);
@@ -944,7 +943,7 @@
msmsdcc_start_command_deferred(struct msmsdcc_host *host,
struct mmc_command *cmd, u32 *c)
{
- DBG(host, "op %d arg %08x flags %08x\n",
+ DBG(host, "op %02x arg %08x flags %08x\n",
cmd->opcode, cmd->arg, cmd->flags);
*c |= (cmd->opcode | MCI_CPSM_ENABLE);
@@ -1393,16 +1392,9 @@
else if (host->curr.data) { /* Non DMA */
msmsdcc_reset_and_restore(host);
msmsdcc_stop_data(host);
- if (cmd->data && cmd->data->stop)
- msmsdcc_start_command(host,
- cmd->data->stop, 0);
- else
- msmsdcc_request_end(host, cmd->mrq);
+ msmsdcc_request_end(host, cmd->mrq);
} else { /* host->data == NULL */
- if (cmd->data && cmd->data->stop) {
- msmsdcc_start_command(host,
- cmd->data->stop, 0);
- } else if (!cmd->error && host->prog_enable) {
+ if (!cmd->error && host->prog_enable) {
if (status & MCI_PROGDONE) {
host->prog_enable = 0;
msmsdcc_request_end(host, cmd->mrq);
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index dce8d6d..c3a756d 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -234,7 +234,6 @@
if (!skb->protocol)
skb->protocol = eth_type_trans(skb, dev->net);
- skb->protocol = eth_type_trans (skb, dev->net);
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb->len;
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 9f689f1..19c0115 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -19,10 +19,12 @@
*/
#include <linux/errno.h>
+#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/string.h>
+#include <linux/slab.h>
/* For archs that don't support NO_IRQ (such as x86), provide a dummy value */
#ifndef NO_IRQ
@@ -386,3 +388,110 @@
return i;
}
+
+struct intc_desc {
+ struct list_head list;
+ struct device_node *dev;
+ struct device_node *interrupt_parent;
+};
+
+/**
+ * of_irq_init - Scan and init matching interrupt controllers in DT
+ * @matches: 0 terminated array of nodes to match and init function to call
+ *
+ * This function scans the device tree for matching interrupt controller nodes,
+ * and calls their initialization functions in order with parents first.
+ */
+void __init of_irq_init(const struct of_device_id *matches)
+{
+ struct device_node *np, *parent = NULL;
+ struct intc_desc *desc, *temp_desc;
+ struct list_head intc_desc_list, intc_parent_list;
+
+ INIT_LIST_HEAD(&intc_desc_list);
+ INIT_LIST_HEAD(&intc_parent_list);
+
+ for_each_matching_node(np, matches) {
+ if (!of_find_property(np, "interrupt-controller", NULL))
+ continue;
+ /*
+ * Here, we allocate and populate an intc_desc with the node
+ * pointer, interrupt-parent device_node etc.
+ */
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ if (WARN_ON(!desc))
+ goto err;
+
+ desc->dev = np;
+ desc->interrupt_parent = of_irq_find_parent(np);
+ if (desc->interrupt_parent == np)
+ desc->interrupt_parent = NULL;
+ list_add_tail(&desc->list, &intc_desc_list);
+ }
+
+ /*
+ * The root irq controller is the one without an interrupt-parent.
+ * That one goes first, followed by the controllers that reference it,
+ * followed by the ones that reference the 2nd level controllers, etc.
+ */
+ while (!list_empty(&intc_desc_list)) {
+ /*
+ * Process all controllers with the current 'parent'.
+ * First pass will be looking for NULL as the parent.
+ * The assumption is that NULL parent means a root controller.
+ */
+ list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
+ const struct of_device_id *match;
+ int ret;
+ of_irq_init_cb_t irq_init_cb;
+
+ if (desc->interrupt_parent != parent)
+ continue;
+
+ list_del(&desc->list);
+ match = of_match_node(matches, desc->dev);
+ if (WARN(!match->data,
+ "of_irq_init: no init function for %s\n",
+ match->compatible)) {
+ kfree(desc);
+ continue;
+ }
+
+ pr_debug("of_irq_init: init %s @ %p, parent %p\n",
+ match->compatible,
+ desc->dev, desc->interrupt_parent);
+ irq_init_cb = match->data;
+ ret = irq_init_cb(desc->dev, desc->interrupt_parent);
+ if (ret) {
+ kfree(desc);
+ continue;
+ }
+
+ /*
+ * This one is now set up; add it to the parent list so
+ * its children can get processed in a subsequent pass.
+ */
+ list_add_tail(&desc->list, &intc_parent_list);
+ }
+
+ /* Get the next pending parent that might have children */
+ desc = list_first_entry(&intc_parent_list, typeof(*desc), list);
+ if (list_empty(&intc_parent_list) || !desc) {
+ pr_err("of_irq_init: children remain, but no parents\n");
+ break;
+ }
+ list_del(&desc->list);
+ parent = desc->dev;
+ kfree(desc);
+ }
+
+ list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
+ list_del(&desc->list);
+ kfree(desc);
+ }
+err:
+ list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
+ list_del(&desc->list);
+ kfree(desc);
+ }
+}
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 5b2328d..2b58215 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1319,6 +1319,40 @@
}
EXPORT_SYMBOL_GPL(regulator_get);
+static void devm_regulator_release(struct device *dev, void *res)
+{
+ regulator_put(*(struct regulator **)res);
+}
+
+/**
+ * devm_regulator_get - Resource managed regulator_get()
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Managed regulator_get(). Regulators returned from this function are
+ * automatically regulator_put() on driver detach. See regulator_get() for more
+ * information.
+ */
+struct regulator *devm_regulator_get(struct device *dev, const char *id)
+{
+ struct regulator **ptr, *regulator;
+
+ ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ regulator = regulator_get(dev, id);
+ if (!IS_ERR(regulator)) {
+ *ptr = regulator;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return regulator;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_get);
+
/**
* regulator_get_exclusive - obtain exclusive access to a regulator.
* @dev: device for regulator "consumer"
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index aaeb790..17b9f0d 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -38,608 +38,49 @@
#include <linux/gpio.h>
#include <linux/remote_spinlock.h>
#include <linux/pm_qos_params.h>
+#include <linux/of.h>
+#include "spi_qsd.h"
-#define SPI_DRV_NAME "spi_qsd"
-#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
-
-#define QSD_REG(x) (x)
-#define QUP_REG(x)
-
-#define SPI_FIFO_WORD_CNT 0x0048
-
-#elif defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
-
-#define QSD_REG(x)
-#define QUP_REG(x) (x)
-
-#define QUP_CONFIG 0x0000 /* N & NO_INPUT/NO_OUPUT bits */
-#define QUP_ERROR_FLAGS 0x0308
-#define QUP_ERROR_FLAGS_EN 0x030C
-#define QUP_ERR_MASK 0x3
-#define SPI_OUTPUT_FIFO_WORD_CNT 0x010C
-#define SPI_INPUT_FIFO_WORD_CNT 0x0214
-#define QUP_MX_WRITE_COUNT 0x0150
-#define QUP_MX_WRITE_CNT_CURRENT 0x0154
-
-#define QUP_CONFIG_SPI_MODE 0x0100
-
-#define GSBI_CTRL_REG 0x0
-#define GSBI_SPI_CONFIG 0x30
-#endif
-
-#define SPI_CONFIG QSD_REG(0x0000) QUP_REG(0x0300)
-#define SPI_IO_CONTROL QSD_REG(0x0004) QUP_REG(0x0304)
-#define SPI_IO_MODES QSD_REG(0x0008) QUP_REG(0x0008)
-#define SPI_SW_RESET QSD_REG(0x000C) QUP_REG(0x000C)
-#define SPI_TIME_OUT QSD_REG(0x0010) QUP_REG(0x0010)
-#define SPI_TIME_OUT_CURRENT QSD_REG(0x0014) QUP_REG(0x0014)
-#define SPI_MX_OUTPUT_COUNT QSD_REG(0x0018) QUP_REG(0x0100)
-#define SPI_MX_OUTPUT_CNT_CURRENT QSD_REG(0x001C) QUP_REG(0x0104)
-#define SPI_MX_INPUT_COUNT QSD_REG(0x0020) QUP_REG(0x0200)
-#define SPI_MX_INPUT_CNT_CURRENT QSD_REG(0x0024) QUP_REG(0x0204)
-#define SPI_MX_READ_COUNT QSD_REG(0x0028) QUP_REG(0x0208)
-#define SPI_MX_READ_CNT_CURRENT QSD_REG(0x002C) QUP_REG(0x020C)
-#define SPI_OPERATIONAL QSD_REG(0x0030) QUP_REG(0x0018)
-#define SPI_ERROR_FLAGS QSD_REG(0x0034) QUP_REG(0x001C)
-#define SPI_ERROR_FLAGS_EN QSD_REG(0x0038) QUP_REG(0x0020)
-#define SPI_DEASSERT_WAIT QSD_REG(0x003C) QUP_REG(0x0310)
-#define SPI_OUTPUT_DEBUG QSD_REG(0x0040) QUP_REG(0x0108)
-#define SPI_INPUT_DEBUG QSD_REG(0x0044) QUP_REG(0x0210)
-#define SPI_TEST_CTRL QSD_REG(0x004C) QUP_REG(0x0024)
-#define SPI_OUTPUT_FIFO QSD_REG(0x0100) QUP_REG(0x0110)
-#define SPI_INPUT_FIFO QSD_REG(0x0200) QUP_REG(0x0218)
-#define SPI_STATE QSD_REG(SPI_OPERATIONAL) QUP_REG(0x0004)
-
-/* SPI_CONFIG fields */
-#define SPI_CFG_INPUT_FIRST 0x00000200
-#define SPI_NO_INPUT 0x00000080
-#define SPI_NO_OUTPUT 0x00000040
-#define SPI_CFG_LOOPBACK 0x00000100
-#define SPI_CFG_N 0x0000001F
-
-/* SPI_IO_CONTROL fields */
-#define SPI_IO_C_CLK_IDLE_HIGH 0x00000400
-#define SPI_IO_C_MX_CS_MODE 0x00000100
-#define SPI_IO_C_CS_N_POLARITY 0x000000F0
-#define SPI_IO_C_CS_N_POLARITY_0 0x00000010
-#define SPI_IO_C_CS_SELECT 0x0000000C
-#define SPI_IO_C_TRISTATE_CS 0x00000002
-#define SPI_IO_C_NO_TRI_STATE 0x00000001
-
-/* SPI_IO_MODES fields */
-#define SPI_IO_M_OUTPUT_BIT_SHIFT_EN QSD_REG(0x00004000) QUP_REG(0x00010000)
-#define SPI_IO_M_PACK_EN QSD_REG(0x00002000) QUP_REG(0x00008000)
-#define SPI_IO_M_UNPACK_EN QSD_REG(0x00001000) QUP_REG(0x00004000)
-#define SPI_IO_M_INPUT_MODE QSD_REG(0x00000C00) QUP_REG(0x00003000)
-#define SPI_IO_M_OUTPUT_MODE QSD_REG(0x00000300) QUP_REG(0x00000C00)
-#define SPI_IO_M_INPUT_FIFO_SIZE QSD_REG(0x000000C0) QUP_REG(0x00000380)
-#define SPI_IO_M_INPUT_BLOCK_SIZE QSD_REG(0x00000030) QUP_REG(0x00000060)
-#define SPI_IO_M_OUTPUT_FIFO_SIZE QSD_REG(0x0000000C) QUP_REG(0x0000001C)
-#define SPI_IO_M_OUTPUT_BLOCK_SIZE QSD_REG(0x00000003) QUP_REG(0x00000003)
-
-#define INPUT_BLOCK_SZ_SHIFT QSD_REG(4) QUP_REG(5)
-#define INPUT_FIFO_SZ_SHIFT QSD_REG(6) QUP_REG(7)
-#define OUTPUT_BLOCK_SZ_SHIFT QSD_REG(0) QUP_REG(0)
-#define OUTPUT_FIFO_SZ_SHIFT QSD_REG(2) QUP_REG(2)
-#define OUTPUT_MODE_SHIFT QSD_REG(8) QUP_REG(10)
-#define INPUT_MODE_SHIFT QSD_REG(10) QUP_REG(12)
-
-/* SPI_OPERATIONAL fields */
-#define SPI_OP_MAX_INPUT_DONE_FLAG 0x00000800
-#define SPI_OP_MAX_OUTPUT_DONE_FLAG 0x00000400
-#define SPI_OP_INPUT_SERVICE_FLAG 0x00000200
-#define SPI_OP_OUTPUT_SERVICE_FLAG 0x00000100
-#define SPI_OP_INPUT_FIFO_FULL 0x00000080
-#define SPI_OP_OUTPUT_FIFO_FULL 0x00000040
-#define SPI_OP_IP_FIFO_NOT_EMPTY 0x00000020
-#define SPI_OP_OP_FIFO_NOT_EMPTY 0x00000010
-#define SPI_OP_STATE_VALID 0x00000004
-#define SPI_OP_STATE 0x00000003
-
-#define SPI_OP_STATE_CLEAR_BITS 0x2
-enum msm_spi_state {
- SPI_OP_STATE_RESET = 0x00000000,
- SPI_OP_STATE_RUN = 0x00000001,
- SPI_OP_STATE_PAUSE = 0x00000003,
-};
-
-/* SPI_ERROR_FLAGS fields */
-#define SPI_ERR_OUTPUT_OVER_RUN_ERR 0x00000020
-#define SPI_ERR_INPUT_UNDER_RUN_ERR 0x00000010
-#define SPI_ERR_OUTPUT_UNDER_RUN_ERR 0x00000008
-#define SPI_ERR_INPUT_OVER_RUN_ERR 0x00000004
-#define SPI_ERR_CLK_OVER_RUN_ERR 0x00000002
-#define SPI_ERR_CLK_UNDER_RUN_ERR 0x00000001
-
-/* We don't allow transactions larger than 4K-64 or 64K-64 due to
- mx_input/output_cnt register size */
-#define SPI_MAX_TRANSFERS QSD_REG(0xFC0) QUP_REG(0xFC0)
-#define SPI_MAX_LEN (SPI_MAX_TRANSFERS * dd->bytes_per_word)
-
-#define SPI_NUM_CHIPSELECTS 4
-#define SPI_SUPPORTED_MODES (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP)
-
-#define SPI_DELAY_THRESHOLD 1
-/* Default timeout is 10 milliseconds */
-#define SPI_DEFAULT_TIMEOUT 10
-/* 250 microseconds */
-#define SPI_TRYLOCK_DELAY 250
-
-/* Data Mover burst size */
-#define DM_BURST_SIZE 16
-/* Data Mover commands should be aligned to 64 bit(8 bytes) */
-#define DM_BYTE_ALIGN 8
-
-static char const * const spi_rsrcs[] = {
- "spi_clk",
- "spi_miso",
- "spi_mosi"
-};
-
-static char const * const spi_cs_rsrcs[] = {
- "spi_cs",
- "spi_cs1",
- "spi_cs2",
- "spi_cs3",
-};
-
-enum msm_spi_mode {
- SPI_FIFO_MODE = 0x0, /* 00 */
- SPI_BLOCK_MODE = 0x1, /* 01 */
- SPI_DMOV_MODE = 0x2, /* 10 */
- SPI_MODE_NONE = 0xFF, /* invalid value */
-};
-
-/* Structure for SPI CS GPIOs */
-struct spi_cs_gpio {
- int gpio_num;
- bool valid;
-};
-
-/* Structures for Data Mover */
-struct spi_dmov_cmd {
- dmov_box box; /* data aligned to max(dm_burst_size, block_size)
- (<= fifo_size) */
- dmov_s single_pad; /* data unaligned to max(dm_burst_size, block_size)
- padded to fit */
- dma_addr_t cmd_ptr;
-};
-
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION("0.3");
-MODULE_ALIAS("platform:"SPI_DRV_NAME);
-
-static struct pm_qos_request_list qos_req_list;
-
-#ifdef CONFIG_DEBUG_FS
-/* Used to create debugfs entries */
-static const struct {
- const char *name;
- mode_t mode;
- int offset;
-} debugfs_spi_regs[] = {
- {"config", S_IRUGO | S_IWUSR, SPI_CONFIG},
- {"io_control", S_IRUGO | S_IWUSR, SPI_IO_CONTROL},
- {"io_modes", S_IRUGO | S_IWUSR, SPI_IO_MODES},
- {"sw_reset", S_IWUSR, SPI_SW_RESET},
- {"time_out", S_IRUGO | S_IWUSR, SPI_TIME_OUT},
- {"time_out_current", S_IRUGO, SPI_TIME_OUT_CURRENT},
- {"mx_output_count", S_IRUGO | S_IWUSR, SPI_MX_OUTPUT_COUNT},
- {"mx_output_cnt_current", S_IRUGO, SPI_MX_OUTPUT_CNT_CURRENT},
- {"mx_input_count", S_IRUGO | S_IWUSR, SPI_MX_INPUT_COUNT},
- {"mx_input_cnt_current", S_IRUGO, SPI_MX_INPUT_CNT_CURRENT},
- {"mx_read_count", S_IRUGO | S_IWUSR, SPI_MX_READ_COUNT},
- {"mx_read_cnt_current", S_IRUGO, SPI_MX_READ_CNT_CURRENT},
- {"operational", S_IRUGO | S_IWUSR, SPI_OPERATIONAL},
- {"error_flags", S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS},
- {"error_flags_en", S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS_EN},
- {"deassert_wait", S_IRUGO | S_IWUSR, SPI_DEASSERT_WAIT},
- {"output_debug", S_IRUGO, SPI_OUTPUT_DEBUG},
- {"input_debug", S_IRUGO, SPI_INPUT_DEBUG},
- {"test_ctrl", S_IRUGO | S_IWUSR, SPI_TEST_CTRL},
- {"output_fifo", S_IWUSR, SPI_OUTPUT_FIFO},
- {"input_fifo" , S_IRUSR, SPI_INPUT_FIFO},
- {"spi_state", S_IRUGO | S_IWUSR, SPI_STATE},
-#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
- {"fifo_word_cnt", S_IRUGO, SPI_FIFO_WORD_CNT},
-#elif defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
- {"qup_config", S_IRUGO | S_IWUSR, QUP_CONFIG},
- {"qup_error_flags", S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS},
- {"qup_error_flags_en", S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS_EN},
- {"mx_write_cnt", S_IRUGO | S_IWUSR, QUP_MX_WRITE_COUNT},
- {"mx_write_cnt_current", S_IRUGO, QUP_MX_WRITE_CNT_CURRENT},
- {"output_fifo_word_cnt", S_IRUGO, SPI_OUTPUT_FIFO_WORD_CNT},
- {"input_fifo_word_cnt", S_IRUGO, SPI_INPUT_FIFO_WORD_CNT},
-#endif
-};
-#endif
-
-struct msm_spi {
- u8 *read_buf;
- const u8 *write_buf;
- void __iomem *base;
- void __iomem *gsbi_base;
- struct device *dev;
- spinlock_t queue_lock;
- struct mutex core_lock;
- struct list_head queue;
- struct workqueue_struct *workqueue;
- struct work_struct work_data;
- struct spi_message *cur_msg;
- struct spi_transfer *cur_transfer;
- struct completion transfer_complete;
- struct clk *clk;
- struct clk *pclk;
- unsigned long mem_phys_addr;
- size_t mem_size;
- unsigned long gsbi_mem_phys_addr;
- size_t gsbi_mem_size;
- int input_fifo_size;
- int output_fifo_size;
- u32 rx_bytes_remaining;
- u32 tx_bytes_remaining;
- u32 clock_speed;
- int irq_in;
- int read_xfr_cnt;
- int write_xfr_cnt;
- int write_len;
- int read_len;
-#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
- int irq_out;
- int irq_err;
-#endif
- int bytes_per_word;
- bool suspended;
- bool transfer_pending;
- wait_queue_head_t continue_suspend;
- /* DMA data */
- enum msm_spi_mode mode;
- bool use_dma;
- int tx_dma_chan;
- int tx_dma_crci;
- int rx_dma_chan;
- int rx_dma_crci;
- /* Data Mover Commands */
- struct spi_dmov_cmd *tx_dmov_cmd;
- struct spi_dmov_cmd *rx_dmov_cmd;
- /* Physical address of the tx dmov box command */
- dma_addr_t tx_dmov_cmd_dma;
- dma_addr_t rx_dmov_cmd_dma;
- struct msm_dmov_cmd tx_hdr;
- struct msm_dmov_cmd rx_hdr;
- int input_block_size;
- int output_block_size;
- int burst_size;
- atomic_t rx_irq_called;
- /* Used to pad messages unaligned to block size */
- u8 *tx_padding;
- dma_addr_t tx_padding_dma;
- u8 *rx_padding;
- dma_addr_t rx_padding_dma;
- u32 unaligned_len;
- /* DMA statistics */
- int stat_dmov_tx_err;
- int stat_dmov_rx_err;
- int stat_rx;
- int stat_dmov_rx;
- int stat_tx;
- int stat_dmov_tx;
-#ifdef CONFIG_DEBUG_FS
- struct dentry *dent_spi;
- struct dentry *debugfs_spi_regs[ARRAY_SIZE(debugfs_spi_regs)];
-#endif
- struct msm_spi_platform_data *pdata; /* Platform data */
- /* Remote Spinlock Data */
- bool use_rlock;
- remote_mutex_t r_lock;
- uint32_t pm_lat;
- /* When set indicates multiple transfers in a single message */
- bool multi_xfr;
- bool done;
- u32 cur_msg_len;
- /* Used in FIFO mode to keep track of the transfer being processed */
- struct spi_transfer *cur_tx_transfer;
- struct spi_transfer *cur_rx_transfer;
- /* Temporary buffer used for WR-WR or WR-RD transfers */
- u8 *temp_buf;
- /* GPIO pin numbers for SPI clk, miso and mosi */
- int spi_gpios[ARRAY_SIZE(spi_rsrcs)];
- /* SPI CS GPIOs for each slave */
- struct spi_cs_gpio cs_gpios[ARRAY_SIZE(spi_cs_rsrcs)];
-};
-
-/* Forward declaration */
-static irqreturn_t msm_spi_input_irq(int irq, void *dev_id);
-static irqreturn_t msm_spi_output_irq(int irq, void *dev_id);
-static irqreturn_t msm_spi_error_irq(int irq, void *dev_id);
-static inline int msm_spi_set_state(struct msm_spi *dd,
- enum msm_spi_state state);
-static void msm_spi_write_word_to_fifo(struct msm_spi *dd);
-static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd);
-
-#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
-/* Interrupt Handling */
-static inline int msm_spi_get_irq_data(struct msm_spi *dd,
- struct platform_device *pdev)
-{
- dd->irq_in = platform_get_irq_byname(pdev, "spi_irq_in");
- dd->irq_out = platform_get_irq_byname(pdev, "spi_irq_out");
- dd->irq_err = platform_get_irq_byname(pdev, "spi_irq_err");
- if ((dd->irq_in < 0) || (dd->irq_out < 0) || (dd->irq_err < 0))
- return -1;
- return 0;
-}
-
-static inline int msm_spi_get_gsbi_resource(struct msm_spi *dd,
- struct platform_device *pdev)
-{
- return 0;
-}
-
-static inline int msm_spi_request_gsbi(struct msm_spi *dd) { return 0; }
-static inline void msm_spi_release_gsbi(struct msm_spi *dd) {}
-static inline void msm_spi_init_gsbi(struct msm_spi *dd) {}
-
-static inline void msm_spi_disable_irqs(struct msm_spi *dd)
-{
- disable_irq(dd->irq_in);
- disable_irq(dd->irq_out);
- disable_irq(dd->irq_err);
-}
-
-static inline void msm_spi_enable_irqs(struct msm_spi *dd)
-{
- enable_irq(dd->irq_in);
- enable_irq(dd->irq_out);
- enable_irq(dd->irq_err);
-}
-
-static inline int msm_spi_request_irq(struct msm_spi *dd,
- const char *name,
- struct spi_master *master)
-{
- int rc;
- rc = request_irq(dd->irq_in, msm_spi_input_irq, IRQF_TRIGGER_RISING,
- name, dd);
- if (rc)
- goto error_irq1;
- rc = request_irq(dd->irq_out, msm_spi_output_irq, IRQF_TRIGGER_RISING,
- name, dd);
- if (rc)
- goto error_irq2;
- rc = request_irq(dd->irq_err, msm_spi_error_irq, IRQF_TRIGGER_RISING,
- name, master);
- if (rc)
- goto error_irq3;
- return 0;
-
-error_irq3:
- free_irq(dd->irq_out, dd);
-error_irq2:
- free_irq(dd->irq_in, dd);
-error_irq1:
- return rc;
-}
-
-static inline void msm_spi_free_irq(struct msm_spi *dd,
- struct spi_master *master)
-{
- free_irq(dd->irq_err, master);
- free_irq(dd->irq_out, dd);
- free_irq(dd->irq_in, dd);
-}
-
-static inline void msm_spi_get_clk_err(struct msm_spi *dd, u32 *spi_err) {}
-static inline void msm_spi_ack_clk_err(struct msm_spi *dd) {}
-static inline void msm_spi_set_qup_config(struct msm_spi *dd, int bpw) {}
-
-static inline int msm_spi_prepare_for_write(struct msm_spi *dd) { return 0; }
-static inline void msm_spi_start_write(struct msm_spi *dd, u32 read_count)
-{
- msm_spi_write_word_to_fifo(dd);
-}
-static inline void msm_spi_set_write_count(struct msm_spi *dd, int val) {}
-
-static inline void msm_spi_complete(struct msm_spi *dd)
-{
- complete(&dd->transfer_complete);
-}
-
-static inline void msm_spi_enable_error_flags(struct msm_spi *dd)
-{
- writel_relaxed(0x0000007B, dd->base + SPI_ERROR_FLAGS_EN);
-}
-
-static inline void msm_spi_clear_error_flags(struct msm_spi *dd)
-{
- writel_relaxed(0x0000007F, dd->base + SPI_ERROR_FLAGS);
-}
-
-#elif defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
-
-/* Interrupt Handling */
-/* In QUP the same interrupt line is used for intput, output and error*/
-static inline int msm_spi_get_irq_data(struct msm_spi *dd,
- struct platform_device *pdev)
-{
- dd->irq_in = platform_get_irq_byname(pdev, "spi_irq_in");
- if (dd->irq_in < 0)
- return -1;
- return 0;
-}
-
-static inline int msm_spi_get_gsbi_resource(struct msm_spi *dd,
- struct platform_device *pdev)
+static inline int msm_spi_configure_gsbi(struct msm_spi *dd,
+ struct platform_device *pdev)
{
struct resource *resource;
+ unsigned long gsbi_mem_phys_addr;
+ size_t gsbi_mem_size;
+ void __iomem *gsbi_base;
- resource = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "gsbi_base");
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!resource)
+ return 0;
+
+ gsbi_mem_phys_addr = resource->start;
+ gsbi_mem_size = resource_size(resource);
+ if (!devm_request_mem_region(&pdev->dev, gsbi_mem_phys_addr,
+ gsbi_mem_size, SPI_DRV_NAME))
return -ENXIO;
- dd->gsbi_mem_phys_addr = resource->start;
- dd->gsbi_mem_size = resource_size(resource);
+
+ gsbi_base = devm_ioremap(&pdev->dev, gsbi_mem_phys_addr,
+ gsbi_mem_size);
+ if (!gsbi_base)
+ return -ENXIO;
+
+ /* Set GSBI to SPI mode */
+ writel_relaxed(GSBI_SPI_CONFIG, gsbi_base + GSBI_CTRL_REG);
return 0;
}
-static inline void msm_spi_release_gsbi(struct msm_spi *dd)
+static inline void msm_spi_register_init(struct msm_spi *dd)
{
- iounmap(dd->gsbi_base);
- release_mem_region(dd->gsbi_mem_phys_addr, dd->gsbi_mem_size);
+ writel_relaxed(0x00000001, dd->base + SPI_SW_RESET);
+ msm_spi_set_state(dd, SPI_OP_STATE_RESET);
+ writel_relaxed(0x00000000, dd->base + SPI_OPERATIONAL);
+ writel_relaxed(0x00000000, dd->base + SPI_CONFIG);
+ writel_relaxed(0x00000000, dd->base + SPI_IO_MODES);
+ if (dd->qup_ver)
+ writel_relaxed(0x00000000, dd->base + QUP_OPERATIONAL_MASK);
}
-static inline int msm_spi_request_gsbi(struct msm_spi *dd)
-{
- if (!request_mem_region(dd->gsbi_mem_phys_addr, dd->gsbi_mem_size,
- SPI_DRV_NAME)) {
- return -ENXIO;
- }
- dd->gsbi_base = ioremap(dd->gsbi_mem_phys_addr, dd->gsbi_mem_size);
- if (!dd->gsbi_base) {
- release_mem_region(dd->gsbi_mem_phys_addr, dd->gsbi_mem_size);
- return -ENXIO;
- }
- return 0;
-}
-
-static inline void msm_spi_init_gsbi(struct msm_spi *dd)
-{
- /* Set GSBI to SPI mode, and CRCI_MUX_CTRL to SPI CRCI ports */
- writel_relaxed(GSBI_SPI_CONFIG, dd->gsbi_base + GSBI_CTRL_REG);
-}
-
-/* Figure which irq occured and call the relevant functions */
-static irqreturn_t msm_spi_qup_irq(int irq, void *dev_id)
-{
- u32 op, ret = IRQ_NONE;
- struct msm_spi *dd = dev_id;
-
- if (readl_relaxed(dd->base + SPI_ERROR_FLAGS) ||
- readl_relaxed(dd->base + QUP_ERROR_FLAGS)) {
- struct spi_master *master = dev_get_drvdata(dd->dev);
- ret |= msm_spi_error_irq(irq, master);
- }
-
- op = readl_relaxed(dd->base + SPI_OPERATIONAL);
- if (op & SPI_OP_INPUT_SERVICE_FLAG) {
- writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG,
- dd->base + SPI_OPERATIONAL);
- /*
- * Ensure service flag was cleared before further
- * processing of interrupt.
- */
- mb();
- ret |= msm_spi_input_irq(irq, dev_id);
- }
-
- if (op & SPI_OP_OUTPUT_SERVICE_FLAG) {
- writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG,
- dd->base + SPI_OPERATIONAL);
- /*
- * Ensure service flag was cleared before further
- * processing of interrupt.
- */
- mb();
- ret |= msm_spi_output_irq(irq, dev_id);
- }
-
- if (dd->done) {
- complete(&dd->transfer_complete);
- dd->done = 0;
- }
- return ret;
-}
-
-static inline int msm_spi_request_irq(struct msm_spi *dd,
- const char *name,
- struct spi_master *master)
-{
- return request_irq(dd->irq_in, msm_spi_qup_irq, IRQF_TRIGGER_HIGH,
- name, dd);
-}
-
-static inline void msm_spi_free_irq(struct msm_spi *dd,
- struct spi_master *master)
-{
- free_irq(dd->irq_in, dd);
-}
-
-static inline void msm_spi_free_output_irq(struct msm_spi *dd) { }
-static inline void msm_spi_free_error_irq(struct msm_spi *dd,
- struct spi_master *master) { }
-
-static inline void msm_spi_disable_irqs(struct msm_spi *dd)
-{
- disable_irq(dd->irq_in);
-}
-
-static inline void msm_spi_enable_irqs(struct msm_spi *dd)
-{
- enable_irq(dd->irq_in);
-}
-
-static inline void msm_spi_get_clk_err(struct msm_spi *dd, u32 *spi_err)
-{
- *spi_err = readl_relaxed(dd->base + QUP_ERROR_FLAGS);
-}
-
-static inline void msm_spi_ack_clk_err(struct msm_spi *dd)
-{
- writel_relaxed(QUP_ERR_MASK, dd->base + QUP_ERROR_FLAGS);
-}
-
-static inline void msm_spi_add_configs(struct msm_spi *dd, u32 *config, int n);
-
-/* QUP has no_input, no_output, and N bits at QUP_CONFIG */
-static inline void msm_spi_set_qup_config(struct msm_spi *dd, int bpw)
-{
- u32 qup_config = readl_relaxed(dd->base + QUP_CONFIG);
-
- msm_spi_add_configs(dd, &qup_config, bpw-1);
- writel_relaxed(qup_config | QUP_CONFIG_SPI_MODE,
- dd->base + QUP_CONFIG);
-}
-
-static inline int msm_spi_prepare_for_write(struct msm_spi *dd)
-{
- if (msm_spi_set_state(dd, SPI_OP_STATE_RUN))
- return -1;
- if (msm_spi_set_state(dd, SPI_OP_STATE_PAUSE))
- return -1;
- return 0;
-}
-
-static inline void msm_spi_start_write(struct msm_spi *dd, u32 read_count)
-{
- if (read_count <= dd->input_fifo_size)
- msm_spi_write_rmn_to_fifo(dd);
- else
- msm_spi_write_word_to_fifo(dd);
-}
-
-static inline void msm_spi_set_write_count(struct msm_spi *dd, int val)
-{
- writel_relaxed(val, dd->base + QUP_MX_WRITE_COUNT);
-}
-
-static inline void msm_spi_complete(struct msm_spi *dd)
-{
- dd->done = 1;
-}
-
-static inline void msm_spi_enable_error_flags(struct msm_spi *dd)
-{
- writel_relaxed(0x00000078, dd->base + SPI_ERROR_FLAGS_EN);
-}
-
-static inline void msm_spi_clear_error_flags(struct msm_spi *dd)
-{
- writel_relaxed(0x0000007C, dd->base + SPI_ERROR_FLAGS);
-}
-
-#endif
-
static inline int msm_spi_request_gpios(struct msm_spi *dd)
{
int i;
@@ -710,8 +151,9 @@
words = 8; /* 32 bytes */
break;
default:
- return -1;
+ return -EINVAL;
}
+
switch (mult) {
case 0:
*fifo_size = words * 2;
@@ -726,8 +168,9 @@
*fifo_size = words * 16;
break;
default:
- return -1;
+ return -EINVAL;
}
+
*block_size = words * sizeof(u32); /* in bytes */
return 0;
}
@@ -781,8 +224,7 @@
fifo_size_err:
dd->use_dma = 0;
- printk(KERN_WARNING "%s: invalid FIFO size, SPI_IO_MODES=0x%x\n",
- __func__, spi_iom);
+ pr_err("%s: invalid FIFO size, SPI_IO_MODES=0x%x\n", __func__, spi_iom);
return;
}
@@ -812,6 +254,7 @@
else
dd->rx_bytes_remaining = 0;
}
+
dd->read_xfr_cnt++;
if (dd->multi_xfr) {
if (!dd->rx_bytes_remaining)
@@ -889,7 +332,7 @@
{
enum msm_spi_state cur_state;
if (msm_spi_wait_valid(dd))
- return -1;
+ return -EIO;
cur_state = readl_relaxed(dd->base + SPI_STATE);
/* Per spec:
For PAUSE_STATE to RESET_STATE, two writes of (10) are required */
@@ -902,7 +345,7 @@
dd->base + SPI_STATE);
}
if (msm_spi_wait_valid(dd))
- return -1;
+ return -EIO;
return 0;
}
@@ -1121,6 +564,48 @@
mb();
}
+/* Figure which irq occured and call the relevant functions */
+static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id)
+{
+ u32 op, ret = IRQ_NONE;
+ struct msm_spi *dd = dev_id;
+
+ if (readl_relaxed(dd->base + SPI_ERROR_FLAGS) ||
+ readl_relaxed(dd->base + QUP_ERROR_FLAGS)) {
+ struct spi_master *master = dev_get_drvdata(dd->dev);
+ ret |= msm_spi_error_irq(irq, master);
+ }
+
+ op = readl_relaxed(dd->base + SPI_OPERATIONAL);
+ if (op & SPI_OP_INPUT_SERVICE_FLAG) {
+ writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG,
+ dd->base + SPI_OPERATIONAL);
+ /*
+ * Ensure service flag was cleared before further
+ * processing of interrupt.
+ */
+ mb();
+ ret |= msm_spi_input_irq(irq, dev_id);
+ }
+
+ if (op & SPI_OP_OUTPUT_SERVICE_FLAG) {
+ writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG,
+ dd->base + SPI_OPERATIONAL);
+ /*
+ * Ensure service flag was cleared before further
+ * processing of interrupt.
+ */
+ mb();
+ ret |= msm_spi_output_irq(irq, dev_id);
+ }
+
+ if (dd->done) {
+ complete(&dd->transfer_complete);
+ dd->done = 0;
+ }
+ return ret;
+}
+
static irqreturn_t msm_spi_input_irq(int irq, void *dev_id)
{
struct msm_spi *dd = dev_id;
@@ -1490,14 +975,14 @@
if (int_loopback && dd->multi_xfr &&
(read_count > dd->input_fifo_size)) {
if (dd->read_len && dd->write_len)
- printk(KERN_WARNING
- "%s:Internal Loopback does not support > fifo size\
- for write-then-read transactions\n",
+ pr_err(
+ "%s:Internal Loopback does not support > fifo size"
+ "for write-then-read transactions\n",
__func__);
else if (dd->write_len && !dd->read_len)
- printk(KERN_WARNING
- "%s:Internal Loopback does not support > fifo size\
- for write-then-write transactions\n",
+ pr_err(
+ "%s:Internal Loopback does not support > fifo size"
+ "for write-then-write transactions\n",
__func__);
return;
}
@@ -1692,43 +1177,84 @@
dd->cs_gpios[cs_num].valid = 1;
}
- dd->cur_transfer = list_first_entry(&dd->cur_msg->transfers,
- struct spi_transfer,
- transfer_list);
- get_transfer_length(dd);
- if (dd->multi_xfr && !dd->read_len && !dd->write_len) {
- /* Handling of multi-transfers. FIFO mode is used by default */
+ if (dd->qup_ver) {
list_for_each_entry(dd->cur_transfer,
- &dd->cur_msg->transfers,
- transfer_list) {
- if (!dd->cur_transfer->len)
- goto error;
- if (xfrs_grped) {
- xfrs_grped--;
- continue;
- } else {
- dd->read_len = dd->write_len = 0;
- xfrs_grped = combine_transfers(dd);
+ &dd->cur_msg->transfers,
+ transfer_list) {
+ u32 spi_ioc;
+ u32 spi_ioc_orig;
+ struct spi_transfer *t = dd->cur_transfer;
+ struct spi_transfer *nxt;
+
+ if (t->transfer_list.next != &dd->cur_msg->transfers) {
+ nxt = list_entry(t->transfer_list.next,
+ struct spi_transfer,
+ transfer_list);
+
+ spi_ioc = readl_relaxed(dd->base +
+ SPI_IO_CONTROL);
+ spi_ioc_orig = spi_ioc;
+ if (t->cs_change == nxt->cs_change)
+ spi_ioc |= SPI_IO_C_FORCE_CS;
+ else
+ spi_ioc &= ~SPI_IO_C_FORCE_CS;
+
+ if (spi_ioc != spi_ioc_orig) {
+ writel_relaxed(spi_ioc,
+ dd->base + SPI_IO_CONTROL);
+ }
}
+
+ dd->cur_msg_len = dd->cur_transfer->len;
+ msm_spi_process_transfer(dd);
+ }
+ } else {
+ dd->cur_transfer = list_first_entry(&dd->cur_msg->transfers,
+ struct spi_transfer,
+ transfer_list);
+ get_transfer_length(dd);
+ if (dd->multi_xfr && !dd->read_len && !dd->write_len) {
+ /*
+ * Handling of multi-transfers.
+ * FIFO mode is used by default
+ */
+ list_for_each_entry(dd->cur_transfer,
+ &dd->cur_msg->transfers,
+ transfer_list) {
+ if (!dd->cur_transfer->len)
+ goto error;
+ if (xfrs_grped) {
+ xfrs_grped--;
+ continue;
+ } else {
+ dd->read_len = dd->write_len = 0;
+ xfrs_grped = combine_transfers(dd);
+ }
+
+ dd->cur_tx_transfer = dd->cur_transfer;
+ dd->cur_rx_transfer = dd->cur_transfer;
+ msm_spi_process_transfer(dd);
+ xfrs_grped--;
+ }
+ } else {
+ /* Handling of a single transfer or
+ * WR-WR or WR-RD transfers
+ */
+ if ((!dd->cur_msg->is_dma_mapped) &&
+ (msm_use_dm(dd, dd->cur_transfer,
+ dd->cur_transfer->bits_per_word))) {
+ /* Mapping of DMA buffers */
+ int ret = msm_spi_map_dma_buffers(dd);
+ if (ret < 0) {
+ dd->cur_msg->status = ret;
+ goto error;
+ }
+ }
+
dd->cur_tx_transfer = dd->cur_transfer;
dd->cur_rx_transfer = dd->cur_transfer;
msm_spi_process_transfer(dd);
- xfrs_grped--;
}
- } else {
- /* Handling of a single transfer or WR-WR or WR-RD transfers */
- if ((!dd->cur_msg->is_dma_mapped) &&
- (msm_use_dm(dd, dd->cur_transfer,
- dd->cur_transfer->bits_per_word))) {
- /* Mapping of DMA buffers */
- int ret = msm_spi_map_dma_buffers(dd);
- if (ret < 0) {
- dd->cur_msg->status = ret;
- goto error;
- }
- }
- dd->cur_tx_transfer = dd->cur_rx_transfer = dd->cur_transfer;
- msm_spi_process_transfer(dd);
}
return;
@@ -1939,6 +1465,7 @@
dd->dent_spi = debugfs_create_dir(dev_name(dd->dev), NULL);
if (dd->dent_spi) {
int i;
+
for (i = 0; i < ARRAY_SIZE(debugfs_spi_regs); i++) {
dd->debugfs_spi_regs[i] =
debugfs_create_file(
@@ -1955,6 +1482,7 @@
{
if (dd->dent_spi) {
int i;
+
debugfs_remove_recursive(dd->dent_spi);
dd->dent_spi = NULL;
for (i = 0; i < ARRAY_SIZE(debugfs_spi_regs); i++)
@@ -2210,6 +1738,23 @@
return 0;
}
+struct msm_spi_platform_data *msm_spi_dt_to_pdata(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct msm_spi_platform_data *pdata;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("Unable to allocate platform data\n");
+ return NULL;
+ }
+
+ of_property_read_u32(node, "spi-max-frequency",
+ &pdata->max_clock_speed);
+
+ return pdata;
+}
+
static int __init msm_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
@@ -2220,7 +1765,7 @@
int i = 0;
int clk_enabled = 0;
int pclk_enabled = 0;
- struct msm_spi_platform_data *pdata = pdev->dev.platform_data;
+ struct msm_spi_platform_data *pdata;
master = spi_alloc_master(&pdev->dev, sizeof(struct msm_spi));
if (!master) {
@@ -2237,23 +1782,29 @@
platform_set_drvdata(pdev, master);
dd = spi_master_get_devdata(master);
+ if (pdev->dev.of_node) {
+ dd->qup_ver = SPI_QUP_VERSION_BFAM;
+ master->dev.of_node = pdev->dev.of_node;
+ pdata = msm_spi_dt_to_pdata(pdev);
+ if (!pdata) {
+ rc = -ENOMEM;
+ goto err_probe_exit;
+ }
+ } else {
+ pdata = pdev->dev.platform_data;
+ dd->qup_ver = SPI_QUP_VERSION_NONE;
+ }
+
dd->pdata = pdata;
- rc = msm_spi_get_irq_data(dd, pdev);
- if (rc)
- goto err_probe_res;
- resource = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "spi_base");
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!resource) {
rc = -ENXIO;
goto err_probe_res;
}
+
dd->mem_phys_addr = resource->start;
dd->mem_size = resource_size(resource);
- rc = msm_spi_get_gsbi_resource(dd, pdev);
- if (rc)
- goto err_probe_res2;
-
if (pdata) {
if (pdata->dma_config) {
rc = pdata->dma_config();
@@ -2265,20 +1816,17 @@
goto skip_dma_resources;
}
}
- resource = platform_get_resource_byname(pdev,
- IORESOURCE_DMA,
- "spidm_channels");
+ resource = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (resource) {
dd->rx_dma_chan = resource->start;
dd->tx_dma_chan = resource->end;
-
- resource = platform_get_resource_byname(pdev,
- IORESOURCE_DMA,
- "spidm_crci");
+ resource = platform_get_resource(pdev, IORESOURCE_DMA,
+ 1);
if (!resource) {
rc = -ENXIO;
goto err_probe_res;
}
+
dd->rx_dma_crci = resource->start;
dd->tx_dma_crci = resource->end;
dd->use_dma = 1;
@@ -2298,14 +1846,13 @@
}
for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
- resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
- spi_rsrcs[i]);
+ resource = platform_get_resource(pdev, IORESOURCE_IO, i);
dd->spi_gpios[i] = resource ? resource->start : -1;
}
for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
- resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
- spi_cs_rsrcs[i]);
+ resource = platform_get_resource(pdev, IORESOURCE_IO,
+ i + ARRAY_SIZE(spi_rsrcs));
dd->cs_gpios[i].gpio_num = resource ? resource->start : -1;
dd->cs_gpios[i].valid = 0;
}
@@ -2320,22 +1867,22 @@
INIT_WORK(&dd->work_data, msm_spi_workq);
init_waitqueue_head(&dd->continue_suspend);
dd->workqueue = create_singlethread_workqueue(
- dev_name(master->dev.parent));
+ dev_name(master->dev.parent));
if (!dd->workqueue)
goto err_probe_workq;
- if (!request_mem_region(dd->mem_phys_addr, dd->mem_size,
- SPI_DRV_NAME)) {
+ if (!devm_request_mem_region(&pdev->dev, dd->mem_phys_addr,
+ dd->mem_size, SPI_DRV_NAME)) {
rc = -ENXIO;
goto err_probe_reqmem;
}
- dd->base = ioremap(dd->mem_phys_addr, dd->mem_size);
- if (!dd->base)
- goto err_probe_ioremap;
- rc = msm_spi_request_gsbi(dd);
- if (rc)
- goto err_probe_ioremap2;
+ dd->base = devm_ioremap(&pdev->dev, dd->mem_phys_addr, dd->mem_size);
+ if (!dd->base) {
+ rc = -ENOMEM;
+ goto err_probe_reqmem;
+ }
+
if (pdata && pdata->rsl_id) {
struct remote_mutex_id rmid;
rmid.r_spinlock_id = pdata->rsl_id;
@@ -2348,16 +1895,18 @@
__func__, rc);
goto err_probe_rlock_init;
}
+
dd->use_rlock = 1;
dd->pm_lat = pdata->pm_lat;
pm_qos_add_request(&qos_req_list, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
}
+
mutex_lock(&dd->core_lock);
if (dd->use_rlock)
remote_mutex_lock(&dd->r_lock);
- locked = 1;
+ locked = 1;
dd->dev = &pdev->dev;
dd->clk = clk_get(&pdev->dev, "core_clk");
if (IS_ERR(dd->clk)) {
@@ -2382,16 +1931,20 @@
__func__);
goto err_probe_clk_enable;
}
- clk_enabled = 1;
+ clk_enabled = 1;
rc = clk_enable(dd->pclk);
if (rc) {
dev_err(&pdev->dev, "%s: unable to enable iface_clk\n",
__func__);
goto err_probe_pclk_enable;
}
+
pclk_enabled = 1;
- msm_spi_init_gsbi(dd);
+ rc = msm_spi_configure_gsbi(dd, pdev);
+ if (rc)
+ goto err_probe_gsbi;
+
msm_spi_calculate_fifo_size(dd);
if (dd->use_dma) {
rc = msm_spi_init_dma(dd);
@@ -2399,13 +1952,7 @@
goto err_probe_dma;
}
- /* Initialize registers */
- writel_relaxed(0x00000001, dd->base + SPI_SW_RESET);
- msm_spi_set_state(dd, SPI_OP_STATE_RESET);
-
- writel_relaxed(0x00000000, dd->base + SPI_OPERATIONAL);
- writel_relaxed(0x00000000, dd->base + SPI_CONFIG);
- writel_relaxed(0x00000000, dd->base + SPI_IO_MODES);
+ msm_spi_register_init(dd);
/*
* The SPI core generates a bogus input overrun error on some targets,
* when a transition from run to reset state occurs and if the FIFO has
@@ -2429,7 +1976,7 @@
dd->multi_xfr = 0;
dd->mode = SPI_MODE_NONE;
- rc = msm_spi_request_irq(dd, pdev->name, master);
+ rc = msm_spi_request_irq(dd, pdev, master);
if (rc)
goto err_probe_irq;
@@ -2451,16 +1998,16 @@
}
spi_debugfs_init(dd);
-
return 0;
err_attrs:
+ spi_unregister_master(master);
err_probe_reg_master:
- msm_spi_free_irq(dd, master);
err_probe_irq:
err_probe_state:
msm_spi_teardown_dma(dd);
err_probe_dma:
+err_probe_gsbi:
if (pclk_enabled)
clk_disable(dd->pclk);
err_probe_pclk_enable:
@@ -2474,14 +2021,10 @@
if (locked) {
if (dd->use_rlock)
remote_mutex_unlock(&dd->r_lock);
+
mutex_unlock(&dd->core_lock);
}
err_probe_rlock_init:
- msm_spi_release_gsbi(dd);
-err_probe_ioremap2:
- iounmap(dd->base);
-err_probe_ioremap:
- release_mem_region(dd->mem_phys_addr, dd->mem_size);
err_probe_reqmem:
destroy_workqueue(dd->workqueue);
err_probe_workq:
@@ -2489,7 +2032,6 @@
err_probe_gpio:
if (pdata && pdata->gpio_release)
pdata->gpio_release();
-err_probe_res2:
err_probe_res:
spi_master_put(master);
err_probe_exit:
@@ -2553,16 +2095,11 @@
spi_debugfs_exit(dd);
sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
- msm_spi_free_irq(dd, master);
msm_spi_teardown_dma(dd);
-
if (pdata && pdata->gpio_release)
pdata->gpio_release();
msm_spi_free_gpios(dd);
- iounmap(dd->base);
- release_mem_region(dd->mem_phys_addr, dd->mem_size);
- msm_spi_release_gsbi(dd);
clk_put(dd->clk);
clk_put(dd->pclk);
destroy_workqueue(dd->workqueue);
@@ -2573,10 +2110,18 @@
return 0;
}
+static struct of_device_id msm_spi_dt_match[] = {
+ {
+ .compatible = "qcom,spi-qup-v2",
+ },
+ {}
+};
+
static struct platform_driver msm_spi_driver = {
.driver = {
.name = SPI_DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = msm_spi_dt_match,
},
.suspend = msm_spi_suspend,
.resume = msm_spi_resume,
@@ -2594,3 +2139,7 @@
platform_driver_unregister(&msm_spi_driver);
}
module_exit(msm_spi_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.4");
+MODULE_ALIAS("platform:"SPI_DRV_NAME);
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
new file mode 100644
index 0000000..bda9e17
--- /dev/null
+++ b/drivers/spi/spi_qsd.h
@@ -0,0 +1,492 @@
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SPI_QSD_H
+#define _SPI_QSD_H
+
+#define SPI_DRV_NAME "spi_qsd"
+
+#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
+
+#define QSD_REG(x) (x)
+#define QUP_REG(x)
+
+#define SPI_FIFO_WORD_CNT 0x0048
+
+#else
+
+#define QSD_REG(x)
+#define QUP_REG(x) (x)
+
+#define QUP_CONFIG 0x0000 /* N & NO_INPUT/NO_OUPUT bits */
+#define QUP_ERROR_FLAGS_EN 0x030C
+#define QUP_ERR_MASK 0x3
+#define SPI_OUTPUT_FIFO_WORD_CNT 0x010C
+#define SPI_INPUT_FIFO_WORD_CNT 0x0214
+#define QUP_MX_WRITE_COUNT 0x0150
+#define QUP_MX_WRITE_CNT_CURRENT 0x0154
+
+#define QUP_CONFIG_SPI_MODE 0x0100
+#endif
+
+#define GSBI_CTRL_REG 0x0
+#define GSBI_SPI_CONFIG 0x30
+#define QUP_HARDWARE_VER 0x0030
+#define QUP_OPERATIONAL_MASK 0x0028
+#define QUP_ERROR_FLAGS 0x0308
+
+#define SPI_CONFIG QSD_REG(0x0000) QUP_REG(0x0300)
+#define SPI_IO_CONTROL QSD_REG(0x0004) QUP_REG(0x0304)
+#define SPI_IO_MODES QSD_REG(0x0008) QUP_REG(0x0008)
+#define SPI_SW_RESET QSD_REG(0x000C) QUP_REG(0x000C)
+#define SPI_TIME_OUT_CURRENT QSD_REG(0x0014) QUP_REG(0x0014)
+#define SPI_MX_OUTPUT_COUNT QSD_REG(0x0018) QUP_REG(0x0100)
+#define SPI_MX_OUTPUT_CNT_CURRENT QSD_REG(0x001C) QUP_REG(0x0104)
+#define SPI_MX_INPUT_COUNT QSD_REG(0x0020) QUP_REG(0x0200)
+#define SPI_MX_INPUT_CNT_CURRENT QSD_REG(0x0024) QUP_REG(0x0204)
+#define SPI_MX_READ_COUNT QSD_REG(0x0028) QUP_REG(0x0208)
+#define SPI_MX_READ_CNT_CURRENT QSD_REG(0x002C) QUP_REG(0x020C)
+#define SPI_OPERATIONAL QSD_REG(0x0030) QUP_REG(0x0018)
+#define SPI_ERROR_FLAGS QSD_REG(0x0034) QUP_REG(0x001C)
+#define SPI_ERROR_FLAGS_EN QSD_REG(0x0038) QUP_REG(0x0020)
+#define SPI_DEASSERT_WAIT QSD_REG(0x003C) QUP_REG(0x0310)
+#define SPI_OUTPUT_DEBUG QSD_REG(0x0040) QUP_REG(0x0108)
+#define SPI_INPUT_DEBUG QSD_REG(0x0044) QUP_REG(0x0210)
+#define SPI_TEST_CTRL QSD_REG(0x004C) QUP_REG(0x0024)
+#define SPI_OUTPUT_FIFO QSD_REG(0x0100) QUP_REG(0x0110)
+#define SPI_INPUT_FIFO QSD_REG(0x0200) QUP_REG(0x0218)
+#define SPI_STATE QSD_REG(SPI_OPERATIONAL) QUP_REG(0x0004)
+
+/* SPI_CONFIG fields */
+#define SPI_CFG_INPUT_FIRST 0x00000200
+#define SPI_NO_INPUT 0x00000080
+#define SPI_NO_OUTPUT 0x00000040
+#define SPI_CFG_LOOPBACK 0x00000100
+#define SPI_CFG_N 0x0000001F
+
+/* SPI_IO_CONTROL fields */
+#define SPI_IO_C_FORCE_CS 0x00000800
+#define SPI_IO_C_CLK_IDLE_HIGH 0x00000400
+#define SPI_IO_C_MX_CS_MODE 0x00000100
+#define SPI_IO_C_CS_N_POLARITY 0x000000F0
+#define SPI_IO_C_CS_N_POLARITY_0 0x00000010
+#define SPI_IO_C_CS_SELECT 0x0000000C
+#define SPI_IO_C_TRISTATE_CS 0x00000002
+#define SPI_IO_C_NO_TRI_STATE 0x00000001
+
+/* SPI_IO_MODES fields */
+#define SPI_IO_M_OUTPUT_BIT_SHIFT_EN QSD_REG(0x00004000) QUP_REG(0x00010000)
+#define SPI_IO_M_PACK_EN QSD_REG(0x00002000) QUP_REG(0x00008000)
+#define SPI_IO_M_UNPACK_EN QSD_REG(0x00001000) QUP_REG(0x00004000)
+#define SPI_IO_M_INPUT_MODE QSD_REG(0x00000C00) QUP_REG(0x00003000)
+#define SPI_IO_M_OUTPUT_MODE QSD_REG(0x00000300) QUP_REG(0x00000C00)
+#define SPI_IO_M_INPUT_FIFO_SIZE QSD_REG(0x000000C0) QUP_REG(0x00000380)
+#define SPI_IO_M_INPUT_BLOCK_SIZE QSD_REG(0x00000030) QUP_REG(0x00000060)
+#define SPI_IO_M_OUTPUT_FIFO_SIZE QSD_REG(0x0000000C) QUP_REG(0x0000001C)
+#define SPI_IO_M_OUTPUT_BLOCK_SIZE QSD_REG(0x00000003) QUP_REG(0x00000003)
+
+#define INPUT_BLOCK_SZ_SHIFT QSD_REG(4) QUP_REG(5)
+#define INPUT_FIFO_SZ_SHIFT QSD_REG(6) QUP_REG(7)
+#define OUTPUT_BLOCK_SZ_SHIFT QSD_REG(0) QUP_REG(0)
+#define OUTPUT_FIFO_SZ_SHIFT QSD_REG(2) QUP_REG(2)
+#define OUTPUT_MODE_SHIFT QSD_REG(8) QUP_REG(10)
+#define INPUT_MODE_SHIFT QSD_REG(10) QUP_REG(12)
+
+/* SPI_OPERATIONAL fields */
+#define SPI_OP_MAX_INPUT_DONE_FLAG 0x00000800
+#define SPI_OP_MAX_OUTPUT_DONE_FLAG 0x00000400
+#define SPI_OP_INPUT_SERVICE_FLAG 0x00000200
+#define SPI_OP_OUTPUT_SERVICE_FLAG 0x00000100
+#define SPI_OP_INPUT_FIFO_FULL 0x00000080
+#define SPI_OP_OUTPUT_FIFO_FULL 0x00000040
+#define SPI_OP_IP_FIFO_NOT_EMPTY 0x00000020
+#define SPI_OP_OP_FIFO_NOT_EMPTY 0x00000010
+#define SPI_OP_STATE_VALID 0x00000004
+#define SPI_OP_STATE 0x00000003
+
+#define SPI_OP_STATE_CLEAR_BITS 0x2
+enum msm_spi_state {
+ SPI_OP_STATE_RESET = 0x00000000,
+ SPI_OP_STATE_RUN = 0x00000001,
+ SPI_OP_STATE_PAUSE = 0x00000003,
+};
+
+/* SPI_ERROR_FLAGS fields */
+#define SPI_ERR_OUTPUT_OVER_RUN_ERR 0x00000020
+#define SPI_ERR_INPUT_UNDER_RUN_ERR 0x00000010
+#define SPI_ERR_OUTPUT_UNDER_RUN_ERR 0x00000008
+#define SPI_ERR_INPUT_OVER_RUN_ERR 0x00000004
+#define SPI_ERR_CLK_OVER_RUN_ERR 0x00000002
+#define SPI_ERR_CLK_UNDER_RUN_ERR 0x00000001
+
+/* We don't allow transactions larger than 4K-64 or 64K-64 due to
+ mx_input/output_cnt register size */
+#define SPI_MAX_TRANSFERS QSD_REG(0xFC0) QUP_REG(0xFC0)
+#define SPI_MAX_LEN (SPI_MAX_TRANSFERS * dd->bytes_per_word)
+
+#define SPI_NUM_CHIPSELECTS 4
+#define SPI_SUPPORTED_MODES (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP)
+
+#define SPI_DELAY_THRESHOLD 1
+/* Default timeout is 10 milliseconds */
+#define SPI_DEFAULT_TIMEOUT 10
+/* 250 microseconds */
+#define SPI_TRYLOCK_DELAY 250
+
+/* Data Mover burst size */
+#define DM_BURST_SIZE 16
+/* Data Mover commands should be aligned to 64 bit(8 bytes) */
+#define DM_BYTE_ALIGN 8
+
+#define SPI_QUP_VERSION_NONE 0x0
+#define SPI_QUP_VERSION_BFAM 0x2
+
+static char const * const spi_rsrcs[] = {
+ "spi_clk",
+ "spi_miso",
+ "spi_mosi"
+};
+
+static char const * const spi_cs_rsrcs[] = {
+ "spi_cs",
+ "spi_cs1",
+ "spi_cs2",
+ "spi_cs3",
+};
+
+enum msm_spi_mode {
+ SPI_FIFO_MODE = 0x0, /* 00 */
+ SPI_BLOCK_MODE = 0x1, /* 01 */
+ SPI_DMOV_MODE = 0x2, /* 10 */
+ SPI_BAM_MODE = 0x3, /* 11 */
+ SPI_MODE_NONE = 0xFF, /* invalid value */
+};
+
+/* Structure for SPI CS GPIOs */
+struct spi_cs_gpio {
+ int gpio_num;
+ bool valid;
+};
+
+/* Structures for Data Mover */
+struct spi_dmov_cmd {
+ dmov_box box; /* data aligned to max(dm_burst_size, block_size)
+ (<= fifo_size) */
+ dmov_s single_pad; /* data unaligned to max(dm_burst_size, block_size)
+ padded to fit */
+ dma_addr_t cmd_ptr;
+};
+
+static struct pm_qos_request_list qos_req_list;
+
+#ifdef CONFIG_DEBUG_FS
+/* Used to create debugfs entries */
+static const struct {
+ const char *name;
+ mode_t mode;
+ int offset;
+} debugfs_spi_regs[] = {
+ {"config", S_IRUGO | S_IWUSR, SPI_CONFIG},
+ {"io_control", S_IRUGO | S_IWUSR, SPI_IO_CONTROL},
+ {"io_modes", S_IRUGO | S_IWUSR, SPI_IO_MODES},
+ {"sw_reset", S_IWUSR, SPI_SW_RESET},
+ {"time_out_current", S_IRUGO, SPI_TIME_OUT_CURRENT},
+ {"mx_output_count", S_IRUGO | S_IWUSR, SPI_MX_OUTPUT_COUNT},
+ {"mx_output_cnt_current", S_IRUGO, SPI_MX_OUTPUT_CNT_CURRENT},
+ {"mx_input_count", S_IRUGO | S_IWUSR, SPI_MX_INPUT_COUNT},
+ {"mx_input_cnt_current", S_IRUGO, SPI_MX_INPUT_CNT_CURRENT},
+ {"mx_read_count", S_IRUGO | S_IWUSR, SPI_MX_READ_COUNT},
+ {"mx_read_cnt_current", S_IRUGO, SPI_MX_READ_CNT_CURRENT},
+ {"operational", S_IRUGO | S_IWUSR, SPI_OPERATIONAL},
+ {"error_flags", S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS},
+ {"error_flags_en", S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS_EN},
+ {"deassert_wait", S_IRUGO | S_IWUSR, SPI_DEASSERT_WAIT},
+ {"output_debug", S_IRUGO, SPI_OUTPUT_DEBUG},
+ {"input_debug", S_IRUGO, SPI_INPUT_DEBUG},
+ {"test_ctrl", S_IRUGO | S_IWUSR, SPI_TEST_CTRL},
+ {"output_fifo", S_IWUSR, SPI_OUTPUT_FIFO},
+ {"input_fifo" , S_IRUSR, SPI_INPUT_FIFO},
+ {"spi_state", S_IRUGO | S_IWUSR, SPI_STATE},
+#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
+ {"fifo_word_cnt", S_IRUGO, SPI_FIFO_WORD_CNT},
+#else
+ {"qup_config", S_IRUGO | S_IWUSR, QUP_CONFIG},
+ {"qup_error_flags", S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS},
+ {"qup_error_flags_en", S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS_EN},
+ {"mx_write_cnt", S_IRUGO | S_IWUSR, QUP_MX_WRITE_COUNT},
+ {"mx_write_cnt_current", S_IRUGO, QUP_MX_WRITE_CNT_CURRENT},
+ {"output_fifo_word_cnt", S_IRUGO, SPI_OUTPUT_FIFO_WORD_CNT},
+ {"input_fifo_word_cnt", S_IRUGO, SPI_INPUT_FIFO_WORD_CNT},
+#endif
+};
+#endif
+
+struct msm_spi {
+ u8 *read_buf;
+ const u8 *write_buf;
+ void __iomem *base;
+ struct device *dev;
+ spinlock_t queue_lock;
+ struct mutex core_lock;
+ struct list_head queue;
+ struct workqueue_struct *workqueue;
+ struct work_struct work_data;
+ struct spi_message *cur_msg;
+ struct spi_transfer *cur_transfer;
+ struct completion transfer_complete;
+ struct clk *clk;
+ struct clk *pclk;
+ unsigned long mem_phys_addr;
+ size_t mem_size;
+ int input_fifo_size;
+ int output_fifo_size;
+ u32 rx_bytes_remaining;
+ u32 tx_bytes_remaining;
+ u32 clock_speed;
+ int irq_in;
+ int read_xfr_cnt;
+ int write_xfr_cnt;
+ int write_len;
+ int read_len;
+#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
+ int irq_out;
+ int irq_err;
+#endif
+ int bytes_per_word;
+ bool suspended;
+ bool transfer_pending;
+ wait_queue_head_t continue_suspend;
+ /* DMA data */
+ enum msm_spi_mode mode;
+ bool use_dma;
+ int tx_dma_chan;
+ int tx_dma_crci;
+ int rx_dma_chan;
+ int rx_dma_crci;
+ /* Data Mover Commands */
+ struct spi_dmov_cmd *tx_dmov_cmd;
+ struct spi_dmov_cmd *rx_dmov_cmd;
+ /* Physical address of the tx dmov box command */
+ dma_addr_t tx_dmov_cmd_dma;
+ dma_addr_t rx_dmov_cmd_dma;
+ struct msm_dmov_cmd tx_hdr;
+ struct msm_dmov_cmd rx_hdr;
+ int input_block_size;
+ int output_block_size;
+ int burst_size;
+ atomic_t rx_irq_called;
+ /* Used to pad messages unaligned to block size */
+ u8 *tx_padding;
+ dma_addr_t tx_padding_dma;
+ u8 *rx_padding;
+ dma_addr_t rx_padding_dma;
+ u32 unaligned_len;
+ /* DMA statistics */
+ int stat_dmov_tx_err;
+ int stat_dmov_rx_err;
+ int stat_rx;
+ int stat_dmov_rx;
+ int stat_tx;
+ int stat_dmov_tx;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dent_spi;
+ struct dentry *debugfs_spi_regs[ARRAY_SIZE(debugfs_spi_regs)];
+#endif
+ struct msm_spi_platform_data *pdata; /* Platform data */
+ /* Remote Spinlock Data */
+ bool use_rlock;
+ remote_mutex_t r_lock;
+ uint32_t pm_lat;
+ /* When set indicates multiple transfers in a single message */
+ bool multi_xfr;
+ bool done;
+ u32 cur_msg_len;
+ /* Used in FIFO mode to keep track of the transfer being processed */
+ struct spi_transfer *cur_tx_transfer;
+ struct spi_transfer *cur_rx_transfer;
+ /* Temporary buffer used for WR-WR or WR-RD transfers */
+ u8 *temp_buf;
+ /* GPIO pin numbers for SPI clk, miso and mosi */
+ int spi_gpios[ARRAY_SIZE(spi_rsrcs)];
+ /* SPI CS GPIOs for each slave */
+ struct spi_cs_gpio cs_gpios[ARRAY_SIZE(spi_cs_rsrcs)];
+ int qup_ver;
+};
+
+/* Forward declaration */
+static irqreturn_t msm_spi_input_irq(int irq, void *dev_id);
+static irqreturn_t msm_spi_output_irq(int irq, void *dev_id);
+static irqreturn_t msm_spi_error_irq(int irq, void *dev_id);
+static inline int msm_spi_set_state(struct msm_spi *dd,
+ enum msm_spi_state state);
+static void msm_spi_write_word_to_fifo(struct msm_spi *dd);
+static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd);
+static irqreturn_t msm_spi_qup_irq(int irq, void *dev_id);
+
+#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
+static inline void msm_spi_disable_irqs(struct msm_spi *dd)
+{
+ disable_irq(dd->irq_in);
+ disable_irq(dd->irq_out);
+ disable_irq(dd->irq_err);
+}
+
+static inline void msm_spi_enable_irqs(struct msm_spi *dd)
+{
+ enable_irq(dd->irq_in);
+ enable_irq(dd->irq_out);
+ enable_irq(dd->irq_err);
+}
+
+static inline int msm_spi_request_irq(struct msm_spi *dd,
+ struct platform_device *pdev,
+ struct spi_master *master)
+{
+ int rc;
+
+ dd->irq_in = platform_get_irq(pdev, 0);
+ dd->irq_out = platform_get_irq(pdev, 1);
+ dd->irq_err = platform_get_irq(pdev, 2);
+ if ((dd->irq_in < 0) || (dd->irq_out < 0) || (dd->irq_err < 0))
+ return -EINVAL;
+
+ rc = devm_request_irq(dd->dev, dd->irq_in, msm_spi_input_irq,
+ IRQF_TRIGGER_RISING, pdev->name, dd);
+ if (rc)
+ goto error_irq;
+
+ rc = devm_request_irq(dd->dev, dd->irq_out, msm_spi_output_irq,
+ IRQF_TRIGGER_RISING, pdev->name, dd);
+ if (rc)
+ goto error_irq;
+
+ rc = devm_request_irq(dd->dev, dd->irq_err, msm_spi_error_irq,
+ IRQF_TRIGGER_RISING, pdev->name, master);
+ if (rc)
+ goto error_irq;
+
+error_irq:
+ return rc;
+}
+
+static inline void msm_spi_get_clk_err(struct msm_spi *dd, u32 *spi_err) {}
+static inline void msm_spi_ack_clk_err(struct msm_spi *dd) {}
+static inline void msm_spi_set_qup_config(struct msm_spi *dd, int bpw) {}
+
+static inline int msm_spi_prepare_for_write(struct msm_spi *dd) { return 0; }
+static inline void msm_spi_start_write(struct msm_spi *dd, u32 read_count)
+{
+ msm_spi_write_word_to_fifo(dd);
+}
+static inline void msm_spi_set_write_count(struct msm_spi *dd, int val) {}
+
+static inline void msm_spi_complete(struct msm_spi *dd)
+{
+ complete(&dd->transfer_complete);
+}
+
+static inline void msm_spi_enable_error_flags(struct msm_spi *dd)
+{
+ writel_relaxed(0x0000007B, dd->base + SPI_ERROR_FLAGS_EN);
+}
+
+static inline void msm_spi_clear_error_flags(struct msm_spi *dd)
+{
+ writel_relaxed(0x0000007F, dd->base + SPI_ERROR_FLAGS);
+}
+
+#else
+/* In QUP the same interrupt line is used for input, output and error*/
+static inline int msm_spi_request_irq(struct msm_spi *dd,
+ struct platform_device *pdev,
+ struct spi_master *master)
+{
+ dd->irq_in = platform_get_irq(pdev, 0);
+ if (dd->irq_in < 0)
+ return -EINVAL;
+
+ return devm_request_irq(dd->dev, dd->irq_in, msm_spi_qup_irq,
+ IRQF_TRIGGER_HIGH, pdev->name, dd);
+}
+
+static inline void msm_spi_disable_irqs(struct msm_spi *dd)
+{
+ disable_irq(dd->irq_in);
+}
+
+static inline void msm_spi_enable_irqs(struct msm_spi *dd)
+{
+ enable_irq(dd->irq_in);
+}
+
+static inline void msm_spi_get_clk_err(struct msm_spi *dd, u32 *spi_err)
+{
+ *spi_err = readl_relaxed(dd->base + QUP_ERROR_FLAGS);
+}
+
+static inline void msm_spi_ack_clk_err(struct msm_spi *dd)
+{
+ writel_relaxed(QUP_ERR_MASK, dd->base + QUP_ERROR_FLAGS);
+}
+
+static inline void msm_spi_add_configs(struct msm_spi *dd, u32 *config, int n);
+
+/* QUP has no_input, no_output, and N bits at QUP_CONFIG */
+static inline void msm_spi_set_qup_config(struct msm_spi *dd, int bpw)
+{
+ u32 qup_config = readl_relaxed(dd->base + QUP_CONFIG);
+
+ msm_spi_add_configs(dd, &qup_config, bpw-1);
+ writel_relaxed(qup_config | QUP_CONFIG_SPI_MODE,
+ dd->base + QUP_CONFIG);
+}
+
+static inline int msm_spi_prepare_for_write(struct msm_spi *dd)
+{
+ if (msm_spi_set_state(dd, SPI_OP_STATE_RUN))
+ return -EINVAL;
+ if (msm_spi_set_state(dd, SPI_OP_STATE_PAUSE))
+ return -EINVAL;
+ return 0;
+}
+
+static inline void msm_spi_start_write(struct msm_spi *dd, u32 read_count)
+{
+ if (read_count <= dd->input_fifo_size)
+ msm_spi_write_rmn_to_fifo(dd);
+ else
+ msm_spi_write_word_to_fifo(dd);
+}
+
+static inline void msm_spi_set_write_count(struct msm_spi *dd, int val)
+{
+ writel_relaxed(val, dd->base + QUP_MX_WRITE_COUNT);
+}
+
+static inline void msm_spi_complete(struct msm_spi *dd)
+{
+ dd->done = 1;
+}
+
+static inline void msm_spi_enable_error_flags(struct msm_spi *dd)
+{
+ writel_relaxed(0x00000078, dd->base + SPI_ERROR_FLAGS_EN);
+}
+
+static inline void msm_spi_clear_error_flags(struct msm_spi *dd)
+{
+ writel_relaxed(0x0000007C, dd->base + SPI_ERROR_FLAGS);
+}
+
+#endif
+#endif
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index e13b4c4..a0763da 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -3,6 +3,7 @@
* Android IPC Subsystem
*
* Copyright (C) 2007-2008 Google, Inc.
+ * Copyright (c) 2012, 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
@@ -97,9 +98,9 @@
BINDER_DEBUG_BUFFER_ALLOC = 1U << 13,
BINDER_DEBUG_PRIORITY_CAP = 1U << 14,
BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15,
+ BINDER_DEBUG_TOP_ERRORS = 1U << 16,
};
-static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR |
- BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION;
+static uint32_t binder_debug_mask;
module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO);
static int binder_debug_no_lock;
@@ -638,7 +639,8 @@
goto free_range;
if (vma == NULL) {
- printk(KERN_ERR "binder: %d: binder_alloc_buf failed to "
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: %d: binder_alloc_buf failed to "
"map pages in userspace, no vma\n", proc->pid);
goto err_no_vma;
}
@@ -651,7 +653,8 @@
BUG_ON(*page);
*page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (*page == NULL) {
- printk(KERN_ERR "binder: %d: binder_alloc_buf failed "
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: %d: binder_alloc_buf failed "
"for page at %p\n", proc->pid, page_addr);
goto err_alloc_page_failed;
}
@@ -660,7 +663,8 @@
page_array_ptr = page;
ret = map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr);
if (ret) {
- printk(KERN_ERR "binder: %d: binder_alloc_buf failed "
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: %d: binder_alloc_buf failed "
"to map page at %p in kernel\n",
proc->pid, page_addr);
goto err_map_kernel_failed;
@@ -669,7 +673,8 @@
(uintptr_t)page_addr + proc->user_buffer_offset;
ret = vm_insert_page(vma, user_page_addr, page[0]);
if (ret) {
- printk(KERN_ERR "binder: %d: binder_alloc_buf failed "
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: %d: binder_alloc_buf failed "
"to map page at %lx in userspace\n",
proc->pid, user_page_addr);
goto err_vm_insert_page_failed;
@@ -718,7 +723,8 @@
size_t size;
if (proc->vma == NULL) {
- printk(KERN_ERR "binder: %d: binder_alloc_buf, no vma\n",
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: %d: binder_alloc_buf, no vma\n",
proc->pid);
return NULL;
}
@@ -756,7 +762,8 @@
}
}
if (best_fit == NULL) {
- printk(KERN_ERR "binder: %d: binder_alloc_buf size %zd failed, "
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: %d: binder_alloc_buf size %zd failed, "
"no address space\n", proc->pid, size);
return NULL;
}
@@ -991,7 +998,8 @@
node->internal_strong_refs == 0 &&
!(node == binder_context_mgr_node &&
node->has_strong_ref)) {
- printk(KERN_ERR "binder: invalid inc strong "
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: invalid inc strong "
"node for %d\n", node->debug_id);
return -EINVAL;
}
@@ -1007,7 +1015,8 @@
node->local_weak_refs++;
if (!node->has_weak_ref && list_empty(&node->work.entry)) {
if (target_list == NULL) {
- printk(KERN_ERR "binder: invalid inc weak node "
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: invalid inc weak node "
"for %d\n", node->debug_id);
return -EINVAL;
}
@@ -1044,7 +1053,7 @@
if (node->proc) {
rb_erase(&node->rb_node, &node->proc->nodes);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "binder: refless node %d deleted\n",
+ "binder: refless node %d deleted\n",
node->debug_id);
} else {
hlist_del(&node->dead_node);
@@ -1263,14 +1272,16 @@
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
"binder: send failed reply for "
"transaction %d to %d:%d\n",
- t->debug_id, target_thread->proc->pid,
+ t->debug_id,
+ target_thread->proc->pid,
target_thread->pid);
binder_pop_transaction(target_thread, t);
target_thread->return_error = error_code;
wake_up_interruptible(&target_thread->wait);
} else {
- printk(KERN_ERR "binder: reply failed, target "
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: reply failed, target "
"thread, %d:%d, has error code %d "
"already\n", target_thread->proc->pid,
target_thread->pid,
@@ -1308,14 +1319,15 @@
int debug_id = buffer->debug_id;
binder_debug(BINDER_DEBUG_TRANSACTION,
- "binder: %d buffer release %d, size %zd-%zd, failed at %p\n",
- proc->pid, buffer->debug_id,
+ "binder: %d buffer release %d, size %zd-%zd, failed at"
+ " %p\n", proc->pid, buffer->debug_id,
buffer->data_size, buffer->offsets_size, failed_at);
if (buffer->target_node)
binder_dec_node(buffer->target_node, 1, 0);
- offp = (size_t *)(buffer->data + ALIGN(buffer->data_size, sizeof(void *)));
+ offp = (size_t *)(buffer->data + ALIGN(buffer->data_size,
+ sizeof(void *)));
if (failed_at)
off_end = failed_at;
else
@@ -1325,7 +1337,8 @@
if (*offp > buffer->data_size - sizeof(*fp) ||
buffer->data_size < sizeof(*fp) ||
!IS_ALIGNED(*offp, sizeof(void *))) {
- printk(KERN_ERR "binder: transaction release %d bad"
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: transaction release %d bad"
"offset %zd, size %zd\n", debug_id,
*offp, buffer->data_size);
continue;
@@ -1334,29 +1347,35 @@
switch (fp->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
- struct binder_node *node = binder_get_node(proc, fp->binder);
+ struct binder_node *node = binder_get_node(proc,
+ fp->binder);
if (node == NULL) {
- printk(KERN_ERR "binder: transaction release %d"
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: transaction release %d"
" bad node %p\n", debug_id, fp->binder);
break;
}
binder_debug(BINDER_DEBUG_TRANSACTION,
" node %d u%p\n",
node->debug_id, node->ptr);
- binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0);
+ binder_dec_node(node, fp->type == BINDER_TYPE_BINDER,
+ 0);
} break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
- struct binder_ref *ref = binder_get_ref(proc, fp->handle);
+ struct binder_ref *ref = binder_get_ref(proc,
+ fp->handle);
if (ref == NULL) {
- printk(KERN_ERR "binder: transaction release %d"
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: transaction release %d"
" bad handle %ld\n", debug_id,
fp->handle);
break;
}
binder_debug(BINDER_DEBUG_TRANSACTION,
" ref %d desc %d (node %d)\n",
- ref->debug_id, ref->desc, ref->node->debug_id);
+ ref->debug_id, ref->desc,
+ ref->node->debug_id);
binder_dec_ref(ref, fp->type == BINDER_TYPE_HANDLE);
} break;
@@ -1368,7 +1387,8 @@
break;
default:
- printk(KERN_ERR "binder: transaction release %d bad "
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: transaction release %d bad "
"object type %lx\n", debug_id, fp->type);
break;
}
@@ -1594,15 +1614,19 @@
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;
- struct binder_node *node = binder_get_node(proc, fp->binder);
+ struct binder_node *node = binder_get_node(proc,
+ fp->binder);
if (node == NULL) {
- node = binder_new_node(proc, fp->binder, fp->cookie);
+ node = binder_new_node(proc, fp->binder,
+ fp->cookie);
if (node == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_new_node_failed;
}
- node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
- node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
+ node->min_priority = fp->flags &
+ FLAT_BINDER_FLAG_PRIORITY_MASK;
+ node->accept_fds = !!(fp->flags &
+ FLAT_BINDER_FLAG_ACCEPTS_FDS);
}
if (fp->cookie != node->cookie) {
binder_user_error("binder: %d:%d sending u%p "
@@ -1632,7 +1656,8 @@
} break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
- struct binder_ref *ref = binder_get_ref(proc, fp->handle);
+ struct binder_ref *ref = binder_get_ref(proc,
+ fp->handle);
if (ref == NULL) {
binder_user_error("binder: %d:%d got "
"transaction with invalid "
@@ -1648,24 +1673,31 @@
fp->type = BINDER_TYPE_WEAK_BINDER;
fp->binder = ref->node->ptr;
fp->cookie = ref->node->cookie;
- binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
+ binder_inc_node(ref->node, fp->type ==
+ BINDER_TYPE_BINDER, 0, NULL);
binder_debug(BINDER_DEBUG_TRANSACTION,
- " ref %d desc %d -> node %d u%p\n",
- ref->debug_id, ref->desc, ref->node->debug_id,
- ref->node->ptr);
+ " ref %d desc %d -> node %d u%p\n",
+ ref->debug_id, ref->desc,
+ ref->node->debug_id,
+ ref->node->ptr);
} else {
struct binder_ref *new_ref;
- new_ref = binder_get_ref_for_node(target_proc, ref->node);
+ new_ref = binder_get_ref_for_node(target_proc,
+ ref->node);
if (new_ref == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
fp->handle = new_ref->desc;
- binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
+ binder_inc_ref(new_ref, fp->type ==
+ BINDER_TYPE_HANDLE, NULL);
binder_debug(BINDER_DEBUG_TRANSACTION,
- " ref %d desc %d -> ref %d desc %d (node %d)\n",
- ref->debug_id, ref->desc, new_ref->debug_id,
- new_ref->desc, ref->node->debug_id);
+ " ref %d desc %d -> ref %d"
+ " desc %d (node %d)\n",
+ ref->debug_id, ref->desc,
+ new_ref->debug_id,
+ new_ref->desc,
+ ref->node->debug_id);
}
} break;
@@ -1675,13 +1707,19 @@
if (reply) {
if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
- binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",
- proc->pid, thread->pid, fp->handle);
+ binder_user_error("binder: %d:%d got"
+ " reply with fd, %ld, but"
+ " target does not allow fds\n",
+ proc->pid, thread->pid,
+ fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
}
} else if (!target_node->accept_fds) {
- binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",
+ binder_user_error(
+ "binder: %d:%d got transaction"
+ " with fd, %ld, but target does"
+ " not allow fds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
@@ -1689,12 +1727,15 @@
file = fget(fp->handle);
if (file == NULL) {
- binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",
+ binder_user_error(
+ "binder: %d:%d got transaction"
+ " with invalid fd, %ld\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fget_failed;
}
- target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
+ target_fd = task_get_unused_fd_flags(target_proc,
+ O_CLOEXEC);
if (target_fd < 0) {
fput(file);
return_error = BR_FAILED_REPLY;
@@ -1702,7 +1743,8 @@
}
task_fd_install(target_proc, target_fd, file);
binder_debug(BINDER_DEBUG_TRANSACTION,
- " fd %ld -> %d\n", fp->handle, target_fd);
+ " fd %ld -> %d\n", fp->handle,
+ target_fd);
/* TODO: fput? */
fp->handle = target_fd;
} break;
@@ -1851,9 +1893,11 @@
break;
}
binder_debug(BINDER_DEBUG_USER_REFS,
- "binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n",
- proc->pid, thread->pid, debug_string, ref->debug_id,
- ref->desc, ref->strong, ref->weak, ref->node->debug_id);
+ "binder: %d:%d %s ref %d desc %d s %d w %d"
+ " for node %d\n", proc->pid, thread->pid,
+ debug_string, ref->debug_id, ref->desc,
+ ref->strong, ref->weak,
+ ref->node->debug_id);
break;
}
case BC_INCREFS_DONE:
@@ -1914,15 +1958,19 @@
binder_debug(BINDER_DEBUG_USER_REFS,
"binder: %d:%d %s node %d ls %d lw %d\n",
proc->pid, thread->pid,
- cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE",
- node->debug_id, node->local_strong_refs, node->local_weak_refs);
+ cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE"
+ : "BC_ACQUIRE_DONE",
+ node->debug_id, node->local_strong_refs,
+ node->local_weak_refs);
break;
}
case BC_ATTEMPT_ACQUIRE:
- printk(KERN_ERR "binder: BC_ATTEMPT_ACQUIRE not supported\n");
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: BC_ATTEMPT_ACQUIRE not supported\n");
return -EINVAL;
case BC_ACQUIRE_RESULT:
- printk(KERN_ERR "binder: BC_ACQUIRE_RESULT not supported\n");
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: BC_ACQUIRE_RESULT not supported\n");
return -EINVAL;
case BC_FREE_BUFFER: {
@@ -1948,9 +1996,11 @@
break;
}
binder_debug(BINDER_DEBUG_FREE_BUFFER,
- "binder: %d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n",
- proc->pid, thread->pid, data_ptr, buffer->debug_id,
- buffer->transaction ? "active" : "finished");
+ "binder: %d:%d BC_FREE_BUFFER u%p found"
+ " buffer %d for %s transaction\n",
+ proc->pid, thread->pid, data_ptr,
+ buffer->debug_id, buffer->transaction ?
+ "active" : "finished");
if (buffer->transaction) {
buffer->transaction->buffer = NULL;
@@ -2047,13 +2097,15 @@
}
binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
- "binder: %d:%d %s %p ref %d desc %d s %d w %d for node %d\n",
+ "binder: %d:%d %s %p ref %d desc %d s %d"
+ " w %d for node %d\n",
proc->pid, thread->pid,
cmd == BC_REQUEST_DEATH_NOTIFICATION ?
"BC_REQUEST_DEATH_NOTIFICATION" :
"BC_CLEAR_DEATH_NOTIFICATION",
cookie, ref->debug_id, ref->desc,
- ref->strong, ref->weak, ref->node->debug_id);
+ ref->strong, ref->weak,
+ ref->node->debug_id);
if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
if (ref->death) {
@@ -2067,10 +2119,12 @@
death = kzalloc(sizeof(*death), GFP_KERNEL);
if (death == NULL) {
thread->return_error = BR_ERROR;
- binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
- "binder: %d:%d "
- "BC_REQUEST_DEATH_NOTIFICATION failed\n",
- proc->pid, thread->pid);
+ binder_debug(
+ BINDER_DEBUG_FAILED_TRANSACTION,
+ "binder: %d:%d "
+ "BC_REQUEST_DEATH_NOTIFICATION"
+ " failed\n",
+ proc->pid, thread->pid);
break;
}
binder_stats_created(BINDER_STAT_DEATH);
@@ -2159,7 +2213,8 @@
} break;
default:
- printk(KERN_ERR "binder: %d:%d unknown command %d\n",
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: %d:%d unknown command %d\n",
proc->pid, thread->pid, cmd);
return -EINVAL;
}
@@ -2629,9 +2684,11 @@
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
- /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/
+ /*binder_debug(BINDER_DEBUG_TOP_ERRORS, "binder_ioctl: %d:%d %x %lx\n",
+ proc->pid, current->pid, cmd, arg);*/
- ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
+ ret = wait_event_interruptible(binder_user_error_wait,
+ binder_stop_on_user_error < 2);
if (ret)
return ret;
@@ -2688,20 +2745,23 @@
break;
}
case BINDER_SET_MAX_THREADS:
- if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
+ if (copy_from_user(&proc->max_threads, ubuf,
+ sizeof(proc->max_threads))) {
ret = -EINVAL;
goto err;
}
break;
case BINDER_SET_CONTEXT_MGR:
if (binder_context_mgr_node != NULL) {
- printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n");
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: BINDER_SET_CONTEXT_MGR already set\n");
ret = -EBUSY;
goto err;
}
if (binder_context_mgr_uid != -1) {
if (binder_context_mgr_uid != current->cred->euid) {
- printk(KERN_ERR "binder: BINDER_SET_"
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: BINDER_SET_"
"CONTEXT_MGR bad uid %d != %d\n",
current->cred->euid,
binder_context_mgr_uid);
@@ -2747,7 +2807,9 @@
mutex_unlock(&binder_lock);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
- printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: %d:%d ioctl %x %lx returned %d\n",
+ proc->pid, current->pid, cmd, arg, ret);
return ret;
}
@@ -2821,7 +2883,9 @@
#ifdef CONFIG_CPU_CACHE_VIPT
if (cache_is_vipt_aliasing()) {
while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) {
- printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder_mmap: %d %lx-%lx maps %p bad alignment\n",
+ proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
vma->vm_start += PAGE_SIZE;
}
}
@@ -2852,7 +2916,8 @@
proc->files = get_files_struct(current);
proc->vma = vma;
- /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n",
+ /*binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder_mmap: %d %lx-%lx maps %p\n",
proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/
return 0;
@@ -2865,7 +2930,8 @@
err_get_vm_area_failed:
err_already_mapped:
err_bad_arg:
- printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n",
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder_mmap: %d %lx-%lx %s failed %d\n",
proc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
return ret;
}
@@ -3020,7 +3086,8 @@
if (t) {
t->buffer = NULL;
buffer->transaction = NULL;
- printk(KERN_ERR "binder: release proc %d, "
+ binder_debug(BINDER_DEBUG_TOP_ERRORS,
+ "binder: release proc %d, "
"transaction %d, not freed\n",
proc->pid, t->debug_id);
/*BUG();*/
diff --git a/drivers/staging/qcache/qcache-main.c b/drivers/staging/qcache/qcache-main.c
index b6de268..f6838d1 100644
--- a/drivers/staging/qcache/qcache-main.c
+++ b/drivers/staging/qcache/qcache-main.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2010,2011, Dan Magenheimer, Oracle Corp.
* Copyright (c) 2010,2011, Nitin Gupta
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Qcache provides an in-kernel "host implementation" for transcendent memory
* and, thus indirectly, for cleancache and frontswap. Qcache includes a
@@ -230,7 +230,6 @@
budnum = zbud_budnum(zh);
BUG_ON(size == 0 || size > zbud_max_buddy_size());
zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
- ASSERT_SPINLOCK(&zbpg->lock);
p = (char *)zbpg;
if (budnum == 0)
p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) &
@@ -270,7 +269,6 @@
ASSERT_SENTINEL(zbpg, ZBPG);
BUG_ON(!list_empty(&zbpg->bud_list));
- ASSERT_SPINLOCK(&zbpg->lock);
BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid));
BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid));
INVERT_SENTINEL(zbpg, ZBPG);
@@ -312,7 +310,6 @@
return;
}
size = zbud_free(zh);
- ASSERT_SPINLOCK(&zbpg->lock);
zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0];
if (zh_other->size == 0) { /* was unbuddied: unlist and free */
chunks = zbud_size_to_chunks(size) ;
@@ -372,7 +369,6 @@
goto init_zh;
found_unbuddied:
- ASSERT_SPINLOCK(&zbpg->lock);
zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
BUG_ON(!((zh0->size == 0) ^ (zh1->size == 0)));
if (zh0->size != 0) { /* buddy0 in use, buddy1 is vacant */
diff --git a/drivers/staging/qcache/tmem.h b/drivers/staging/qcache/tmem.h
index 344561f..9f6bfbb 100644
--- a/drivers/staging/qcache/tmem.h
+++ b/drivers/staging/qcache/tmem.h
@@ -4,7 +4,7 @@
* Transcendent memory
*
* Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*/
#ifndef _TMEM_H_
@@ -49,8 +49,6 @@
#define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0)
#endif
-#define ASSERT_SPINLOCK(_l) WARN_ON(!spin_is_locked(_l))
-
/*
* A pool is the highest-level data structure managed by tmem and
* usually corresponds to a large independent set of pages such as
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 63d8666..a616ffc 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -81,7 +81,7 @@
/* Initial temperature threshold values */
#define TSENS_LOWER_LIMIT_TH 0x50
#define TSENS_UPPER_LIMIT_TH 0xdf
-#define TSENS_MIN_LIMIT_TH 0x38
+#define TSENS_MIN_LIMIT_TH 0x0
#define TSENS_MAX_LIMIT_TH 0xff
#define TSENS_S0_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x00003628)
@@ -424,6 +424,15 @@
return tsens_tz_get_trip_temp(thermal, TSENS_TRIP_STAGE3, temp);
}
+static int tsens_tz_notify(struct thermal_zone_device *thermal,
+ int count, enum thermal_trip_type type)
+{
+ /* TSENS driver does not shutdown the device.
+ All Thermal notification are sent to the
+ thermal daemon to take appropriate action */
+ return 1;
+}
+
static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
int trip, long temp)
{
@@ -519,6 +528,7 @@
.get_trip_temp = tsens_tz_get_trip_temp,
.set_trip_temp = tsens_tz_set_trip_temp,
.get_crit_temp = tsens_tz_get_crit_temp,
+ .notify = tsens_tz_notify,
};
static void notify_uspace_tsens_fn(struct work_struct *work)
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 9e1e388..6e3982e 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -2,7 +2,7 @@
* drivers/serial/msm_serial.c - driver for msm7k serial device and console
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2012, 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
@@ -1007,6 +1007,10 @@
break;
case 3:
clk_en(port, 0);
+ ret = clk_set_rate(msm_hsl_port->clk, 0);
+ if (ret)
+ pr_err("%s(): Error setting UART clock rate to zero.\n",
+ __func__);
break;
default:
pr_err("%s(): msm_serial_hsl: Unknown PM state %d\n",
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 94ed950..97e7aa4 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -594,6 +594,24 @@
default USB_GADGET
select USB_GADGET_SELECTED
+config USB_GADGET_CI13XXX_MSM_HSIC
+ boolean "MIPS HSIC CI13xxx for MSM"
+ depends on ARCH_MSM
+ select USB_GADGET_DUALSPEED
+ help
+ MSM SoC has chipidea USB controller. This driver uses
+ ci13xxx_udc core. Support USB-HSIC core.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "ci13xxx_msm_hsic" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_CI13XXX_MSM_HSIC
+ tristate
+ depends on USB_GADGET_CI13XXX_MSM_HSIC
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
#
# LAST -- dummy/emulated controller
#
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 064960c..141f649 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -27,6 +27,7 @@
obj-$(CONFIG_USB_EG20T) += pch_udc.o
obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o
mv_udc-y := mv_udc_core.o mv_udc_phy.o
+obj-$(CONFIG_USB_CI13XXX_MSM_HSIC) += ci13xxx_msm_hsic.o
obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
obj-$(CONFIG_USB_MSM_72K) += msm72k_udc.o
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
new file mode 100644
index 0000000..135c84d
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -0,0 +1,484 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/usb.h>
+
+#include <linux/usb/gadget.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb/msm_hsusb.h>
+
+#include <mach/clk.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_xo.h>
+
+#include "ci13xxx_udc.c"
+
+#define MSM_USB_BASE (mhsic->regs)
+
+#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
+#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
+#define USB_PHY_VDD_DIG_LOAD 49360 /* uA */
+#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
+#define HSIC_CFG_REG 0x30
+#define HSIC_IO_CAL_PER_REG 0x33
+#define HSIC_DBG1_REG 0x38
+
+struct msm_hsic_per *the_mhsic;
+
+struct msm_hsic_per {
+ struct device *dev;
+ struct clk *iface_clk;
+ struct clk *core_clk;
+ struct clk *alt_core_clk;
+ struct clk *phy_clk;
+ struct clk *cal_clk;
+ struct regulator *hsic_vddcx;
+ bool async_int;
+ void __iomem *regs;
+ int irq;
+};
+
+static int msm_hsic_init_vddcx(struct msm_hsic_per *mhsic, int init)
+{
+ int ret = 0;
+
+ if (!init)
+ goto disable_reg;
+
+ mhsic->hsic_vddcx = regulator_get(mhsic->dev, "HSIC_VDDCX");
+ if (IS_ERR(mhsic->hsic_vddcx)) {
+ dev_err(mhsic->dev, "unable to get hsic vddcx\n");
+ return PTR_ERR(mhsic->hsic_vddcx);
+ }
+
+ ret = regulator_set_voltage(mhsic->hsic_vddcx,
+ USB_PHY_VDD_DIG_VOL_MIN,
+ USB_PHY_VDD_DIG_VOL_MAX);
+ if (ret) {
+ dev_err(mhsic->dev, "unable to set the voltage"
+ "for hsic vddcx\n");
+ goto reg_set_voltage_err;
+ }
+
+ ret = regulator_set_optimum_mode(mhsic->hsic_vddcx,
+ USB_PHY_VDD_DIG_LOAD);
+ if (ret < 0) {
+ pr_err("%s: Unable to set optimum mode of the regulator:"
+ "VDDCX\n", __func__);
+ goto reg_optimum_mode_err;
+ }
+
+ ret = regulator_enable(mhsic->hsic_vddcx);
+ if (ret) {
+ dev_err(mhsic->dev, "unable to enable hsic vddcx\n");
+ goto reg_enable_err;
+ }
+
+ return 0;
+
+disable_reg:
+ regulator_disable(mhsic->hsic_vddcx);
+reg_enable_err:
+ regulator_set_optimum_mode(mhsic->hsic_vddcx, 0);
+reg_optimum_mode_err:
+ regulator_set_voltage(mhsic->hsic_vddcx, 0,
+ USB_PHY_VDD_DIG_VOL_MIN);
+reg_set_voltage_err:
+ regulator_put(mhsic->hsic_vddcx);
+
+ return ret;
+
+}
+
+static int ulpi_write(struct msm_hsic_per *mhsic, u32 val, u32 reg)
+{
+ int cnt = 0;
+
+ /* initiate write operation */
+ writel_relaxed(ULPI_RUN | ULPI_WRITE |
+ ULPI_ADDR(reg) | ULPI_DATA(val),
+ USB_ULPI_VIEWPORT);
+
+ /* wait for completion */
+ while (cnt < ULPI_IO_TIMEOUT_USEC) {
+ if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
+ break;
+ udelay(1);
+ cnt++;
+ }
+
+ if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+ dev_err(mhsic->dev, "ulpi_write: timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int msm_hsic_phy_clk_reset(struct msm_hsic_per *mhsic)
+{
+ int ret;
+
+ ret = clk_reset(mhsic->core_clk, CLK_RESET_ASSERT);
+ if (ret) {
+ clk_disable(mhsic->alt_core_clk);
+ dev_err(mhsic->dev, "usb phy clk assert failed\n");
+ return ret;
+ }
+ usleep_range(10000, 12000);
+ clk_disable(mhsic->alt_core_clk);
+
+ ret = clk_reset(mhsic->core_clk, CLK_RESET_DEASSERT);
+ if (ret)
+ dev_err(mhsic->dev, "usb phy clk deassert failed\n");
+
+ return ret;
+}
+
+static int msm_hsic_phy_reset(struct msm_hsic_per *mhsic)
+{
+ u32 val;
+ int ret;
+
+ ret = msm_hsic_phy_clk_reset(mhsic);
+ if (ret)
+ return ret;
+
+ val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
+ writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+ /*
+ * Ensure that RESET operation is completed before
+ * turning off clock.
+ */
+ mb();
+ dev_dbg(mhsic->dev, "phy_reset: success\n");
+
+ return 0;
+}
+
+static int msm_hsic_enable_clocks(struct platform_device *pdev,
+ struct msm_hsic_per *mhsic, bool enable)
+{
+ int ret = 0;
+
+ if (!enable)
+ goto put_clocks;
+
+ mhsic->iface_clk = clk_get(&pdev->dev, "iface_clk");
+ if (IS_ERR(mhsic->iface_clk)) {
+ dev_err(mhsic->dev, "failed to get iface_clk\n");
+ ret = PTR_ERR(mhsic->iface_clk);
+ goto put_iface_clk;
+ }
+
+ mhsic->core_clk = clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(mhsic->core_clk)) {
+ dev_err(mhsic->dev, "failed to get core_clk\n");
+ ret = PTR_ERR(mhsic->core_clk);
+ goto put_core_clk;
+ }
+
+ mhsic->phy_clk = clk_get(&pdev->dev, "phy_clk");
+ if (IS_ERR(mhsic->phy_clk)) {
+ dev_err(mhsic->dev, "failed to get phy_clk\n");
+ ret = PTR_ERR(mhsic->phy_clk);
+ goto put_phy_clk;
+ }
+
+ mhsic->alt_core_clk = clk_get(&pdev->dev, "alt_core_clk");
+ if (IS_ERR(mhsic->alt_core_clk)) {
+ dev_err(mhsic->dev, "failed to get alt_core_clk\n");
+ ret = PTR_ERR(mhsic->alt_core_clk);
+ goto put_alt_core_clk;
+ }
+
+ mhsic->cal_clk = clk_get(&pdev->dev, "cal_clk");
+ if (IS_ERR(mhsic->cal_clk)) {
+ dev_err(mhsic->dev, "failed to get cal_clk\n");
+ ret = PTR_ERR(mhsic->cal_clk);
+ goto put_cal_clk;
+ }
+
+ clk_enable(mhsic->iface_clk);
+ clk_enable(mhsic->core_clk);
+ clk_enable(mhsic->phy_clk);
+ clk_enable(mhsic->alt_core_clk);
+ clk_enable(mhsic->cal_clk);
+
+ return 0;
+
+put_clocks:
+ clk_disable(mhsic->iface_clk);
+ clk_disable(mhsic->core_clk);
+ clk_disable(mhsic->phy_clk);
+ clk_disable(mhsic->alt_core_clk);
+ clk_disable(mhsic->cal_clk);
+put_cal_clk:
+ clk_put(mhsic->cal_clk);
+put_alt_core_clk:
+ clk_put(mhsic->alt_core_clk);
+put_phy_clk:
+ clk_put(mhsic->phy_clk);
+put_core_clk:
+ clk_put(mhsic->core_clk);
+put_iface_clk:
+ clk_put(mhsic->iface_clk);
+
+ return ret;
+}
+
+static int msm_hsic_reset(struct msm_hsic_per *mhsic)
+{
+ int cnt = 0;
+ int ret;
+
+ ret = msm_hsic_phy_reset(mhsic);
+ if (ret) {
+ dev_err(mhsic->dev, "phy_reset failed\n");
+ return ret;
+ }
+
+ writel_relaxed(USBCMD_RESET, USB_USBCMD);
+ while (cnt < LINK_RESET_TIMEOUT_USEC) {
+ if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
+ break;
+ udelay(1);
+ cnt++;
+ }
+ if (cnt >= LINK_RESET_TIMEOUT_USEC)
+ return -ETIMEDOUT;
+
+ /* Reset PORTSC and select ULPI phy */
+ writel_relaxed(0x80000000, USB_PORTSC);
+ return 0;
+}
+
+static void msm_hsic_start(void)
+{
+ int ret;
+
+ /* programmable length of connect signaling (33.2ns) */
+ ret = ulpi_write(the_mhsic, 3, HSIC_DBG1_REG);
+ if (ret) {
+ pr_err("%s: Unable to program length of connect signaling\n",
+ __func__);
+ }
+
+ /*set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */
+ ret = ulpi_write(the_mhsic, 0xFF, HSIC_IO_CAL_PER_REG);
+
+ if (ret) {
+ pr_err("%s: Unable to set periodic calibration interval\n",
+ __func__);
+ }
+
+ /* Enable periodic IO calibration in HSIC_CFG register */
+ ret = ulpi_write(the_mhsic, 0xE9, HSIC_CFG_REG);
+ if (ret) {
+ pr_err("%s: Unable to enable periodic IO calibration\n",
+ __func__);
+ }
+}
+
+/**
+ * Dummy match function - will be called only for HSIC msm
+ * device (msm_device_gadget_hsic_peripheral).
+ */
+static inline int __match(struct device *dev, void *data) { return 1; }
+
+static void msm_hsic_connect_peripheral(struct device *msm_udc_dev)
+{
+ struct device *dev;
+ struct usb_gadget *gadget;
+
+ dev = device_find_child(msm_udc_dev, NULL, __match);
+ gadget = dev_to_usb_gadget(dev);
+ usb_gadget_vbus_connect(gadget);
+}
+
+static irqreturn_t msm_udc_hsic_irq(int irq, void *data)
+{
+ return udc_irq();
+}
+
+static void ci13xxx_msm_hsic_notify_event(struct ci13xxx *udc, unsigned event)
+{
+ struct device *dev = udc->gadget.dev.parent;
+ struct msm_hsic_per *mhsic = the_mhsic;
+
+ switch (event) {
+ case CI13XXX_CONTROLLER_RESET_EVENT:
+ dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
+ writel_relaxed(0, USB_AHBBURST);
+ writel_relaxed(0, USB_AHBMODE);
+ break;
+ case CI13XXX_CONTROLLER_CONNECT_EVENT:
+ dev_dbg(dev, "CI13XXX_CONTROLLER_CONNECT_EVENT received\n");
+ msm_hsic_start();
+ break;
+ default:
+ dev_dbg(dev, "unknown ci13xxx_udc event\n");
+ break;
+ }
+}
+
+static struct ci13xxx_udc_driver ci13xxx_msm_udc_hsic_driver = {
+ .name = "ci13xxx_msm_hsic",
+ .flags = CI13XXX_REGS_SHARED |
+ CI13XXX_PULLUP_ON_VBUS |
+ CI13XXX_DISABLE_STREAMING |
+ CI13XXX_ZERO_ITC,
+
+ .notify_event = ci13xxx_msm_hsic_notify_event,
+};
+
+static int __devinit msm_hsic_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct msm_hsic_per *mhsic;
+ int ret = 0;
+
+ dev_dbg(&pdev->dev, "msm-hsic probe\n");
+
+ mhsic = kzalloc(sizeof(struct msm_hsic_per), GFP_KERNEL);
+ if (!mhsic) {
+ dev_err(&pdev->dev, "unable to allocate msm_hsic\n");
+ return -ENOMEM;
+ }
+ the_mhsic = mhsic;
+ platform_set_drvdata(pdev, mhsic);
+ mhsic->dev = &pdev->dev;
+
+ mhsic->irq = platform_get_irq(pdev, 0);
+ if (mhsic->irq < 0) {
+ dev_err(&pdev->dev, "Unable to get IRQ resource\n");
+ ret = mhsic->irq;
+ goto error;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get memory resource\n");
+ ret = -ENODEV;
+ goto error;
+ }
+ mhsic->regs = ioremap(res->start, resource_size(res));
+ if (!mhsic->regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto unmap;
+ }
+ dev_info(&pdev->dev, "HSIC Peripheral regs = %p\n", mhsic->regs);
+
+ ret = msm_hsic_enable_clocks(pdev, mhsic, true);
+
+ if (ret) {
+ dev_err(&pdev->dev, "msm_hsic_enable_clocks failed\n");
+ ret = -ENODEV;
+ goto deinit_clocks;
+ }
+ ret = msm_hsic_init_vddcx(mhsic, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to initialize VDDCX\n");
+ ret = -ENODEV;
+ goto deinit_vddcx;
+ }
+
+ ret = msm_hsic_reset(mhsic);
+ if (ret) {
+ dev_err(&pdev->dev, "msm_hsic_reset failed\n");
+ ret = -ENODEV;
+ goto deinit_vddcx;
+ }
+
+ ret = udc_probe(&ci13xxx_msm_udc_hsic_driver, &pdev->dev, mhsic->regs);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "udc_probe failed\n");
+ ret = -ENODEV;
+ goto deinit_vddcx;
+ }
+
+ msm_hsic_connect_peripheral(&pdev->dev);
+
+ ret = request_irq(mhsic->irq, msm_udc_hsic_irq,
+ IRQF_SHARED, pdev->name, pdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ ret = -ENODEV;
+ goto udc_remove;
+ }
+
+ pm_runtime_no_callbacks(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+udc_remove:
+ udc_remove();
+deinit_vddcx:
+ msm_hsic_init_vddcx(mhsic, 0);
+deinit_clocks:
+ msm_hsic_enable_clocks(pdev, mhsic, 0);
+unmap:
+ iounmap(mhsic->regs);
+error:
+ kfree(mhsic);
+ return ret;
+}
+
+static int __devexit hsic_msm_remove(struct platform_device *pdev)
+{
+ struct msm_hsic_per *mhsic = platform_get_drvdata(pdev);
+
+ device_init_wakeup(&pdev->dev, 0);
+ msm_hsic_init_vddcx(mhsic, 0);
+ msm_hsic_enable_clocks(pdev, mhsic, 0);
+ udc_remove();
+ iounmap(mhsic->regs);
+ kfree(mhsic);
+
+ return 0;
+}
+static struct platform_driver msm_hsic_peripheral_driver = {
+ .probe = msm_hsic_probe,
+ .remove = __devexit_p(hsic_msm_remove),
+ .driver = {
+ .name = "msm_hsic_peripheral",
+ },
+};
+
+static int __init msm_hsic_peripheral_init(void)
+{
+ return platform_driver_probe(&msm_hsic_peripheral_driver,
+ msm_hsic_probe);
+}
+
+static void __exit msm_hsic_peripheral_exit(void)
+{
+ platform_driver_unregister(&msm_hsic_peripheral_driver);
+}
+
+module_init(msm_hsic_peripheral_init);
+module_exit(msm_hsic_peripheral_exit);
+
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 703494a..35327cc 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2816,8 +2816,12 @@
}
spin_unlock_irqrestore(udc->lock, flags);
- if (is_active)
+ if (is_active) {
hw_device_state(udc->ep0out.qh.dma);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_CONNECT_EVENT);
+ }
else
hw_device_state(0);
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 35b0712..fce611a 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -127,6 +127,7 @@
#define CI13XXX_ZERO_ITC BIT(4)
#define CI13XXX_CONTROLLER_RESET_EVENT 0
+#define CI13XXX_CONTROLLER_CONNECT_EVENT 1
void (*notify_event) (struct ci13xxx *udc, unsigned event);
};
@@ -233,7 +234,10 @@
"[%s] " format "\n", __func__, ## args); \
} while (0)
+#ifndef err
#define err(format, args...) ci13xxx_printk(KERN_ERR, format, ## args)
+#endif
+
#define warn(format, args...) ci13xxx_printk(KERN_WARNING, format, ## args)
#define info(format, args...) ci13xxx_printk(KERN_INFO, format, ## args)
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index f492143..10a9256 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -2,7 +2,7 @@
* Diag Function Device - Route ARM9 and ARM11 DIAG messages
* between HOST and DEVICE.
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -525,6 +525,7 @@
if (rc) {
ERROR(dev->cdev, "can't enable %s, result %d\n",
dev->in->name, rc);
+ dev->in->driver_data = NULL;
return rc;
}
dev->out->driver_data = dev;
@@ -533,6 +534,8 @@
ERROR(dev->cdev, "can't enable %s, result %d\n",
dev->out->name, rc);
usb_ep_disable(dev->in);
+ dev->in->driver_data = NULL;
+ dev->out->driver_data = NULL;
return rc;
}
schedule_work(&dev->config_work);
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index cbcf5ac..177176e 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -435,6 +435,7 @@
pr_debug("%s: port#%d\n", __func__, dev->port_num);
usb_ep_disable(dev->notify);
+ dev->notify->driver_data = NULL;
atomic_set(&dev->online, 0);
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index de8c8ed..d9a901b 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -477,6 +477,7 @@
if (gser->notify->driver_data) {
DBG(cdev, "reset generic ctl ttyGS%d\n", gser->port_num);
usb_ep_disable(gser->notify);
+ gser->notify->driver_data = NULL;
}
gser->notify_desc = ep_choose(cdev->gadget,
gser->hs.notify,
@@ -519,6 +520,7 @@
#ifdef CONFIG_MODEM_SUPPORT
usb_ep_fifo_flush(gser->notify);
usb_ep_disable(gser->notify);
+ gser->notify->driver_data = NULL;
#endif
gser->online = 0;
}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 0360f56..ca298cd 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -2766,14 +2766,17 @@
if (fsg->bulk_in_enabled) {
usb_ep_disable(fsg->bulk_in);
fsg->bulk_in_enabled = 0;
+ fsg_bulk_in->driver_data = NULL;
}
if (fsg->bulk_out_enabled) {
usb_ep_disable(fsg->bulk_out);
fsg->bulk_out_enabled = 0;
+ fsg_bulk_out->driver_data = NULL;
}
if (fsg->intr_in_enabled) {
usb_ep_disable(fsg->intr_in);
fsg->intr_in_enabled = 0;
+ fsg_intr_in->driver_data = NULL;
}
fsg->running = 0;
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 05692bb..da312d4 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -160,6 +160,13 @@
#define gadget_is_ci13xxx_msm(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_CI13XXX_MSM_HSIC
+#define gadget_is_ci13xxx_msm_hsic(g) \
+ (!strncmp("ci13xxx_msm_hsic", (g)->name, 16))
+#else
+#define gadget_is_ci13xxx_msm_hsic(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_RENESAS_USBHS
#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name))
#else
@@ -231,6 +238,8 @@
return 0x30;
else if (gadget_is_msm72k(gadget))
return 0x31;
+ else if (gadget_is_ci13xxx_msm_hsic(gadget))
+ return 0x32;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index df0646f..23e0da8 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -602,7 +602,7 @@
struct bam_ch_info *d;
spin_lock_irqsave(&port->port_lock_ul, flags);
- spin_lock_irqsave(&port->port_lock_dl, flags);
+ spin_lock(&port->port_lock_dl);
if (!port || !port->port_usb)
goto free_buf_out;
@@ -619,7 +619,7 @@
dev_kfree_skb_any(skb);
free_buf_out:
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
}
@@ -643,15 +643,17 @@
unsigned long flags;
spin_lock_irqsave(&port->port_lock_ul, flags);
- spin_lock_irqsave(&port->port_lock_dl, flags);
+ spin_lock(&port->port_lock_dl);
port->port_usb = 0;
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
/* disable endpoints */
usb_ep_disable(port->gr->out);
usb_ep_disable(port->gr->in);
+ port->gr->in->driver_data = NULL;
+ port->gr->out->driver_data = NULL;
}
static void gbam_connect_work(struct work_struct *w)
@@ -662,13 +664,13 @@
unsigned long flags;
spin_lock_irqsave(&port->port_lock_ul, flags);
- spin_lock_irqsave(&port->port_lock_dl, flags);
+ spin_lock(&port->port_lock_dl);
if (!port->port_usb) {
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
return;
}
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
if (!test_bit(BAM_CH_READY, &d->flags))
@@ -712,9 +714,9 @@
}
port->gr->out->driver_data = port;
spin_lock_irqsave(&port->port_lock_ul, flags);
- spin_lock_irqsave(&port->port_lock_dl, flags);
+ spin_lock(&port->port_lock_dl);
port->port_usb = port->gr;
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
@@ -773,10 +775,10 @@
/* if usb is online, try opening bam_ch */
spin_lock_irqsave(&port->port_lock_ul, flags);
- spin_lock_irqsave(&port->port_lock_dl, flags);
+ spin_lock(&port->port_lock_dl);
if (port->port_usb)
queue_work(gbam_wq, &port->connect_w);
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
break;
@@ -805,12 +807,12 @@
d = &port->data_ch;
spin_lock_irqsave(&port->port_lock_ul, flags);
- spin_lock_irqsave(&port->port_lock_dl, flags);
+ spin_lock(&port->port_lock_dl);
if (port->port_usb) {
ep_in = port->port_usb->in;
ep_out = port->port_usb->out;
}
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
if (ep_in)
@@ -822,6 +824,9 @@
msm_bam_dmux_close(d->id);
+ /* bam dmux will free all pending skbs */
+ d->pending_with_bam = 0;
+
clear_bit(BAM_CH_READY, &d->flags);
clear_bit(BAM_CH_OPENED, &d->flags);
}
@@ -941,7 +946,7 @@
if (!port)
continue;
spin_lock_irqsave(&port->port_lock_ul, flags);
- spin_lock_irqsave(&port->port_lock_dl, flags);
+ spin_lock(&port->port_lock_dl);
d = &port->data_ch;
@@ -964,7 +969,7 @@
test_bit(BAM_CH_OPENED, &d->flags),
test_bit(BAM_CH_READY, &d->flags));
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
}
@@ -989,7 +994,7 @@
continue;
spin_lock_irqsave(&port->port_lock_ul, flags);
- spin_lock_irqsave(&port->port_lock_dl, flags);
+ spin_lock(&port->port_lock_dl);
d = &port->data_ch;
@@ -999,7 +1004,7 @@
d->tohost_drp_cnt = 0;
d->tomodem_drp_cnt = 0;
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
}
return count;
@@ -1066,10 +1071,10 @@
gbam_free_buffers(port);
spin_lock_irqsave(&port->port_lock_ul, flags);
- spin_lock_irqsave(&port->port_lock_dl, flags);
+ spin_lock(&port->port_lock_dl);
port->port_usb = 0;
n_tx_req_queued = 0;
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
/* disable endpoints */
@@ -1131,7 +1136,7 @@
gr->out->driver_data = port;
spin_lock_irqsave(&port->port_lock_ul, flags);
- spin_lock_irqsave(&port->port_lock_dl, flags);
+ spin_lock(&port->port_lock_dl);
port->port_usb = gr;
d->to_host = 0;
@@ -1139,7 +1144,7 @@
d->pending_with_bam = 0;
d->tohost_drp_cnt = 0;
d->tomodem_drp_cnt = 0;
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 56559bf..ec9ac24 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -38,6 +38,7 @@
#include <linux/regulator/consumer.h>
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/pm_qos_params.h>
+#include <linux/power_supply.h>
#include <mach/clk.h>
#include <mach/msm_xo.h>
@@ -838,6 +839,35 @@
}
#endif
+static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
+{
+ struct power_supply *psy;
+
+ psy = power_supply_get_by_name("usb");
+ if (!psy)
+ goto psy_not_supported;
+
+ if (motg->cur_power == 0 && mA > 0) {
+ /* Enable charging */
+ if (power_supply_set_online(psy, true))
+ goto psy_not_supported;
+ } else if (motg->cur_power > 0 && mA == 0) {
+ /* Disable charging */
+ if (power_supply_set_online(psy, false))
+ goto psy_not_supported;
+ return 0;
+ }
+ /* Set max current limit */
+ if (power_supply_set_current_limit(psy, 1000*mA))
+ goto psy_not_supported;
+
+ return 0;
+
+psy_not_supported:
+ dev_dbg(motg->otg.dev, "Power Supply doesn't support USB charger\n");
+ return -ENXIO;
+}
+
static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
{
if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
@@ -851,7 +881,14 @@
return;
dev_info(motg->otg.dev, "Avail curr from USB = %u\n", mA);
- pm8921_charger_vbus_draw(mA);
+
+ /*
+ * Use Power Supply API if supported, otherwise fallback
+ * to legacy pm8921 API.
+ */
+ if (msm_otg_notify_power_supply(motg, mA))
+ pm8921_charger_vbus_draw(mA);
+
motg->cur_power = mA;
}
@@ -1676,11 +1713,12 @@
else
clear_bit(B_SESS_VLD, &motg->inputs);
} else if (pdata->otg_control == OTG_PMIC_CONTROL) {
- if (irq_read_line(motg->pdata->pmic_id_irq))
- set_bit(ID, &motg->inputs);
- else
- clear_bit(ID, &motg->inputs);
-
+ if (pdata->pmic_id_irq) {
+ if (irq_read_line(pdata->pmic_id_irq))
+ set_bit(ID, &motg->inputs);
+ else
+ clear_bit(ID, &motg->inputs);
+ }
/*
* VBUS initial state is reported after PMIC
* driver initialization. Wait for it.
@@ -1693,10 +1731,18 @@
break;
case USB_PERIPHERAL:
set_bit(ID, &motg->inputs);
- if (otgsc & OTGSC_BSV)
- set_bit(B_SESS_VLD, &motg->inputs);
- else
- clear_bit(B_SESS_VLD, &motg->inputs);
+ if (pdata->otg_control == OTG_PHY_CONTROL) {
+ if (otgsc & OTGSC_BSV)
+ set_bit(B_SESS_VLD, &motg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &motg->inputs);
+ } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
+ /*
+ * VBUS initial state is reported after PMIC
+ * driver initialization. Wait for it.
+ */
+ wait_for_completion(&pmic_vbus_init);
+ }
break;
default:
break;
@@ -2474,7 +2520,8 @@
goto free_irq;
}
- if (motg->pdata->otg_control == OTG_PMIC_CONTROL) {
+ if (motg->pdata->mode == USB_OTG &&
+ motg->pdata->otg_control == OTG_PMIC_CONTROL) {
if (motg->pdata->pmic_id_irq) {
ret = request_irq(motg->pdata->pmic_id_irq,
msm_pmic_id_irq,
@@ -2508,7 +2555,8 @@
if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
- motg->pdata->pmic_id_irq)
+ (!(motg->pdata->mode == USB_OTG) ||
+ motg->pdata->pmic_id_irq))
motg->caps = ALLOW_PHY_POWER_COLLAPSE |
ALLOW_PHY_RETENTION |
ALLOW_PHY_COMP_DISABLE;
diff --git a/drivers/video/msm/external_common.h b/drivers/video/msm/external_common.h
index c795a94..2a243cd 100644
--- a/drivers/video/msm/external_common.h
+++ b/drivers/video/msm/external_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -136,10 +136,10 @@
480, 10, 2, 33, TRUE, 25200, 60000, FALSE, TRUE}
#define HDMI_SETTINGS_720x480p60_4_3 \
{HDMI_VFRMT_720x480p60_4_3, 720, 16, 62, 60, TRUE, \
- 480, 9, 6, 30, TRUE, 27027, 60000, FALSE, TRUE}
+ 480, 9, 6, 30, TRUE, 27030, 60000, FALSE, TRUE}
#define HDMI_SETTINGS_720x480p60_16_9 \
{HDMI_VFRMT_720x480p60_16_9, 720, 16, 62, 60, TRUE, \
- 480, 9, 6, 30, TRUE, 27027, 60000, FALSE, TRUE}
+ 480, 9, 6, 30, TRUE, 27030, 60000, FALSE, TRUE}
#define HDMI_SETTINGS_1280x720p60_16_9 \
{HDMI_VFRMT_1280x720p60_16_9, 1280, 110, 40, 220, FALSE, \
720, 5, 5, 20, FALSE, 74250, 60000, FALSE, TRUE}
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index aaad2df..fc6054f 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -2324,29 +2324,6 @@
msm_hdmi_init_ddc();
- /* Read Bksv 5 bytes at 0x00 in HDCP port */
- ret = hdmi_msm_ddc_read(0x74, 0x00, bksv, 5, 5, "Bksv", TRUE);
- if (ret) {
- DEV_ERR("%s(%d): Read BKSV failed", __func__, __LINE__);
- goto error;
- }
- /* check there are 20 ones in BKSV */
- if (hdmi_msm_count_one(bksv, 5) != 20) {
- DEV_ERR("HDCP: BKSV read from Sink doesn't have "
- "20 1's and 20 0's, FAIL (BKSV="
- "%02x%02x%02x%02x%02x)\n",
- bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]);
- ret = -EINVAL;
- goto error;
- }
-
- link0_bksv_0 = bksv[3];
- link0_bksv_0 = (link0_bksv_0 << 8) | bksv[2];
- link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1];
- link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0];
- link0_bksv_1 = bksv[4];
- DEV_DBG("HDCP: BKSV=%02x%08x\n", link0_bksv_1, link0_bksv_0);
-
/* read Bcaps at 0x40 in HDCP Port */
ret = hdmi_msm_ddc_read(0x74, 0x40, &bcaps, 1, 5, "Bcaps",
TRUE);
@@ -2494,6 +2471,29 @@
DEV_DBG("HDCP: Link0-AKSV=%02x%08x\n",
link0_aksv_1 & 0xFF, link0_aksv_0);
+ /* Read Bksv 5 bytes at 0x00 in HDCP port */
+ ret = hdmi_msm_ddc_read(0x74, 0x00, bksv, 5, 5, "Bksv", TRUE);
+ if (ret) {
+ DEV_ERR("%s(%d): Read BKSV failed", __func__, __LINE__);
+ goto error;
+ }
+ /* check there are 20 ones in BKSV */
+ if (hdmi_msm_count_one(bksv, 5) != 20) {
+ DEV_ERR("HDCP: BKSV read from Sink doesn't have "
+ "20 1's and 20 0's, FAIL (BKSV="
+ "%02x%02x%02x%02x%02x)\n",
+ bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ link0_bksv_0 = bksv[3];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[2];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0];
+ link0_bksv_1 = bksv[4];
+ DEV_DBG("HDCP: BKSV=%02x%08x\n", link0_bksv_1, link0_bksv_0);
+
/* 0x0134 HDCP_RCVPORT_DATA0
[31:0] LINK0_BKSV_0 */
HDMI_OUTP(0x0134, link0_bksv_0);
@@ -3073,7 +3073,7 @@
{4096, 27000}, {6272, 30000}, {6144, 27000}, {12544, 30000},
{12288, 27000}, {25088, 30000}, {24576, 27000} }),
/* 27.027MHz */
- HDMI_MSM_AUDIO_ARCS(27027, {
+ HDMI_MSM_AUDIO_ARCS(27030, {
{4096, 27027}, {6272, 30030}, {6144, 27027}, {12544, 30030},
{12288, 27027}, {25088, 30030}, {24576, 27027} }),
/* 74.250MHz */
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index f847c73..db60546 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -49,7 +49,7 @@
static struct clk *mdp_pclk;
static struct clk *mdp_lut_clk;
int mdp_rev;
-
+static boolean mdp_hist_force_stop = FALSE;
static struct regulator *footswitch;
static unsigned int mdp_footswitch_on;
@@ -429,6 +429,11 @@
goto error;
}
+ if (mdp_hist_force_stop && (mdp_rev == MDP_REV_303)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
if (!mdp_is_hist_start) {
printk(KERN_ERR "%s histogram not started\n", __func__);
ret = -EPERM;
@@ -442,8 +447,14 @@
wait_for_completion_killable(&mdp_hist_comp);
mutex_lock(&mdp_hist_mutex);
- if (mdp_is_hist_data)
+ if (mdp_is_hist_data) {
+ if (mdp_hist_force_stop && (mdp_rev == MDP_REV_303)) {
+ pr_debug("%s histogram stopped\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
ret = _mdp_copy_hist_data(hist);
+ }
error:
mutex_unlock(&mdp_hist_mutex);
return ret;
@@ -729,6 +740,12 @@
if ((mdp_all_blocks_off) && (mdp_current_clk_on)) {
mutex_lock(&mdp_suspend_mutex);
if (block == MDP_MASTER_BLOCK || mdp_suspended) {
+ if ((mdp_prim_panel_type == MIPI_CMD_PANEL) &&
+ (mdp_rev == MDP_REV_303)) {
+ mdp_hist_force_stop = TRUE;
+ complete(&mdp_hist_comp);
+ }
+
mdp_current_clk_on = FALSE;
mb();
/* turn off MDP clks */
@@ -903,6 +920,7 @@
dma->busy = FALSE;
mdp_pipe_ctrl(MDP_DMA2_BLOCK,
MDP_BLOCK_POWER_OFF, TRUE);
+ mdp_hist_force_stop = FALSE;
complete(&dma->comp);
}
#endif
@@ -1624,8 +1642,8 @@
if (mdp_version < 0x04030303) {
pr_err("%s: writeback panel not supprted\n",
__func__);
- rc = -ENODEV;
- goto mdp_probe_err;
+ platform_device_put(msm_fb_dev);
+ return -ENODEV;
}
pdata->on = mdp4_overlay_writeback_on;
pdata->off = mdp4_overlay_writeback_off;
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 645a0c3..ecb0a24 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -418,6 +418,7 @@
char *rgb_base;
uint32 src_size, src_xy, dst_size, dst_xy;
uint32 format, pattern;
+ uint32 offset = 0;
rgb_base = MDP_BASE + MDP4_RGB_BASE;
rgb_base += (MDP4_RGB_OFF * pipe->pipe_num);
@@ -427,6 +428,16 @@
dst_size = ((pipe->dst_h << 16) | pipe->dst_w);
dst_xy = ((pipe->dst_y << 16) | pipe->dst_x);
+ if ((pipe->src_x + pipe->src_w) > 0x7FF) {
+ offset += pipe->src_x * pipe->bpp;
+ src_xy &= 0xFFFF0000;
+ }
+
+ if ((pipe->src_y + pipe->src_h) > 0x7FF) {
+ offset += pipe->src_y * pipe->src_width * pipe->bpp;
+ src_xy &= 0x0000FFFF;
+ }
+
format = mdp4_overlay_format(pipe);
pattern = mdp4_overlay_unpack_pattern(pipe);
@@ -443,7 +454,7 @@
outpdw(rgb_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */
outpdw(rgb_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */
- outpdw(rgb_base + 0x0010, pipe->srcp0_addr);
+ outpdw(rgb_base + 0x0010, pipe->srcp0_addr + offset);
outpdw(rgb_base + 0x0040, pipe->srcp0_ystride);
outpdw(rgb_base + 0x0050, format);/* MDP_RGB_SRC_FORMAT */
@@ -548,6 +559,21 @@
mdp4_scale_setup(pipe);
+ luma_offset = 0;
+ chroma_offset = 0;
+
+ if (ptype == OVERLAY_TYPE_RGB) {
+ if ((pipe->src_y + pipe->src_h) > 0x7FF) {
+ luma_offset = pipe->src_y * pipe->src_width * pipe->bpp;
+ src_xy &= 0x0000FFFF;
+ }
+
+ if ((pipe->src_x + pipe->src_w) > 0x7FF) {
+ luma_offset += pipe->src_x * pipe->bpp;
+ src_xy &= 0xFFFF0000;
+ }
+ }
+
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
outpdw(vg_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */
@@ -567,9 +593,6 @@
if (ptype != OVERLAY_TYPE_RGB) {
mdp4_overlay_vg_get_src_offset(pipe, vg_base, &luma_offset,
&chroma_offset);
- } else {
- luma_offset = 0;
- chroma_offset = 0;
}
/* luma component plane */
@@ -1804,8 +1827,8 @@
}
- pipe->src_width = req->src.width & 0x07ff; /* source img width */
- pipe->src_height = req->src.height & 0x07ff; /* source img height */
+ pipe->src_width = req->src.width & 0x1fff; /* source img width */
+ pipe->src_height = req->src.height & 0x1fff; /* source img height */
pipe->src_h = req->src_rect.h & 0x07ff;
pipe->src_w = req->src_rect.w & 0x07ff;
pipe->src_y = req->src_rect.y & 0x07ff;
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index a905ec0..5ad6de3f 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -451,6 +451,29 @@
complete(&dma->comp);
}
+static void mdp4_overlay_lcdc_prefill(struct msm_fb_data_type *mfd)
+{
+ unsigned long flag;
+
+ if (lcdc_pipe->blt_addr) {
+ mdp4_overlay_lcdc_dma_busy_wait(mfd);
+
+ mdp4_lcdc_blt_ov_update(lcdc_pipe);
+ lcdc_pipe->ov_cnt++;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
+ mdp_intr_mask |= INTR_OVERLAY0_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_enable_irq(MDP_OVERLAY0_TERM);
+ mfd->dma->busy = TRUE;
+ mb(); /* make sure all registers updated */
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ outpdw(MDP_BASE + 0x0004, 0); /* kickoff overlay engine */
+ mdp4_stat.kickoff_ov0++;
+ mb();
+ }
+}
/*
* make sure the MIPI_DSI_WRITEBACK_SIZE defined at boardfile
* has enough space h * w * 3 * 2
@@ -490,6 +513,10 @@
msleep(20);
mdp4_overlayproc_cfg(lcdc_pipe);
mdp4_overlay_dmap_xy(lcdc_pipe);
+ if (lcdc_pipe->blt_addr) {
+ mdp4_overlay_lcdc_prefill(mfd);
+ mdp4_overlay_lcdc_prefill(mfd);
+ }
MDP_OUTP(MDP_BASE + LCDC_BASE, 1); /* start lcdc */
}
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 6025139..89ccbb9 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -2556,6 +2556,7 @@
int ret;
struct msmfb_overlay_data req;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct msm_fb_panel_data *pdata;
if (mfd->overlay_play_enable == 0) /* nothing to do */
return 0;
@@ -2579,6 +2580,19 @@
ret = mdp4_overlay_play(info, &req);
+ if (unset_bl_level && !bl_updated) {
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->
+ dev.platform_data;
+ if ((pdata) && (pdata->set_backlight)) {
+ down(&mfd->sem);
+ mfd->bl_level = unset_bl_level;
+ pdata->set_backlight(mfd);
+ bl_level_old = unset_bl_level;
+ up(&mfd->sem);
+ }
+ bl_updated = 1;
+ }
+
return ret;
}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index e9c5193..a0d30b6 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -63,6 +63,7 @@
#define DDL_FW_AUX_HOST_CMD_SPACE_SIZE (DDL_KILO_BYTE(8))
#define DDL_FW_INST_GLOBAL_CONTEXT_SPACE_SIZE (DDL_KILO_BYTE(800))
#define DDL_FW_H264DEC_CONTEXT_SPACE_SIZE (DDL_KILO_BYTE(800))
+#define DDL_FW_H264ENC_CONTEXT_SPACE_SIZE (DDL_KILO_BYTE(20))
#define DDL_FW_OTHER_CONTEXT_SPACE_SIZE (DDL_KILO_BYTE(10))
#define VCD_DEC_CPB_SIZE (DDL_KILO_BYTE(512))
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index b3790a5..d54c01e 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -751,6 +751,7 @@
sz_cur_c = sz_dpb_c;
} else
status = VCD_ERR_NOT_SUPPORTED;
+ sz_context = DDL_FW_OTHER_CONTEXT_SPACE_SIZE;
if (!status) {
sz_strm = DDL_ALIGN(ddl_get_yuv_buf_size(width, height,
DDL_YUV_BUF_TYPE_LINEAR) + ddl_get_yuv_buf_size(width,
@@ -768,6 +769,7 @@
} else if (codec == VCD_CODEC_H264) {
sz_md = DDL_ALIGN(mb_x * 48, DDL_KILO_BYTE(2));
sz_pred = DDL_ALIGN(2 * 8 * 1024, DDL_KILO_BYTE(2));
+ sz_context = DDL_FW_H264ENC_CONTEXT_SPACE_SIZE;
if (ddl) {
if (ddl->codec_data.encoder.
entropy_control.entropy_sel ==
@@ -792,7 +794,6 @@
sz_mb_info = DDL_ALIGN(mb_x * mb_y * 6 * 8,
DDL_KILO_BYTE(2));
}
- sz_context = DDL_FW_OTHER_CONTEXT_SPACE_SIZE;
if (buf_size) {
buf_size->sz_cur_y = sz_cur_y;
buf_size->sz_cur_c = sz_cur_c;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index f69a471..7ccf4c2 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,8 +24,6 @@
static struct time_data proc_time[MAX_TIME_DATA];
#define DDL_MSG_TIME(x...) printk(KERN_DEBUG x)
-#define DDL_FW_CHANGE_ENDIAN
-
static unsigned int vidc_mmu_subsystem[] = {
MSM_SUBSYSTEM_VIDEO, MSM_SUBSYSTEM_VIDEO_FWARE};
@@ -65,7 +63,7 @@
}
addr->alloc_handle = ion_alloc(
ddl_context->video_ion_client, alloc_size, SZ_4K,
- (1<<res_trk_get_mem_type()));
+ res_trk_get_mem_type());
if (IS_ERR_OR_NULL(addr->alloc_handle)) {
DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
__func__);
@@ -289,23 +287,6 @@
}
#endif
-#ifdef DDL_FW_CHANGE_ENDIAN
-static void ddl_fw_change_endian(u8 *fw, u32 fw_size)
-{
- u32 i = 0;
- u8 temp;
- for (i = 0; i < fw_size; i = i + 4) {
- temp = fw[i];
- fw[i] = fw[i+3];
- fw[i+3] = temp;
- temp = fw[i+1];
- fw[i+1] = fw[i+2];
- fw[i+2] = temp;
- }
- return;
-}
-#endif
-
u32 ddl_fw_init(struct ddl_buf_addr *dram_base)
{
@@ -319,9 +300,6 @@
vidc_video_codec_fw_size);
memcpy(dest_addr, vidc_video_codec_fw,
vidc_video_codec_fw_size);
-#ifdef DDL_FW_CHANGE_ENDIAN
- ddl_fw_change_endian(dest_addr, vidc_video_codec_fw_size);
-#endif
return true;
}
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 9c2e5d1..795d1e3 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -28,16 +28,152 @@
static unsigned int vidc_clk_table[3] = {
48000000, 133330000, 200000000
};
+static unsigned int restrk_mmu_subsystem[] = {
+ MSM_SUBSYSTEM_VIDEO, MSM_SUBSYSTEM_VIDEO_FWARE};
static struct res_trk_context resource_context;
#define VIDC_FW "vidc_1080p.fw"
#define VIDC_FW_SIZE SZ_1M
+struct res_trk_vidc_mmu_clk {
+ char *mmu_clk_name;
+ struct clk *mmu_clk;
+};
+
+static struct res_trk_vidc_mmu_clk vidc_mmu_clks[] = {
+ {"mdp_iommu_clk"}, {"rot_iommu_clk"},
+ {"vcodec_iommu0_clk"}, {"vcodec_iommu1_clk"},
+ {"smmu_iface_clk"}
+};
+
unsigned char *vidc_video_codec_fw;
u32 vidc_video_codec_fw_size;
static u32 res_trk_get_clk(void);
static void res_trk_put_clk(void);
+static void *res_trk_pmem_map
+ (struct ddl_buf_addr *addr, size_t sz, u32 alignment)
+{
+ u32 offset = 0, flags = 0;
+ u32 index = 0;
+ struct ddl_context *ddl_context;
+ struct msm_mapped_buffer *mapped_buffer = NULL;
+ ddl_context = ddl_get_context();
+ if (!addr->alloced_phys_addr) {
+ pr_err(" %s() alloced addres NULL", __func__);
+ goto bail_out;
+ }
+ flags = MSM_SUBSYSTEM_MAP_IOVA | MSM_SUBSYSTEM_MAP_KADDR;
+ if (alignment == DDL_KILO_BYTE(128))
+ index = 1;
+ else if (alignment > SZ_4K)
+ flags |= MSM_SUBSYSTEM_ALIGN_IOVA_8K;
+
+ addr->mapped_buffer =
+ msm_subsystem_map_buffer((unsigned long)addr->alloced_phys_addr,
+ sz, flags, &restrk_mmu_subsystem[index],
+ sizeof(restrk_mmu_subsystem[index])/sizeof(unsigned int));
+ if (IS_ERR(addr->mapped_buffer)) {
+ pr_err(" %s() buffer map failed", __func__);
+ goto bail_out;
+ }
+ mapped_buffer = addr->mapped_buffer;
+ if (!mapped_buffer->vaddr || !mapped_buffer->iova[0]) {
+ pr_err("%s() map buffers failed\n", __func__);
+ goto bail_out;
+ }
+ addr->physical_base_addr = (u8 *)mapped_buffer->iova[0];
+ addr->virtual_base_addr = mapped_buffer->vaddr;
+ addr->align_physical_addr = (u8 *) DDL_ALIGN((u32)
+ addr->physical_base_addr, alignment);
+ offset = (u32)(addr->align_physical_addr -
+ addr->physical_base_addr);
+ addr->align_virtual_addr = addr->virtual_base_addr + offset;
+ addr->buffer_size = sz;
+ return addr->virtual_base_addr;
+bail_out:
+ return NULL;
+}
+
+static void *res_trk_pmem_alloc
+ (struct ddl_buf_addr *addr, size_t sz, u32 alignment)
+{
+ u32 alloc_size;
+ struct ddl_context *ddl_context;
+ int rc = -EINVAL;
+ ion_phys_addr_t phyaddr = 0;
+ size_t len = 0;
+ DBG_PMEM("\n%s() IN: Requested alloc size(%u)", __func__, (u32)sz);
+ if (!addr) {
+ DDL_MSG_ERROR("\n%s() Invalid Parameters", __func__);
+ goto bail_out;
+ }
+ ddl_context = ddl_get_context();
+ res_trk_set_mem_type(addr->mem_type);
+ alloc_size = (sz + alignment);
+ if (res_trk_get_enable_ion()) {
+ if (!ddl_context->video_ion_client)
+ ddl_context->video_ion_client =
+ res_trk_get_ion_client();
+ if (!ddl_context->video_ion_client) {
+ DDL_MSG_ERROR("%s() :DDL ION Client Invalid handle\n",
+ __func__);
+ goto bail_out;
+ }
+ addr->alloc_handle = ion_alloc(
+ ddl_context->video_ion_client, alloc_size, SZ_4K,
+ res_trk_get_mem_type());
+ if (IS_ERR_OR_NULL(addr->alloc_handle)) {
+ DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
+ __func__);
+ goto bail_out;
+ }
+ rc = ion_phys(ddl_context->video_ion_client,
+ addr->alloc_handle, &phyaddr,
+ &len);
+ if (rc || !phyaddr) {
+ DDL_MSG_ERROR("%s():DDL ION client physical failed\n",
+ __func__);
+ goto free_acm_ion_alloc;
+ }
+ addr->alloced_phys_addr = phyaddr;
+ } else {
+ addr->alloced_phys_addr = (phys_addr_t)
+ allocate_contiguous_memory_nomap(alloc_size,
+ res_trk_get_mem_type(), SZ_4K);
+ if (!addr->alloced_phys_addr) {
+ DDL_MSG_ERROR("%s() : acm alloc failed (%d)\n",
+ __func__, alloc_size);
+ goto bail_out;
+ }
+ }
+
+ addr->buffer_size = sz;
+ return (void *)addr->alloced_phys_addr;
+
+free_acm_ion_alloc:
+ if (ddl_context->video_ion_client) {
+ if (addr->alloc_handle) {
+ ion_free(ddl_context->video_ion_client,
+ addr->alloc_handle);
+ addr->alloc_handle = NULL;
+ }
+ }
+bail_out:
+ return NULL;
+}
+
+static void res_trk_pmem_unmap(struct ddl_buf_addr *addr)
+{
+ if (!addr) {
+ pr_err("%s() invalid args\n", __func__);
+ return;
+ }
+ if (addr->mapped_buffer)
+ msm_subsystem_unmap_buffer(addr->mapped_buffer);
+ addr->mapped_buffer = NULL;
+}
+
static u32 res_trk_get_clk()
{
if (resource_context.vcodec_clk ||
@@ -252,6 +388,7 @@
u32 res_trk_power_down(void)
{
VCDRES_MSG_LOW("clk_regime_rail_disable");
+ res_trk_pmem_unmap(&resource_context.firmware_addr);
#ifdef CONFIG_MSM_BUS_SCALING
msm_bus_scale_client_update_request(resource_context.pcl, 0);
msm_bus_scale_unregister_client(resource_context.pcl);
@@ -299,7 +436,6 @@
if (dev_ctxt->reqd_perf_lvl + dev_ctxt->curr_perf_lvl == 0)
bus_clk_index = 2;
-
bus_clk_index = (bus_clk_index << 1) + (client_type + 1);
VCDRES_MSG_LOW("%s(), bus_clk_index = %d", __func__, bus_clk_index);
VCDRES_MSG_LOW("%s(),context.pcl = %x", __func__, resource_context.pcl);
@@ -415,6 +551,7 @@
} else {
memset(&resource_context, 0, sizeof(resource_context));
mutex_init(&resource_context.lock);
+ mutex_init(&resource_context.secure_lock);
resource_context.device = device;
resource_context.irq_num = irq;
resource_context.vidc_platform_data =
@@ -435,7 +572,7 @@
return;
}
resource_context.fw_mem_type =
- resource_context.vidc_platform_data->memtype;
+ ION_MM_FIRMWARE_HEAP_ID;
resource_context.cmd_mem_type =
ION_CP_MFC_HEAP_ID;
}
@@ -454,12 +591,12 @@
}
resource_context.core_type = VCD_CORE_1080P;
resource_context.firmware_addr.mem_type = DDL_FW_MEM;
- if (!ddl_pmem_alloc(&resource_context.firmware_addr,
+ if (!res_trk_pmem_alloc(&resource_context.firmware_addr,
VIDC_FW_SIZE, DDL_KILO_BYTE(128))) {
pr_err("%s() Firmware buffer allocation failed",
__func__);
memset(&resource_context.firmware_addr, 0,
- sizeof(resource_context.firmware_addr));
+ sizeof(resource_context.firmware_addr));
}
}
}
@@ -470,27 +607,48 @@
u32 res_trk_get_firmware_addr(struct ddl_buf_addr *firm_addr)
{
- int status = -1;
- if (resource_context.firmware_addr.mapped_buffer) {
- memcpy(firm_addr, &resource_context.firmware_addr,
- sizeof(struct ddl_buf_addr));
- status = 0;
+ if (!firm_addr || resource_context.firmware_addr.mapped_buffer) {
+ pr_err("%s() invalid params", __func__);
+ return -EINVAL;
}
- return status;
+ if (!res_trk_pmem_map(&resource_context.firmware_addr,
+ resource_context.firmware_addr.buffer_size,
+ DDL_KILO_BYTE(128))) {
+ pr_err("%s() Firmware buffer mapping failed",
+ __func__);
+ return -EINVAL;
+ }
+ memcpy(firm_addr, &resource_context.firmware_addr,
+ sizeof(struct ddl_buf_addr));
+ return 0;
}
-u32 res_trk_get_mem_type(void)
+int res_trk_get_mem_type(void)
{
+ int mem_type = -1;
switch (resource_context.res_mem_type) {
case DDL_FW_MEM:
- return resource_context.fw_mem_type;
+ mem_type = resource_context.fw_mem_type;
+ break;
case DDL_MM_MEM:
- return resource_context.memtype;
+ mem_type = resource_context.memtype;
+ break;
case DDL_CMD_MEM:
- return resource_context.memtype;
+ if (res_trk_check_for_sec_session())
+ mem_type = resource_context.cmd_mem_type;
+ else
+ mem_type = resource_context.memtype;
+ break;
default:
- return 0;
+ return mem_type;
}
+ if (resource_context.vidc_platform_data->enable_ion) {
+ if (res_trk_check_for_sec_session())
+ mem_type = (ION_HEAP(mem_type) | ION_SECURE);
+ else
+ mem_type = ION_HEAP(mem_type);
+ }
+ return mem_type;
}
u32 res_trk_get_enable_ion(void)
@@ -520,3 +678,109 @@
{
return resource_context.disable_fullhd;
}
+
+int res_trk_enable_iommu_clocks(void)
+{
+ int ret = 0, i;
+ if (resource_context.mmu_clks_on) {
+ pr_err(" %s: Clocks are already on", __func__);
+ return -EINVAL;
+ }
+ resource_context.mmu_clks_on = 1;
+ for (i = 0; i < ARRAY_SIZE(vidc_mmu_clks); i++) {
+ vidc_mmu_clks[i].mmu_clk = clk_get(resource_context.device,
+ vidc_mmu_clks[i].mmu_clk_name);
+ if (IS_ERR(vidc_mmu_clks[i].mmu_clk)) {
+ pr_err(" %s: Get failed for clk %s", __func__,
+ vidc_mmu_clks[i].mmu_clk_name);
+ ret = PTR_ERR(vidc_mmu_clks[i].mmu_clk);
+ }
+ if (!ret) {
+ ret = clk_enable(vidc_mmu_clks[i].mmu_clk);
+ if (ret) {
+ clk_put(vidc_mmu_clks[i].mmu_clk);
+ vidc_mmu_clks[i].mmu_clk = NULL;
+ }
+ }
+ if (ret) {
+ for (i--; i >= 0; i--) {
+ clk_disable(vidc_mmu_clks[i].mmu_clk);
+ clk_put(vidc_mmu_clks[i].mmu_clk);
+ vidc_mmu_clks[i].mmu_clk = NULL;
+ }
+ resource_context.mmu_clks_on = 0;
+ pr_err("%s() clocks enable failed", __func__);
+ break;
+ }
+ }
+ return ret;
+}
+
+int res_trk_disable_iommu_clocks(void)
+{
+ int i;
+ if (!resource_context.mmu_clks_on) {
+ pr_err(" %s: clks are already off", __func__);
+ return -EINVAL;
+ }
+ resource_context.mmu_clks_on = 0;
+ for (i = 0; i < ARRAY_SIZE(vidc_mmu_clks); i++) {
+ clk_disable(vidc_mmu_clks[i].mmu_clk);
+ clk_put(vidc_mmu_clks[i].mmu_clk);
+ vidc_mmu_clks[i].mmu_clk = NULL;
+ }
+ return 0;
+}
+
+int res_trk_check_for_sec_session()
+{
+ int rc;
+ mutex_lock(&resource_context.secure_lock);
+ rc = (resource_context.secure_session) ? -EBUSY : 0;
+ mutex_unlock(&resource_context.secure_lock);
+ return rc;
+}
+int res_trk_open_secure_session()
+{
+ int rc;
+ mutex_lock(&resource_context.secure_lock);
+ if (resource_context.secure_session) {
+ pr_err("Secure session already open");
+ rc = -EBUSY;
+ goto error_open;
+ }
+ resource_context.secure_session = 1;
+ rc = res_trk_enable_iommu_clocks();
+ if (rc) {
+ pr_err("IOMMU clock enabled failed while open");
+ goto error_open;
+ }
+ msm_ion_secure_heap(ION_HEAP(resource_context.memtype));
+ msm_ion_secure_heap(ION_HEAP(resource_context.cmd_mem_type));
+ res_trk_disable_iommu_clocks();
+ mutex_unlock(&resource_context.secure_lock);
+ return 0;
+error_open:
+ mutex_unlock(&resource_context.secure_lock);
+ return rc;
+}
+
+int res_trk_close_secure_session()
+{
+ int rc;
+ mutex_lock(&resource_context.secure_lock);
+ rc = res_trk_enable_iommu_clocks();
+ if (rc) {
+ pr_err("IOMMU clock enabled failed while close");
+ goto error_close;
+ }
+ msm_ion_unsecure_heap(ION_HEAP(resource_context.memtype));
+ msm_ion_unsecure_heap(ION_HEAP(resource_context.cmd_mem_type));
+ res_trk_disable_iommu_clocks();
+ resource_context.secure_session = 0;
+ mutex_unlock(&resource_context.secure_lock);
+ return 0;
+error_close:
+ mutex_unlock(&resource_context.secure_lock);
+ return rc;
+}
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
index be5045f..bf8607d 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
@@ -28,6 +28,7 @@
#define RESTRK_1080P_MIN_PERF_LEVEL RESTRK_1080P_VGA_PERF_LEVEL
#define RESTRK_1080P_MAX_PERF_LEVEL RESTRK_1080P_1080P_PERF_LEVEL
+
struct res_trk_context {
struct device *device;
u32 irq_num;
@@ -52,6 +53,9 @@
u32 disable_dmx;
u32 disable_fullhd;
enum ddl_mem_area res_mem_type;
+ u32 mmu_clks_on;
+ u32 secure_session;
+ struct mutex secure_lock;
};
#if DEBUG
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
index fd4ca3e..f91ddb5 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
@@ -29,10 +29,15 @@
u32 res_trk_download_firmware(void);
u32 res_trk_get_core_type(void);
u32 res_trk_get_firmware_addr(struct ddl_buf_addr *firm_addr);
-u32 res_trk_get_mem_type(void);
+int res_trk_get_mem_type(void);
u32 res_trk_get_enable_ion(void);
u32 res_trk_get_disable_fullhd(void);
struct ion_client *res_trk_get_ion_client(void);
u32 res_trk_get_disable_dmx(void);
void res_trk_set_mem_type(enum ddl_mem_area mem_type);
+int res_trk_enable_iommu_clocks(void);
+int res_trk_disable_iommu_clocks(void);
+int res_trk_check_for_sec_session(void);
+int res_trk_open_secure_session(void);
+int res_trk_close_secure_session(void);
#endif
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
index ee76ff1..7c3325a 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
@@ -728,3 +728,18 @@
{
return 0;
}
+
+int res_trk_check_for_sec_session()
+{
+ return 0;
+}
+
+int res_trk_open_secure_session()
+{
+ return -EINVAL;
+}
+
+int res_trk_close_secure_session()
+{
+ return 0;
+}
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h
index 3012858..2b92a42 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,7 @@
struct msm_vidc_platform_data *vidc_platform_data;
u32 core_type;
int memtype;
+ u32 secure_session;
};
#if DEBUG
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
index 34f2103..237d143 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
@@ -32,4 +32,7 @@
u32 res_trk_get_enable_ion(void);
struct ion_client *res_trk_get_ion_client(void);
void res_trk_set_mem_type(enum ddl_mem_area mem_type);
+int res_trk_check_for_sec_session(void);
+int res_trk_open_secure_session(void);
+int res_trk_close_secure_session(void);
#endif
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index b90248e..980ec21 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -29,6 +29,7 @@
#include <linux/clk.h>
#include <linux/timer.h>
#include <mach/msm_subsystem_map.h>
+#include "vcd_res_tracker_api.h"
#include "vidc_type.h"
#include "vcd_api.h"
#include "vdec_internal.h"
@@ -40,11 +41,13 @@
#define INFO(x...) pr_info(x)
#define ERR(x...) pr_err(x)
-#define VID_DEC_NAME "msm_vidc_dec"
+#define VID_DEC_NAME "msm_vidc_dec"
+static char *node_name[2] = {"", "_sec"};
static struct vid_dec_dev *vid_dec_device_p;
static dev_t vid_dec_dev_num;
static struct class *vid_dec_class;
+
static unsigned int vidc_mmu_subsystem[] = {
MSM_SUBSYSTEM_VIDEO};
static s32 vid_dec_get_empty_client_index(void)
@@ -1958,34 +1961,30 @@
return true;
}
-static int vid_dec_open(struct inode *inode, struct file *file)
+struct video_client_ctx *vid_dec_open_client(void)
{
s32 client_index;
struct video_client_ctx *client_ctx;
u32 vcd_status = VCD_ERR_FAIL;
- u8 client_count = 0;
-
- DBG("msm_vidc_dec: Inside %s()", __func__);
- mutex_lock(&vid_dec_device_p->lock);
+ u8 client_count;
client_count = vcd_get_num_of_clients();
if (client_count == VIDC_MAX_NUM_CLIENTS) {
ERR("ERROR : vid_dec_open() max number of clients"
- "limit reached\n");
- mutex_unlock(&vid_dec_device_p->lock);
- return -ENODEV;
+ "limit reached\n");
+ goto client_failure;
}
DBG(" Virtual Address of ioremap is %p\n", vid_dec_device_p->virt_base);
if (!vid_dec_device_p->num_clients) {
if (!vidc_load_firmware())
- return -ENODEV;
+ goto client_failure;
}
client_index = vid_dec_get_empty_client_index();
if (client_index == -1) {
ERR("%s() : No free clients client_index == -1\n", __func__);
- return -ENODEV;
+ goto client_failure;
}
client_ctx = &vid_dec_device_p->vdec_clients[client_index];
vid_dec_device_p->num_clients++;
@@ -2002,30 +2001,84 @@
client_ctx->user_ion_client = vcd_get_ion_client();
if (!client_ctx->user_ion_client) {
ERR("vcd_open ion client get failed");
- return -EFAULT;
+ goto client_failure;
}
}
vcd_status = vcd_open(vid_dec_device_p->device_handle, true,
- vid_dec_vcd_cb, client_ctx);
+ vid_dec_vcd_cb, client_ctx);
if (!vcd_status) {
wait_for_completion(&client_ctx->event);
if (client_ctx->event_status) {
ERR("callback for vcd_open returned error: %u",
client_ctx->event_status);
- mutex_unlock(&vid_dec_device_p->lock);
- return -EFAULT;
+ goto client_failure;
}
} else {
ERR("vcd_open returned error: %u", vcd_status);
- mutex_unlock(&vid_dec_device_p->lock);
- return -EFAULT;
+ goto client_failure;
}
client_ctx->seq_header_set = false;
- file->private_data = client_ctx;
+ return client_ctx;
+client_failure:
+ return NULL;
+}
+
+static int vid_dec_open_secure(struct inode *inode, struct file *file)
+{
+ mutex_lock(&vid_dec_device_p->lock);
+ if (res_trk_check_for_sec_session() || vcd_get_num_of_clients()) {
+ ERR("Secure session present return failure\n");
+ mutex_unlock(&vid_dec_device_p->lock);
+ return -ENODEV;
+ }
+ if (res_trk_open_secure_session()) {
+ ERR("Secure session operation failure\n");
+ mutex_unlock(&vid_dec_device_p->lock);
+ return -ENODEV;
+ }
+ file->private_data = vid_dec_open_client();
+ if (!file->private_data) {
+ res_trk_close_secure_session();
+ mutex_unlock(&vid_dec_device_p->lock);
+ return -ENODEV;
+ }
mutex_unlock(&vid_dec_device_p->lock);
return 0;
}
+static int vid_dec_open(struct inode *inode, struct file *file)
+{
+ INFO("msm_vidc_dec: Inside %s()", __func__);
+ mutex_lock(&vid_dec_device_p->lock);
+ if (res_trk_check_for_sec_session()) {
+ ERR("Secure session present return failure\n");
+ mutex_unlock(&vid_dec_device_p->lock);
+ return -ENODEV;
+ }
+ file->private_data = vid_dec_open_client();
+ if (!file->private_data) {
+ mutex_unlock(&vid_dec_device_p->lock);
+ return -ENODEV;
+ }
+ mutex_unlock(&vid_dec_device_p->lock);
+ return 0;
+}
+
+static int vid_dec_release_secure(struct inode *inode, struct file *file)
+{
+ struct video_client_ctx *client_ctx = file->private_data;
+
+ INFO("msm_vidc_dec: Inside %s()", __func__);
+ res_trk_close_secure_session();
+ vid_dec_close_client(client_ctx);
+ vidc_release_firmware();
+#ifndef USE_RES_TRACKER
+ vidc_disable_clk();
+#endif
+ INFO("msm_vidc_dec: Return from %s()", __func__);
+ return 0;
+}
+
static int vid_dec_release(struct inode *inode, struct file *file)
{
struct video_client_ctx *client_ctx = file->private_data;
@@ -2040,11 +2093,20 @@
return 0;
}
-static const struct file_operations vid_dec_fops = {
- .owner = THIS_MODULE,
- .open = vid_dec_open,
- .release = vid_dec_release,
- .unlocked_ioctl = vid_dec_ioctl,
+static const struct file_operations vid_dec_fops[2] = {
+ {
+ .owner = THIS_MODULE,
+ .open = vid_dec_open,
+ .release = vid_dec_release,
+ .unlocked_ioctl = vid_dec_ioctl,
+ },
+ {
+ .owner = THIS_MODULE,
+ .open = vid_dec_open_secure,
+ .release = vid_dec_release_secure,
+ .unlocked_ioctl = vid_dec_ioctl,
+ },
+
};
void vid_dec_interrupt_deregister(void)
@@ -2110,7 +2172,7 @@
static int __init vid_dec_init(void)
{
- int rc = 0;
+ int rc = 0, i = 0, j = 0;
struct device *class_devp;
DBG("msm_vidc_dec: Inside %s()", __func__);
@@ -2121,7 +2183,8 @@
return -ENOMEM;
}
- rc = alloc_chrdev_region(&vid_dec_dev_num, 0, 1, VID_DEC_NAME);
+ rc = alloc_chrdev_region(&vid_dec_dev_num, 0, NUM_OF_DRIVER_NODES,
+ VID_DEC_NAME);
if (rc < 0) {
ERR("%s: alloc_chrdev_region Failed rc = %d\n",
__func__, rc);
@@ -2136,49 +2199,59 @@
goto error_vid_dec_class_create;
}
+ for (i = 0; i < NUM_OF_DRIVER_NODES; i++) {
+ class_devp = device_create(vid_dec_class, NULL,
+ (vid_dec_dev_num + i),
+ NULL, VID_DEC_NAME "%s",
+ node_name[i]);
- class_devp = device_create(vid_dec_class, NULL, vid_dec_dev_num, NULL,
- VID_DEC_NAME);
+ if (IS_ERR(class_devp)) {
+ rc = PTR_ERR(class_devp);
+ ERR("%s: class device_create failed %d\n",
+ __func__, rc);
+ if (!i)
+ goto error_vid_dec_class_device_create;
+ else
+ goto error_vid_dec_cdev_add;
+ }
- if (IS_ERR(class_devp)) {
- rc = PTR_ERR(class_devp);
- ERR("%s: class device_create failed %d\n",
- __func__, rc);
- goto error_vid_dec_class_device_create;
- }
+ vid_dec_device_p->device[i] = class_devp;
- vid_dec_device_p->device = class_devp;
+ cdev_init(&vid_dec_device_p->cdev[i], &vid_dec_fops[i]);
+ vid_dec_device_p->cdev[i].owner = THIS_MODULE;
+ rc = cdev_add(&(vid_dec_device_p->cdev[i]),
+ (vid_dec_dev_num+i), 1);
- cdev_init(&vid_dec_device_p->cdev, &vid_dec_fops);
- vid_dec_device_p->cdev.owner = THIS_MODULE;
- rc = cdev_add(&(vid_dec_device_p->cdev), vid_dec_dev_num, 1);
-
- if (rc < 0) {
- ERR("%s: cdev_add failed %d\n", __func__, rc);
- goto error_vid_dec_cdev_add;
+ if (rc < 0) {
+ ERR("%s: cdev_add failed %d\n", __func__, rc);
+ goto error_vid_dec_cdev_add;
+ }
}
vid_dec_vcd_init();
return 0;
error_vid_dec_cdev_add:
+ for (j = i-1; j >= 0; j--)
+ cdev_del(&(vid_dec_device_p->cdev[j]));
device_destroy(vid_dec_class, vid_dec_dev_num);
error_vid_dec_class_device_create:
class_destroy(vid_dec_class);
error_vid_dec_class_create:
- unregister_chrdev_region(vid_dec_dev_num, 1);
+ unregister_chrdev_region(vid_dec_dev_num, NUM_OF_DRIVER_NODES);
error_vid_dec_alloc_chrdev_region:
kfree(vid_dec_device_p);
-
return rc;
}
static void __exit vid_dec_exit(void)
{
- DBG("msm_vidc_dec: Inside %s()", __func__);
- cdev_del(&(vid_dec_device_p->cdev));
+ int i = 0;
+ INFO("msm_vidc_dec: Inside %s()", __func__);
+ for (i = 0; i < NUM_OF_DRIVER_NODES; i++)
+ cdev_del(&(vid_dec_device_p->cdev[i]));
device_destroy(vid_dec_class, vid_dec_dev_num);
class_destroy(vid_dec_class);
- unregister_chrdev_region(vid_dec_dev_num, 1);
+ unregister_chrdev_region(vid_dec_dev_num, NUM_OF_DRIVER_NODES);
kfree(vid_dec_device_p);
DBG("msm_vidc_dec: Return from %s()", __func__);
}
diff --git a/drivers/video/msm/vidc/common/dec/vdec_internal.h b/drivers/video/msm/vidc/common/dec/vdec_internal.h
index 867c3b3..f310e25 100644
--- a/drivers/video/msm/vidc/common/dec/vdec_internal.h
+++ b/drivers/video/msm/vidc/common/dec/vdec_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010, 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,14 +18,16 @@
#include <linux/cdev.h>
#include "vidc_init.h"
+#define NUM_OF_DRIVER_NODES 2
+
struct vid_dec_msg {
struct list_head list;
struct vdec_msginfo vdec_msg_info;
};
struct vid_dec_dev {
- struct cdev cdev;
- struct device *device;
+ struct cdev cdev[NUM_OF_DRIVER_NODES];
+ struct device *device[NUM_OF_DRIVER_NODES];
resource_size_t phys_base;
void __iomem *virt_base;
unsigned int irq;
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 3cd4e76..97fc758 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -32,6 +32,7 @@
#include "vcd_api.h"
#include "venc_internal.h"
#include "vidc_init.h"
+#include "vcd_res_tracker_api.h"
#define VID_ENC_NAME "msm_vidc_enc"
@@ -516,9 +517,10 @@
stop_cmd = 0;
client_count = vcd_get_num_of_clients();
- if (client_count == VIDC_MAX_NUM_CLIENTS) {
+ if (client_count == VIDC_MAX_NUM_CLIENTS ||
+ res_trk_check_for_sec_session()) {
ERR("ERROR : vid_enc_open() max number of clients"
- "limit reached\n");
+ "limit reached or secure session is open\n");
mutex_unlock(&vid_enc_device_p->lock);
return -ENODEV;
}
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index e4bd50d..1709cc2 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -502,7 +502,7 @@
} else {
buff_ion_handle = ion_import_fd(
client_ctx->user_ion_client, pmem_fd);
- if (!buff_ion_handle) {
+ if (IS_ERR_OR_NULL(buff_ion_handle)) {
ERR("%s(): get_ION_handle failed\n",
__func__);
goto ion_error;
@@ -558,7 +558,7 @@
ion_error:
if (*kernel_vaddr)
ion_unmap_kernel(client_ctx->user_ion_client, buff_ion_handle);
- if (buff_ion_handle)
+ if (!IS_ERR_OR_NULL(buff_ion_handle))
ion_free(client_ctx->user_ion_client, buff_ion_handle);
bail_out_add:
mutex_unlock(&client_ctx->enrty_queue_lock);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_api.c b/drivers/video/msm/vidc/common/vcd/vcd_api.c
index 4889761..5e9fd55 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -89,7 +89,10 @@
return VCD_ERR_ILLEGAL_PARM;
}
-
+ if (res_trk_check_for_sec_session() && vcd_get_num_of_clients()) {
+ VCD_MSG_ERROR("Secure session in progress");
+ return VCD_ERR_BAD_STATE;
+ }
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index bb3e652..b5fcc1c 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -69,7 +69,7 @@
} else {
map_buffer->alloc_handle = ion_alloc(
cctxt->vcd_ion_client, sz, SZ_4K,
- (1<<memtype));
+ memtype);
if (!map_buffer->alloc_handle) {
pr_err("%s() ION alloc failed", __func__);
goto bailout;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 7213b52..b9d46fa 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -107,6 +107,28 @@
}
#endif
+/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
+static inline int clk_prepare_enable(struct clk *clk)
+{
+ int ret;
+
+ ret = clk_prepare(clk);
+ if (ret)
+ return ret;
+ ret = clk_enable(clk);
+ if (ret)
+ clk_unprepare(clk);
+
+ return ret;
+}
+
+/* clk_disable_unprepare helps cases using clk_disable in non-atomic context. */
+static inline void clk_disable_unprepare(struct clk *clk)
+{
+ clk_disable(clk);
+ clk_unprepare(clk);
+}
+
/**
* clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
* This is only valid once the clock source has been enabled.
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index d61b934..9aa557a 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -26,6 +26,9 @@
#define MXT_ROTATED_180 0x6
#define MXT_DIAGONAL_COUNTER 0x7
+/* MXT_TOUCH_KEYARRAY_T15 */
+#define MXT_KEYARRAY_MAX_KEYS 32
+
/* The platform data for the Atmel maXTouch touchscreen driver */
struct mxt_platform_data {
const u8 *config;
@@ -38,6 +41,7 @@
bool digital_pwr_regulator;
int reset_gpio;
int irq_gpio;
+ int *key_codes;
u8(*read_chg) (void);
int (*init_hw) (bool);
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 4f8756a..41f99e4 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -2,6 +2,7 @@
* include/linux/ion.h
*
* Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2012, 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
@@ -29,13 +30,18 @@
* @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved
* carveout heap, allocations are physically
* contiguous
- * @ION_HEAP_END: helper for iterating over heaps
+ * @ION_HEAP_TYPE_IOMMU: IOMMU memory
+ * @ION_HEAP_TYPE_CP: memory allocated from a prereserved
+ * carveout heap, allocations are physically
+ * contiguous. Used for content protection.
+ * @ION_HEAP_END: helper for iterating over heaps
*/
enum ion_heap_type {
ION_HEAP_TYPE_SYSTEM,
ION_HEAP_TYPE_SYSTEM_CONTIG,
ION_HEAP_TYPE_CARVEOUT,
ION_HEAP_TYPE_IOMMU,
+ ION_HEAP_TYPE_CP,
ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
are at the end of this enum */
ION_NUM_HEAPS,
@@ -44,6 +50,7 @@
#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM)
#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
+#define ION_HEAP_CP_MASK (1 << ION_HEAP_TYPE_CP)
/**
@@ -56,14 +63,17 @@
*/
enum ion_heap_ids {
+ INVALID_HEAP_ID = -1,
ION_IOMMU_HEAP_ID = 4,
ION_CP_MM_HEAP_ID = 8,
ION_CP_MFC_HEAP_ID = 12,
ION_CP_WB_HEAP_ID = 16, /* 8660 only */
ION_CAMERA_HEAP_ID = 20, /* 8660 only */
ION_SF_HEAP_ID = 24,
+ ION_QSECOM_HEAP_ID = 27,
ION_AUDIO_HEAP_ID = 28,
+ ION_MM_FIRMWARE_HEAP_ID = 29,
ION_SYSTEM_HEAP_ID = 30,
ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_SECURE flag */
@@ -87,6 +97,8 @@
#define ION_IOMMU_HEAP_NAME "iommu"
#define ION_MFC_HEAP_NAME "mfc"
#define ION_WB_HEAP_NAME "wb"
+#define ION_MM_FIRMWARE_HEAP_NAME "mm_fw"
+#define ION_QSECOM_HEAP_NAME "qsecom"
#define CACHED 1
#define UNCACHED 0
@@ -120,6 +132,8 @@
* @name: used for debug purposes
* @base: base address of heap in physical memory if applicable
* @size: size of the heap in bytes if applicable
+ * @memory_type: Memory type used for the heap
+ * @ion_memory_id: Memory ID used to identify the memory to TZ
* @request_region: function to be called when the number of allocations goes
* from 0 -> 1
* @release_region: function to be called when the number of allocations goes
@@ -135,6 +149,22 @@
ion_phys_addr_t base;
size_t size;
enum ion_memory_types memory_type;
+ void *extra_data;
+};
+
+struct ion_cp_heap_pdata {
+ enum ion_permission_type permission_type;
+ unsigned int align;
+ ion_phys_addr_t secure_base; /* Base addr used when heap is shared */
+ size_t secure_size; /* Size used for securing heap when heap is shared*/
+ int (*request_region)(void *);
+ int (*release_region)(void *);
+ void *(*setup_region)(void);
+};
+
+struct ion_co_heap_pdata {
+ int adjacent_mem_id;
+ unsigned int align;
int (*request_region)(void *);
int (*release_region)(void *);
void *(*setup_region)(void);
@@ -386,6 +416,48 @@
int domain_num, int partition_num);
+/**
+ * ion_secure_heap - secure a heap
+ *
+ * @client - a client that has allocated from the heap heap_id
+ * @heap_id - heap id to secure.
+ *
+ * Secure a heap
+ * Returns 0 on success
+ */
+int ion_secure_heap(struct ion_device *dev, int heap_id);
+
+/**
+ * ion_unsecure_heap - un-secure a heap
+ *
+ * @client - a client that has allocated from the heap heap_id
+ * @heap_id - heap id to un-secure.
+ *
+ * Un-secure a heap
+ * Returns 0 on success
+ */
+int ion_unsecure_heap(struct ion_device *dev, int heap_id);
+
+/**
+ * msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap.
+ *
+ * @heap_id - heap id to secure.
+ *
+ * Secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_secure_heap(int heap_id);
+
+/**
+ * msm_ion_unsecure_heap - unsecure a heap. Wrapper around ion_unsecure_heap.
+ *
+ * @heap_id - heap id to secure.
+ *
+ * Un-secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_unsecure_heap(int heap_id);
+
#else
static inline struct ion_client *ion_client_create(struct ion_device *dev,
unsigned int heap_mask, const char *name)
@@ -475,7 +547,27 @@
return;
}
+static inline int ion_secure_heap(struct ion_device *dev, int heap_id)
+{
+ return -ENODEV;
+}
+
+static inline int ion_unsecure_heap(struct ion_device *dev, int heap_id)
+{
+ return -ENODEV;
+}
+
+static inline int msm_ion_secure_heap(int heap_id)
+{
+ return -ENODEV;
+
+}
+
+static inline int msm_ion_unsecure_heap(int heap_id)
+{
+ return -ENODEV;
+}
#endif /* CONFIG_ION */
#endif /* __KERNEL__ */
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 99834e58..60ee260 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -89,8 +89,14 @@
hw < d->hwirq_base + d->nr_irq; \
hw++, irq = irq_domain_to_irq(d, hw))
-extern void irq_domain_add(struct irq_domain *domain);
+extern int irq_domain_add(struct irq_domain *domain);
extern void irq_domain_del(struct irq_domain *domain);
+extern void irq_domain_register(struct irq_domain *domain);
+extern void irq_domain_register_irq(struct irq_domain *domain, int hwirq);
+extern void irq_domain_unregister(struct irq_domain *domain);
+extern void irq_domain_unregister_irq(struct irq_domain *domain, int hwirq);
+extern int irq_domain_find_free_range(unsigned int from, unsigned int cnt);
+
#endif /* CONFIG_IRQ_DOMAIN */
#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
diff --git a/include/linux/mfd/pm8xxx/pm8038.h b/include/linux/mfd/pm8xxx/pm8038.h
index e733842..203095a 100644
--- a/include/linux/mfd/pm8xxx/pm8038.h
+++ b/include/linux/mfd/pm8xxx/pm8038.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,9 @@
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/regulator/pm8xxx-regulator.h>
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/mfd/pm8xxx/pm8921-charger.h>
+#include <linux/mfd/pm8xxx/pm8921-bms.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
#define PM8038_CORE_DEV_NAME "pm8038-core"
@@ -69,7 +72,10 @@
struct pm8xxx_misc_platform_data *misc_pdata;
struct pm8xxx_regulator_platform_data *regulator_pdatas;
int num_regulators;
+ struct pm8921_charger_platform_data *charger_pdata;
+ struct pm8921_bms_platform_data *bms_pdata;
struct pm8xxx_adc_platform_data *adc_pdata;
+ struct pm8xxx_ccadc_platform_data *ccadc_pdata;
};
#endif
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index cd2e61c..d0307ee 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -33,6 +33,8 @@
u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
};
+typedef int (*of_irq_init_cb_t)(struct device_node *, struct device_node *);
+
/*
* Workarounds only applied to 32bit powermac machines
*/
@@ -73,6 +75,7 @@
struct resource *res, int nr_irqs);
extern struct device_node *of_irq_find_parent(struct device_node *child);
+extern void of_irq_init(const struct of_device_id *matches);
#endif /* CONFIG_OF_IRQ */
#endif /* CONFIG_OF */
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index fb5d4e4..f46449a 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -135,6 +135,8 @@
/* regulator get and put */
struct regulator *__must_check regulator_get(struct device *dev,
const char *id);
+struct regulator *__must_check devm_regulator_get(struct device *dev,
+ const char *id);
struct regulator *__must_check regulator_get_exclusive(struct device *dev,
const char *id);
void regulator_put(struct regulator *regulator);
@@ -202,6 +204,13 @@
*/
return NULL;
}
+
+static inline struct regulator *__must_check
+devm_regulator_get(struct device *dev, const char *id)
+{
+ return NULL;
+}
+
static inline void regulator_put(struct regulator *regulator)
{
}
diff --git a/include/linux/tzcom.h b/include/linux/tzcom.h
index a1b3dfc..448ab2a 100644
--- a/include/linux/tzcom.h
+++ b/include/linux/tzcom.h
@@ -6,6 +6,7 @@
#include <linux/types.h>
#include <linux/ioctl.h>
+#define MAX_ION_FD 4
/**
* struct tzcom_register_svc_op_req - for register service ioctl request
* @svc_id - service id (shared between userspace and TZ)
@@ -49,6 +50,8 @@
/**
* struct tzcom_send_cmd_op_req - for send command ioctl request
* @cmd_id - command to execute on TZBSP side
+ * @ifd_data_fd - ion handle to some memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
* @cmd_len - command buffer length
* @cmd_buf - command buffer
* @resp_len - response buffer length
@@ -63,6 +66,34 @@
};
/**
+ * struct tzcom_ion_fd_info - ion fd handle data information
+ * @fd - ion handle to some memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ */
+struct tzcom_ion_fd_info {
+ int32_t fd;
+ uint32_t cmd_buf_offset;
+};
+
+/**
+ * struct tzcom_send_cmd_op_req - for send command ioctl request
+ * @cmd_id - command to execute on TZBSP side
+ * @ifd_data_fd - ion handle to some memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ * @cmd_len - command buffer length
+ * @cmd_buf - command buffer
+ * @resp_len - response buffer length
+ * @resp_buf - response buffer
+ */
+struct tzcom_send_cmd_fd_op_req {
+ uint32_t cmd_id; /* in */
+ struct tzcom_ion_fd_info ifd_data[MAX_ION_FD];
+ unsigned int cmd_len; /* in */
+ void *cmd_buf; /* in */
+ unsigned int resp_len; /* in/out */
+ void *resp_buf; /* in/out */
+};
+/**
* struct tzcom_cont_cmd_op_req - for continue command ioctl request. used
* as a trigger from HLOS service to notify TZCOM that it's done with its
* operation and provide the response for TZCOM can continue the incomplete
@@ -99,5 +130,7 @@
_IOWR(TZCOM_IOC_MAGIC, 5, struct tzcom_cont_cmd_op_req)
#define TZCOM_IOCTL_ABORT_REQ _IO(TZCOM_IOC_MAGIC, 6)
-
+/* For TZ service */
+#define TZCOM_IOCTL_SEND_CMD_FD_REQ \
+ _IOWR(TZCOM_IOC_MAGIC, 7, struct tzcom_send_cmd_fd_op_req)
#endif /* __TZCOM_H_ */
diff --git a/include/media/msm/vidc_init.h b/include/media/msm/vidc_init.h
index 677a918..60cc35f 100644
--- a/include/media/msm/vidc_init.h
+++ b/include/media/msm/vidc_init.h
@@ -43,6 +43,7 @@
struct buf_addr_table output_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
struct list_head msg_queue;
struct mutex msg_queue_lock;
+ struct mutex enrty_queue_lock;
wait_queue_head_t msg_wait;
struct completion event;
struct vcd_property_h264_mv_buffer vcd_h264_mv_buffer;
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 423a849..a984943 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -396,11 +396,11 @@
#define CMD_AXI_CFG_ZSL 43
#define CMD_AXI_CFG_SNAP_VPE 44
#define CMD_AXI_CFG_SNAP_THUMB_VPE 45
-#define CMD_AXI_CFG_VIDEO_ALL_CHNLS 46
-#define CMD_AXI_CFG_ZSL_ALL_CHNLS 47
-#define CMD_CONFIG_PING_ADDR 48
-#define CMD_CONFIG_PONG_ADDR 49
-#define CMD_CONFIG_FREE_BUF_ADDR 50
+#define CMD_CONFIG_PING_ADDR 46
+#define CMD_CONFIG_PONG_ADDR 47
+#define CMD_CONFIG_FREE_BUF_ADDR 48
+#define CMD_AXI_CFG_ZSL_ALL_CHNLS 49
+#define CMD_AXI_CFG_VIDEO_ALL_CHNLS 50
/* vfe config command: config command(from config thread)*/
struct msm_vfe_cfg_cmd {
@@ -467,6 +467,9 @@
uint32_t len;
uint32_t y_off;
uint32_t cbcr_off;
+ uint32_t planar0_off;
+ uint32_t planar1_off;
+ uint32_t planar2_off;
uint8_t active;
};
@@ -487,8 +490,9 @@
#define OUTPUT_2_AND_CAMIF_TO_AXI_VIA_OUTPUT_1 6
#define OUTPUT_1_2_AND_3 7
#define OUTPUT_ALL_CHNLS 8
-#define OUTPUT_ZSL_ALL_CHNLS 9
-#define LAST_AXI_OUTPUT_MODE_ENUM OUTPUT_ZSL_ALL_CHNLS
+#define OUTPUT_VIDEO_ALL_CHNLS 9
+#define OUTPUT_ZSL_ALL_CHNLS 10
+#define LAST_AXI_OUTPUT_MODE_ENUM = OUTPUT_ZSL_ALL_CHNLS
#define MSM_FRAME_PREV_1 0
#define MSM_FRAME_PREV_2 1
@@ -528,6 +532,9 @@
uint32_t phy_offset;
uint32_t y_off;
uint32_t cbcr_off;
+ uint32_t planar0_off;
+ uint32_t planar1_off;
+ uint32_t planar2_off;
int fd;
void *cropinfo;
@@ -557,10 +564,10 @@
};
struct msm_st_half {
- uint32_t buf_y_off;
- uint32_t buf_cbcr_off;
- uint32_t buf_y_stride;
- uint32_t buf_cbcr_stride;
+ uint32_t buf_p0_off;
+ uint32_t buf_p1_off;
+ uint32_t buf_p0_stride;
+ uint32_t buf_p1_stride;
uint32_t pix_x_off;
uint32_t pix_y_off;
struct msm_st_crop stCropInfo;
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 489c248..8b753bd 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012 Code Aurora Forum. All rights reserved.
*
* This file is based on include/net/bluetooth/hci_core.h
*
@@ -354,6 +354,8 @@
__u8 stereo_prg;
__u8 rds_sync_status;
__u8 mute_mode;
+ char sinr;
+ __u8 intf_det_th;
} __packed;
struct hci_ev_rds_rx_data {
@@ -548,6 +550,7 @@
V4L2_CID_PRIVATE_IRIS_SET_AUDIO_PATH, /* TAVARUA specific command */
V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION,
V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM, /* TAVARUA specific command */
+ V4L2_CID_PRIVATE_IRIS_GET_SINR,
/*using private CIDs under userclass*/
V4L2_CID_PRIVATE_IRIS_READ_DEFAULT = 0x00980928,
@@ -687,7 +690,7 @@
#define MAX_PS_LENGTH (96)
#define MAX_RT_LENGTH (64)
#define RDS_GRP_CNTR_LEN (36)
-
+#define RX_RT_DATA_LENGTH (63)
/* Search direction */
#define SRCH_DIR_UP (0)
#define SRCH_DIR_DOWN (1)
diff --git a/include/media/videobuf2-msm-mem.h b/include/media/videobuf2-msm-mem.h
index 916c458..0c7cf8c 100644
--- a/include/media/videobuf2-msm-mem.h
+++ b/include/media/videobuf2-msm-mem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -60,6 +60,7 @@
int subsys_id;
unsigned long mapped_phyaddr;
struct ion_handle *ion_handle;
+ struct ion_client *client;
};
void videobuf2_queue_pmem_contig_init(struct vb2_queue *q,
enum v4l2_buf_type type,
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 155c6fd..7e9f5f4 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -65,6 +65,7 @@
#define BT_SECURITY_HIGH 3
#define BT_DEFER_SETUP 7
+#define BT_FLUSHABLE 8
#define BT_POWER 9
struct bt_power {
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 744eb72..cd85855 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -700,6 +700,12 @@
__le16 voice_setting;
} __packed;
+#define HCI_OP_WRITE_AUTOMATIC_FLUSH_TIMEOUT 0x0c28
+struct hci_cp_write_automatic_flush_timeout {
+ __le16 handle;
+ __le16 timeout;
+} __packed;
+
#define HCI_OP_HOST_BUFFER_SIZE 0x0c33
struct hci_cp_host_buffer_size {
__le16 acl_mtu;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 5339785..857f654 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2011, Code Aurora Forum. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2012, Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -240,8 +240,11 @@
rwlock_t adv_entries_lock;
struct timer_list adv_timer;
- struct timer_list disc_timer;
- struct timer_list disc_le_timer;
+ struct timer_list disco_timer;
+ struct timer_list disco_le_timer;
+ __u8 disco_state;
+ int disco_int_phase;
+ int disco_int_count;
struct hci_dev_stats stat;
@@ -1037,6 +1040,8 @@
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name);
void mgmt_inquiry_started(u16 index);
void mgmt_inquiry_complete_evt(u16 index, u8 status);
+void mgmt_disco_timeout(unsigned long data);
+void mgmt_disco_le_timeout(unsigned long data);
int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status);
/* LE SMP Management interface */
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b98af28..312de3f 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum. All rights reserved.
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2010 Google Inc.
@@ -32,6 +32,7 @@
#define L2CAP_DEFAULT_MIN_MTU 48
#define L2CAP_DEFAULT_MAX_SDU_SIZE 0xffff
#define L2CAP_DEFAULT_FLUSH_TO 0xffff
+#define L2CAP_MAX_FLUSH_TO 0x7ff
#define L2CAP_DEFAULT_TX_WINDOW 63
#define L2CAP_DEFAULT_MAX_TX 3
#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
@@ -293,8 +294,6 @@
struct l2cap_conf_prm {
__u8 fcs;
- __le16 retrans_timeout;
- __le16 monitor_timeout;
__le32 flush_to;
};
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 2fcde6f..3fffcc5 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -896,6 +896,7 @@
struct snd_pcm_runtime *runtime;
struct snd_pcm_hw_params params;
int runtime_update;
+ bool hwparam_set;
};
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 200ce83..3b5340b 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -13,20 +13,51 @@
* irq_domain_add() - Register an irq_domain
* @domain: ptr to initialized irq_domain structure
*
- * Registers an irq_domain structure. The irq_domain must at a minimum be
+ * Adds a irq_domain structure. The irq_domain must at a minimum be
+ * initialized with an ops structure pointer, and either a ->to_irq hook or
+ * a valid irq_base value. The irq range must be mutually exclusive with
+ * domains already registered. Everything else is optional.
+ */
+int irq_domain_add(struct irq_domain *domain)
+{
+ struct irq_domain *curr;
+ uint32_t d_highirq = domain->irq_base + domain->nr_irq - 1;
+
+ if (!domain->nr_irq)
+ return -EINVAL;
+
+ mutex_lock(&irq_domain_mutex);
+ /* insert in ascending order of domain->irq_base */
+ list_for_each_entry(curr, &irq_domain_list, list) {
+ uint32_t c_highirq = curr->irq_base + curr->nr_irq - 1;
+ if (domain->irq_base < curr->irq_base &&
+ d_highirq < curr->irq_base) {
+ break;
+ }
+ if (d_highirq <= c_highirq) {
+ mutex_unlock(&irq_domain_mutex);
+ return -EINVAL;
+ }
+ }
+ list_add_tail(&domain->list, &curr->list);
+ mutex_unlock(&irq_domain_mutex);
+
+ return 0;
+}
+
+/**
+ * irq_domain_register() - Register an entire irq_domain
+ * @domain: ptr to initialized irq_domain structure
+ *
+ * Registers the entire irq_domain. The irq_domain must at a minimum be
* initialized with an ops structure pointer, and either a ->to_irq hook or
* a valid irq_base value. Everything else is optional.
*/
-void irq_domain_add(struct irq_domain *domain)
+void irq_domain_register(struct irq_domain *domain)
{
struct irq_data *d;
int hwirq, irq;
- /*
- * This assumes that the irq_domain owner has already allocated
- * the irq_descs. This block will be removed when support for dynamic
- * allocation of irq_descs is added to irq_domain.
- */
irq_domain_for_each_irq(domain, hwirq, irq) {
d = irq_get_irq_data(irq);
if (!d) {
@@ -41,24 +72,55 @@
d->domain = domain;
d->hwirq = hwirq;
}
-
- mutex_lock(&irq_domain_mutex);
- list_add(&domain->list, &irq_domain_list);
- mutex_unlock(&irq_domain_mutex);
}
/**
- * irq_domain_del() - Unregister an irq_domain
+ * irq_domain_register_irq() - Register an irq_domain
+ * @domain: ptr to initialized irq_domain structure
+ * @hwirq: irq_domain hwirq to register
+ *
+ * Registers a specific hwirq within the irq_domain. The irq_domain
+ * must at a minimum be initialized with an ops structure pointer, and
+ * either a ->to_irq hook or a valid irq_base value. Everything else is
+ * optional.
+ */
+void irq_domain_register_irq(struct irq_domain *domain, int hwirq)
+{
+ struct irq_data *d;
+
+ d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+ if (!d) {
+ WARN(1, "error: assigning domain to non existant irq_desc");
+ return;
+ }
+ if (d->domain) {
+ /* things are broken; just report, don't clean up */
+ WARN(1, "error: irq_desc already assigned to a domain");
+ return;
+ }
+ d->domain = domain;
+ d->hwirq = hwirq;
+}
+
+/**
+ * irq_domain_del() - Removes a irq_domain from the system
* @domain: ptr to registered irq_domain.
*/
void irq_domain_del(struct irq_domain *domain)
{
- struct irq_data *d;
- int hwirq, irq;
-
mutex_lock(&irq_domain_mutex);
list_del(&domain->list);
mutex_unlock(&irq_domain_mutex);
+}
+
+/**
+ * irq_domain_unregister() - Unregister an irq_domain
+ * @domain: ptr to registered irq_domain.
+ */
+void irq_domain_unregister(struct irq_domain *domain)
+{
+ struct irq_data *d;
+ int hwirq, irq;
/* Clear the irq_domain assignments */
irq_domain_for_each_irq(domain, hwirq, irq) {
@@ -67,6 +129,60 @@
}
}
+/**
+ * irq_domain_unregister_irq() - Unregister a hwirq within a irq_domain
+ * @domain: ptr to registered irq_domain.
+ * @hwirq: irq_domain hwirq to unregister.
+ */
+void irq_domain_unregister_irq(struct irq_domain *domain, int hwirq)
+{
+ struct irq_data *d;
+
+ /* Clear the irq_domain assignment */
+ d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+ d->domain = NULL;
+}
+
+/**
+ * irq_domain_find_free_range() - Find an available irq range
+ * @from: lowest logical irq number to request from
+ * @cnt: number of interrupts to search for
+ *
+ * Finds an available logical irq range from the domains specified
+ * on the system. The from parameter can be used to allocate a range
+ * at least as great as the specified irq number.
+ */
+int irq_domain_find_free_range(unsigned int from, unsigned int cnt)
+{
+ struct irq_domain *curr, *prev = NULL;
+
+ if (list_empty(&irq_domain_list))
+ return from;
+
+ list_for_each_entry(curr, &irq_domain_list, list) {
+ if (prev == NULL) {
+ if ((from + cnt - 1) < curr->irq_base)
+ return from;
+ } else {
+ uint32_t p_next_irq = prev->irq_base + prev->nr_irq;
+ uint32_t start_irq;
+ if (from >= curr->irq_base)
+ continue;
+ if (from < p_next_irq)
+ start_irq = p_next_irq;
+ else
+ start_irq = from;
+ if ((curr->irq_base - start_irq) >= cnt)
+ return p_next_irq;
+ }
+ prev = curr;
+ }
+ curr = list_entry(curr->list.prev, struct irq_domain, list);
+
+ return from > curr->irq_base + curr->nr_irq ?
+ from : curr->irq_base + curr->nr_irq;
+}
+
#if defined(CONFIG_OF_IRQ)
/**
* irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
@@ -91,6 +207,7 @@
list_for_each_entry(domain, &irq_domain_list, list) {
if (!domain->ops->dt_translate)
continue;
+
rc = domain->ops->dt_translate(domain, controller,
intspec, intsize, &hwirq, &type);
if (rc == 0)
@@ -154,6 +271,7 @@
void irq_domain_add_simple(struct device_node *controller, int irq_base)
{
struct irq_domain *domain;
+ int rc;
domain = kzalloc(sizeof(*domain), GFP_KERNEL);
if (!domain) {
@@ -164,7 +282,12 @@
domain->irq_base = irq_base;
domain->of_node = of_node_get(controller);
domain->ops = &irq_domain_simple_ops;
- irq_domain_add(domain);
+ rc = irq_domain_add(domain);
+ if (rc) {
+ WARN(1, "Unable to create irq domain\n");
+ return;
+ }
+ irq_domain_register(domain);
}
EXPORT_SYMBOL_GPL(irq_domain_add_simple);
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index 1f06468..6fd4ffd 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -59,18 +59,19 @@
continue;
}
+ fmt = NULL;
tb_fmt = kmalloc(sizeof(*tb_fmt), GFP_KERNEL);
- if (tb_fmt)
+ if (tb_fmt) {
fmt = kmalloc(strlen(*iter) + 1, GFP_KERNEL);
- if (tb_fmt && fmt) {
- list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
- strcpy(fmt, *iter);
- tb_fmt->fmt = fmt;
- *iter = tb_fmt->fmt;
- } else {
- kfree(tb_fmt);
- *iter = NULL;
+ if (fmt) {
+ list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
+ strcpy(fmt, *iter);
+ tb_fmt->fmt = fmt;
+ } else
+ kfree(tb_fmt);
}
+ *iter = fmt;
+
}
mutex_unlock(&btrace_mutex);
}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 53a9cac..ccf3623 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -430,9 +430,10 @@
BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
+ /* Make sure no timers are running */
del_timer(&conn->idle_timer);
-
del_timer(&conn->disc_timer);
+ del_timer(&conn->smp_timer);
if (conn->type == ACL_LINK) {
struct hci_conn *sco = conn->link;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index dd1d6e8..47bfde5 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -1464,6 +1464,10 @@
skb_queue_head_init(&hdev->raw_q);
setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);
+ setup_timer(&hdev->disco_timer, mgmt_disco_timeout,
+ (unsigned long) hdev);
+ setup_timer(&hdev->disco_le_timer, mgmt_disco_le_timeout,
+ (unsigned long) hdev);
for (i = 0; i < NUM_REASSEMBLY; i++)
hdev->reassembly[i] = NULL;
@@ -1571,8 +1575,12 @@
hci_unregister_sysfs(hdev);
+ /* Disable all timers */
hci_del_off_timer(hdev);
del_timer(&hdev->adv_timer);
+ del_timer(&hdev->cmd_timer);
+ del_timer(&hdev->disco_timer);
+ del_timer(&hdev->disco_le_timer);
destroy_workqueue(hdev->workqueue);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index f311e10..ded74dc 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum. All rights reserved.
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2010 Google Inc.
@@ -90,6 +90,8 @@
static int l2cap_deaggregate(struct hci_chan *chan, struct l2cap_pinfo *pi);
static void l2cap_chan_ready(struct sock *sk);
static void l2cap_conn_del(struct hci_conn *hcon, int err);
+static u16 l2cap_get_smallest_flushto(struct l2cap_chan_list *l);
+static void l2cap_set_acl_flushto(struct hci_conn *hcon, u16 flush_to);
/* ---- L2CAP channels ---- */
static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
@@ -519,6 +521,11 @@
l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING;
l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
}
+
+ if (l2cap_get_smallest_flushto(l) > l2cap_pi(sk)->flush_to) {
+ /*if flush timeout of the channel is lesser than existing */
+ l2cap_set_acl_flushto(conn->hcon, l2cap_pi(sk)->flush_to);
+ }
/* Otherwise, do not set scid/dcid/omtu. These will be set up
* by l2cap_fixed_channel_config()
*/
@@ -538,11 +545,18 @@
BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
if (conn) {
+ struct l2cap_chan_list *l = &conn->chan_list;
/* Unlink from channel list */
- l2cap_chan_unlink(&conn->chan_list, sk);
+ l2cap_chan_unlink(l, sk);
l2cap_pi(sk)->conn = NULL;
if (!l2cap_pi(sk)->fixed_channel)
hci_conn_put(conn->hcon);
+
+ read_lock(&l->lock);
+ if (l2cap_pi(sk)->flush_to < l2cap_get_smallest_flushto(l))
+ l2cap_set_acl_flushto(conn->hcon,
+ l2cap_get_smallest_flushto(l));
+ read_unlock(&l->lock);
}
if (l2cap_pi(sk)->ampcon) {
@@ -3198,6 +3212,44 @@
return chan;
}
+static void l2cap_get_ertm_timeouts(struct l2cap_conf_rfc *rfc,
+ struct l2cap_pinfo *pi)
+{
+ if (pi->amp_id && pi->ampcon) {
+ u64 ertm_to = pi->ampcon->hdev->amp_be_flush_to;
+
+ /* Class 1 devices have must have ERTM timeouts
+ * exceeding the Link Supervision Timeout. The
+ * default Link Supervision Timeout for AMP
+ * controllers is 10 seconds.
+ *
+ * Class 1 devices use 0xffffffff for their
+ * best-effort flush timeout, so the clamping logic
+ * will result in a timeout that meets the above
+ * requirement. ERTM timeouts are 16-bit values, so
+ * the maximum timeout is 65.535 seconds.
+ */
+
+ /* Convert timeout to milliseconds and round */
+ ertm_to = div_u64(ertm_to + 999, 1000);
+
+ /* This is the recommended formula for class 2 devices
+ * that start ERTM timers when packets are sent to the
+ * controller.
+ */
+ ertm_to = 3 * ertm_to + 500;
+
+ if (ertm_to > 0xffff)
+ ertm_to = 0xffff;
+
+ rfc->retrans_timeout = cpu_to_le16((u16) ertm_to);
+ rfc->monitor_timeout = rfc->retrans_timeout;
+ } else {
+ rfc->retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
+ rfc->monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+ }
+}
+
int l2cap_build_conf_req(struct sock *sk, void *data)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -3248,10 +3300,10 @@
rfc.txwin_size = L2CAP_TX_WIN_MAX_ENHANCED;
else
rfc.txwin_size = pi->tx_win;
- rfc.max_transmit = pi->max_tx;
- rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
- rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
- rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
+ rfc.max_transmit = pi->max_tx;
+ rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
+ l2cap_get_ertm_timeouts(&rfc, pi);
+
if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->imtu)
rfc.max_pdu_size = cpu_to_le16(pi->imtu);
@@ -3323,30 +3375,16 @@
struct l2cap_conf_req *req = data;
struct l2cap_conf_rfc rfc = { .mode = pi->mode };
void *ptr = req->data;
- u32 be_flush_to;
BT_DBG("sk %p", sk);
- /* convert to milliseconds, round up */
- be_flush_to = (pi->conn->hcon->hdev->amp_be_flush_to + 999) / 1000;
-
switch (pi->mode) {
case L2CAP_MODE_ERTM:
rfc.mode = L2CAP_MODE_ERTM;
rfc.txwin_size = pi->tx_win;
rfc.max_transmit = pi->max_tx;
- if (pi->amp_move_id) {
- rfc.retrans_timeout =
- cpu_to_le16((3 * be_flush_to) + 500);
- rfc.monitor_timeout =
- cpu_to_le16((3 * be_flush_to) + 500);
- } else {
- rfc.retrans_timeout =
- cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
- rfc.monitor_timeout =
- cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
- }
rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
+ l2cap_get_ertm_timeouts(&rfc, pi);
if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->imtu)
rfc.max_pdu_size = cpu_to_le16(pi->imtu);
@@ -3360,17 +3398,16 @@
(unsigned long) &rfc);
if (pi->conn->feat_mask & L2CAP_FEAT_FCS) {
-
/* TODO assign fcs for br/edr based on socket config option */
- if (pi->amp_move_id)
+ /* FCS is not used with AMP because it is redundant - lower
+ * layers already include a checksum. */
+ if (pi->amp_id)
pi->local_conf.fcs = L2CAP_FCS_NONE;
else
pi->local_conf.fcs = L2CAP_FCS_CRC16;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
- pi->local_conf.fcs);
-
- pi->fcs = pi->local_conf.fcs | pi->remote_conf.fcs;
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->local_conf.fcs);
+ pi->fcs = pi->local_conf.fcs | pi->remote_conf.fcs;
}
req->dcid = cpu_to_le16(pi->dcid);
@@ -3532,15 +3569,9 @@
case L2CAP_MODE_ERTM:
if (!(pi->conf_state & L2CAP_CONF_EXT_WIN_RECV))
pi->remote_tx_win = rfc.txwin_size;
-
pi->remote_max_tx = rfc.max_transmit;
-
pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
-
- rfc.retrans_timeout =
- cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
- rfc.monitor_timeout =
- cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+ l2cap_get_ertm_timeouts(&rfc, pi);
pi->conf_state |= L2CAP_CONF_MODE_DONE;
@@ -3646,9 +3677,6 @@
case L2CAP_CONF_RFC:
if (olen == sizeof(rfc))
memcpy(&rfc, (void *) val, olen);
- if (pi->mode != rfc.mode ||
- rfc.mode == L2CAP_MODE_BASIC)
- result = L2CAP_CONF_UNACCEPT;
break;
case L2CAP_CONF_FCS:
@@ -3684,6 +3712,9 @@
BT_DBG("result 0x%2.2x cur mode 0x%2.2x req mode 0x%2.2x",
result, pi->mode, rfc.mode);
+ if (pi->mode != rfc.mode || rfc.mode == L2CAP_MODE_BASIC)
+ result = L2CAP_CONF_UNACCEPT;
+
if (result == L2CAP_CONF_SUCCESS) {
/* Configure output options and let the other side know
* which ones we don't like. */
@@ -3703,38 +3734,26 @@
pi->remote_tx_win);
}
+ pi->remote_mps = rfc.max_pdu_size;
+
if (rfc.mode == L2CAP_MODE_ERTM) {
- pi->remote_conf.retrans_timeout =
- le16_to_cpu(rfc.retrans_timeout);
- pi->remote_conf.monitor_timeout =
- le16_to_cpu(rfc.monitor_timeout);
-
- BT_DBG("remote conf monitor timeout %d",
- pi->remote_conf.monitor_timeout);
-
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
- sizeof(rfc), (unsigned long) &rfc);
+ l2cap_get_ertm_timeouts(&rfc, pi);
+ } else {
+ rfc.retrans_timeout = 0;
+ rfc.monitor_timeout = 0;
}
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
+ sizeof(rfc), (unsigned long) &rfc);
}
if (result != L2CAP_CONF_SUCCESS)
goto done;
- pi->fcs = pi->remote_conf.fcs | pi->local_conf.fcs ;
+ pi->fcs = pi->remote_conf.fcs | pi->local_conf.fcs;
- if (pi->rx_state == L2CAP_ERTM_RX_STATE_WAIT_F_FLAG) {
+ if (pi->rx_state == L2CAP_ERTM_RX_STATE_WAIT_F_FLAG)
pi->flush_to = pi->remote_conf.flush_to;
- pi->retrans_timeout = pi->remote_conf.retrans_timeout;
-
- if (pi->amp_move_id)
- pi->monitor_timeout = pi->remote_conf.monitor_timeout;
- else
- pi->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
- BT_DBG("mode %d monitor timeout %d",
- pi->mode, pi->monitor_timeout);
-
- }
done:
rsp->scid = cpu_to_le16(pi->dcid);
@@ -3958,34 +3977,41 @@
if (type == L2CAP_CONF_RFC) {
if (olen == sizeof(rfc))
memcpy(&rfc, (void *)val, olen);
- if (rfc.mode != pi->mode &&
- rfc.mode != L2CAP_MODE_ERTM) {
- err = -ECONNREFUSED;
- goto done;
+
+ if (rfc.mode != pi->mode) {
+ l2cap_send_disconn_req(pi->conn, sk,
+ ECONNRESET);
+ return -ECONNRESET;
}
- break;
+
+ goto done;
}
}
}
+ BT_ERR("Expected RFC option was missing, using existing values");
+
+ rfc.mode = pi->mode;
+ rfc.retrans_timeout = cpu_to_le16(pi->retrans_timeout);
+ rfc.monitor_timeout = cpu_to_le16(pi->monitor_timeout);
+
done:
l2cap_ertm_stop_ack_timer(pi);
l2cap_ertm_stop_retrans_timer(pi);
l2cap_ertm_stop_monitor_timer(pi);
+ pi->mps = le16_to_cpu(rfc.max_pdu_size);
+ if (pi->mode == L2CAP_MODE_ERTM) {
+ pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
+ pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
+ }
+
if (l2cap_pi(sk)->reconf_state == L2CAP_RECONF_ACC) {
l2cap_pi(sk)->reconf_state = L2CAP_RECONF_NONE;
/* Respond to poll */
err = l2cap_answer_move_poll(sk);
-
} else if (l2cap_pi(sk)->reconf_state == L2CAP_RECONF_INT) {
-
- /* If moving to BR/EDR, use default timeout defined by
- * the spec */
- if (pi->amp_move_id == 0)
- pi->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
-
if (pi->mode == L2CAP_MODE_ERTM) {
l2cap_ertm_tx(sk, NULL, NULL,
L2CAP_ERTM_EVENT_EXPLICIT_POLL);
@@ -7590,6 +7616,33 @@
return 0;
}
+static void l2cap_set_acl_flushto(struct hci_conn *hcon, u16 flush_to)
+{
+ struct hci_cp_write_automatic_flush_timeout flush_tm;
+ if (hcon && hcon->hdev) {
+ flush_tm.handle = hcon->handle;
+ if (flush_to == L2CAP_DEFAULT_FLUSH_TO)
+ flush_to = 0;
+ flush_tm.timeout = (flush_to < L2CAP_MAX_FLUSH_TO) ?
+ flush_to : L2CAP_MAX_FLUSH_TO;
+ hci_send_cmd(hcon->hdev,
+ HCI_OP_WRITE_AUTOMATIC_FLUSH_TIMEOUT,
+ 4, &(flush_tm));
+ }
+}
+
+static u16 l2cap_get_smallest_flushto(struct l2cap_chan_list *l)
+{
+ int ret_flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ struct sock *s;
+ for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+ if (l2cap_pi(s)->flush_to > 0 &&
+ l2cap_pi(s)->flush_to < ret_flush_to)
+ ret_flush_to = l2cap_pi(s)->flush_to;
+ }
+ return ret_flush_to;
+}
+
static int l2cap_debugfs_show(struct seq_file *f, void *p)
{
struct sock *sk;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 9beea74..94cacde 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright (c) 2000-2001, 2011-2012 Code Aurora Forum. All rights reserved.
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2010 Google Inc.
@@ -626,6 +626,7 @@
l2cap_pi(sk)->fcs = opts.fcs;
l2cap_pi(sk)->max_tx = opts.max_tx;
l2cap_pi(sk)->tx_win = opts.txwin_size;
+ l2cap_pi(sk)->flush_to = opts.flush_to;
break;
case L2CAP_LM:
@@ -766,6 +767,15 @@
break;
+ case BT_FLUSHABLE:
+ if (get_user(opt, (u32 __user *) optval)) {
+ err = -EFAULT;
+ break;
+ }
+ l2cap_pi(sk)->flushable = opt;
+
+ break;
+
default:
err = -ENOPROTOOPT;
break;
@@ -1113,8 +1123,6 @@
static void set_default_config(struct l2cap_conf_prm *conf_prm)
{
conf_prm->fcs = L2CAP_FCS_CRC16;
- conf_prm->retrans_timeout = 0;
- conf_prm->monitor_timeout = 0;
conf_prm->flush_to = L2CAP_DEFAULT_FLUSH_TO;
}
@@ -1176,14 +1184,6 @@
pi->extended_control = 0;
pi->local_conf.fcs = pi->fcs;
- if (pi->mode == L2CAP_MODE_BASIC) {
- pi->local_conf.retrans_timeout = 0;
- pi->local_conf.monitor_timeout = 0;
- } else {
- pi->local_conf.retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
- pi->local_conf.monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
- }
-
pi->local_conf.flush_to = pi->flush_to;
set_default_config(&pi->remote_conf);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7f2cff8..67a2900 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1,6 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2010 Nokia Corporation
+ Copyright (c) 2011-2012 Code Aurora Forum. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
@@ -34,18 +35,9 @@
#define MGMT_VERSION 0
#define MGMT_REVISION 1
-enum scan_mode {
- SCAN_IDLE,
- SCAN_LE,
- SCAN_BR
-};
-
-struct disco_interleave {
- u16 index;
- enum scan_mode mode;
- int int_phase;
- int int_count;
-};
+#define SCAN_IDLE 0x00
+#define SCAN_LE 0x01
+#define SCAN_BR 0x02
struct pending_cmd {
struct list_head list;
@@ -1571,8 +1563,8 @@
if (!hdev)
goto not_found;
- del_timer_sync(&hdev->disc_le_timer);
- del_timer_sync(&hdev->disc_timer);
+ del_timer(&hdev->disco_le_timer);
+ del_timer(&hdev->disco_timer);
hci_dev_put(hdev);
not_found:
@@ -1858,8 +1850,8 @@
if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
struct hci_dev *hdev = hci_dev_get(cmd->index);
if (hdev) {
- del_timer_sync(&hdev->disc_le_timer);
- del_timer_sync(&hdev->disc_timer);
+ del_timer(&hdev->disco_le_timer);
+ del_timer(&hdev->disco_timer);
hci_dev_put(hdev);
}
}
@@ -1883,7 +1875,7 @@
{
struct hci_dev *hdev;
struct hci_cp_le_set_scan_enable le_cp = {1, 0};
- struct pending_cmd *cmd;
+ struct mgmt_mode cp = {0};
int err = -1;
BT_DBG("");
@@ -1891,7 +1883,6 @@
hdev = hci_dev_get(index);
if (!hdev || !lmp_le_capable(hdev)) {
- struct mgmt_mode cp = {0};
mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
discovery_terminated, NULL);
@@ -1904,20 +1895,20 @@
return;
}
- cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
- if (cmd && cmd->param) {
- struct disco_interleave *ilp = cmd->param;
-
+ if (hdev->disco_state != SCAN_IDLE) {
err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
sizeof(le_cp), &le_cp);
- if (err >= 0 && hdev) {
- mod_timer(&hdev->disc_le_timer, jiffies +
- msecs_to_jiffies(ilp->int_phase * 1000));
- ilp->mode = SCAN_LE;
+ if (err >= 0) {
+ mod_timer(&hdev->disco_le_timer, jiffies +
+ msecs_to_jiffies(hdev->disco_int_phase * 1000));
+ hdev->disco_state = SCAN_LE;
} else
- ilp->mode = SCAN_IDLE;
+ hdev->disco_state = SCAN_IDLE;
}
+ if (hdev->disco_state == SCAN_IDLE)
+ mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
+
if (err < 0)
mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
discovery_terminated, NULL);
@@ -1926,82 +1917,74 @@
hci_dev_put(hdev);
}
-static void disco_to(unsigned long data)
+void mgmt_disco_timeout(unsigned long data)
{
- struct disco_interleave *ilp = (void *)data;
- struct hci_dev *hdev;
+ struct hci_dev *hdev = (void *) data;
struct pending_cmd *cmd;
+ struct mgmt_mode cp = {0};
- BT_DBG("hci%d", ilp->index);
+ BT_DBG("hci%d", hdev->id);
- hdev = hci_dev_get(ilp->index);
+ hdev = hci_dev_get(hdev->id);
- if (hdev) {
- hci_dev_lock_bh(hdev);
- del_timer_sync(&hdev->disc_le_timer);
+ if (!hdev)
+ return;
- cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
+ hci_dev_lock_bh(hdev);
+ del_timer(&hdev->disco_le_timer);
- if (ilp->mode != SCAN_IDLE) {
- struct hci_cp_le_set_scan_enable le_cp = {0, 0};
+ if (hdev->disco_state != SCAN_IDLE) {
+ struct hci_cp_le_set_scan_enable le_cp = {0, 0};
- if (ilp->mode == SCAN_LE)
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
- sizeof(le_cp), &le_cp);
- else
- hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
- 0, NULL);
-
- ilp->mode = SCAN_IDLE;
- }
-
- if (cmd) {
- struct mgmt_mode cp = {0};
-
- mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
- sizeof(cp), NULL);
- mgmt_pending_remove(cmd);
- }
-
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
- }
-}
-
-static void disco_le_to(unsigned long data)
-{
- struct disco_interleave *ilp = (void *)data;
- struct hci_dev *hdev;
- struct pending_cmd *cmd;
- struct hci_cp_le_set_scan_enable le_cp = {0, 0};
-
- BT_DBG("hci%d", ilp->index);
-
- hdev = hci_dev_get(ilp->index);
-
- if (hdev) {
- hci_dev_lock_bh(hdev);
-
- cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
-
- if (ilp->mode == SCAN_LE)
+ if (hdev->disco_state == SCAN_LE)
hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
sizeof(le_cp), &le_cp);
+ else
+ hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
- /* re-start BR scan */
- if (cmd) {
- struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
- ilp->int_phase *= 2;
- ilp->int_count = 0;
- cp.num_rsp = (u8) ilp->int_phase;
- hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
- ilp->mode = SCAN_BR;
- } else
- ilp->mode = SCAN_IDLE;
-
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
+ hdev->disco_state = SCAN_IDLE;
}
+
+ mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
+
+ cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
+ if (cmd)
+ mgmt_pending_remove(cmd);
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+}
+
+void mgmt_disco_le_timeout(unsigned long data)
+{
+ struct hci_dev *hdev = (void *)data;
+ struct hci_cp_le_set_scan_enable le_cp = {0, 0};
+
+ BT_DBG("hci%d", hdev->id);
+
+ hdev = hci_dev_get(hdev->id);
+
+ if (!hdev)
+ return;
+
+ hci_dev_lock_bh(hdev);
+
+ if (hdev->disco_state == SCAN_LE)
+ hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
+ sizeof(le_cp), &le_cp);
+
+ /* re-start BR scan */
+ if (hdev->disco_state != SCAN_IDLE) {
+ struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
+ hdev->disco_int_phase *= 2;
+ hdev->disco_int_count = 0;
+ cp.num_rsp = (u8) hdev->disco_int_phase;
+ hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+ hdev->disco_state = SCAN_BR;
+ }
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
}
static int start_discovery(struct sock *sk, u16 index)
@@ -2019,6 +2002,11 @@
hci_dev_lock_bh(hdev);
+ if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
+ err = -EBUSY;
+ goto failed;
+ }
+
cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
if (!cmd) {
err = -ENOMEM;
@@ -2052,30 +2040,23 @@
if (err < 0)
mgmt_pending_remove(cmd);
else if (lmp_le_capable(hdev)) {
- struct disco_interleave il, *ilp;
-
- il.int_phase = 1;
- il.int_count = 0;
- il.index = index;
- il.mode = SCAN_BR;
- mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
- sizeof(struct disco_interleave));
- cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
- if (cmd) {
- ilp = cmd->param;
- setup_timer(&hdev->disc_le_timer, disco_le_to,
- (unsigned long) ilp);
- setup_timer(&hdev->disc_timer, disco_to,
- (unsigned long) ilp);
- mod_timer(&hdev->disc_timer,
- jiffies + msecs_to_jiffies(20000));
- }
+ hdev->disco_int_phase = 1;
+ hdev->disco_int_count = 0;
+ hdev->disco_state = SCAN_BR;
+ mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
+ del_timer(&hdev->disco_le_timer);
+ del_timer(&hdev->disco_timer);
+ mod_timer(&hdev->disco_timer,
+ jiffies + msecs_to_jiffies(20000));
}
failed:
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
+ if (err < 0)
+ return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
+
return err;
}
@@ -2083,10 +2064,10 @@
{
struct hci_cp_le_set_scan_enable le_cp = {0, 0};
struct mgmt_mode mode_cp = {0};
- struct disco_interleave *ilp = NULL;
struct hci_dev *hdev;
struct pending_cmd *cmd = NULL;
int err = -EPERM;
+ u8 state;
BT_DBG("");
@@ -2096,38 +2077,32 @@
hci_dev_lock_bh(hdev);
- if (lmp_le_capable(hdev)) {
- cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
+ state = hdev->disco_state;
+ hdev->disco_state = SCAN_IDLE;
+ del_timer(&hdev->disco_le_timer);
+ del_timer(&hdev->disco_timer);
- ilp = cmd->param;
- }
-
- if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
+ if (state == SCAN_LE) {
err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
sizeof(le_cp), &le_cp);
+ if (err >= 0) {
+ mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
+ discovery_terminated, NULL);
- if (err < 0) {
- if (!ilp || (ilp->mode == SCAN_BR))
- err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
- 0, NULL);
+ err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
+ NULL, 0);
+ }
}
- if (ilp) {
- ilp->mode = SCAN_IDLE;
- del_timer_sync(&hdev->disc_le_timer);
- del_timer_sync(&hdev->disc_timer);
- }
+ if (err < 0)
+ err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+ cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
if (err < 0 && cmd)
mgmt_pending_remove(cmd);
mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
-failed:
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
@@ -2822,7 +2797,7 @@
u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
{
struct mgmt_ev_device_found ev;
- struct pending_cmd *cmd;
+ struct hci_dev *hdev;
int err;
BT_DBG("le: %d", le);
@@ -2845,36 +2820,38 @@
if (err < 0)
return err;
- cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
- if (cmd) {
- struct disco_interleave *ilp = cmd->param;
- struct hci_dev *hdev = hci_dev_get(index);
+ hdev = hci_dev_get(index);
- ilp->int_count++;
- if (hdev && ilp->int_count >= ilp->int_phase) {
- /* Inquiry scan for General Discovery LAP */
- struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
- struct hci_cp_le_set_scan_enable le_cp = {0, 0};
+ if (!hdev)
+ return 0;
- ilp->int_phase *= 2;
- ilp->int_count = 0;
- if (ilp->mode == SCAN_LE) {
- /* cancel LE scan */
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
- sizeof(le_cp), &le_cp);
- /* start BR scan */
- cp.num_rsp = (u8) ilp->int_phase;
- hci_send_cmd(hdev, HCI_OP_INQUIRY,
- sizeof(cp), &cp);
- ilp->mode = SCAN_BR;
- del_timer_sync(&hdev->disc_le_timer);
- }
+ if (hdev->disco_state == SCAN_IDLE)
+ goto done;
+
+ hdev->disco_int_count++;
+
+ if (hdev->disco_int_count >= hdev->disco_int_phase) {
+ /* Inquiry scan for General Discovery LAP */
+ struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
+ struct hci_cp_le_set_scan_enable le_cp = {0, 0};
+
+ hdev->disco_int_phase *= 2;
+ hdev->disco_int_count = 0;
+ if (hdev->disco_state == SCAN_LE) {
+ /* cancel LE scan */
+ hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
+ sizeof(le_cp), &le_cp);
+ /* start BR scan */
+ cp.num_rsp = (u8) hdev->disco_int_phase;
+ hci_send_cmd(hdev, HCI_OP_INQUIRY,
+ sizeof(cp), &cp);
+ hdev->disco_state = SCAN_BR;
+ del_timer_sync(&hdev->disco_le_timer);
}
-
- if (hdev)
- hci_dev_put(hdev);
}
+done:
+ hci_dev_put(hdev);
return 0;
}
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index deef8ac..cec01f1 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,8 @@
#define TABLA_TX_DAI_ID 2
#define TABLA_CFILT_FAST_MODE 0x00
#define TABLA_CFILT_SLOW_MODE 0x40
+#define MBHC_FW_READ_ATTEMPTS 15
+#define MBHC_FW_READ_TIMEOUT 2000000
#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
@@ -104,6 +106,7 @@
u16 dce_mb;
u16 sta_z;
u16 sta_mb;
+ u32 t_sta_dce;
u32 t_dce;
u32 t_sta;
u32 micb_mv;
@@ -186,6 +189,10 @@
/* Callback function to enable MCLK */
int (*mclk_cb) (struct snd_soc_codec*, int);
+
+ /* Work to perform MBHC Firmware Read */
+ struct delayed_work mbhc_firmware_dwork;
+ const struct firmware *mbhc_fw;
};
#ifdef CONFIG_DEBUG_FS
@@ -819,6 +826,14 @@
SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
sb_tx7_to_tx10_mux_text);
+static const struct soc_enum sb_tx9_mux_enum =
+ SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
+ sb_tx7_to_tx10_mux_text);
+
+static const struct soc_enum sb_tx10_mux_enum =
+ SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
+ sb_tx7_to_tx10_mux_text);
+
static const struct soc_enum sb_tx1_mux_enum =
SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
@@ -924,6 +939,12 @@
static const struct snd_kcontrol_new sb_tx8_mux =
SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
+static const struct snd_kcontrol_new sb_tx9_mux =
+ SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx10_mux =
+ SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
+
static const struct snd_kcontrol_new sb_tx1_mux =
SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
@@ -2143,6 +2164,14 @@
SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
0, 0),
+ SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
+ SND_SOC_DAPM_AIF_OUT("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
+ 0, 0),
+
+ SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
+ SND_SOC_DAPM_AIF_OUT("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
+ 0, 0),
+
/* Digital Mic Inputs */
SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
@@ -2218,6 +2247,31 @@
{"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
{"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
+ {"SLIM TX9", NULL, "SLIM TX9 MUX"},
+ {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
+ {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
+ {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
+ {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
+ {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
+ {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
+ {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
+ {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
+ {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
+ {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
+
+ {"SLIM TX10", NULL, "SLIM TX10 MUX"},
+ {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
+ {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
+ {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
+ {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
+ {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
+ {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
+ {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
+ {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
+ {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
+ {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
+
+
/* Earpiece (RX MIX1) */
{"EAR", NULL, "EAR PA"},
{"EAR PA", NULL, "DAC1"},
@@ -2945,7 +2999,7 @@
.rate_max = 48000,
.rate_min = 8000,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
},
.ops = &tabla_dai_ops,
},
@@ -3028,6 +3082,8 @@
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+ usleep_range(tabla->mbhc_data.t_sta_dce,
+ tabla->mbhc_data.t_sta_dce);
snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
usleep_range(tabla->mbhc_data.t_dce,
tabla->mbhc_data.t_dce);
@@ -3036,7 +3092,8 @@
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
- usleep_range(50, 50);
+ usleep_range(tabla->mbhc_data.t_sta_dce,
+ tabla->mbhc_data.t_sta_dce);
snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
usleep_range(tabla->mbhc_data.t_sta,
tabla->mbhc_data.t_sta);
@@ -3333,19 +3390,8 @@
nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
mclk_rate = tabla->mclk_freq;
- dce_wait = (1000 * 512 * ncic * nmeas) / (mclk_rate / 1000);
- if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
- dce_wait = dce_wait + 10000;
- else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
- dce_wait = dce_wait + 9810;
- else
- WARN(1, "Unsupported mclk freq %d\n", tabla->mclk_freq);
-
- sta_wait = (1000 * 128 * navg) / (mclk_rate / 1000);
-
- /* Add 10 microseconds to handle error margin */
- dce_wait = dce_wait + 10;
- sta_wait = sta_wait + 10;
+ dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
+ sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
tabla->mbhc_data.t_dce = dce_wait;
tabla->mbhc_data.t_sta = sta_wait;
@@ -3462,8 +3508,11 @@
tabla->mbhc_data.nready = 2;
tabla->mbhc_data.npoll = 7;
tabla->mbhc_data.nbounce_wait = 23;
- }
+ } else
+ WARN(1, "Unsupported mclk freq %d\n", tabla->mclk_freq);
+ tabla->mbhc_data.t_sta_dce = ((1000 * 256) / (tabla->mclk_freq / 1000) *
+ tabla->mbhc_data.nready) + 10;
tabla->mbhc_data.v_ins_hu =
tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
tabla->mbhc_data.v_ins_h =
@@ -3545,6 +3594,91 @@
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
}
+static bool tabla_mbhc_fw_validate(const struct firmware *fw)
+{
+ u32 cfg_offset;
+ struct tabla_mbhc_imped_detect_cfg *imped_cfg;
+ struct tabla_mbhc_btn_detect_cfg *btn_cfg;
+
+ if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
+ return false;
+
+ /* previous check guarantees that there is enough fw data up
+ * to num_btn
+ */
+ btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
+ cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
+ if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
+ return false;
+
+ /* previous check guarantees that there is enough fw data up
+ * to start of impedance detection configuration
+ */
+ imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
+ cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
+
+ if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
+ return false;
+
+ if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
+ return false;
+
+ return true;
+}
+static void mbhc_fw_read(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct tabla_priv *tabla;
+ struct snd_soc_codec *codec;
+ const struct firmware *fw;
+ int ret = -1, retry = 0, rc;
+
+ dwork = to_delayed_work(work);
+ tabla = container_of(dwork, struct tabla_priv,
+ mbhc_firmware_dwork);
+ codec = tabla->codec;
+
+ while (retry < MBHC_FW_READ_ATTEMPTS) {
+ retry++;
+ pr_info("%s:Attempt %d to request MBHC firmware\n",
+ __func__, retry);
+ ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
+ codec->dev);
+
+ if (ret != 0) {
+ usleep_range(MBHC_FW_READ_TIMEOUT,
+ MBHC_FW_READ_TIMEOUT);
+ } else {
+ pr_info("%s: MBHC Firmware read succesful\n", __func__);
+ break;
+ }
+ }
+
+ if (ret != 0) {
+ pr_err("%s: Cannot load MBHC firmware use default cal\n",
+ __func__);
+ } else if (tabla_mbhc_fw_validate(fw) == false) {
+ pr_err("%s: Invalid MBHC cal data size use default cal\n",
+ __func__);
+ release_firmware(fw);
+ } else {
+ tabla->calibration = (void *)fw->data;
+ tabla->mbhc_fw = fw;
+ }
+
+ tabla->mclk_cb(codec, 1);
+ tabla_mbhc_init(codec);
+ tabla_mbhc_cal(codec);
+ tabla_mbhc_calc_thres(codec);
+ tabla->mclk_cb(codec, 0);
+ tabla_codec_calibrate_hs_polling(codec);
+ rc = tabla_codec_enable_hs_detect(codec, 1);
+
+ if (IS_ERR_VALUE(rc))
+ pr_err("%s: Failed to setup MBHC detection\n", __func__);
+
+}
+
int tabla_hs_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *headset_jack,
struct snd_soc_jack *button_jack,
@@ -3553,7 +3687,7 @@
int read_fw_bin, u32 mclk_rate)
{
struct tabla_priv *tabla;
- int rc;
+ int rc = 0;
if (!codec || !calibration) {
pr_err("Error: no codec or calibration\n");
@@ -3571,7 +3705,7 @@
/* Put CFILT in fast mode by default */
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
0x40, TABLA_CFILT_FAST_MODE);
-
+ INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
@@ -3585,8 +3719,8 @@
tabla_codec_calibrate_hs_polling(codec);
rc = tabla_codec_enable_hs_detect(codec, 1);
} else {
- pr_err("%s: MBHC firmware read not supported\n", __func__);
- rc = -EINVAL;
+ schedule_delayed_work(&tabla->mbhc_firmware_dwork,
+ usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
}
if (!IS_ERR_VALUE(rc)) {
@@ -4339,6 +4473,7 @@
/* Make sure mbhc intenal calibration data is zeroed out */
memset(&tabla->mbhc_data, 0,
sizeof(struct mbhc_internal_cal_data));
+ tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
snd_soc_codec_set_drvdata(codec, tabla);
@@ -4505,6 +4640,8 @@
tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
tabla_codec_disable_clock_block(codec);
tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
+ if (tabla->mbhc_fw)
+ release_firmware(tabla->mbhc_fw);
kfree(tabla);
return 0;
}
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 66c3e39..77bfc73 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -21,7 +21,7 @@
#define TABLA_REG_VAL(reg, val) {reg, 0, val}
-
+#define DEFAULT_DCE_STA_WAIT 55
#define DEFAULT_DCE_WAIT 60000
#define DEFAULT_STA_WAIT 5000
@@ -197,3 +197,29 @@
sizeof(TABLA_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_high[0])))) \
)
+/* minimum size of calibration data assuming there is only one button and
+ * one rload.
+ */
+#define TABLA_MBHC_CAL_MIN_SIZE ( \
+ sizeof(struct tabla_mbhc_general_cfg) + \
+ sizeof(struct tabla_mbhc_plug_detect_cfg) + \
+ sizeof(struct tabla_mbhc_plug_type_cfg) + \
+ sizeof(struct tabla_mbhc_btn_detect_cfg) + \
+ sizeof(struct tabla_mbhc_imped_detect_cfg) + \
+ (sizeof(u16) * 2))
+
+#define TABLA_MBHC_CAL_BTN_SZ(cfg_ptr) ( \
+ sizeof(struct tabla_mbhc_btn_detect_cfg) + \
+ (cfg_ptr->num_btn * (sizeof(cfg_ptr->_v_btn_low[0]) + \
+ sizeof(cfg_ptr->_v_btn_high[0]))))
+
+#define TABLA_MBHC_CAL_IMPED_MIN_SZ ( \
+ sizeof(struct tabla_mbhc_imped_detect_cfg) + \
+ sizeof(u16) * 2)
+
+#define TABLA_MBHC_CAL_IMPED_SZ(cfg_ptr) ( \
+ sizeof(struct tabla_mbhc_imped_detect_cfg) + \
+ (cfg_ptr->_n_rload * (sizeof(cfg_ptr->_rload[0]) + \
+ sizeof(cfg_ptr->_alpha[0]))))
+
+
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 590d4af..d0497b1 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -47,10 +47,10 @@
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 1200 * 1024 * 2,
- .period_bytes_min = 60 * 1024,
+ .period_bytes_min = 4800,
.period_bytes_max = 1200 * 1024,
.periods_min = 2,
- .periods_max = 40,
+ .periods_max = 512,
.fifo_size = 0,
};
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index b2adf5d..96260ab 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -237,26 +237,49 @@
{
struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
u8 pgd_la, inf_la;
+ u16 *slave_port_mapping;
memset(dai_data->port_config.slimbus.slave_port_mapping, 0,
sizeof(dai_data->port_config.slimbus.slave_port_mapping));
dai_data->channels = params_channels(params);
+
+ slave_port_mapping = dai_data->port_config.slimbus.slave_port_mapping;
+
switch (dai_data->channels) {
+ case 4:
+ if (dai->id == SLIMBUS_0_TX) {
+ slave_port_mapping[0] = 7;
+ slave_port_mapping[1] = 8;
+ slave_port_mapping[2] = 9;
+ slave_port_mapping[3] = 10;
+ } else {
+ return -EINVAL;
+ }
+ break;
+ case 3:
+ if (dai->id == SLIMBUS_0_TX) {
+ slave_port_mapping[0] = 7;
+ slave_port_mapping[1] = 8;
+ slave_port_mapping[2] = 9;
+ } else {
+ return -EINVAL;
+ }
+ break;
case 2:
if (dai->id == SLIMBUS_0_RX) {
- dai_data->port_config.slimbus.slave_port_mapping[0] = 1;
- dai_data->port_config.slimbus.slave_port_mapping[1] = 2;
+ slave_port_mapping[0] = 1;
+ slave_port_mapping[1] = 2;
} else {
- dai_data->port_config.slimbus.slave_port_mapping[0] = 7;
- dai_data->port_config.slimbus.slave_port_mapping[1] = 8;
+ slave_port_mapping[0] = 7;
+ slave_port_mapping[1] = 8;
}
break;
case 1:
if (dai->id == SLIMBUS_0_RX)
- dai_data->port_config.slimbus.slave_port_mapping[0] = 1;
+ slave_port_mapping[0] = 1;
else
- dai_data->port_config.slimbus.slave_port_mapping[0] = 7;
+ slave_port_mapping[0] = 7;
break;
default:
return -EINVAL;
@@ -829,7 +852,7 @@
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 0ba9513..ed880e8 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -39,6 +39,11 @@
struct snd_pcm *pcm;
};
+#define PLAYBACK_NUM_PERIODS 8
+#define PLAYBACK_PERIOD_SIZE 2048
+#define CAPTURE_NUM_PERIODS 16
+#define CAPTURE_PERIOD_SIZE 320
+
static struct snd_pcm_hardware msm_pcm_hardware_capture = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -51,11 +56,11 @@
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
- .buffer_bytes_max = 320 * 16,
- .period_bytes_min = 320,
- .period_bytes_max = 320,
- .periods_min = 16,
- .periods_max = 16,
+ .buffer_bytes_max = CAPTURE_NUM_PERIODS * CAPTURE_PERIOD_SIZE,
+ .period_bytes_min = CAPTURE_PERIOD_SIZE,
+ .period_bytes_max = CAPTURE_PERIOD_SIZE,
+ .periods_min = CAPTURE_NUM_PERIODS,
+ .periods_max = CAPTURE_NUM_PERIODS,
.fifo_size = 0,
};
@@ -71,11 +76,11 @@
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
- .buffer_bytes_max = 2048 * 8,
- .period_bytes_min = 2048,
- .period_bytes_max = 2048,
- .periods_min = 8,
- .periods_max = 8,
+ .buffer_bytes_max = PLAYBACK_NUM_PERIODS * PLAYBACK_PERIOD_SIZE,
+ .period_bytes_min = PLAYBACK_PERIOD_SIZE,
+ .period_bytes_max = PLAYBACK_PERIOD_SIZE,
+ .periods_min = PLAYBACK_NUM_PERIODS,
+ .periods_max = PLAYBACK_NUM_PERIODS,
.fifo_size = 0,
};
@@ -84,7 +89,7 @@
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
};
-static uint32_t in_frame_info[8][2];
+static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
.count = ARRAY_SIZE(supported_sample_rates),
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 21bbcf2..74a66945 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -56,6 +56,7 @@
pr_debug("task_name = %s pid = %d\n",
this_afe.task->comm, this_afe.task->pid);
send_sig(SIGUSR1, this_afe.task, 0);
+ return 0;
}
if (data->payload_size) {
uint32_t *payload;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index ab7f9f7..62168d2 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -515,6 +515,7 @@
pr_err("%s:map_buffer failed,"
"error = %ld\n",
__func__, PTR_ERR((void *)buf[cnt].mem_buffer));
+ mutex_unlock(&ac->cmd_lock);
goto fail;
}
buf[cnt].data =
@@ -522,6 +523,7 @@
if (!buf[cnt].data) {
pr_err("%s:invalid vaddr,"
" iomap failed\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
goto fail;
}
buf[cnt].used = 1;
@@ -944,6 +946,7 @@
idx = port->cpu_buf;
if (port->buf == NULL) {
pr_debug("%s:Buffer pointer null\n", __func__);
+ mutex_unlock(&port->lock);
return NULL;
}
/* dir 0: used = 0 means buf in use
diff --git a/sound/soc/soc-dsp.c b/sound/soc/soc-dsp.c
index 706954b..6d4f178 100644
--- a/sound/soc/soc-dsp.c
+++ b/sound/soc/soc-dsp.c
@@ -176,6 +176,12 @@
if (!paths)
goto out;
+ if (list == NULL) {
+ pr_err("%s:Widget list is not configured. paths=%d",
+ __func__, paths);
+ goto out;
+ }
+
/* find BE DAI widgets and and connect the to FE */
for (i = 0; i < list->num_widgets; i++) {
@@ -497,6 +503,7 @@
dsp_params->fe->dai_link->name);
soc_pcm_close(be_substream);
+ dsp_params->be->dsp[stream].hwparam_set = false;
be_substream->runtime = NULL;
}
return 0;
@@ -551,7 +558,8 @@
continue;
/* first time the dsp_params is open ? */
- if (dsp_params->be->dsp[stream].users != 1)
+ if ((dsp_params->be->dsp[stream].users != 1) &&
+ (dsp_params->be->dsp[stream].hwparam_set == true))
continue;
dev_dbg(&dsp_params->be->dev, "dsp: hw_params BE %s\n",
@@ -577,6 +585,7 @@
dev_err(&dsp_params->be->dev, "dsp: hw_params BE failed %d\n", ret);
return ret;
}
+ dsp_params->be->dsp[stream].hwparam_set = true;
}
return 0;
}
@@ -852,6 +861,7 @@
dsp_params->fe->dai_link->name);
soc_pcm_hw_free(be_substream);
+ dsp_params->be->dsp[stream].hwparam_set = false;
}
return 0;