Merge changes Ia0648af6,Ie257475a into msm-3.0
* changes:
msm: kgsl: add a225-specific registers to dumps
msm: kgsl: fix format of the rbbm read error message
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 9952818..bc350a7 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -220,7 +220,7 @@
# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
CONFIG_DIAG_CHAR=y
# CONFIG_HW_RANDOM is not set
-CONFIG_DCC_TTY=y
+# CONFIG_DCC_TTY is not set
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_MSM is not set
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 0419929..e6b7b79 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -180,10 +180,8 @@
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_DIAG_CHAR=y
-CONFIG_HVC_DCC=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
-CONFIG_DCC_TTY=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_MSM is not set
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 6f33d86..c294d59 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -242,6 +242,8 @@
select FIX_MOVABLE_ZONE if ENABLE_DMM
select CLEANCACHE
select QCACHE
+ select MIGHT_HAVE_PCI
+ select ARCH_SUPPORTS_MSI
config ARCH_MSMCOPPER
bool "MSM Copper"
@@ -1216,6 +1218,13 @@
prompt "Package 4"
endchoice
+config MSM_PCIE
+ bool "MSM PCIe Controller driver"
+ depends on PCI && PCI_MSI
+ help
+ Enables the PCIe functionality by configures PCIe core on
+ MSM chipset and by enabling the ARM PCI framework extension.
+
config MSM_RPC_SDIO_XPRT
depends on MSM_SDIO_AL
default y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index c5b0081..000cf43 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -156,6 +156,8 @@
obj-$(CONFIG_MSM_PM) += pm.o
obj-$(CONFIG_MSM_NOPM) += no-pm.o
+obj-$(CONFIG_MSM_PCIE) += pcie.o pcie_irq.o
+
obj-$(CONFIG_MSM_SPM_V1) += spm.o
obj-$(CONFIG_MSM_SPM_V2) += spm-v2.o spm_devices.o
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index ceae29c..df041f0 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2139,6 +2139,7 @@
&apq_cpudai_slimbus_1_rx,
&apq_cpudai_slimbus_1_tx,
&apq_cpudai_slimbus_2_tx,
+ &apq_cpudai_slimbus_3_rx,
&apq8064_rpm_device,
&apq8064_rpm_log_device,
&apq8064_rpm_stat_device,
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 6fd0f1b..f52d312 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -41,6 +41,7 @@
#include <linux/i2c/isa1200.h>
#include <linux/gpio_keys.h>
#include <linux/memory.h>
+#include <linux/memblock.h>
#include <linux/slimbus/slimbus.h>
#include <linux/mfd/wcd9xxx/core.h>
@@ -76,6 +77,7 @@
#include <mach/ion.h>
#include <mach/mdm2.h>
#include <mach/msm_rtb.h>
+#include <linux/fmem.h>
#include "timer.h"
#include "devices.h"
@@ -122,17 +124,29 @@
#else
#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
#endif
-
+#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
#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 0x300000 /* (3MB) */
+#define MSM_ION_HEAP_NUM 8
+
+
+#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
#define MSM_ION_MFC_SIZE SZ_8K
#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)
+#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE
+#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE
+
+#define MSM8930_FIXED_AREA_START 0xa0000000
+#define MAX_FIXED_AREA_SIZE 0x10000000
+#define MSM_MM_FW_SIZE 0x200000
+#define MSM8930_FW_START (MSM8930_FIXED_AREA_START - MSM_MM_FW_SIZE)
+
#else
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
#define MSM_ION_HEAP_NUM 1
@@ -218,6 +232,9 @@
#endif /* CONFIG_MSM_MULTIMEDIA_USE_ION */
#endif /* CONFIG_ANDROID_PMEM */
+struct fmem_platform_data msm8930_fmem_pdata = {
+};
+
#define DSP_RAM_BASE_8960 0x8da00000
#define DSP_RAM_SIZE_8960 0x1800000
static int dspcrashd_pdata_8960 = 0xDEADDEAD;
@@ -294,24 +311,36 @@
return MEMTYPE_EBI1;
}
+#define FMEM_ENABLED 1
#ifdef CONFIG_ION_MSM
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct ion_cp_heap_pdata cp_mm_msm8930_ion_pdata = {
.permission_type = IPT_TYPE_MM_CARVEOUT,
.align = PAGE_SIZE,
+ .reusable = FMEM_ENABLED,
+ .mem_is_fmem = FMEM_ENABLED,
+ .fixed_position = FIXED_MIDDLE,
};
static struct ion_cp_heap_pdata cp_mfc_msm8930_ion_pdata = {
.permission_type = IPT_TYPE_MFC_SHAREDMEM,
.align = PAGE_SIZE,
+ .reusable = 0,
+ .mem_is_fmem = FMEM_ENABLED,
+ .fixed_position = FIXED_HIGH,
};
+
static struct ion_co_heap_pdata co_msm8930_ion_pdata = {
.adjacent_mem_id = INVALID_HEAP_ID,
.align = PAGE_SIZE,
+ .mem_is_fmem = 0,
};
+
static struct ion_co_heap_pdata fw_co_msm8930_ion_pdata = {
.adjacent_mem_id = ION_CP_MM_HEAP_ID,
.align = SZ_128K,
+ .mem_is_fmem = FMEM_ENABLED,
+ .fixed_position = FIXED_LOW,
};
#endif
@@ -399,15 +428,180 @@
};
#endif
+struct platform_device msm8930_fmem_device = {
+ .name = "fmem",
+ .id = 1,
+ .dev = { .platform_data = &msm8930_fmem_pdata },
+};
+
+static void __init reserve_mem_for_ion(enum ion_memory_types mem_type,
+ unsigned long size)
+{
+ msm8930_reserve_table[mem_type].size += size;
+}
+
+static void __init msm8930_reserve_fixed_area(unsigned long fixed_area_size)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+ int ret;
+
+ if (fixed_area_size > MAX_FIXED_AREA_SIZE)
+ panic("fixed area size is larger than %dM\n",
+ MAX_FIXED_AREA_SIZE >> 20);
+
+ reserve_info->fixed_area_size = fixed_area_size;
+ reserve_info->fixed_area_start = MSM8930_FW_START;
+
+ ret = memblock_remove(reserve_info->fixed_area_start,
+ reserve_info->fixed_area_size);
+ BUG_ON(ret);
+#endif
+}
+
+/**
+ * Reserve memory for ION and calculate amount of reusable memory for fmem.
+ * We only reserve memory for heaps that are not reusable. However, we only
+ * support one reusable heap at the moment so we ignore the reusable flag for
+ * other than the first heap with reusable flag set. Also handle special case
+ * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
+ * at a higher address than FW in addition to not more than 256MB away from the
+ * base address of the firmware. This means that if MM is reusable the other
+ * two heaps must be allocated in the same region as FW. This is handled by the
+ * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * adjacent to the FW heap for content protection purposes.
+ */
static void __init reserve_ion_memory(void)
{
#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;
+ unsigned int i;
+ unsigned int reusable_count = 0;
+ unsigned int fixed_size = 0;
+ unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
+ unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+
+ msm8930_fmem_pdata.size = 0;
+ msm8930_fmem_pdata.reserved_size_low = 0;
+ msm8930_fmem_pdata.reserved_size_high = 0;
+ fixed_low_size = 0;
+ fixed_middle_size = 0;
+ fixed_high_size = 0;
+
+ /* We only support 1 reusable heap. Check if more than one heap
+ * is specified as reusable and set as non-reusable if found.
+ */
+ for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+ const struct ion_platform_heap *heap =
+ &(msm8930_ion_pdata.heaps[i]);
+
+ if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+ struct ion_cp_heap_pdata *data = heap->extra_data;
+
+ reusable_count += (data->reusable) ? 1 : 0;
+
+ if (data->reusable && reusable_count > 1) {
+ pr_err("%s: Too many heaps specified as "
+ "reusable. Heap %s was not configured "
+ "as reusable.\n", __func__, heap->name);
+ data->reusable = 0;
+ }
+ }
+ }
+
+ for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+ const struct ion_platform_heap *heap =
+ &(msm8930_ion_pdata.heaps[i]);
+
+ if (heap->extra_data) {
+ int fixed_position = NOT_FIXED;
+ int mem_is_fmem = 0;
+
+ switch (heap->type) {
+ case ION_HEAP_TYPE_CP:
+ mem_is_fmem = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->mem_is_fmem;
+ fixed_position = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ case ION_HEAP_TYPE_CARVEOUT:
+ mem_is_fmem = ((struct ion_co_heap_pdata *)
+ heap->extra_data)->mem_is_fmem;
+ fixed_position = ((struct ion_co_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ default:
+ break;
+ }
+
+ if (fixed_position != NOT_FIXED)
+ fixed_size += heap->size;
+ else
+ reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
+
+ if (fixed_position == FIXED_LOW)
+ fixed_low_size += heap->size;
+ else if (fixed_position == FIXED_MIDDLE)
+ fixed_middle_size += heap->size;
+ else if (fixed_position == FIXED_HIGH)
+ fixed_high_size += heap->size;
+
+ if (mem_is_fmem)
+ msm8930_fmem_pdata.size += heap->size;
+ }
+ }
+
+ if (!fixed_size)
+ return;
+
+ if (msm8930_fmem_pdata.size) {
+ msm8930_fmem_pdata.reserved_size_low = fixed_low_size;
+ msm8930_fmem_pdata.reserved_size_high = fixed_high_size;
+ }
+
+ /* Since the fixed area may be carved out of lowmem,
+ * make sure the length is a multiple of 1M.
+ */
+ fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
+ & SECTION_MASK;
+ msm8930_reserve_fixed_area(fixed_size);
+
+ fixed_low_start = MSM8930_FIXED_AREA_START;
+ fixed_middle_start = fixed_low_start + fixed_low_size;
+ fixed_high_start = fixed_middle_start + fixed_middle_size;
+
+ for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+ struct ion_platform_heap *heap = &(msm8930_ion_pdata.heaps[i]);
+
+ if (heap->extra_data) {
+ int fixed_position = NOT_FIXED;
+
+ switch (heap->type) {
+ case ION_HEAP_TYPE_CP:
+ fixed_position = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ case ION_HEAP_TYPE_CARVEOUT:
+ fixed_position = ((struct ion_co_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ default:
+ break;
+ }
+
+ switch (fixed_position) {
+ case FIXED_LOW:
+ heap->base = fixed_low_start;
+ break;
+ case FIXED_MIDDLE:
+ heap->base = fixed_middle_start;
+ break;
+ case FIXED_HIGH:
+ heap->base = fixed_high_start;
+ break;
+ default:
+ break;
+ }
+ }
+ }
#endif
}
@@ -428,6 +622,7 @@
static struct reserve_info msm8930_reserve_info __initdata = {
.memtype_reserve_table = msm8930_reserve_table,
.calculate_reserve_sizes = msm8930_calculate_reserve_sizes,
+ .reserve_fixed_area = msm8930_reserve_fixed_area,
.paddr_to_memtype = msm8930_paddr_to_memtype,
};
@@ -448,12 +643,15 @@
/* Check if 32 bit overflow occured */
if (high < mb->start)
- high = ~0UL;
+ high -= PAGE_SIZE;
+
+ if (high < MAX_FIXED_AREA_SIZE + MSM8930_FIXED_AREA_START)
+ panic("fixed area extends beyond end of memory\n");
low &= ~(bank_size - 1);
if (high - low <= bank_size)
- return;
+ goto no_dmm;
msm8930_reserve_info.bank_size = bank_size;
#ifdef CONFIG_ENABLE_DMM
@@ -464,10 +662,11 @@
msm8930_reserve_info.low_unstable_address,
msm8930_reserve_info.max_unstable_size,
msm8930_reserve_info.bank_size);
-#else
- msm8930_reserve_info.low_unstable_address = 0;
- msm8930_reserve_info.max_unstable_size = 0;
+ return;
#endif
+no_dmm:
+ msm8930_reserve_info.low_unstable_address = high;
+ msm8930_reserve_info.max_unstable_size = 0;
}
static void __init place_movable_zone(void)
@@ -490,6 +689,18 @@
static void __init msm8930_reserve(void)
{
msm_reserve();
+ if (msm8930_fmem_pdata.size) {
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+ if (reserve_info->fixed_area_size) {
+ msm8930_fmem_pdata.phys =
+ reserve_info->fixed_area_start + MSM_MM_FW_SIZE;
+ pr_info("mm fw at %lx (fixed) size %x\n",
+ reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
+ pr_info("fmem start %lx (fixed) size %lx\n",
+ msm8930_fmem_pdata.phys, msm8930_fmem_pdata.size);
+ }
+#endif
+ }
}
static int msm8930_change_memory_power(u64 start, u64 size,
@@ -1740,6 +1951,7 @@
&msm8930_android_pmem_audio_device,
#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
#endif /*CONFIG_ANDROID_PMEM*/
+ &msm8930_fmem_device,
&msm_device_bam_dmux,
&msm_fm_platform_init,
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index e97fdad..bd89e34 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -120,14 +120,38 @@
static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data;
-struct msm_camera_device_platform_data msm_camera_device_data_csi1 = {
- .csid_core = 1,
- .is_csic = 1,
+struct msm_camera_device_platform_data msm_camera_device_data_csi1[] = {
+ {
+ .csid_core = 1,
+ .is_csic = 1,
+ .ioclk = {
+ .vfe_clk_rate = 192000000,
+ },
+ },
+ {
+ .csid_core = 1,
+ .is_csic = 1,
+ .ioclk = {
+ .vfe_clk_rate = 266667000,
+ },
+ },
};
-struct msm_camera_device_platform_data msm_camera_device_data_csi0 = {
- .csid_core = 0,
- .is_csic = 1,
+struct msm_camera_device_platform_data msm_camera_device_data_csi0[] = {
+ {
+ .csid_core = 0,
+ .is_csic = 1,
+ .ioclk = {
+ .vfe_clk_rate = 192000000,
+ },
+ },
+ {
+ .csid_core = 0,
+ .is_csic = 1,
+ .ioclk = {
+ .vfe_clk_rate = 266667000,
+ },
+ },
};
static struct i2c_board_info msm_act_main_cam_i2c_info = {
@@ -159,7 +183,7 @@
.sensor_name = "s5k4e1",
.sensor_reset_enable = 1,
.pmic_gpio_enable = 0,
- .pdata = &msm_camera_device_data_csi1,
+ .pdata = &msm_camera_device_data_csi1[0],
.flash_data = &flash_s5k4e1,
.sensor_platform_info = &sensor_board_info_s5k4e1,
.csi_if = 1,
@@ -187,7 +211,7 @@
.pmic_gpio_enable = 1,
.sensor_reset = GPIO_SKU1_CAM_VGA_RESET_N,
.sensor_pwd = GPIO_SKU1_CAM_VGA_SHDN,
- .pdata = &msm_camera_device_data_csi0,
+ .pdata = &msm_camera_device_data_csi0[0],
.flash_data = &flash_ov7692,
.sensor_platform_info = &sensor_board_info_ov7692,
.csi_if = 1,
@@ -230,7 +254,7 @@
.pmic_gpio_enable = 1,
.sensor_reset = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
.sensor_pwd = GPIO_SKU3_CAM_5MP_SHDN_N,
- .pdata = &msm_camera_device_data_csi1,
+ .pdata = &msm_camera_device_data_csi1[0],
.flash_data = &flash_ov5647,
.sensor_platform_info = &sensor_board_info_ov5647,
.csi_if = 1,
@@ -257,7 +281,7 @@
.sensor_name = "mt9e013",
.sensor_reset_enable = 1,
.pmic_gpio_enable = 0,
- .pdata = &msm_camera_device_data_csi1,
+ .pdata = &msm_camera_device_data_csi1[1],
.flash_data = &flash_mt9e013,
.sensor_platform_info = &sensor_board_info_mt9e013,
.csi_if = 1,
@@ -283,7 +307,7 @@
.sensor_name = "ov9726",
.sensor_reset_enable = 0,
.pmic_gpio_enable = 0,
- .pdata = &msm_camera_device_data_csi0,
+ .pdata = &msm_camera_device_data_csi0[0],
.flash_data = &flash_ov9726,
.sensor_platform_info = &sensor_board_info_ov9726,
.csi_if = 1,
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 4df2232..49945d0 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -186,6 +186,56 @@
#define MXT_TS_IRQ_GPIO 48
#define MXT_TS_RESET_GPIO 26
+#define MAX_VKEY_LEN 100
+
+static ssize_t mxt_virtual_keys_register(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ char *virtual_keys = __stringify(EV_KEY) ":" __stringify(KEY_MENU) \
+ ":60:840:120:80" ":" __stringify(EV_KEY) \
+ ":" __stringify(KEY_HOME) ":180:840:120:80" \
+ ":" __stringify(EV_KEY) ":" \
+ __stringify(KEY_BACK) ":300:840:120:80" \
+ ":" __stringify(EV_KEY) ":" \
+ __stringify(KEY_SEARCH) ":420:840:120:80" "\n";
+
+ return snprintf(buf, strnlen(virtual_keys, MAX_VKEY_LEN) + 1 , "%s",
+ virtual_keys);
+}
+
+static struct kobj_attribute mxt_virtual_keys_attr = {
+ .attr = {
+ .name = "virtualkeys.atmel_mxt_ts",
+ .mode = S_IRUGO,
+ },
+ .show = &mxt_virtual_keys_register,
+};
+
+static struct attribute *mxt_virtual_key_properties_attrs[] = {
+ &mxt_virtual_keys_attr.attr,
+ NULL,
+};
+
+static struct attribute_group mxt_virtual_key_properties_attr_group = {
+ .attrs = mxt_virtual_key_properties_attrs,
+};
+
+struct kobject *mxt_virtual_key_properties_kobj;
+
+static int mxt_vkey_setup(void)
+{
+ int retval;
+
+ mxt_virtual_key_properties_kobj =
+ kobject_create_and_add("board_properties", NULL);
+ if (mxt_virtual_key_properties_kobj)
+ retval = sysfs_create_group(mxt_virtual_key_properties_kobj,
+ &mxt_virtual_key_properties_attr_group);
+ if (!mxt_virtual_key_properties_kobj || retval)
+ pr_err("failed to create mxt board_properties\n");
+
+ return retval;
+}
static const u8 mxt_config_data[] = {
/* T6 Object */
@@ -232,6 +282,51 @@
80, 100, 15, 3,
};
+static const u8 mxt_config_data_evt[] = {
+ /* T6 Object */
+ 0, 0, 0, 0, 0, 0,
+ /* T38 Object */
+ 20, 0, 0, 0, 0, 0, 0, 0,
+ /* T7 Object */
+ 24, 12, 10,
+ /* T8 Object */
+ 30, 0, 20, 20, 0, 0, 9, 45, 10, 192,
+ /* T9 Object */
+ 3, 0, 0, 18, 11, 0, 16, 60, 3, 1,
+ 0, 1, 1, 0, 10, 10, 10, 10, 107, 3,
+ 223, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 15, 0, 0, 2,
+ /* T15 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ /* T18 Object */
+ 0, 0,
+ /* T19 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ /* T23 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* T25 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* T40 Object */
+ 17, 0, 0, 30, 30,
+ /* T42 Object */
+ 3, 20, 45, 40, 128, 0, 0, 0,
+ /* T46 Object */
+ 0, 2, 16, 16, 0, 0, 0, 0, 0,
+ /* T47 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* T48 Object */
+ 1, 128, 96, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 6, 6, 0, 0, 63, 4, 64,
+ 10, 0, 32, 5, 0, 38, 0, 8, 0, 0,
+ 0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+
static struct mxt_config_info mxt_config_array[] = {
{
.config = mxt_config_data,
@@ -715,7 +810,17 @@
i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
synaptic_i2c_clearpad3k,
ARRAY_SIZE(synaptic_i2c_clearpad3k));
- } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+ } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+ machine_is_msm8625_evt()) {
+ /* Use configuration data for EVT */
+ if (machine_is_msm8625_evt()) {
+ mxt_config_array[0].config = mxt_config_data_evt;
+ mxt_config_array[0].config_length =
+ ARRAY_SIZE(mxt_config_data_evt);
+ mxt_platform_data.panel_maxy = 875;
+ mxt_vkey_setup();
+ }
+
rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_IRQ_GPIO, 0,
GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
GPIO_CFG_8MA), GPIO_CFG_ENABLE);
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 13866e7..e5a31f2a 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -7517,7 +7517,7 @@
"msm_ebi2", "mem_clk");
return;
}
- clk_enable(mem_clk);
+ clk_prepare_enable(mem_clk);
clk_put(mem_clk);
ebi2_cfg_ptr = ioremap_nocache(0x1a100000, sizeof(uint32_t));
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 9ada0dd..2c533d9 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -582,6 +582,11 @@
.id = 0x4005,
};
+struct platform_device apq_cpudai_slimbus_3_rx = {
+ .name = "msm-dai-q6",
+ .id = 0x4006,
+};
+
static struct resource resources_ssbi_pmic1[] = {
{
.start = MSM_PMIC1_SSBI_CMD_PHYS,
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 6a03a77..f8cb345 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -690,7 +690,7 @@
.memtype = MEMTYPE_EBI1,
.enable_ion = 0,
#endif
- .disable_dmx = 0,
+ .disable_dmx = 1,
.disable_fullhd = 0,
};
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 6a56c04..31142c1 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -264,6 +264,7 @@
extern struct platform_device apq_cpudai_slimbus_1_rx;
extern struct platform_device apq_cpudai_slimbus_1_tx;
extern struct platform_device apq_cpudai_slimbus_2_tx;
+extern struct platform_device apq_cpudai_slimbus_3_rx;
extern struct platform_device apq_cpudai_slim_4_rx;
extern struct platform_device apq_cpudai_slim_4_tx;
diff --git a/arch/arm/mach-msm/include/mach/hardware.h b/arch/arm/mach-msm/include/mach/hardware.h
index 2d12609..f1095af 100644
--- a/arch/arm/mach-msm/include/mach/hardware.h
+++ b/arch/arm/mach-msm/include/mach/hardware.h
@@ -1,6 +1,7 @@
/* arch/arm/mach-msm/include/mach/hardware.h
*
* Copyright (C) 2007 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
@@ -14,5 +15,10 @@
*/
#ifndef __ASM_ARCH_MSM_HARDWARE_H
+#define __ASM_ARCH_MSM_HARDWARE_H
+
+#define PCIBIOS_MIN_IO 0x10000000
+#define PCIBIOS_MIN_MEM 0x10000000
+#define pcibios_assign_all_busses() 1
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index ff011a8..e3904b4 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -45,8 +45,14 @@
#define NR_WCD9XXX_IRQS 49
#define NR_TABLA_IRQS NR_WCD9XXX_IRQS
#define NR_GPIO_EXPANDER_IRQS 64
+#ifdef CONFIG_PCI_MSI
+#define NR_PCIE_MSI_IRQS 256
+#define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
+ NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS + NR_PCIE_MSI_IRQS)
+#else
#define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS)
+#endif
#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
#define NR_MSM_GPIOS NR_GPIO_IRQS
@@ -85,4 +91,9 @@
#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
#define MSM_INT_TO_REG(base, irq) (base + irq / 32)
+#if defined(CONFIG_PCI_MSI) && defined(CONFIG_MSM_PCIE)
+#define MSM_PCIE_MSI_INT(n) (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS + \
+ NR_PM8821_IRQS + NR_TABLA_IRQS + NR_GPIO_EXPANDER_IRQS + (n))
+#endif
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_pcie.h b/arch/arm/mach-msm/include/mach/msm_pcie.h
new file mode 100644
index 0000000..008c984
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_pcie.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_PCIE_H
+#define __ASM_ARCH_MSM_PCIE_H
+
+#include <linux/types.h>
+
+/* gpios */
+enum msm_pcie_gpio {
+ MSM_PCIE_GPIO_RST_N,
+ MSM_PCIE_GPIO_PWR_EN,
+ MSM_PCIE_MAX_GPIO
+};
+
+/* gpio info structrue */
+struct msm_pcie_gpio_info_t {
+ char *name;
+ uint32_t num;
+ uint32_t on;
+};
+
+/* msm pcie platfrom data */
+struct msm_pcie_platform {
+ struct msm_pcie_gpio_info_t *gpio;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
new file mode 100644
index 0000000..4e2b1083
--- /dev/null
+++ b/arch/arm/mach-msm/pcie.c
@@ -0,0 +1,669 @@
+/* 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.
+ */
+
+/*
+ * MSM PCIe controller driver.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <asm/mach/pci.h>
+#include <mach/gpiomux.h>
+#include <mach/hardware.h>
+#include <mach/msm_iomap.h>
+
+#include "pcie.h"
+
+/* Root Complex Port vendor/device IDs */
+#define PCIE_VENDOR_ID_RCP 0x17cb
+#define PCIE_DEVICE_ID_RCP 0x0101
+
+#define PCIE20_PARF_PCS_DEEMPH 0x34
+#define PCIE20_PARF_PCS_SWING 0x38
+#define PCIE20_PARF_PHY_CTRL 0x40
+#define PCIE20_PARF_PHY_REFCLK 0x4C
+#define PCIE20_PARF_CONFIG_BITS 0x50
+
+#define PCIE20_ELBI_SYS_CTRL 0x04
+
+#define PCIE20_CAP 0x70
+#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10)
+
+#define PCIE20_COMMAND_STATUS 0x04
+#define PCIE20_BUSNUMBERS 0x18
+#define PCIE20_MEMORY_BASE_LIMIT 0x20
+
+#define PCIE20_PLR_IATU_VIEWPORT 0x900
+#define PCIE20_PLR_IATU_CTRL1 0x904
+#define PCIE20_PLR_IATU_CTRL2 0x908
+#define PCIE20_PLR_IATU_LBAR 0x90C
+#define PCIE20_PLR_IATU_UBAR 0x910
+#define PCIE20_PLR_IATU_LAR 0x914
+#define PCIE20_PLR_IATU_LTAR 0x918
+#define PCIE20_PLR_IATU_UTAR 0x91c
+
+#define PCIE_RESET (MSM_CLK_CTL_BASE + 0x22dc)
+#define PCIE_SFAB_AXI_S5_FCLK_CTL (MSM_CLK_CTL_BASE + 0x2154)
+
+#define MSM_PCIE_DEV_BAR_ADDR PCIBIOS_MIN_MEM
+#define MSM_PCIE_DEV_CFG_ADDR 0x01000000
+
+#define RD 0
+#define WR 1
+
+/* debug mask sys interface */
+static int msm_pcie_debug_mask;
+module_param_named(debug_mask, msm_pcie_debug_mask,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+/* resources from device file */
+enum msm_pcie_res {
+ MSM_PCIE_RES_PARF,
+ MSM_PCIE_RES_ELBI,
+ MSM_PCIE_RES_PCIE20,
+ MSM_PCIE_RES_AXI_BAR,
+ MSM_PCIE_RES_AXI_CONF,
+ MSM_PCIE_MAX_RES
+};
+
+/* msm pcie device data */
+static struct msm_pcie_dev_t msm_pcie_dev;
+
+/* regulators */
+static struct msm_pcie_vreg_info_t msm_pcie_vreg_info[MSM_PCIE_MAX_VREG] = {
+ {NULL, "vp_pcie", 1050000, 1050000, 40900},
+ {NULL, "vptx_pcie", 1050000, 1050000, 18200},
+ {NULL, "vdd_pcie_vph", 0, 0, 0},
+ {NULL, "pcie_ext_3p3v", 0, 0, 0}
+};
+
+/* clocks */
+static struct msm_pcie_clk_info_t msm_pcie_clk_info[MSM_PCIE_MAX_CLK] = {
+ {NULL, "bus_clk"},
+ {NULL, "iface_clk"},
+ {NULL, "ref_clk"}
+};
+
+/* resources */
+static struct msm_pcie_res_info_t msm_pcie_res_info[MSM_PCIE_MAX_RES] = {
+ {"parf", 0, 0, 0},
+ {"elbi", 0, 0, 0},
+ {"pcie20", 0, 0, 0},
+ {"axi_bar", 0, 0, 0},
+ {"axi_conf", 0, 0, 0},
+};
+
+int msm_pcie_get_debug_mask(void)
+{
+ return msm_pcie_debug_mask;
+}
+
+static void msm_pcie_write_mask(void __iomem *addr,
+ uint32_t clear_mask, uint32_t set_mask)
+{
+ uint32_t val;
+
+ val = (readl_relaxed(addr) & ~clear_mask) | set_mask;
+ writel_relaxed(val, addr);
+ wmb(); /* ensure data is written to hardware register */
+}
+
+static int msm_pcie_is_link_up(void)
+{
+ return readl_relaxed(msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS) &
+ BIT(29);
+}
+
+static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
+ int where, int size, u32 *val)
+{
+ uint32_t word_offset, byte_offset, mask;
+ uint32_t rd_val, wr_val;
+ struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+ void __iomem *config_base;
+
+ /*
+ * Only buses 0 and 1 are supported. RC port on bus 0 and EP in bus 1.
+ * For downstream bus (1), make sure link is up
+ */
+ if ((bus->number > 1) || (devfn != 0)) {
+ PCIE_DBG("invalid %s - bus %d devfn %d\n",
+ (oper == RD) ? "rd" : "wr", bus->number, devfn);
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else if ((bus->number != 0) && !msm_pcie_is_link_up()) {
+ PCIE_DBG("%s fail, link down - bus %d devfn %d\n",
+ (oper == RD) ? "rd" : "wr", bus->number, devfn);
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ word_offset = where & ~0x3;
+ byte_offset = where & 0x3;
+ mask = (~0 >> (8 * (4 - size))) << (8 * byte_offset);
+
+ config_base = (bus->number == 0) ? dev->pcie20 : dev->axi_conf;
+ rd_val = readl_relaxed(config_base + word_offset);
+
+ if (oper == RD) {
+ *val = ((rd_val & mask) >> (8 * byte_offset));
+
+ PCIE_DBG("%d:0x%02x + 0x%04x[%d] -> 0x%08x; rd 0x%08x\n",
+ bus->number, devfn, where, size, *val, rd_val);
+ } else {
+ wr_val = (rd_val & ~mask) |
+ ((*val << (8 * byte_offset)) & mask);
+ writel_relaxed(wr_val, config_base + word_offset);
+ wmb(); /* ensure config data is written to hardware register */
+
+ PCIE_DBG("%d:0x%02x + 0x%04x[%d] <- 0x%08x;"
+ " rd 0x%08x val 0x%08x\n", bus->number,
+ devfn, where, size, wr_val, rd_val, *val);
+ }
+
+ return 0;
+}
+
+static int msm_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+ int size, u32 *val)
+{
+ return msm_pcie_oper_conf(bus, devfn, RD, where, size, val);
+}
+
+static int msm_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+ int where, int size, u32 val)
+{
+ return msm_pcie_oper_conf(bus, devfn, WR, where, size, &val);
+}
+
+static struct pci_ops msm_pcie_ops = {
+ .read = msm_pcie_rd_conf,
+ .write = msm_pcie_wr_conf,
+};
+
+static int __devinit msm_pcie_gpio_init(void)
+{
+ int rc, i;
+ struct msm_pcie_gpio_info_t *info;
+
+ for (i = 0; i < MSM_PCIE_MAX_GPIO; i++) {
+ info = &msm_pcie_dev.gpio[i];
+
+ rc = gpio_request(info->num, info->name);
+ if (rc) {
+ pr_err("can't get gpio %s; %d\n", info->name, rc);
+ break;
+ }
+
+ rc = gpio_direction_output(info->num, 0);
+ if (rc) {
+ pr_err("can't set gpio direction %s; %d\n",
+ info->name, rc);
+ gpio_free(info->num);
+ break;
+ }
+ }
+
+ if (rc)
+ while (i--)
+ gpio_free(msm_pcie_dev.gpio[i].num);
+
+ return rc;
+}
+
+static void msm_pcie_gpio_deinit(void)
+{
+ int i;
+
+ for (i = 0; i < MSM_PCIE_MAX_GPIO; i++)
+ gpio_free(msm_pcie_dev.gpio[i].num);
+}
+
+static int __devinit msm_pcie_vreg_init(struct device *dev)
+{
+ int i, rc = 0;
+ struct regulator *vreg;
+ struct msm_pcie_vreg_info_t *info;
+
+ for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
+ info = &msm_pcie_dev.vreg[i];
+
+ vreg = regulator_get(dev, info->name);
+ if (!vreg || IS_ERR(vreg)) {
+ rc = (PTR_ERR(vreg)) ? PTR_ERR(vreg) : -ENODEV;
+ pr_err("can't get %s; %d\n", info->name, rc);
+ break;
+ }
+
+ if (info->max_v) {
+ rc = regulator_set_voltage(vreg,
+ info->min_v, info->max_v);
+ if (rc) {
+ pr_err("can't set voltage %s; %d\n",
+ info->name, rc);
+ regulator_put(vreg);
+ break;
+ }
+ }
+
+ if (info->opt_mode) {
+ rc = regulator_set_optimum_mode(vreg, info->opt_mode);
+ if (rc < 0) {
+ pr_err("can't set mode %s; %d\n",
+ info->name, rc);
+ regulator_put(vreg);
+ break;
+ }
+ }
+
+ rc = regulator_enable(vreg);
+ if (rc) {
+ pr_err("can't enable %s, %d\n", info->name, rc);
+ regulator_put(vreg);
+ break;
+ }
+ info->hdl = vreg;
+ }
+
+ if (rc)
+ while (i--) {
+ regulator_disable(msm_pcie_dev.vreg[i].hdl);
+ regulator_put(msm_pcie_dev.vreg[i].hdl);
+ msm_pcie_dev.vreg[i].hdl = NULL;
+ }
+
+ return rc;
+}
+
+static void msm_pcie_vreg_deinit(void)
+{
+ int i;
+
+ for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
+ regulator_disable(msm_pcie_dev.vreg[i].hdl);
+ regulator_put(msm_pcie_dev.vreg[i].hdl);
+ msm_pcie_dev.vreg[i].hdl = NULL;
+ }
+}
+
+static int __devinit msm_pcie_clk_init(struct device *dev)
+{
+ int i, rc = 0;
+ struct clk *clk_hdl;
+ struct msm_pcie_clk_info_t *info;
+
+ for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
+ info = &msm_pcie_dev.clk[i];
+
+ clk_hdl = clk_get(dev, info->name);
+ if (!clk_hdl || IS_ERR(clk_hdl)) {
+ rc = (PTR_ERR(clk_hdl)) ? PTR_ERR(clk_hdl) : -ENODEV;
+ pr_err("can't get clk %s; %d\n", info->name, rc);
+ break;
+ }
+ clk_prepare_enable(clk_hdl);
+ info->hdl = clk_hdl;
+ }
+
+ if (rc)
+ while (i--) {
+ clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
+ clk_put(msm_pcie_dev.clk[i].hdl);
+ msm_pcie_dev.clk[i].hdl = NULL;
+ }
+
+ return rc;
+}
+
+static void msm_pcie_clk_deinit(void)
+{
+ int i;
+
+ for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
+ clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
+ clk_put(msm_pcie_dev.clk[i].hdl);
+ msm_pcie_dev.clk[i].hdl = NULL;
+ }
+}
+
+static void __devinit msm_pcie_config_controller(void)
+{
+ struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+ struct msm_pcie_res_info_t *axi_bar = &dev->res[MSM_PCIE_RES_AXI_BAR];
+ struct msm_pcie_res_info_t *axi_conf = &dev->res[MSM_PCIE_RES_AXI_CONF];
+
+ /*
+ * program and enable address translation region 0 (device config
+ * address space); region type config;
+ * axi config address range to device config address range
+ */
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
+ /* ensure that hardware locks the region before programming it */
+ wmb();
+
+ writel_relaxed(4, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
+ writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
+ writel_relaxed(axi_conf->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
+ writel_relaxed(axi_conf->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
+ writel_relaxed(MSM_PCIE_DEV_CFG_ADDR,
+ dev->pcie20 + PCIE20_PLR_IATU_LTAR);
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
+ /* ensure that hardware registers the configuration */
+ wmb();
+
+ /*
+ * program and enable address translation region 2 (device resource
+ * address space); region type memory;
+ * axi device bar address range to device bar address range
+ */
+ writel_relaxed(2, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
+ /* ensure that hardware locks the region before programming it */
+ wmb();
+
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
+ writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
+ writel_relaxed(axi_bar->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
+ writel_relaxed(axi_bar->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
+ writel_relaxed(MSM_PCIE_DEV_BAR_ADDR,
+ dev->pcie20 + PCIE20_PLR_IATU_LTAR);
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
+ /* ensure that hardware registers the configuration */
+ wmb();
+}
+
+static int __devinit msm_pcie_get_resources(struct platform_device *pdev)
+{
+ int i, rc = 0;
+ struct resource *res;
+ struct msm_pcie_res_info_t *info;
+ struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+
+ for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
+ info = &dev->res[i];
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, info->name);
+ if (!res) {
+ pr_err("can't get %s resource\n", info->name);
+ rc = -ENOMEM;
+ break;
+ }
+
+ info->base = ioremap(res->start, resource_size(res));
+ if (!info->base) {
+ pr_err("can't remap %s\n", info->name);
+ rc = -ENOMEM;
+ break;
+ }
+
+ info->start = res->start;
+ info->end = res->end;
+ }
+
+ if (rc) {
+ while (i--) {
+ iounmap(dev->res[i].base);
+ dev->res[i].base = NULL;
+ }
+ } else {
+ dev->parf = dev->res[MSM_PCIE_RES_PARF].base;
+ dev->elbi = dev->res[MSM_PCIE_RES_ELBI].base;
+ dev->pcie20 = dev->res[MSM_PCIE_RES_PCIE20].base;
+ dev->axi_conf = dev->res[MSM_PCIE_RES_AXI_CONF].base;
+ }
+
+ return rc;
+}
+
+static void __devexit msm_pcie_release_resources(void)
+{
+ int i;
+
+ for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
+ iounmap(msm_pcie_dev.res[i].base);
+ msm_pcie_dev.res[i].base = NULL;
+ }
+
+ msm_pcie_dev.parf = NULL;
+ msm_pcie_dev.elbi = NULL;
+ msm_pcie_dev.pcie20 = NULL;
+ msm_pcie_dev.axi_conf = NULL;
+}
+
+static int __devinit msm_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+ int rc;
+ struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+ uint32_t val;
+
+ PCIE_DBG("bus %d\n", nr);
+ if (nr != 0)
+ return 0;
+
+ /* assert PCIe reset link to keep EP in reset */
+ gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
+ dev->gpio[MSM_PCIE_GPIO_RST_N].on);
+
+ /* enable power */
+ rc = msm_pcie_vreg_init(&dev->pdev->dev);
+ if (rc)
+ goto out;
+
+ /* assert PCIe PARF reset while powering the core */
+ msm_pcie_write_mask(PCIE_RESET, 0, BIT(2));
+
+ /* enable clocks */
+ rc = msm_pcie_clk_init(&dev->pdev->dev);
+ if (rc)
+ goto clk_fail;
+
+ /* enable pcie power; wait 3ms for clock to stabilize */
+ gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_PWR_EN].num,
+ dev->gpio[MSM_PCIE_GPIO_PWR_EN].on);
+ usleep(3000);
+
+ /*
+ * de-assert PCIe PARF reset;
+ * wait 1us before accessing PARF registers
+ */
+ msm_pcie_write_mask(PCIE_RESET, BIT(2), 0);
+ udelay(1);
+
+ /* enable PCIe clocks and resets */
+ msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0);
+
+ /* PARF programming */
+ writel_relaxed(0x282828, dev->parf + PCIE20_PARF_PCS_DEEMPH);
+ writel_relaxed(0x7F7F, dev->parf + PCIE20_PARF_PCS_SWING);
+ writel_relaxed((4<<24), dev->parf + PCIE20_PARF_CONFIG_BITS);
+ /* ensure that hardware registers the PARF configuration */
+ wmb();
+
+ /* enable reference clock */
+ msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16));
+
+ /* enable access to PCIe slave port on system fabric */
+ writel_relaxed(BIT(4), PCIE_SFAB_AXI_S5_FCLK_CTL);
+ /* ensure that access is enabled before proceeding */
+ wmb();
+
+ /* de-assert PICe PHY, Core, POR and AXI clk domain resets */
+ msm_pcie_write_mask(PCIE_RESET, BIT(5), 0);
+ msm_pcie_write_mask(PCIE_RESET, BIT(4), 0);
+ msm_pcie_write_mask(PCIE_RESET, BIT(3), 0);
+ msm_pcie_write_mask(PCIE_RESET, BIT(0), 0);
+
+ /* wait 150ms for clock acquisition */
+ udelay(150);
+
+ /* de-assert PCIe reset link to bring EP out of reset */
+ gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
+ !dev->gpio[MSM_PCIE_GPIO_RST_N].on);
+
+ /* enable link training */
+ msm_pcie_write_mask(dev->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0));
+
+ /* poll for link to come up for upto 100ms */
+ rc = readl_poll_timeout(
+ (msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS),
+ val, (val & BIT(29)), 10000, 100000);
+ if (rc) {
+ pr_err("link initialization failed\n");
+ goto link_fail;
+ } else
+ pr_info("link initialized\n");
+
+ msm_pcie_config_controller();
+ rc = msm_pcie_irq_init(dev);
+ if (!rc)
+ goto out;
+
+link_fail:
+ msm_pcie_clk_deinit();
+clk_fail:
+ msm_pcie_vreg_deinit();
+out:
+ return (rc) ? 0 : 1;
+}
+
+static struct pci_bus __devinit *msm_pcie_scan_bus(int nr,
+ struct pci_sys_data *sys)
+{
+ struct pci_bus *bus = NULL;
+
+ PCIE_DBG("bus %d\n", nr);
+ if (nr == 0)
+ bus = pci_scan_bus(sys->busnr, &msm_pcie_ops, sys);
+
+ return bus;
+}
+
+static int __devinit msm_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ PCIE_DBG("slot %d pin %d\n", slot, pin);
+ return (pin <= 4) ? (PCIE20_INTA + pin - 1) : 0;
+}
+
+static struct hw_pci msm_pci __devinitdata = {
+ .nr_controllers = 1,
+ .swizzle = pci_std_swizzle,
+ .setup = msm_pcie_setup,
+ .scan = msm_pcie_scan_bus,
+ .map_irq = msm_pcie_map_irq,
+};
+
+static int __devinit msm_pcie_probe(struct platform_device *pdev)
+{
+ const struct msm_pcie_platform *pdata;
+ int rc;
+
+ PCIE_DBG("\n");
+
+ msm_pcie_dev.pdev = pdev;
+ pdata = pdev->dev.platform_data;
+ msm_pcie_dev.gpio = pdata->gpio;
+ msm_pcie_dev.vreg = msm_pcie_vreg_info;
+ msm_pcie_dev.clk = msm_pcie_clk_info;
+ msm_pcie_dev.res = msm_pcie_res_info;
+
+ rc = msm_pcie_get_resources(msm_pcie_dev.pdev);
+ if (rc)
+ return rc;
+
+ rc = msm_pcie_gpio_init();
+ if (rc) {
+ msm_pcie_release_resources();
+ return rc;
+ }
+
+ /* kick start ARM PCI configuration framework */
+ pci_common_init(&msm_pci);
+ return 0;
+}
+
+static int __devexit msm_pcie_remove(struct platform_device *pdev)
+{
+ PCIE_DBG("\n");
+
+ msm_pcie_irq_deinit(&msm_pcie_dev);
+ msm_pcie_vreg_deinit();
+ msm_pcie_clk_deinit();
+ msm_pcie_gpio_deinit();
+ msm_pcie_release_resources();
+
+ msm_pcie_dev.pdev = NULL;
+ msm_pcie_dev.vreg = NULL;
+ msm_pcie_dev.clk = NULL;
+ msm_pcie_dev.gpio = NULL;
+ return 0;
+}
+
+static struct platform_driver msm_pcie_driver = {
+ .probe = msm_pcie_probe,
+ .remove = __devexit_p(msm_pcie_remove),
+ .driver = {
+ .name = "msm_pcie",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_pcie_init(void)
+{
+ PCIE_DBG("\n");
+ return platform_driver_register(&msm_pcie_driver);
+}
+subsys_initcall(msm_pcie_init);
+
+/* RC do not represent the right class; set it to PCI_CLASS_BRIDGE_PCI */
+static void __devinit msm_pcie_fixup_header(struct pci_dev *dev)
+{
+ PCIE_DBG("hdr_type %d\n", dev->hdr_type);
+ if (dev->hdr_type == 1)
+ dev->class = (dev->class & 0xff) | (PCI_CLASS_BRIDGE_PCI << 8);
+}
+DECLARE_PCI_FIXUP_HEADER(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+ msm_pcie_fixup_header);
+
+/*
+ * actual physical (BAR) address of the device resources starts from 0x10xxxxxx;
+ * the system axi address for the device resources starts from 0x08xxxxxx;
+ * correct the device resource structure here; address translation unit handles
+ * the required translations
+ */
+static void __devinit msm_pcie_fixup_final(struct pci_dev *dev)
+{
+ int i;
+
+ PCIE_DBG("vendor 0x%x 0x%x\n", dev->vendor, dev->device);
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (dev->resource[i].start & 0xFF000000) {
+ dev->resource[i].start &= 0x00FFFFFF;
+ dev->resource[i].start |= 0x08000000;
+ dev->resource[i].end &= 0x00FFFFFF;
+ dev->resource[i].end |= 0x08000000;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, msm_pcie_fixup_final);
diff --git a/arch/arm/mach-msm/pcie.h b/arch/arm/mach-msm/pcie.h
new file mode 100644
index 0000000..4866ec5
--- /dev/null
+++ b/arch/arm/mach-msm/pcie.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_PCIE_H
+#define __ARCH_ARM_MACH_MSM_PCIE_H
+
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <mach/msm_pcie.h>
+
+#define MSM_PCIE_MAX_VREG 4
+#define MSM_PCIE_MAX_CLK 3
+
+#define PCIE_DBG(x...) do { \
+ if (msm_pcie_get_debug_mask()) \
+ pr_info(x); \
+ } while (0)
+
+/* voltage regulator info structrue */
+struct msm_pcie_vreg_info_t {
+ struct regulator *hdl;
+ char *name;
+ uint32_t max_v;
+ uint32_t min_v;
+ uint32_t opt_mode;
+};
+
+/* clock info structure */
+struct msm_pcie_clk_info_t {
+ struct clk *hdl;
+ char *name;
+};
+
+/* resource info structure */
+struct msm_pcie_res_info_t {
+ char *name;
+ uint32_t start;
+ uint32_t end;
+ void __iomem *base;
+};
+
+/* msm pcie device structure */
+struct msm_pcie_dev_t {
+ struct platform_device *pdev;
+
+ struct msm_pcie_vreg_info_t *vreg;
+ struct msm_pcie_gpio_info_t *gpio;
+ struct msm_pcie_clk_info_t *clk;
+ struct msm_pcie_res_info_t *res;
+
+ void __iomem *parf;
+ void __iomem *elbi;
+ void __iomem *pcie20;
+ void __iomem *axi_conf;
+};
+
+extern uint32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev);
+extern void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev);
+extern int msm_pcie_get_debug_mask(void);
+
+#endif
diff --git a/arch/arm/mach-msm/pcie_irq.c b/arch/arm/mach-msm/pcie_irq.c
new file mode 100644
index 0000000..df100db
--- /dev/null
+++ b/arch/arm/mach-msm/pcie_irq.c
@@ -0,0 +1,170 @@
+/* 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.
+ */
+
+/*
+ * MSM PCIe controller IRQ driver.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+#include <mach/irqs.h>
+
+#include "pcie.h"
+
+/* Any address will do here, as it won't be dereferenced */
+#define MSM_PCIE_MSI_PHY 0xa0000000
+
+#define PCIE20_MSI_CTRL_ADDR (0x820)
+#define PCIE20_MSI_CTRL_UPPER_ADDR (0x824)
+#define PCIE20_MSI_CTRL_INTR_EN (0x828)
+#define PCIE20_MSI_CTRL_INTR_MASK (0x82C)
+#define PCIE20_MSI_CTRL_INTR_STATUS (0x830)
+
+#define PCIE20_MSI_CTRL_MAX 8
+
+static DECLARE_BITMAP(msi_irq_in_use, NR_PCIE_MSI_IRQS);
+
+irqreturn_t handle_msi_irq(int irq, void *data)
+{
+ int i, j;
+ unsigned long val;
+ struct msm_pcie_dev_t *dev = data;
+ void __iomem *ctrl_status;
+
+ /* check for set bits, clear it by setting that bit
+ and trigger corresponding irq */
+ for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++) {
+ ctrl_status = dev->pcie20 +
+ PCIE20_MSI_CTRL_INTR_STATUS + (i * 12);
+
+ val = readl_relaxed(ctrl_status);
+ while (val) {
+ j = find_first_bit(&val, 32);
+ writel_relaxed(BIT(j), ctrl_status);
+ /* ensure that interrupt is cleared (acked) */
+ wmb();
+
+ generic_handle_irq(MSM_PCIE_MSI_INT(j + (32 * i)));
+ val = readl_relaxed(ctrl_status);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+uint32_t __devinit msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
+{
+ int i, rc;
+
+ PCIE_DBG("\n");
+
+ /* program MSI controller and enable all interrupts */
+ writel_relaxed(MSM_PCIE_MSI_PHY, dev->pcie20 + PCIE20_MSI_CTRL_ADDR);
+ writel_relaxed(0, dev->pcie20 + PCIE20_MSI_CTRL_UPPER_ADDR);
+
+ for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++)
+ writel_relaxed(~0, dev->pcie20 +
+ PCIE20_MSI_CTRL_INTR_EN + (i * 12));
+
+ /* ensure that hardware is configured before proceeding */
+ wmb();
+
+ /* register handler for physical MSI interrupt line */
+ rc = request_irq(PCIE20_INT_MSI, handle_msi_irq, IRQF_TRIGGER_RISING,
+ "msm_pcie_msi", dev);
+ if (rc)
+ pr_err("Unable to allocate msi interrupt\n");
+
+ return rc;
+}
+
+void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
+{
+ free_irq(PCIE20_INT_MSI, dev);
+}
+
+void msm_pcie_destroy_irq(unsigned int irq)
+{
+ int pos = irq - MSM_PCIE_MSI_INT(0);
+
+ dynamic_irq_cleanup(irq);
+ clear_bit(pos, msi_irq_in_use);
+}
+
+/* hookup to linux pci msi framework */
+void arch_teardown_msi_irq(unsigned int irq)
+{
+ PCIE_DBG("irq %d deallocated\n", irq);
+ msm_pcie_destroy_irq(irq);
+}
+
+static void msm_pcie_msi_nop(struct irq_data *d)
+{
+ return;
+}
+
+static struct irq_chip pcie_msi_chip = {
+ .name = "msm-pcie-msi",
+ .irq_ack = msm_pcie_msi_nop,
+ .irq_enable = unmask_msi_irq,
+ .irq_disable = mask_msi_irq,
+ .irq_mask = mask_msi_irq,
+ .irq_unmask = unmask_msi_irq,
+};
+
+static int msm_pcie_create_irq(void)
+{
+ int irq, pos;
+
+again:
+ pos = find_first_zero_bit(msi_irq_in_use, NR_PCIE_MSI_IRQS);
+ irq = MSM_PCIE_MSI_INT(pos);
+ if (irq >= (MSM_PCIE_MSI_INT(0) + NR_PCIE_MSI_IRQS))
+ return -ENOSPC;
+
+ if (test_and_set_bit(pos, msi_irq_in_use))
+ goto again;
+
+ dynamic_irq_init(irq);
+ return irq;
+}
+
+/* hookup to linux pci msi framework */
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+{
+ int irq;
+ struct msi_msg msg;
+
+ irq = msm_pcie_create_irq();
+ if (irq < 0)
+ return irq;
+
+ PCIE_DBG("irq %d allocated\n", irq);
+
+ irq_set_msi_desc(irq, desc);
+
+ /* write msi vector and data */
+ msg.address_hi = 0;
+ msg.address_lo = MSM_PCIE_MSI_PHY;
+ msg.data = irq - MSM_PCIE_MSI_INT(0);
+ write_msi_msg(irq, &msg);
+
+ irq_set_chip_and_handler(irq, &pcie_msi_chip, handle_simple_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ return 0;
+}
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index fa9159e..0ecea85 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -350,13 +350,14 @@
}
mutex_lock(&pil->lock);
- if (!pil->count++) {
+ if (!pil->count) {
ret = load_image(pil);
if (ret) {
retval = ERR_PTR(ret);
goto err_load;
}
}
+ pil->count++;
pil_set_state(pil, PIL_ONLINE);
mutex_unlock(&pil->lock);
out:
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index c888815..0eabd1b 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -214,9 +214,9 @@
global*global_timer_offset;
if (!(clock->flags & MSM_CLOCK_FLAGS_UNSTABLE_COUNT))
- return __raw_readl(addr);
+ return __raw_readl_no_log(addr);
- t1 = __raw_readl(addr);
+ t1 = __raw_readl_no_log(addr);
t2 = __raw_readl_no_log(addr);
if ((t2-t1) <= 1)
return t2;
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index d889c4d..7f57fe6 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -620,7 +620,7 @@
}
static int iommu_map_all(unsigned long domain_num, struct ion_cp_heap *cp_heap,
- int partition, unsigned long prot, unsigned long align)
+ int partition, unsigned long prot)
{
unsigned long left_to_map = cp_heap->total_size;
unsigned long order = get_order(SZ_64K);
@@ -718,8 +718,7 @@
data->iova_addr = cp_heap->iommu_iova[domain_num] + offset;
return 0;
} else if (cp_heap->iommu_map_all) {
- ret = iommu_map_all(domain_num, cp_heap, partition_num,
- align, prot);
+ ret = iommu_map_all(domain_num, cp_heap, partition_num, prot);
if (!ret) {
unsigned long offset =
buffer->priv_phys - cp_heap->base;
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 9f80a73..da3e4b2 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -44,7 +44,7 @@
#define KGSL_PAGETABLE_ENTRY_SIZE 4
/* Pagetable Virtual Address base */
-#define KGSL_PAGETABLE_BASE 0x66000000
+#define KGSL_PAGETABLE_BASE 0x10000000
/* Extra accounting entries needed in the pagetable */
#define KGSL_PT_EXTRA_ENTRIES 16
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index b4dcf7c..880fde1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -518,14 +518,6 @@
"for GPUMMU: %x\n", CONFIG_MSM_KGSL_PAGE_TABLE_SIZE);
return -EINVAL;
}
-
- /* allocate memory used for completing r/w operations that
- * cannot be mapped by the MMU
- */
- status = kgsl_allocate_contiguous(&mmu->setstate_memory, 64);
- if (!status)
- kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
- mmu->setstate_memory.size);
}
dev_info(mmu->device->dev, "|%s| MMU type set for device is GPUMMU\n",
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 99acccb..4f27e6c 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -297,6 +297,61 @@
return ret;
}
+/*
+ * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
+ * of the respective iommu units
+ * @mmu - Pointer to mmu structure
+ *
+ * Return - 0 on success else error code
+ */
+static int kgsl_set_register_map(struct kgsl_mmu *mmu)
+{
+ struct platform_device *pdev =
+ container_of(mmu->device->parentdev, struct platform_device,
+ dev);
+ struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
+ struct kgsl_iommu *iommu = mmu->device->mmu.priv;
+ struct kgsl_iommu_unit *iommu_unit;
+ int i = 0, ret = 0;
+
+ for (; i < pdata_dev->iommu_count; i++) {
+ struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
+ iommu_unit = &iommu->iommu_units[i];
+ /* set up the IOMMU register map for the given IOMMU unit */
+ if (!data.physstart || !data.physend) {
+ KGSL_CORE_ERR("The register range for IOMMU unit not"
+ " specified\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ iommu_unit->reg_map.hostptr = ioremap(data.physstart,
+ data.physend - data.physstart + 1);
+ if (!iommu_unit->reg_map.hostptr) {
+ KGSL_CORE_ERR("Failed to map SMMU register address "
+ "space from %x to %x\n", data.physstart,
+ data.physend - data.physstart + 1);
+ ret = -ENOMEM;
+ i--;
+ goto err;
+ }
+ iommu_unit->reg_map.size = data.physend - data.physstart + 1;
+ iommu_unit->reg_map.physaddr = data.physstart;
+ memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
+ iommu_unit->reg_map.size);
+ }
+ iommu->unit_count = pdata_dev->iommu_count;
+ return ret;
+err:
+ /* Unmap any mapped IOMMU regions */
+ for (; i >= 0; i--) {
+ iommu_unit = &iommu->iommu_units[i];
+ iounmap(iommu_unit->reg_map.hostptr);
+ iommu_unit->reg_map.size = 0;
+ iommu_unit->reg_map.physaddr = 0;
+ }
+ return ret;
+}
+
static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pagetable)
{
@@ -335,6 +390,9 @@
status = kgsl_get_iommu_ctxt(mmu);
if (status)
goto done;
+ status = kgsl_set_register_map(mmu);
+ if (status)
+ goto done;
dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
__func__);
@@ -346,6 +404,53 @@
return status;
}
+/*
+ * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
+ * for iommu. This function is only called once during first start, successive
+ * start do not call this funciton.
+ * @mmu - Pointer to mmu structure
+ *
+ * Create the initial defaultpagetable and setup the iommu mappings to it
+ * Return - 0 on success else error code
+ */
+static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
+{
+ int status = 0;
+ int i = 0;
+ struct kgsl_iommu *iommu = mmu->priv;
+
+ mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+ /* Return error if the default pagetable doesn't exist */
+ if (mmu->defaultpagetable == NULL) {
+ status = -ENOMEM;
+ goto err;
+ }
+ /* Map the IOMMU regsiters to only defaultpagetable */
+ for (i = 0; i < iommu->unit_count; i++) {
+ iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
+ status = kgsl_mmu_map(mmu->defaultpagetable,
+ &(iommu->iommu_units[i].reg_map),
+ GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ if (status) {
+ iommu->iommu_units[i].reg_map.priv &=
+ ~KGSL_MEMFLAGS_GLOBAL;
+ goto err;
+ }
+ }
+ return status;
+err:
+ for (i--; i >= 0; i--) {
+ kgsl_mmu_unmap(mmu->defaultpagetable,
+ &(iommu->iommu_units[i].reg_map));
+ iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
+ }
+ if (mmu->defaultpagetable) {
+ kgsl_mmu_putpagetable(mmu->defaultpagetable);
+ mmu->defaultpagetable = NULL;
+ }
+ return status;
+}
+
static int kgsl_iommu_start(struct kgsl_mmu *mmu)
{
int status;
@@ -353,13 +458,13 @@
if (mmu->flags & KGSL_FLAGS_STARTED)
return 0;
+ if (mmu->defaultpagetable == NULL) {
+ status = kgsl_iommu_setup_defaultpagetable(mmu);
+ if (status)
+ return -ENOMEM;
+ }
kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
- if (mmu->defaultpagetable == NULL)
- mmu->defaultpagetable =
- kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
- /* Return error if the default pagetable doesn't exist */
- if (mmu->defaultpagetable == NULL)
- return -ENOMEM;
+
mmu->hwpagetable = mmu->defaultpagetable;
status = kgsl_attach_pagetable_iommu_domain(mmu);
@@ -455,6 +560,17 @@
static int kgsl_iommu_close(struct kgsl_mmu *mmu)
{
+ struct kgsl_iommu *iommu = mmu->priv;
+ int i;
+ for (i = 0; i < iommu->unit_count; i++) {
+ if (iommu->iommu_units[i].reg_map.gpuaddr)
+ kgsl_mmu_unmap(mmu->defaultpagetable,
+ &(iommu->iommu_units[i].reg_map));
+ if (iommu->iommu_units[i].reg_map.hostptr)
+ iounmap(iommu->iommu_units[i].reg_map.hostptr);
+ kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
+ iommu->iommu_units[i].reg_map.sglen);
+ }
if (mmu->defaultpagetable)
kgsl_mmu_putpagetable(mmu->defaultpagetable);
@@ -464,11 +580,16 @@
static unsigned int
kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
{
- /* Current base is always the hwpagetables domain as we
- * do not use per process pagetables right not for iommu.
- * This will change when we switch to per process pagetables.
- */
- return (unsigned int)mmu->hwpagetable->priv;
+ unsigned int pt_base;
+ struct kgsl_iommu *iommu = mmu->priv;
+ /* Return the current pt base by reading IOMMU pt_base register */
+ kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
+ pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
+ (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
+ KGSL_IOMMU_TTBR0);
+ kgsl_iommu_disable_clk(mmu);
+ return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
+ KGSL_IOMMU_TTBR0_PA_SHIFT);
}
struct kgsl_mmu_ops iommu_ops = {
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index e2033c5..5a92f513 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -15,6 +15,17 @@
#include <mach/iommu.h>
+/* IOMMU registers and masks */
+#define KGSL_IOMMU_TTBR0 0x10
+#define KGSL_IOMMU_TTBR1 0x14
+#define KGSL_IOMMU_TTBR0_PA_MASK 0x0003FFFF
+#define KGSL_IOMMU_TTBR0_PA_SHIFT 14
+#define KGSL_IOMMU_CTX_TLBIALL 0x800
+#define KGSL_IOMMU_CONTEXTIDR 0x8
+#define KGSL_IOMMU_CONTEXTIDR_ASID_MASK 0xFF
+#define KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT 0
+#define KGSL_IOMMU_CTX_TLBIASID 0x804
+#define KGSL_IOMMU_CTX_SHIFT 12
/*
* Max number of iommu units that the gpu core can have
* On APQ8064, KGSL can control a maximum of 2 IOMMU units.
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 4ba9e7f..5fdc182 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -343,26 +343,30 @@
int kgsl_mmu_init(struct kgsl_device *device)
{
+ int status = 0;
struct kgsl_mmu *mmu = &device->mmu;
mmu->device = device;
+ status = kgsl_allocate_contiguous(&mmu->setstate_memory, PAGE_SIZE);
+ if (status)
+ return status;
+ kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
+ mmu->setstate_memory.size);
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) {
- int status = 0;
- status = kgsl_allocate_contiguous(&mmu->setstate_memory, 64);
- if (!status) {
- kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
- mmu->setstate_memory.size);
- dev_info(device->dev, "|%s| MMU type set for device is "
+ dev_info(device->dev, "|%s| MMU type set for device is "
"NOMMU\n", __func__);
- }
- return status;
+ goto done;
} else if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
mmu->mmu_ops = &gpummu_ops;
else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
mmu->mmu_ops = &iommu_ops;
- return mmu->mmu_ops->mmu_init(mmu);
+ status = mmu->mmu_ops->mmu_init(mmu);
+done:
+ if (status)
+ kgsl_sharedmem_free(&mmu->setstate_memory);
+ return status;
}
EXPORT_SYMBOL(kgsl_mmu_init);
@@ -734,12 +738,11 @@
{
struct kgsl_mmu *mmu = &device->mmu;
- if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
- kgsl_sharedmem_free(&mmu->setstate_memory);
+ kgsl_sharedmem_free(&mmu->setstate_memory);
+ if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE)
return 0;
- } else {
+ else
return mmu->mmu_ops->mmu_close(mmu);
- }
}
EXPORT_SYMBOL(kgsl_mmu_close);
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index e643def..c04ece2 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -211,10 +211,11 @@
init_completion(&csid_dev->reset_complete);
- enable_irq(csid_dev->irq->start);
+ rc = request_irq(csid_dev->irq->start, msm_csid_irq,
+ IRQF_TRIGGER_RISING, "csid", csid_dev);
msm_csid_reset(csid_dev);
- return 0;
+ return rc;
clk_enable_failed:
msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
@@ -230,10 +231,15 @@
static int msm_csid_release(struct v4l2_subdev *sd)
{
+ uint32_t irq;
struct csid_device *csid_dev;
csid_dev = v4l2_get_subdevdata(sd);
- disable_irq(csid_dev->irq->start);
+ irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
+ msm_camera_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
+ msm_camera_io_w(0, csid_dev->base + CSID_IRQ_MASK_ADDR);
+
+ free_irq(csid_dev->irq->start, csid_dev);
msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0);
@@ -328,17 +334,6 @@
goto csid_no_resource;
}
- rc = request_irq(new_csid_dev->irq->start, msm_csid_irq,
- IRQF_TRIGGER_RISING, "csid", new_csid_dev);
- if (rc < 0) {
- release_mem_region(new_csid_dev->mem->start,
- resource_size(new_csid_dev->mem));
- pr_err("%s: irq request fail\n", __func__);
- rc = -EBUSY;
- goto csid_no_resource;
- }
- disable_irq(new_csid_dev->irq->start);
-
new_csid_dev->pdev = pdev;
msm_cam_register_subdev_node(&new_csid_dev->subdev, CSID_DEV, pdev->id);
return 0;
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 254cf3a..8720d70 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1568,6 +1568,7 @@
struct msm_cam_v4l2_device *pcam = video_drvdata(f);
struct msm_cam_v4l2_dev_inst *pcam_inst;
struct msm_cam_media_controller *pmctl = NULL;
+ struct msm_cam_server_queue *queue = NULL;
D("%s\n", __func__);
@@ -1609,12 +1610,11 @@
pcam->vnode_id, pcam->use_count);
pcam->use_count++;
if (pcam->use_count == 1) {
- struct msm_cam_server_queue *queue;
pcam->server_queue_idx = server_q_idx;
queue = &g_server_dev.server_queue[server_q_idx];
queue->ctrl = NULL;
queue->ctrl_data = kzalloc(sizeof(uint8_t) *
- max_control_command_size, GFP_KERNEL);
+ max_control_command_size, GFP_KERNEL);
msm_queue_init(&queue->ctrl_q, "control");
msm_queue_init(&queue->eventData_q, "eventdata");
queue->queue_active = 1;
@@ -1623,7 +1623,7 @@
if (rc < 0) {
pr_err("%s: cam_server_open_session failed %d\n",
__func__, rc);
- goto err;
+ goto msm_cam_server_open_session_failed;
}
pmctl = msm_camera_get_mctl(pcam->mctl_handle);
@@ -1636,26 +1636,26 @@
/* Should be set to sensor ops if any but right now its OK!! */
if (!pmctl->mctl_open) {
- D("%s: media contoller is not inited\n",
- __func__);
+ D("%s: media contoller is not inited\n", __func__);
rc = -ENODEV;
- goto err;
+ goto mctl_open_failed;
}
/* Now we really have to activate the camera */
D("%s: call mctl_open\n", __func__);
rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);
-
if (rc < 0) {
pr_err("%s: HW open failed rc = 0x%x\n", __func__, rc);
- goto err;
+ goto mctl_open_failed;
}
pmctl->pcam_ptr = pcam;
rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
- pcam->pvdev);
+ pcam->pvdev);
if (rc < 0) {
- goto err;
+ pr_err("%s: msm_setup_v4l2_event_queue failed %d",
+ __func__, rc);
+ goto mctl_event_q_setup_failed;
}
}
pcam_inst->vbqueue_initialized = 0;
@@ -1666,21 +1666,26 @@
D("f->private_data = 0x%x, pcam = 0x%x\n",
(u32)f->private_data, (u32)pcam_inst);
-
if (pcam->use_count == 1) {
rc = msm_send_open_server(pcam);
if (rc < 0) {
- mutex_unlock(&pcam->vid_lock);
- pr_err("%s failed\n", __func__);
- return rc;
+ pr_err("%s: msm_send_open_server failed %d\n",
+ __func__, rc);
+ goto msm_send_open_server_failed;
}
}
mutex_unlock(&pcam->vid_lock);
D("%s: end", __func__);
- /* rc = msm_cam_server_open_session(g_server_dev, pcam);*/
return rc;
-err:
+msm_send_open_server_failed:
+ v4l2_fh_del(&pcam_inst->eventHandle);
+ v4l2_fh_exit(&pcam_inst->eventHandle);
+mctl_event_q_setup_failed:
+ if (pmctl->mctl_release)
+ if (pmctl->mctl_release(pmctl) < 0)
+ pr_err("%s: mctl_release failed\n", __func__);
+mctl_open_failed:
if (pcam->use_count == 1) {
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
if (ion_client_created) {
@@ -1688,6 +1693,20 @@
kref_put(&pmctl->refcount, msm_release_ion_client);
}
#endif
+ if (msm_cam_server_close_session(&g_server_dev, pcam) < 0)
+ pr_err("%s: msm_cam_server_close_session failed\n",
+ __func__);
+ }
+msm_cam_server_open_session_failed:
+ if (pcam->use_count == 1) {
+ queue->queue_active = 0;
+ msm_drain_eventq(&queue->eventData_q);
+ kfree(queue->ctrl_data);
+ queue->ctrl_data = NULL;
+ msm_queue_drain(&queue->ctrl_q, list_control);
+ msm_drain_eventq(&queue->eventData_q);
+ queue = NULL;
+
pcam->dev_inst[i] = NULL;
pcam->use_count = 0;
}
@@ -1909,16 +1928,18 @@
switch (cmd) {
case MSM_CAM_V4L2_IOCTL_GET_CAMERA_INFO:
if (copy_from_user(&temp_cam_info,
- (void __user *)ioctl_ptr->ioctl_ptr,
- sizeof(struct msm_camera_info))) {
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_camera_info))) {
rc = -EINVAL;
return rc;
}
for (i = 0; i < g_server_dev.camera_info.num_cameras; i++) {
if (copy_to_user((void __user *)
- temp_cam_info.video_dev_name[i],
- g_server_dev.camera_info.video_dev_name[i],
- strlen(g_server_dev.camera_info.video_dev_name[i]))) {
+ temp_cam_info.video_dev_name[i],
+ g_server_dev.camera_info.video_dev_name[i],
+ strnlen(
+ g_server_dev.camera_info.video_dev_name[i],
+ MAX_DEV_NAME_LEN))) {
rc = -EINVAL;
return rc;
}
@@ -2059,6 +2080,7 @@
break;
}
default:
+ pr_err("%s: Invalid IOCTL = %d", __func__, cmd);
break;
}
return rc;
@@ -2152,7 +2174,7 @@
D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
switch (cmd) {
- /* memory management shall be handeld here*/
+ /* memory management shall be handeld here*/
case MSM_CAM_IOCTL_REGISTER_PMEM:
return msm_register_pmem(
&config_cam->p_mctl->stats_info.pmem_stats_list,
@@ -2164,31 +2186,38 @@
&config_cam->p_mctl->stats_info.pmem_stats_list,
(void __user *)arg, config_cam->p_mctl->client);
break;
+
case VIDIOC_SUBSCRIBE_EVENT:
if (copy_from_user(&temp_sub,
(void __user *)arg,
sizeof(struct v4l2_event_subscription))) {
- rc = -EINVAL;
- return rc;
+ rc = -EINVAL;
+ return rc;
}
rc = msm_server_v4l2_subscribe_event
(&config_cam->config_stat_event_queue.eventHandle,
- &temp_sub);
- if (rc < 0)
+ &temp_sub);
+ if (rc < 0) {
+ pr_err("%s: cam_v4l2_subscribe_event failed rc=%d\n",
+ __func__, rc);
return rc;
+ }
break;
case VIDIOC_UNSUBSCRIBE_EVENT:
if (copy_from_user(&temp_sub, (void __user *)arg,
- sizeof(struct v4l2_event_subscription))) {
+ sizeof(struct v4l2_event_subscription))) {
rc = -EINVAL;
return rc;
}
rc = msm_server_v4l2_unsubscribe_event
(&config_cam->config_stat_event_queue.eventHandle,
- &temp_sub);
- if (rc < 0)
+ &temp_sub);
+ if (rc < 0) {
+ pr_err("%s: server_unsubscribe_event failed rc=%d\n",
+ __func__, rc);
return rc;
+ }
break;
case VIDIOC_DQEVENT: {
@@ -2334,8 +2363,8 @@
static int msm_open_config(struct inode *inode, struct file *fp)
{
int rc;
- struct msm_cam_config_dev *config_cam =
- container_of(inode->i_cdev, struct msm_cam_config_dev, config_cdev);
+ struct msm_cam_config_dev *config_cam = container_of(inode->i_cdev,
+ struct msm_cam_config_dev, config_cdev);
D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
@@ -2404,7 +2433,7 @@
};
int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
- struct video_device *pvdev)
+ struct video_device *pvdev)
{
int rc = 0;
/* v4l2_fh support */
@@ -2414,6 +2443,7 @@
rc = v4l2_fh_init(eventHandle, pvdev);
if (rc < 0)
return rc;
+
if (eventHandle->events == NULL) {
rc = v4l2_event_init(eventHandle);
if (rc < 0)
@@ -2427,7 +2457,6 @@
v4l2_fh_add(eventHandle);
return rc;
-
}
static int msm_setup_config_dev(int node, char *device_name)
@@ -2448,8 +2477,8 @@
D("%s\n", __func__);
devno = MKDEV(MAJOR(msm_devno), dev_num+1);
- device_config = device_create(msm_class, NULL, devno, NULL,
- "%s%d", device_name, dev_num);
+ device_config = device_create(msm_class, NULL, devno, NULL, "%s%d",
+ device_name, dev_num);
if (IS_ERR(device_config)) {
rc = PTR_ERR(device_config);
@@ -2457,8 +2486,7 @@
goto config_setup_fail;
}
- cdev_init(&config_cam->config_cdev,
- &msm_fops_config);
+ cdev_init(&config_cam->config_cdev, &msm_fops_config);
config_cam->config_cdev.owner = THIS_MODULE;
rc = cdev_add(&config_cam->config_cdev, devno, 1);
@@ -2467,12 +2495,12 @@
device_destroy(msm_class, devno);
goto config_setup_fail;
}
- g_server_dev.config_info.config_dev_name[dev_num]
- = dev_name(device_config);
+
+ g_server_dev.config_info.config_dev_name[dev_num] =
+ dev_name(device_config);
D("%s Connected config device %s\n", __func__,
g_server_dev.config_info.config_dev_name[dev_num]);
- g_server_dev.config_info.config_dev_id[dev_num]
- = dev_num;
+ g_server_dev.config_info.config_dev_id[dev_num] = dev_num;
config_cam->config_stat_event_queue.pvdev = video_device_alloc();
if (config_cam->config_stat_event_queue.pvdev == NULL) {
@@ -2485,6 +2513,7 @@
config_cam->config_stat_event_queue.pvdev);
if (rc < 0) {
pr_err("%s failed to initialize event queue\n", __func__);
+ video_device_release(config_cam->config_stat_event_queue.pvdev);
goto config_setup_fail;
}
@@ -2493,7 +2522,6 @@
config_setup_fail:
kfree(config_cam);
return rc;
-
}
static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
@@ -2697,13 +2725,13 @@
video_set_drvdata(g_server_dev.video_dev, &g_server_dev);
strlcpy(g_server_dev.media_dev.model, "qcamera",
- sizeof(g_server_dev.media_dev.model));
+ sizeof(g_server_dev.media_dev.model));
g_server_dev.media_dev.dev = &pdev->dev;
rc = media_device_register(&g_server_dev.media_dev);
g_server_dev.v4l2_dev.mdev = &g_server_dev.media_dev;
rc = video_register_device(g_server_dev.video_dev,
- VFL_TYPE_GRABBER, 100);
+ VFL_TYPE_GRABBER, 100);
mutex_init(&g_server_dev.server_lock);
mutex_init(&g_server_dev.server_queue_lock);
@@ -2719,8 +2747,11 @@
&g_server_dev.server_command_queue.eventHandle,
g_server_dev.server_command_queue.pvdev);
- if (rc < 0)
+ if (rc < 0) {
pr_err("%s failed to initialize event queue\n", __func__);
+ video_device_release(g_server_dev.server_command_queue.pvdev);
+ return rc;
+ }
for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
struct msm_cam_server_queue *queue;
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 671dfd7..04e224c 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -244,7 +244,7 @@
struct v4l2_subdev *ispif_sdev; /* ispif sub device */
struct v4l2_subdev *gemini_sdev; /* gemini sub device */
struct v4l2_subdev *vpe_sdev; /* vpe sub device */
- struct v4l2_subdev *axi_sdev; /* vpe sub device */
+ struct v4l2_subdev *axi_sdev; /* axi sub device */
struct v4l2_subdev *eeprom_sdev; /* eeprom sub device */
struct msm_isp_ops *isp_sdev; /* isp sub device : camif/VFE */
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index d791771..e878063 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -583,23 +583,22 @@
if (rc < 0) {
pr_err("%s: msm_mctl_register_subdevs failed:%d\n",
__func__, rc);
- goto msm_open_done;
+ goto register_sdev_failed;
}
- /* then sensor - move sub dev later*/
+ /* then sensor - move sub dev later */
rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);
-
if (rc < 0) {
- pr_err("%s: isp init failed: %d\n", __func__, rc);
- goto msm_open_done;
+ pr_err("%s: sensor powerup failed: %d\n", __func__, rc);
+ goto sensor_sdev_failed;
}
+
if (p_mctl->act_sdev)
rc = v4l2_subdev_call(p_mctl->act_sdev,
- core, s_power, 1);
-
+ core, s_power, 1);
if (rc < 0) {
pr_err("%s: act power failed:%d\n", __func__, rc);
- goto msm_open_done;
+ goto act_power_up_failed;
}
if (camdev->is_csiphy) {
@@ -607,8 +606,8 @@
VIDIOC_MSM_CSIPHY_INIT, NULL);
if (rc < 0) {
pr_err("%s: csiphy initialization failed %d\n",
- __func__, rc);
- goto msm_open_done;
+ __func__, rc);
+ goto csiphy_init_failed;
}
}
@@ -617,17 +616,18 @@
VIDIOC_MSM_CSID_INIT, &csid_version);
if (rc < 0) {
pr_err("%s: csid initialization failed %d\n",
- __func__, rc);
- goto msm_open_done;
+ __func__, rc);
+ goto csid_init_failed;
}
}
+
if (camdev->is_csic) {
rc = v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
VIDIOC_MSM_CSIC_INIT, &csid_version);
if (rc < 0) {
pr_err("%s: csic initialization failed %d\n",
- __func__, rc);
- goto msm_open_done;
+ __func__, rc);
+ goto csic_init_failed;
}
}
@@ -638,7 +638,7 @@
if (rc < 0) {
pr_err("%s: isp init failed: %d\n",
__func__, rc);
- goto msm_open_done;
+ goto isp_open_failed;
}
}
@@ -646,9 +646,9 @@
rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
VIDIOC_MSM_AXI_INIT, p_mctl);
if (rc < 0) {
- pr_err("%s: vpe initialization failed %d\n",
- __func__, rc);
- goto msm_open_done;
+ pr_err("%s: axi initialization failed %d\n",
+ __func__, rc);
+ goto axi_init_failed;
}
}
@@ -658,7 +658,7 @@
if (rc < 0) {
pr_err("%s: vpe initialization failed %d\n",
__func__, rc);
- goto msm_open_done;
+ goto vpe_init_failed;
}
}
@@ -667,23 +667,65 @@
VIDIOC_MSM_ISPIF_INIT, &csid_version);
if (rc < 0) {
pr_err("%s: ispif initialization failed %d\n",
- __func__, rc);
- goto msm_open_done;
+ __func__, rc);
+ goto ispif_init_failed;
}
}
if (camdev->is_ispif) {
pm_qos_add_request(&p_mctl->pm_qos_req_list,
- PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
pm_qos_update_request(&p_mctl->pm_qos_req_list,
- MSM_V4L2_SWFI_LATENCY);
+ MSM_V4L2_SWFI_LATENCY);
}
p_mctl->apps_id = apps_id;
p_mctl->opencnt++;
+ } else {
+ D("%s: camera is already open", __func__);
}
+ mutex_unlock(&p_mctl->lock);
-msm_open_done:
+ return rc;
+
+ispif_init_failed:
+ if (camdev->is_vpe)
+ if (v4l2_subdev_call(p_mctl->vpe_sdev, core, ioctl,
+ VIDIOC_MSM_VPE_RELEASE, NULL) < 0)
+ pr_err("%s: vpe release failed %d\n", __func__, rc);
+vpe_init_failed:
+ if (p_mctl->axi_sdev)
+ if (v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
+ VIDIOC_MSM_AXI_RELEASE, NULL) < 0)
+ pr_err("%s: axi release failed %d\n", __func__, rc);
+axi_init_failed:
+ if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
+ p_mctl->isp_sdev->isp_release(p_mctl->isp_sdev->sd);
+isp_open_failed:
+ if (camdev->is_csic)
+ if (v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
+ VIDIOC_MSM_CSIC_RELEASE, NULL) < 0)
+ pr_err("%s: csic release failed %d\n", __func__, rc);
+csic_init_failed:
+ if (camdev->is_csid)
+ if (v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
+ VIDIOC_MSM_CSID_RELEASE, NULL) < 0)
+ pr_err("%s: csid release failed %d\n", __func__, rc);
+csid_init_failed:
+ if (camdev->is_csiphy)
+ if (v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
+ VIDIOC_MSM_CSIPHY_RELEASE, NULL) < 0)
+ pr_err("%s: csiphy release failed %d\n", __func__, rc);
+csiphy_init_failed:
+ if (p_mctl->act_sdev)
+ if (v4l2_subdev_call(p_mctl->act_sdev, core,
+ s_power, 0) < 0)
+ pr_err("%s: act power down failed:%d\n", __func__, rc);
+act_power_up_failed:
+ if (v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0) < 0)
+ pr_err("%s: sensor powerdown failed: %d\n", __func__, rc);
+sensor_sdev_failed:
+register_sdev_failed:
+ wake_unlock(&p_mctl->wake_lock);
mutex_unlock(&p_mctl->lock);
return rc;
}
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index e265b25..becdd95 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -4177,16 +4177,18 @@
switch (cmd) {
case VIDIOC_MSM_AXI_INIT:
rc = msm_axi_subdev_init(sd,
- (struct msm_cam_media_controller *)arg);
+ (struct msm_cam_media_controller *)arg);
break;
case VIDIOC_MSM_AXI_CFG:
rc = msm_axi_config(sd, arg);
break;
case VIDIOC_MSM_AXI_IRQ:
msm_axi_process_irq(sd, arg);
+ rc = 0;
break;
case VIDIOC_MSM_AXI_RELEASE:
msm_axi_subdev_release(sd);
+ rc = 0;
break;
default:
pr_err("%s: command not found\n", __func__);
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 40154ef..d9d315e 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -22,6 +22,7 @@
#include <media/v4l2-subdev.h>
#include <media/msm_isp.h>
#include <mach/msm_adsp.h>
+#include <linux/clk.h>
#include <mach/clk.h>
#include <mach/camera.h>
#include "msm_vfe7x27a_v4l2.h"
@@ -1729,12 +1730,38 @@
return;
}
+static int msm_vfe_subdev_s_crystal_freq(struct v4l2_subdev *sd,
+ u32 freq, u32 flags)
+{
+ int rc = 0;
+ int round_rate;
+
+ round_rate = clk_round_rate(vfe2x_ctrl->vfe_clk[0], freq);
+ if (rc < 0) {
+ pr_err("%s: clk_round_rate failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = clk_set_rate(vfe2x_ctrl->vfe_clk[0], round_rate);
+ if (rc < 0)
+ pr_err("%s: clk_set_rate failed %d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static const struct v4l2_subdev_video_ops msm_vfe_subdev_video_ops = {
+ .s_crystal_freq = msm_vfe_subdev_s_crystal_freq,
+};
+
static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
.ioctl = msm_vfe_subdev_ioctl,
};
static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
.core = &msm_vfe_subdev_core_ops,
+ .video = &msm_vfe_subdev_video_ops,
};
static const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index d4d07cd..ff5bb49 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -587,6 +587,7 @@
msm_sensor_enable_i2c_mux(data->sensor_platform_info->i2c_conf);
return rc;
+
enable_clk_failed:
msm_camera_config_gpio_table(data, 0);
config_gpio_failed:
@@ -643,13 +644,14 @@
s_ctrl->sensor_id_info->sensor_id_reg_addr, &chipid,
MSM_CAMERA_I2C_WORD_DATA);
if (rc < 0) {
- CDBG("%s: read id failed\n", __func__);
+ pr_err("%s: %s: read id failed\n", __func__,
+ s_ctrl->sensordata->sensor_name);
return rc;
}
CDBG("msm_sensor id: %d\n", chipid);
if (chipid != s_ctrl->sensor_id_info->sensor_id) {
- CDBG("msm_sensor_match_id chip id doesnot match\n");
+ pr_err("msm_sensor_match_id chip id doesnot match\n");
return -ENODEV;
}
return rc;
@@ -726,10 +728,30 @@
int rc = 0;
struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
mutex_lock(s_ctrl->msm_sensor_mutex);
- if (on)
+ if (on) {
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
- else
+ if (rc < 0) {
+ pr_err("%s: %s power_up failed rc = %d\n", __func__,
+ s_ctrl->sensordata->sensor_name, rc);
+ } else {
+ if (s_ctrl->func_tbl->sensor_match_id)
+ rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
+ else
+ rc = msm_sensor_match_id(s_ctrl);
+ if (rc < 0) {
+ pr_err("%s: %s match_id failed rc=%d\n",
+ __func__,
+ s_ctrl->sensordata->sensor_name, rc);
+ if (s_ctrl->func_tbl->sensor_power_down(s_ctrl)
+ < 0)
+ pr_err("%s: %s power_down failed\n",
+ __func__,
+ s_ctrl->sensordata->sensor_name);
+ }
+ }
+ } else {
rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ }
mutex_unlock(s_ctrl->msm_sensor_mutex);
return rc;
}
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index ca2bb98..83c83d1 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -100,6 +100,65 @@
{0x4004, 0x04},
};
+static struct msm_camera_i2c_reg_conf ov5647_video_60fps_settings[] = {
+ {0x3035, 0x21},
+ {0x3036, 0x38},
+ {0x3821, 0x07},
+ {0x3820, 0x41},
+ {0x3612, 0x49},
+ {0x3618, 0x00},
+ {0x380c, 0x07},
+ {0x380d, 0x30},
+ {0x380e, 0x01},
+ {0x380f, 0xf8},
+ {0x3814, 0x71},
+ {0x3815, 0x71},
+ {0x3709, 0x52},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0xe0},
+ {0x3800, 0x00},
+ {0x3801, 0x10},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x2f},
+ {0x3806, 0x07},
+ {0x3807, 0x9f},
+ {0x4004, 0x02},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_video_90fps_settings[] = {
+ {0x3035, 0x11},
+ {0x3036, 0x2a},
+ {0x3821, 0x07},
+ {0x3820, 0x41},
+ {0x3612, 0x49},
+ {0x3618, 0x00},
+ {0x380c, 0x07},
+ {0x380d, 0x30},
+ {0x380e, 0x01},
+ {0x380f, 0xf8},
+ {0x3814, 0x71},
+ {0x3815, 0x71},
+ {0x3709, 0x52},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0xe0},
+ {0x3800, 0x00},
+ {0x3801, 0x10},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x2f},
+ {0x3806, 0x07},
+ {0x3807, 0x9f},
+ {0x4004, 0x02},
+};
+
+
static struct msm_camera_i2c_reg_conf ov5647_recommend_settings[] = {
{0x3035, 0x11},
{0x303c, 0x11},
@@ -247,6 +306,10 @@
ARRAY_SIZE(ov5647_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
{&ov5647_prev_settings[0],
ARRAY_SIZE(ov5647_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov5647_video_60fps_settings[0],
+ ARRAY_SIZE(ov5647_video_60fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov5647_video_90fps_settings[0],
+ ARRAY_SIZE(ov5647_video_90fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
};
static struct msm_camera_csi_params ov5647_csi_params = {
@@ -286,6 +349,25 @@
.op_pixel_clk = 159408000,
.binning_factor = 0x0,
},
+ { /* For 60fps */
+ .x_output = 0x280, /*640*/
+ .y_output = 0x1E0, /*480*/
+ .line_length_pclk = 0x73C,
+ .frame_length_lines = 0x1F8,
+ .vt_pixel_clk = 56004480,
+ .op_pixel_clk = 159408000,
+ .binning_factor = 0x0,
+ },
+ { /* For 90fps */
+ .x_output = 0x280, /*640*/
+ .y_output = 0x1E0, /*480*/
+ .line_length_pclk = 0x73C,
+ .frame_length_lines = 0x1F8,
+ .vt_pixel_clk = 56004480,
+ .op_pixel_clk = 159408000,
+ .binning_factor = 0x0,
+ },
+
};
static struct msm_sensor_output_reg_addr_t ov5647_reg_addr = {
@@ -298,6 +380,8 @@
static struct msm_camera_csi_params *ov5647_csi_params_array[] = {
&ov5647_csi_params,
&ov5647_csi_params,
+ &ov5647_csi_params,
+ &ov5647_csi_params,
};
static struct msm_sensor_id_info_t ov5647_id_info = {
@@ -443,11 +527,12 @@
u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
uint8_t gain_lsb, gain_hsb;
- pr_info(KERN_ERR "preview exposure setting 0x%x, 0x%x, %d",
+ CDBG(KERN_ERR "preview exposure setting 0x%x, 0x%x, %d",
gain, line, line);
gain_lsb = (uint8_t) (gain);
gain_hsb = (uint8_t)((gain & 0x300)>>8);
+
/* adjust frame rate */
if (line > 980 && line <= 984) {
@@ -634,12 +719,12 @@
{
int32_t rc = 0;
static int csi_config;
-
s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
if (csi_config == 0 || res == 0)
msleep(66);
else
msleep(266);
+
msm_camera_i2c_write(
s_ctrl->sensor_i2c_client,
0x4800, 0x25,
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index a311029..080a87c 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -145,6 +145,11 @@
#define MP3_1_SHIFT 5
#define MP3_2_SHIFT 2
+#define REG_HSED_BIAS0_CNTL2 0xA1
+#define REG_HSED_BIAS1_CNTL2 0x135
+#define REG_HSED_BIAS2_CNTL2 0x138
+#define HSED_EN_MASK 0xC0
+
struct pm8xxx_misc_chip {
struct list_head link;
struct pm8xxx_misc_platform_data pdata;
@@ -1100,6 +1105,52 @@
}
EXPORT_SYMBOL_GPL(pm8xxx_aux_clk_control);
+int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias, bool enable)
+{
+ struct pm8xxx_misc_chip *chip;
+ unsigned long flags;
+ int rc = 0;
+ u16 addr;
+
+ switch (bias) {
+ case PM8XXX_HSED_BIAS0:
+ addr = REG_HSED_BIAS0_CNTL2;
+ break;
+ case PM8XXX_HSED_BIAS1:
+ addr = REG_HSED_BIAS1_CNTL2;
+ break;
+ case PM8XXX_HSED_BIAS2:
+ addr = REG_HSED_BIAS2_CNTL2;
+ break;
+ default:
+ pr_err("Invalid BIAS line\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
+
+ /* Loop over all attached PMICs and call specific functions for them. */
+ list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
+ switch (chip->version) {
+ case PM8XXX_VERSION_8058:
+ case PM8XXX_VERSION_8921:
+ rc = pm8xxx_misc_masked_write(chip, addr,
+ HSED_EN_MASK, enable ? HSED_EN_MASK : 0);
+ if (rc < 0)
+ pr_err("Enable HSED BIAS failed rc=%d\n", rc);
+ break;
+ default:
+ /* Functionality not supported */
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
+
+ return rc;
+}
+EXPORT_SYMBOL(pm8xxx_hsed_bias_control);
+
static int __devinit pm8xxx_misc_probe(struct platform_device *pdev)
{
const struct pm8xxx_misc_platform_data *pdata = pdev->dev.platform_data;
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 28505636..d489233 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -31,6 +31,17 @@
{
int i, ret, count;
unsigned char pending;
+ struct sdio_func *func;
+
+ /*
+ * Optimization, if there is only 1 function interrupt registered
+ * call irq handler directly
+ */
+ func = card->sdio_single_irq;
+ if (func) {
+ func->irq_handler(func);
+ return 1;
+ }
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
if (ret) {
@@ -42,7 +53,7 @@
count = 0;
for (i = 1; i <= 7; i++) {
if (pending & (1 << i)) {
- struct sdio_func *func = card->sdio_func[i - 1];
+ func = card->sdio_func[i - 1];
if (!func) {
printk(KERN_WARNING "%s: pending IRQ for "
"non-existent function\n",
@@ -192,6 +203,24 @@
return 0;
}
+/* If there is only 1 function registered set sdio_single_irq */
+static void sdio_single_irq_set(struct mmc_card *card)
+{
+ struct sdio_func *func;
+ int i;
+
+ card->sdio_single_irq = NULL;
+ if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
+ card->host->sdio_irqs == 1)
+ for (i = 0; i < card->sdio_funcs; i++) {
+ func = card->sdio_func[i];
+ if (func && func->irq_handler) {
+ card->sdio_single_irq = func;
+ break;
+ }
+ }
+}
+
/**
* sdio_claim_irq - claim the IRQ for a SDIO function
* @func: SDIO function
@@ -233,6 +262,7 @@
ret = sdio_card_irq_get(func->card);
if (ret)
func->irq_handler = NULL;
+ sdio_single_irq_set(func->card);
return ret;
}
@@ -257,6 +287,7 @@
if (func->irq_handler) {
func->irq_handler = NULL;
sdio_card_irq_put(func->card);
+ sdio_single_irq_set(func->card);
}
ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 0d6c5f1..73a31716 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -79,6 +79,9 @@
static int msmsdcc_dbg_init(void);
#endif
+static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
+ *data);
+
static u64 dma_mask = DMA_BIT_MASK(32);
static unsigned int msmsdcc_pwrsave = 1;
@@ -482,8 +485,9 @@
if (!mrq->data->error)
mrq->data->error = -EIO;
}
- dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
- host->dma.dir);
+ if (!mrq->data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
+ host->dma.num_ents, host->dma.dir);
if (host->curr.user_pages) {
struct scatterlist *sg = host->dma.sg;
@@ -649,9 +653,9 @@
}
/* Unmap sg buffers */
- dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
- host->sps.dir);
-
+ if (!mrq->data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
+ host->sps.num_ents, host->sps.dir);
host->sps.sg = NULL;
host->sps.busy = 0;
@@ -720,8 +724,9 @@
mrq->data->error = -EIO;
/* Unmap sg buffers */
- dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
- host->sps.dir);
+ if (!mrq->data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
+ host->sps.num_ents, host->sps.dir);
host->sps.sg = NULL;
host->sps.busy = 0;
@@ -816,15 +821,13 @@
else
host->dma.dir = DMA_TO_DEVICE;
- n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
- host->dma.num_ents, host->dma.dir);
-
- if (n != host->dma.num_ents) {
- pr_err("%s: Unable to map in all sg elements\n",
- mmc_hostname(host->mmc));
- host->dma.sg = NULL;
- host->dma.num_ents = 0;
- return -ENOMEM;
+ if (!data->host_cookie) {
+ n = msmsdcc_prep_xfer(host, data);
+ if (unlikely(n < 0)) {
+ host->dma.sg = NULL;
+ host->dma.num_ents = 0;
+ return -ENOMEM;
+ }
}
/* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
@@ -893,8 +896,9 @@
unmap:
if (err) {
- dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
- host->dma.num_ents, host->dma.dir);
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
+ host->dma.num_ents, host->dma.dir);
pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
mmc_hostname(host->mmc), err);
}
@@ -902,6 +906,44 @@
return err;
}
+static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
+ struct mmc_data *data)
+{
+ int rc = 0;
+ unsigned int dir;
+
+ /* Prevent memory corruption */
+ BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
+
+ if (data->flags & MMC_DATA_READ)
+ dir = DMA_FROM_DEVICE;
+ else
+ dir = DMA_TO_DEVICE;
+
+ /* Make sg buffers DMA ready */
+ rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ dir);
+
+ if (unlikely(rc != data->sg_len)) {
+ pr_err("%s: Unable to map in all sg elements, rc=%d\n",
+ mmc_hostname(host->mmc), rc);
+ rc = -ENOMEM;
+ goto dma_map_err;
+ }
+
+ pr_debug("%s: %s: %s: sg_len=%d\n",
+ mmc_hostname(host->mmc), __func__,
+ dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
+ data->sg_len);
+
+ goto out;
+
+dma_map_err:
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ data->flags);
+out:
+ return rc;
+}
#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
/**
* Submits data transfer request to SPS driver
@@ -916,7 +958,7 @@
* @return 0 if success else negative value
*/
static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
- struct mmc_data *data)
+ struct mmc_data *data)
{
int rc = 0;
u32 flags;
@@ -925,9 +967,6 @@
struct scatterlist *sg = data->sg;
struct sps_pipe *sps_pipe_handle;
- /* Prevent memory corruption */
- BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
-
host->sps.sg = data->sg;
host->sps.num_ents = data->sg_len;
host->sps.xfer_req_cnt = 0;
@@ -939,24 +978,15 @@
sps_pipe_handle = host->sps.cons.pipe_handle;
}
- /* Make sg buffers DMA ready */
- rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- host->sps.dir);
-
- if (rc != data->sg_len) {
- pr_err("%s: Unable to map in all sg elements, rc=%d\n",
- mmc_hostname(host->mmc), rc);
- host->sps.sg = NULL;
- host->sps.num_ents = 0;
- rc = -ENOMEM;
- goto dma_map_err;
+ if (!data->host_cookie) {
+ rc = msmsdcc_prep_xfer(host, data);
+ if (unlikely(rc < 0)) {
+ host->dma.sg = NULL;
+ host->dma.num_ents = 0;
+ goto out;
+ }
}
- pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
- mmc_hostname(host->mmc), __func__,
- host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
- (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
-
for (i = 0; i < data->sg_len; i++) {
/*
* Check if this is the last buffer to transfer?
@@ -993,8 +1023,9 @@
dma_map_err:
/* unmap sg buffers */
- dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
- host->sps.dir);
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
+ host->sps.num_ents, host->sps.dir);
out:
return rc;
}
@@ -1833,6 +1864,63 @@
}
static void
+msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+ bool is_first_request)
+{
+ struct msmsdcc_host *host = mmc_priv(mmc);
+ struct mmc_data *data = mrq->data;
+ int rc = 0;
+
+ if (unlikely(!data)) {
+ pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
+ __func__);
+ return;
+ }
+ if (unlikely(data->host_cookie)) {
+ /* Very wrong */
+ data->host_cookie = 0;
+ pr_err("%s: %s Request reposted for prepare\n",
+ mmc_hostname(mmc), __func__);
+ return;
+ }
+
+ if (!msmsdcc_is_dma_possible(host, data))
+ return;
+
+ rc = msmsdcc_prep_xfer(host, data);
+ if (unlikely(rc < 0)) {
+ data->host_cookie = 0;
+ return;
+ }
+
+ data->host_cookie = 1;
+}
+
+static void
+msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
+{
+ struct msmsdcc_host *host = mmc_priv(mmc);
+ unsigned int dir;
+ struct mmc_data *data = mrq->data;
+
+ if (unlikely(!data)) {
+ pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
+ __func__);
+ return;
+ }
+ if (data->flags & MMC_DATA_READ)
+ dir = DMA_FROM_DEVICE;
+ else
+ dir = DMA_TO_DEVICE;
+
+ if (data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, dir);
+
+ data->host_cookie = 0;
+}
+
+static void
msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
{
if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
@@ -3561,6 +3649,8 @@
static const struct mmc_host_ops msmsdcc_ops = {
.enable = msmsdcc_enable,
.disable = msmsdcc_disable,
+ .pre_req = msmsdcc_pre_req,
+ .post_req = msmsdcc_post_req,
.request = msmsdcc_request,
.set_ios = msmsdcc_set_ios,
.get_ro = msmsdcc_get_ro,
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 0921b4f..35ea497 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -1109,6 +1109,7 @@
struct msm_endpoint *ept = ui->ept + bit;
struct msm_request *req;
unsigned long flags;
+ int req_dequeue = 1;
unsigned info;
/*
@@ -1128,12 +1129,23 @@
break;
}
+dequeue:
/* clean speculative fetches on req->item->info */
dma_coherent_post_ops();
info = req->item->info;
/* if the transaction is still in-flight, stop here */
- if (info & INFO_ACTIVE)
- break;
+ if (info & INFO_ACTIVE) {
+ if (req_dequeue) {
+ req_dequeue = 0;
+ ui->dTD_update_fail_count++;
+ ept->dTD_update_fail_count++;
+ udelay(10);
+ goto dequeue;
+ } else {
+ break;
+ }
+ }
+ req_dequeue = 0;
del_timer(&ept->prime_timer);
/* advance ept queue to the next request */
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 9794918..96e5a90 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -88,7 +88,8 @@
return;
}
- cbs->read_complete_cb(cbs->ctxt,
+ if (cbs && cbs->read_complete_cb)
+ cbs->read_complete_cb(cbs->ctxt,
urb->transfer_buffer,
urb->transfer_buffer_length,
urb->status < 0 ? urb->status : urb->actual_length);
@@ -172,7 +173,8 @@
return;
}
- cbs->write_complete_cb(cbs->ctxt,
+ if (cbs && cbs->write_complete_cb)
+ cbs->write_complete_cb(cbs->ctxt,
urb->transfer_buffer,
urb->transfer_buffer_length,
urb->status < 0 ? urb->status : urb->actual_length);
diff --git a/drivers/video/msm/mipi_toshiba.h b/drivers/video/msm/mipi_toshiba.h
index 632bbd3..4107161 100644
--- a/drivers/video/msm/mipi_toshiba.h
+++ b/drivers/video/msm/mipi_toshiba.h
@@ -21,9 +21,9 @@
int mipi_toshiba_device_register(struct msm_panel_info *pinfo,
u32 channel, u32 panel);
-#define MIPI_TOSHIBA_PWM_FREQ_HZ 300
+#define MIPI_TOSHIBA_PWM_FREQ_HZ 3921
#define MIPI_TOSHIBA_PWM_PERIOD_USEC (USEC_PER_SEC / MIPI_TOSHIBA_PWM_FREQ_HZ)
-#define MIPI_TOSHIBA_PWM_LEVEL 100
+#define MIPI_TOSHIBA_PWM_LEVEL 255
#define MIPI_TOSHIBA_PWM_DUTY_LEVEL \
(MIPI_TOSHIBA_PWM_PERIOD_USEC / MIPI_TOSHIBA_PWM_LEVEL)
diff --git a/include/linux/mfd/pm8xxx/misc.h b/include/linux/mfd/pm8xxx/misc.h
index 77683ce..c4b0ea4 100644
--- a/include/linux/mfd/pm8xxx/misc.h
+++ b/include/linux/mfd/pm8xxx/misc.h
@@ -89,6 +89,12 @@
XO_DIV_64,
};
+enum pm8xxx_hsed_bias {
+ PM8XXX_HSED_BIAS0,
+ PM8XXX_HSED_BIAS1,
+ PM8XXX_HSED_BIAS2,
+};
+
#if defined(CONFIG_MFD_PM8XXX_MISC) || defined(CONFIG_MFD_PM8XXX_MISC_MODULE)
/**
@@ -210,6 +216,14 @@
enum pm8xxx_aux_clk_div divider,
bool enable);
+/**
+ * pm8xxx_hsed_bias_control - Control the HSED_BIAS signal
+ * @bias: the bias line to be controlled (of the 3)
+ * @enable: enable/disable the bias line
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias, bool enable);
#else
static inline int pm8xxx_reset_pwr_off(int reset)
@@ -259,6 +273,11 @@
{
return -ENODEV;
}
+static inline int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias,
+ bool enable)
+{
+ return -ENODEV;
+}
#endif
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 8a0c4d5..aa808dc 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -228,6 +228,7 @@
struct sdio_cccr cccr; /* common card info */
struct sdio_cis cis; /* common tuple info */
struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */
+ struct sdio_func *sdio_single_irq; /* SDIO function when only one IRQ active */
unsigned num_info; /* number of info strings */
const char **info; /* info strings */
struct sdio_func_tuple *tuples; /* unknown common tuples */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index b920a72..f13b52b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1370,6 +1370,16 @@
}
#endif /* NET_SKBUFF_DATA_USES_OFFSET */
+static inline void skb_mac_header_rebuild(struct sk_buff *skb)
+{
+ if (skb_mac_header_was_set(skb)) {
+ const unsigned char *old_mac = skb_mac_header(skb);
+
+ skb_set_mac_header(skb, -skb->mac_len);
+ memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+ }
+}
+
static inline int skb_checksum_start_offset(const struct sk_buff *skb)
{
return skb->csum_start - skb_headroom(skb);
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index b806040..134d044 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -352,8 +352,53 @@
u16 reserved;
} __attribute__ ((packed));
+/* Parameter ID used to configure and enable/disable the loopback path. The
+ * difference with respect to the existing API, AFE_PORT_CMD_LOOPBACK, is that
+ * it allows Rx port to be configured as source port in loopback path. Port-id
+ * in AFE_PORT_CMD_SET_PARAM cmd is the source port whcih can be Tx or Rx port.
+ * In addition, we can configure the type of routing mode to handle different
+ * use cases.
+*/
+enum {
+ /* Regular loopback from source to destination port */
+ LB_MODE_DEFAULT = 1,
+ /* Sidetone feed from Tx source to Rx destination port */
+ LB_MODE_SIDETONE,
+ /* Echo canceller reference, voice + audio + DTMF */
+ LB_MODE_EC_REF_VOICE_AUDIO,
+ /* Echo canceller reference, voice alone */
+ LB_MODE_EC_REF_VOICE
+};
+
+#define AFE_PARAM_ID_LOOPBACK_CONFIG 0x0001020B
+#define AFE_API_VERSION_LOOPBACK_CONFIG 0x1
+struct afe_param_loopback_cfg {
+ /* Minor version used for tracking the version of the configuration
+ * interface.
+ */
+ uint32_t loopback_cfg_minor_version;
+
+ /* Destination Port Id. */
+ uint16_t dst_port_id;
+
+ /* Specifies data path type from src to dest port. Supported values:
+ * LB_MODE_DEFAULT
+ * LB_MODE_SIDETONE
+ * LB_MODE_EC_REF_VOICE_AUDIO
+ * LB_MODE_EC_REF_VOICE
+ */
+ uint16_t routing_mode;
+
+ /* Specifies whether to enable (1) or disable (0) an AFE loopback. */
+ uint16_t enable;
+
+ /* Reserved for 32-bit alignment. This field must be set to 0. */
+ uint16_t reserved;
+} __packed;
#define AFE_MODULE_ID_PORT_INFO 0x00010200
+/* Module ID for the loopback-related parameters. */
+#define AFE_MODULE_LOOPBACK 0x00010205
struct afe_param_payload {
u32 module_id;
u32 param_id;
@@ -364,6 +409,7 @@
struct afe_param_sampling_rate sampling_rate;
struct afe_param_channels channels;
struct afe_param_loopback_gain loopback_gain;
+ struct afe_param_loopback_cfg loopback_cfg;
} __attribute__((packed)) param;
} __attribute__ ((packed));
diff --git a/include/sound/q6afe.h b/include/sound/q6afe.h
index 9893075..8cdcc18 100644
--- a/include/sound/q6afe.h
+++ b/include/sound/q6afe.h
@@ -74,6 +74,7 @@
int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
int afe_close(int port_id);
int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
+int afe_loopback_cfg(u16 enable, u16 dst_port, u16 src_port, u16 mode);
int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain);
int afe_loopback_gain(u16 port_id, u16 volume);
int afe_validate_port(u16 port_id);
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
index 6341818..e3db3f9 100644
--- a/net/ipv4/xfrm4_mode_beet.c
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -110,10 +110,7 @@
skb_push(skb, sizeof(*iph));
skb_reset_network_header(skb);
-
- memmove(skb->data - skb->mac_len, skb_mac_header(skb),
- skb->mac_len);
- skb_set_mac_header(skb, -skb->mac_len);
+ skb_mac_header_rebuild(skb);
xfrm4_beet_make_header(skb);
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index 534972e..ed4bf11 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -66,7 +66,6 @@
static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
{
- const unsigned char *old_mac;
int err = -EINVAL;
if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
@@ -84,10 +83,9 @@
if (!(x->props.flags & XFRM_STATE_NOECN))
ipip_ecn_decapsulate(skb);
- old_mac = skb_mac_header(skb);
- skb_set_mac_header(skb, -skb->mac_len);
- memmove(skb_mac_header(skb), old_mac, skb->mac_len);
skb_reset_network_header(skb);
+ skb_mac_header_rebuild(skb);
+
err = 0;
out:
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
index 3437d7d..f37cba9 100644
--- a/net/ipv6/xfrm6_mode_beet.c
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -80,7 +80,6 @@
static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
{
struct ipv6hdr *ip6h;
- const unsigned char *old_mac;
int size = sizeof(struct ipv6hdr);
int err;
@@ -90,10 +89,7 @@
__skb_push(skb, size);
skb_reset_network_header(skb);
-
- old_mac = skb_mac_header(skb);
- skb_set_mac_header(skb, -skb->mac_len);
- memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+ skb_mac_header_rebuild(skb);
xfrm6_beet_make_header(skb);
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 4d6edff..23ecd68 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -63,7 +63,6 @@
static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
{
int err = -EINVAL;
- const unsigned char *old_mac;
if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6)
goto out;
@@ -80,10 +79,9 @@
if (!(x->props.flags & XFRM_STATE_NOECN))
ipip6_ecn_decapsulate(skb);
- old_mac = skb_mac_header(skb);
- skb_set_mac_header(skb, -skb->mac_len);
- memmove(skb_mac_header(skb), old_mac, skb->mac_len);
skb_reset_network_header(skb);
+ skb_mac_header_rebuild(skb);
+
err = 0;
out:
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index e5b9d16..94dd695 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -824,7 +824,7 @@
#define ALL_INIT_DATA_SECTIONS \
".init.setup$", ".init.rodata$", \
- ".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$" \
+ ".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$", \
".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$"
#define ALL_EXIT_DATA_SECTIONS \
".exit.data$", ".devexit.data$", ".cpuexit.data$", ".memexit.data$"
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 4b6d83b..9041bd7 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1498,7 +1498,7 @@
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
unsigned int cfilt;
- switch (sitar->micbias) {
+ switch (sitar->mbhc_cfg.micbias) {
case SITAR_MICBIAS1:
cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index b0244af..c8ef419 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -62,7 +62,9 @@
enum {
SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
- SLIM_2_RX_1 = 147, /* HDMI RX */
+ SLIM_3_RX_1 = 151, /* External echo-cancellation ref */
+ SLIM_3_RX_2 = 152, /* External echo-cancellation ref */
+ SLIM_3_TX_1 = 147, /* HDMI RX */
SLIM_4_TX_1 = 148, /* In-call recording RX */
SLIM_4_TX_2 = 149, /* In-call recording RX */
SLIM_4_RX_1 = 150, /* In-call music delivery TX */
@@ -80,6 +82,7 @@
static int msm_ext_top_spk_pamp;
static int msm_slim_0_rx_ch = 1;
static int msm_slim_0_tx_ch = 1;
+static int msm_slim_3_rx_ch = 1;
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_ch = 1;
@@ -636,6 +639,25 @@
return 1;
}
+static int msm_slim_3_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_3_rx_ch = %d\n", __func__,
+ msm_slim_3_rx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_3_rx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_3_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_3_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_3_rx_ch = %d\n", __func__,
+ msm_slim_3_rx_ch);
+ return 1;
+}
+
static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -713,6 +735,24 @@
return 0;
}
+static const struct snd_kcontrol_new slim_3_mixer_controls[] = {
+ SOC_ENUM_EXT("SLIM_3_RX Channels", msm_enum[1],
+ msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put),
+};
+
+static int msm_slim_3_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err = 0;
+ struct snd_soc_platform *platform = rtd->platform;
+
+ err = snd_soc_add_platform_controls(platform,
+ slim_3_mixer_controls,
+ ARRAY_SIZE(slim_3_mixer_controls));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
static int msm_incall_rec_init(struct snd_soc_pcm_runtime *rtd)
{
int err = 0;
@@ -845,6 +885,13 @@
user_set_tx_ch = msm_slim_0_tx_ch;
else if (codec_dai->id == 4)
user_set_tx_ch = params_channels(params);
+ else if (codec_dai->id == 5) {
+ /* DAI 5 is used for external EC reference from codec.
+ * Since Rx is fed as reference for EC, the config of
+ * this DAI is based on that of the Rx path.
+ */
+ user_set_tx_ch = msm_slim_0_rx_ch;
+ }
pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
codec_dai->name, codec_dai->id, user_set_tx_ch);
@@ -919,6 +966,35 @@
return ret;
}
+static int msm_slimbus_3_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[2] = {SLIM_3_RX_1, SLIM_3_RX_2};
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: slim_3_rx_ch %d, sch %d %d\n",
+ __func__, msm_slim_3_rx_ch,
+ rx_ch[0], rx_ch[1]);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm_slim_3_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: Erorr %d setting SLIM_3 RX channel map\n",
+ __func__, ret);
+
+ goto end;
+ }
+ } else {
+ pr_err("%s: SLIMBUS_3_TX not defined for this DAI\n", __func__);
+ }
+
+end:
+ return ret;
+}
+
static int msm_slimbus_4_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -1093,6 +1169,22 @@
return 0;
}
+static int msm_slim_3_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_slim_3_rx_ch;
+
+ return 0;
+}
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1257,6 +1349,12 @@
.shutdown = msm_shutdown,
};
+static struct snd_soc_ops msm_slimbus_3_be_ops = {
+ .startup = msm_startup,
+ .hw_params = msm_slimbus_3_hw_params,
+ .shutdown = msm_shutdown,
+};
+
static struct snd_soc_ops msm_slimbus_4_be_ops = {
.startup = msm_startup,
.hw_params = msm_slimbus_4_hw_params,
@@ -1505,7 +1603,7 @@
.codec_name = "tabla_codec",
.codec_dai_name = "tabla_rx2",
.no_pcm = 1,
- /* .be_id = do not care */
+ .be_id = MSM_BACKEND_DAI_EXTPROC_RX,
.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
.init = &msm_stubrx_init,
.ops = &msm_be_ops,
@@ -1518,7 +1616,7 @@
.codec_name = "tabla_codec",
.codec_dai_name = "tabla_tx1",
.no_pcm = 1,
- /* .be_id = do not care */
+ .be_id = MSM_BACKEND_DAI_EXTPROC_TX,
.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
.ops = &msm_be_ops,
},
@@ -1588,6 +1686,36 @@
.init = &msm_incall_rec_init,
.ops = &msm_slimbus_4_be_ops,
},
+ {
+ .name = LPASS_BE_STUB_1_TX,
+ .stream_name = "Stub1 Capture",
+ .cpu_dai_name = "msm-dai-stub",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_tx3",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ /* This BE is used for external EC reference from codec. Since
+ * Rx is fed as reference for EC, the config of this DAI is
+ * based on that of the Rx path.
+ */
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ },
+ {
+
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .init = &msm_slim_3_init,
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_slim_3_rx_be_hw_params_fixup,
+ .ops = &msm_slimbus_3_be_ops,
+ },
};
struct snd_soc_card snd_soc_card_msm = {
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 28d192e..fb7756c 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -590,6 +590,7 @@
case SLIMBUS_0_RX:
case SLIMBUS_1_RX:
+ case SLIMBUS_3_RX:
case SLIMBUS_0_TX:
case SLIMBUS_1_TX:
case SLIMBUS_2_TX:
@@ -1117,6 +1118,7 @@
switch (dai->id) {
case SLIMBUS_0_RX:
case SLIMBUS_1_RX:
+ case SLIMBUS_3_RX:
case SLIMBUS_4_RX:
/* channel number to be between 128 and 255. For RX port
* use channel numbers from 138 to 144, for TX port
@@ -1466,6 +1468,21 @@
.remove = msm_dai_q6_dai_remove,
};
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_3_rx_dai = {
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
/* To do: change to register DAIs as batch */
static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
{
@@ -1512,6 +1529,10 @@
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_slimbus_2_tx_dai);
break;
+ case SLIMBUS_3_RX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_slimbus_3_rx_dai);
+ break;
case INT_BT_SCO_RX:
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_bt_sco_rx_dai);
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 39ce436..ec0d947 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -333,21 +333,20 @@
kfree(prtd);
return -ENOMEM;
}
+
+ pr_debug("%s: session ID %d\n", __func__,
+ prtd->audio_client->session);
+ prtd->session_id = prtd->audio_client->session;
+ msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+ prtd->cmd_ack = 1;
+
}
/* Capture path */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
runtime->hw = msm_pcm_hardware_capture;
}
- pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
-
- prtd->session_id = prtd->audio_client->session;
- msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- prtd->cmd_ack = 1;
-
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&constraints_sample_rates);
@@ -619,6 +618,7 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd = runtime->private_data;
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct audio_buffer *buf;
int dir, ret;
int format = FORMAT_LINEAR_PCM;
@@ -641,6 +641,12 @@
kfree(prtd);
return -ENOMEM;
}
+
+ pr_debug("%s: session ID %d\n", __func__,
+ prtd->audio_client->session);
+ prtd->session_id = prtd->audio_client->session;
+ msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
}
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 4f0e952..02cc6ce 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -134,6 +134,9 @@
{ SLIMBUS_1_TX, 0, 0, 0, 0, 0},
{ SLIMBUS_4_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_4_TX, 0, 0, 0, 0, 0},
+ { SLIMBUS_3_RX, 0, 0, 0, 0, 0},
+ { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
+ { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
};
@@ -150,6 +153,16 @@
{INVALID_SESSION, INVALID_SESSION},
};
+static uint8_t is_be_dai_extproc(int be_dai)
+{
+ if (be_dai == MSM_BACKEND_DAI_EXTPROC_RX ||
+ be_dai == MSM_BACKEND_DAI_EXTPROC_TX ||
+ be_dai == MSM_BACKEND_DAI_EXTPROC_EC_TX)
+ return 1;
+ else
+ return 0;
+}
+
static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
int path_type)
{
@@ -161,7 +174,7 @@
MSM_AFE_PORT_TYPE_RX : MSM_AFE_PORT_TYPE_TX);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if ((i != MSM_BACKEND_DAI_EXTPROC_RX) &&
+ if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions)))
@@ -200,7 +213,7 @@
fe_dai_map[fedai_id][session_type] = dspst_id;
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if ((i != MSM_BACKEND_DAI_EXTPROC_RX) &&
+ if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
@@ -243,7 +256,7 @@
if (eq_data[fedai_id].enable)
msm_send_eq_values(fedai_id);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if ((i != MSM_BACKEND_DAI_EXTPROC_RX) &&
+ if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
@@ -296,7 +309,7 @@
mutex_lock(&routing_lock);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if ((i != MSM_BACKEND_DAI_EXTPROC_RX) &&
+ if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions)))
@@ -1166,6 +1179,12 @@
msm_routing_put_voice_stub_mixer),
};
+static const struct snd_kcontrol_new slimbus_3_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+};
+
static const struct snd_kcontrol_new tx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1227,7 +1246,7 @@
};
static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
- SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_RX,
+ SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
@@ -1236,6 +1255,9 @@
SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
@@ -1268,6 +1290,11 @@
msm_routing_put_port_mixer),
};
+static const struct snd_kcontrol_new sbus_3_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = {
SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
@@ -1580,6 +1607,8 @@
SND_SOC_DAPM_AIF_IN("STUB_TX", "Stub Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_1_TX", "Slimbus1 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("STUB_1_TX", "Stub1 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_RX", "Slimbus3 Playback", 0, 0, 0, 0),
/* Switch Definitions */
SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
@@ -1659,6 +1688,8 @@
stub_rx_mixer_controls, ARRAY_SIZE(stub_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Mixer", SND_SOC_NOPM, 0, 0,
slimbus_1_rx_mixer_controls, ARRAY_SIZE(slimbus_1_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_3_RX_Voice Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_3_rx_mixer_controls, ARRAY_SIZE(slimbus_3_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Port Mixer",
SND_SOC_NOPM, 0, 0, sbus_0_rx_port_mixer_controls,
ARRAY_SIZE(sbus_0_rx_port_mixer_controls)),
@@ -1680,6 +1711,9 @@
SND_SOC_DAPM_MIXER("SEC_I2S_RX Port Mixer",
SND_SOC_NOPM, 0, 0, sec_i2s_rx_port_mixer_controls,
ARRAY_SIZE(sec_i2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_3_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, sbus_3_rx_port_mixer_controls,
+ ARRAY_SIZE(sbus_3_rx_port_mixer_controls)),
};
static const struct snd_soc_dapm_route intercon[] = {
@@ -1845,6 +1879,7 @@
{"Voice Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
{"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -1853,10 +1888,16 @@
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIMBUS_3_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX_Voice Mixer"},
+
{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
+ {"SLIMBUS_3_RX Port Mixer", "INTERNAL_BT_SCO_RX", "INT_BT_SCO_RX"},
+ {"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX Port Mixer"},
+
{"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
{"HDMI", NULL, "HDMI_RX Port Mixer"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index b7c7631..5f5c12a 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -37,7 +37,8 @@
#define LPASS_BE_STUB_TX "(Backend) STUB_TX"
#define LPASS_BE_SLIMBUS_1_RX "(Backend) SLIMBUS_1_RX"
#define LPASS_BE_SLIMBUS_1_TX "(Backend) SLIMBUS_1_TX"
-
+#define LPASS_BE_STUB_1_TX "(Backend) STUB_1_TX"
+#define LPASS_BE_SLIMBUS_3_RX "(Backend) SLIMBUS_3_RX"
#define LPASS_BE_SLIMBUS_4_RX "(Backend) SLIMBUS_4_RX"
#define LPASS_BE_SLIMBUS_4_TX "(Backend) SLIMBUS_4_TX"
@@ -88,7 +89,10 @@
MSM_BACKEND_DAI_SLIMBUS_1_TX,
MSM_BACKEND_DAI_SLIMBUS_4_RX,
MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_BACKEND_DAI_SLIMBUS_3_RX,
MSM_BACKEND_DAI_EXTPROC_RX,
+ MSM_BACKEND_DAI_EXTPROC_TX,
+ MSM_BACKEND_DAI_EXTPROC_EC_TX,
MSM_BACKEND_DAI_MAX,
};
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index dc120b08..9f058b9 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -147,6 +147,7 @@
case HDMI_RX:
case SLIMBUS_0_RX:
case SLIMBUS_1_RX:
+ case SLIMBUS_3_RX:
case INT_BT_SCO_RX:
case INT_BT_A2DP_RX:
case INT_FM_RX:
@@ -206,6 +207,7 @@
case SLIMBUS_1_RX:
case SLIMBUS_1_TX:
case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
case INT_BT_SCO_RX:
case INT_BT_SCO_TX:
case INT_BT_A2DP_RX:
@@ -271,6 +273,7 @@
case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
+ case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -305,6 +308,7 @@
case SLIMBUS_1_RX:
case SLIMBUS_1_TX:
case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
case SLIMBUS_4_RX:
case SLIMBUS_4_TX:
ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
@@ -676,7 +680,7 @@
return ret;
}
-int afe_loopback(u16 enable, u16 rx_port, u16 tx_port)
+int afe_loopback(u16 enable, u16 dst_port, u16 src_port)
{
struct afe_loopback_command lb_cmd;
int ret = 0;
@@ -685,6 +689,11 @@
if (ret != 0)
return ret;
+ if ((afe_get_port_type(dst_port) == MSM_AFE_PORT_TYPE_RX) &&
+ (afe_get_port_type(src_port) == MSM_AFE_PORT_TYPE_RX))
+ return afe_loopback_cfg(enable, dst_port, src_port,
+ LB_MODE_EC_REF_VOICE_AUDIO);
+
lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(20), APR_PKT_VER);
lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
@@ -693,8 +702,8 @@
lb_cmd.hdr.dest_port = 0;
lb_cmd.hdr.token = 0;
lb_cmd.hdr.opcode = AFE_PORT_CMD_LOOPBACK;
- lb_cmd.tx_port_id = tx_port;
- lb_cmd.rx_port_id = rx_port;
+ lb_cmd.tx_port_id = src_port;
+ lb_cmd.rx_port_id = dst_port;
lb_cmd.mode = 0xFFFF;
lb_cmd.enable = (enable ? 1 : 0);
atomic_set(&this_afe.state, 1);
@@ -716,6 +725,63 @@
return ret;
}
+int afe_loopback_cfg(u16 enable, u16 dst_port, u16 src_port, u16 mode)
+{
+ struct afe_port_cmd_set_param lp_cfg;
+ int ret = 0;
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0)
+ return ret;
+
+ pr_debug("%s: src_port %d, dst_port %d\n",
+ __func__, src_port, dst_port);
+
+ lp_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ lp_cfg.hdr.pkt_size = sizeof(lp_cfg);
+ lp_cfg.hdr.src_port = 0;
+ lp_cfg.hdr.dest_port = 0;
+ lp_cfg.hdr.token = 0;
+ lp_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
+
+ lp_cfg.port_id = src_port;
+ lp_cfg.payload_size = sizeof(struct afe_param_payload);
+ lp_cfg.payload_address = 0;
+
+ lp_cfg.payload.module_id = AFE_MODULE_LOOPBACK;
+ lp_cfg.payload.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
+ lp_cfg.payload.param_size = sizeof(struct afe_param_loopback_cfg);
+ lp_cfg.payload.reserved = 0;
+
+ lp_cfg.payload.param.loopback_cfg.loopback_cfg_minor_version =
+ AFE_API_VERSION_LOOPBACK_CONFIG;
+ lp_cfg.payload.param.loopback_cfg.dst_port_id = dst_port;
+ lp_cfg.payload.param.loopback_cfg.routing_mode = mode;
+ lp_cfg.payload.param.loopback_cfg.enable = enable;
+ lp_cfg.payload.param.loopback_cfg.reserved = 0;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lp_cfg);
+ if (ret < 0) {
+ pr_err("%s: AFE loopback config failed for src_port %d, dst_port %d\n",
+ __func__, src_port, dst_port);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (ret < 0) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return ret;
+}
int afe_loopback_gain(u16 port_id, u16 volume)
{