Merge "msm: defconfig: 9615: Disable the HVC_DCC and DCC consoles" into msm-3.0
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/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-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/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/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/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/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/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/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/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/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/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/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/msm/apq8064.c b/sound/soc/msm/apq8064.c
index f8ddb0b..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;
@@ -926,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)
{
@@ -1100,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)
{
@@ -1264,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,
@@ -1611,6 +1702,20 @@
.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-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 7cb58cb..02cc6ce 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -134,6 +134,7 @@
{ 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},
@@ -1178,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,
@@ -1283,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,
@@ -1596,6 +1608,7 @@
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,
@@ -1675,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)),
@@ -1696,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[] = {
@@ -1870,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 26ce53c..5f5c12a 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -38,7 +38,7 @@
#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"
@@ -89,6 +89,7 @@
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,
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)
{