Merge remote branch 'origin/msm-3.0' into msm-3.4
* origin/msm-3.0: (87 commits)
Revert "msm: kgsl: Add VBIF error detection"
tspp: 8960: adding TSPP driver for 8960
board-8960: Merge secure and non secure firmware heaps.
msm: msm_dsps: Move to the new clk_prepare/unprepare API.
diag: Protect SMD channel from getting NULL value
camera: Mercury hardware JPEG decoder driver support.
msm: 8064-regulator: Remove 5V FRC gpio external regulator
diag: Respond to Get Subsystem Mask request
Revert "msm_fb: display: Attach and detach MDP IOMMU on suspend/resume"
Revert "msm_fb: display: Add MDP IOMMU detach support for DTV"
msm: rpm-8930: Fix incorrect RPM enumeration and DMM
msm: board-8930: Configure GPU turbo clock to 400MHz
usb: mdm_bridge: Fix bug in handling error condition
msm: vidc: Invalidate the cache before processing metadata.
video: msm: wfd: Add turbo mode support
tty: n_smux: Add Dedicated Power Control Queue
defconfig: msm-copper: Enable SPI ethernet support
msm: acpuclock-8960: Add PVS support on 8064
ASoC: mdm9615: Set correct GPIOs for AUX PCM
msm: 9615: Add auxpcm support over secondary audio interface
...
Conflicts:
arch/arm/configs/msm-copper_defconfig
drivers/char/diag/diagchar_core.c
drivers/char/diag/diagfwd_hsic.h
drivers/media/video/msm/msm_camera.c
drivers/media/video/msm/msm_mctl.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/wcd9xxx-slimslave.c
drivers/spmi/spmi.c
drivers/tty/n_smux.c
drivers/usb/otg/msm_otg.c
sound/soc/msm/msm-pcm-routing.h
Signed-off-by: Steve Muckle <smuckle@codeaurora.org>
Change-Id: I49d4ceff17714a7ba51243de63f27b7e78647bda
diff --git a/Documentation/devicetree/bindings/pil/pil-mba.txt b/Documentation/devicetree/bindings/pil/pil-mba.txt
new file mode 100644
index 0000000..7aafd219
--- /dev/null
+++ b/Documentation/devicetree/bindings/pil/pil-mba.txt
@@ -0,0 +1,27 @@
+Qualcomm Modem Boot Authenticator Peripheral Image Loader
+
+pil-mba is a peripheral image loader (PIL) driver. It is used for loading
+modem images using the self-authenticating hardware and software features
+of the Modem Boot Authenticator.
+
+Required properties:
+- compatible: Must be "qcom,pil-mba"
+- reg: Two pairs of physical base addresses and sizes. The
+ first corresponds to the Relay Message Buffer (RMB)
+ register base. The second specifies the address at which
+ the primary modem image metadata should be stored.
+- qcom,firmware-name: Base name of the firmware image. Ex. "modem"
+
+Optional properties:
+- qcom,depends-on: firmware-name of a prerequisite image that must already
+ be running.
+
+Example:
+ qcom,mba@fc820000 {
+ compatible = "qcom,pil-mba";
+ reg = <0xfc820000 0x0020>,
+ <0x0d1f0000 0x4000>;
+
+ qcom,firmware-name = "modem";
+ qcom,depends-on = "mba";
+ };
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
new file mode 100644
index 0000000..95e7f88
--- /dev/null
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -0,0 +1,32 @@
+Qualcomm MSS QDSP6v5 Peripheral Image Loader
+
+pil-qdsp6v5-mss is a peripheral image loader (PIL) driver. It is used for
+loading QDSP6v5 (Hexagon) firmware images for modem subsystems into memory and
+preparing the subsystem's processor to execute code. It's also responsible for
+shutting down the processor when it's not needed.
+
+Required properties:
+- compatible: Must be "qcom,pil-q6v5-mss"
+- reg: Four pairs of physical base addresses and region sizes of
+ memory mapped registers. The first region corresponds to
+ QDSP6SS_PUB, the second to the bus port halt register
+ base, the third to the MSS_RELAY_MSG_BUFFER base, and the
+ fourth to the MSS_RESTART register.
+- vdd_mss-supply: Reference to the regulator that supplies the processor.
+- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
+- qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
+ images and self-authentication is not desired;
+ <1> if the hardware requires self-authenticating images.
+
+Example:
+ qcom,mss@fc880000 {
+ compatible = "qcom,pil-q6v5-mss";
+ reg = <0xfc880000 0x100>,
+ <0xfd485000 0x400>,
+ <0xfc820000 0x020>,
+ <0xfc401680 0x004>;
+ vdd_mss-supply = <&pm8841_s3>;
+
+ qcom,firmware-name = "mba";
+ qcom,pil-self-auth = <1>;
+ };
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 87f63ff..eb781b7 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -291,6 +291,27 @@
qcom,firmware-name = "adsp";
};
+ qcom,mss@fc880000 {
+ compatible = "qcom,pil-q6v5-mss";
+ reg = <0xfc880000 0x100>,
+ <0xfd485000 0x400>,
+ <0xfc820000 0x020>,
+ <0xfc401680 0x004>;
+ vdd_mss-supply = <&pm8841_s3>;
+
+ qcom,firmware-name = "mba";
+ qcom,pil-self-auth = <1>;
+ };
+
+ qcom,mba@fc820000 {
+ compatible = "qcom,pil-mba";
+ reg = <0xfc820000 0x0020>,
+ <0x0d1fc000 0x4000>;
+
+ qcom,firmware-name = "modem";
+ qcom,depends-on = "mba";
+ };
+
qcom,pronto@fb21b000 {
compatible = "qcom,pil-pronto";
reg = <0xfb21b000 0x3000>,
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 148f17f..473a7d5 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -45,9 +45,10 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_PIL_LPASS_QDSP6V5=y
-CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_MBA=y
CONFIG_MSM_PIL_PRONTO=y
-CONFIG_MSM_IOMMU=y
+CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_OCMEM=y
CONFIG_NO_HZ=y
@@ -76,6 +77,7 @@
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
CONFIG_IPV6=y
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
@@ -96,6 +98,7 @@
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_NETDEVICES=y
+CONFIG_KS8851=m
# CONFIG_MSM_RMNET is not set
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
@@ -107,6 +110,7 @@
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
CONFIG_DCC_TTY=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
@@ -163,6 +167,7 @@
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_MSM_IOMMU=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -199,4 +204,3 @@
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
-CONFIG_HW_RANDOM_MSM=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 4000a0f..c39b403 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -272,6 +272,7 @@
CONFIG_FB_MSM_TRIPLE_BUFFER=y
CONFIG_FB_MSM_MDP40=y
CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index fdcd566..8dda15f 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -274,6 +274,7 @@
CONFIG_FB_MSM_TRIPLE_BUFFER=y
CONFIG_FB_MSM_MDP40=y
CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index a2cba84..08b65db 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1841,8 +1841,22 @@
tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
depends on MSM_PIL
help
- Support for booting and shutting down QDSP6v5 processors (Hexagon)
- processors in low power audio subsystems.
+ Support for booting and shutting down QDSP6v5 (Hexagon) processors
+ in low power audio subsystems.
+
+config MSM_PIL_MSS_QDSP6V5
+ tristate "MSS QDSP6v5 (Hexagon) Boot Support"
+ depends on MSM_PIL
+ help
+ Support for booting and shutting down QDSP6v5 (Hexagon) processors
+ in modem subsystems.
+
+config MSM_PIL_MBA
+ tristate "Support for modem self-authentication"
+ depends on MSM_PIL_MSS_QDSP6V5
+ help
+ Support for booting self-authenticating modems using the Modem Boot
+ Authenticator.
config MSM_PIL_RIVA
tristate "RIVA (WCNSS) Boot Support"
@@ -2264,6 +2278,16 @@
For production builds, you should probably say 'N' here.
+config MSM_L1_ERR_LOG
+ bool "Log CPU ERP events to system memory"
+ depends on MSM_CACHE_ERP
+ help
+ Enable logging CPU ERP events to an area of memory that will be
+ preserved across a system reset. This may be useful for detecting and
+ troubleshooting ERP-related system crashes in the field.
+
+ For production builds, you may want to say 'Y' here.
+
config MSM_L2_ERP_PRINT_ACCESS_ERRORS
bool "Report L2 master port slave/decode errors in kernel log"
depends on MSM_CACHE_ERP
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 44bef1b..f316f36 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -70,6 +70,8 @@
obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V5) += pil-q6v5.o pil-q6v5-lpass.o
+obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-q6v5-mss.o
+obj-$(CONFIG_MSM_PIL_MBA) += pil-mba.o
obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
obj-$(CONFIG_MSM_PIL_VIDC) += pil-vidc.o
@@ -328,7 +330,7 @@
ifdef CONFIG_VCM
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
endif
-obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o
+obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o
obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index f467aba..a58eb6e 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -105,6 +105,14 @@
HFPLL_VDD_NOM
};
+enum pvs {
+ PVS_SLOW,
+ PVS_NOM,
+ PVS_FAST,
+ PVS_FASTER,
+ NUM_PVS
+};
+
struct vreg {
const char name[15];
const unsigned int max_vdd;
@@ -602,7 +610,7 @@
};
/* TODO: Update core voltages when data is available. */
-static struct acpu_level acpu_freq_tbl_8064[] = {
+static struct acpu_level acpu_freq_tbl_8064_slow[] = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 975000 },
@@ -629,6 +637,60 @@
{ 0, { 0 } }
};
+static struct acpu_level acpu_freq_tbl_8064_nom[] = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 925000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 925000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 950000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 950000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 975000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 975000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1025000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1025000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1050000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1050000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1075000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1075000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1125000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1125000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1150000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1150000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1175000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1175000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1187500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1187500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1212500 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_8064_fast[] = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 850000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 850000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 875000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 875000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 900000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 900000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 925000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 925000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 975000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 975000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1000000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1000000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1025000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1025000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1075000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1075000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1100000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1100000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1125000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1125000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1137500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1137500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1175000 },
+ { 0, { 0 } }
+};
+
/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
#undef L2
#define L2(x) (&l2_freq_tbl_8930[(x)])
@@ -711,6 +773,26 @@
{ 0, { 0 } }
};
+static struct acpu_level *acpu_freq_tbl_8960_v1[NUM_PVS] __initdata = {
+ [PVS_SLOW] = acpu_freq_tbl_8960_kraitv1_slow,
+ [PVS_NOM] = acpu_freq_tbl_8960_kraitv1_nom_fast,
+ [PVS_FAST] = acpu_freq_tbl_8960_kraitv1_nom_fast,
+};
+
+static struct acpu_level *acpu_freq_tbl_8960_v2[NUM_PVS] __initdata = {
+ [PVS_SLOW] = acpu_freq_tbl_8960_kraitv2_slow,
+ [PVS_NOM] = acpu_freq_tbl_8960_kraitv2_nom,
+ [PVS_FAST] = acpu_freq_tbl_8960_kraitv2_fast,
+};
+
+/* TODO: update the faster table when data is available */
+static struct acpu_level *acpu_freq_tbl_8064[NUM_PVS] __initdata = {
+ [PVS_SLOW] = acpu_freq_tbl_8064_slow,
+ [PVS_NOM] = acpu_freq_tbl_8064_nom,
+ [PVS_FAST] = acpu_freq_tbl_8064_fast,
+ [PVS_FASTER] = acpu_freq_tbl_8064_fast,
+};
+
static unsigned long acpuclk_8960_get_rate(int cpu)
{
return scalable[cpu].current_speed->khz;
@@ -1416,57 +1498,60 @@
tbl->vdd_core = 1150000;
}
+static enum pvs __init get_pvs(void)
+{
+ uint32_t pte_efuse, pvs;
+
+ pte_efuse = readl_relaxed(QFPROM_PTE_EFUSE_ADDR);
+ pvs = (pte_efuse >> 10) & 0x7;
+ if (pvs == 0x7)
+ pvs = (pte_efuse >> 13) & 0x7;
+
+ switch (pvs) {
+ case 0x0:
+ case 0x7:
+ pr_info("ACPU PVS: Slow\n");
+ return PVS_SLOW;
+ case 0x1:
+ pr_info("ACPU PVS: Nominal\n");
+ return PVS_NOM;
+ case 0x3:
+ pr_info("ACPU PVS: Fast\n");
+ return PVS_FAST;
+ case 0x4:
+ if (cpu_is_apq8064()) {
+ pr_info("ACPU PVS: Faster\n");
+ return PVS_FASTER;
+ }
+ default:
+ pr_warn("ACPU PVS: Unknown. Defaulting to slow\n");
+ return PVS_SLOW;
+ }
+}
+
static struct acpu_level * __init select_freq_plan(void)
{
struct acpu_level *l, *max_acpu_level = NULL;
/* Select frequency tables. */
if (cpu_is_msm8960()) {
- uint32_t pte_efuse, pvs;
- struct acpu_level *v1, *v2;
-
- pte_efuse = readl_relaxed(QFPROM_PTE_EFUSE_ADDR);
- pvs = (pte_efuse >> 10) & 0x7;
- if (pvs == 0x7)
- pvs = (pte_efuse >> 13) & 0x7;
-
- switch (pvs) {
- case 0x0:
- case 0x7:
- pr_info("ACPU PVS: Slow\n");
- v1 = acpu_freq_tbl_8960_kraitv1_slow;
- v2 = acpu_freq_tbl_8960_kraitv2_slow;
- break;
- case 0x1:
- pr_info("ACPU PVS: Nominal\n");
- v1 = acpu_freq_tbl_8960_kraitv1_nom_fast;
- v2 = acpu_freq_tbl_8960_kraitv2_nom;
- break;
- case 0x3:
- pr_info("ACPU PVS: Fast\n");
- v1 = acpu_freq_tbl_8960_kraitv1_nom_fast;
- v2 = acpu_freq_tbl_8960_kraitv2_fast;
- break;
- default:
- pr_warn("ACPU PVS: Unknown. Defaulting to slow.\n");
- v1 = acpu_freq_tbl_8960_kraitv1_slow;
- v2 = acpu_freq_tbl_8960_kraitv2_slow;
- break;
- }
+ enum pvs pvs_id = get_pvs();
scalable = scalable_8960;
if (cpu_is_krait_v1()) {
- acpu_freq_tbl = v1;
+ acpu_freq_tbl = acpu_freq_tbl_8960_v1[pvs_id];
l2_freq_tbl = l2_freq_tbl_8960_kraitv1;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv1);
} else {
- acpu_freq_tbl = v2;
+ acpu_freq_tbl = acpu_freq_tbl_8960_v2[pvs_id];
l2_freq_tbl = l2_freq_tbl_8960_kraitv2;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv2);
}
} else if (cpu_is_apq8064()) {
+ enum pvs pvs_id = get_pvs();
+
scalable = scalable_8064;
- acpu_freq_tbl = acpu_freq_tbl_8064;
+ acpu_freq_tbl = acpu_freq_tbl_8064[pvs_id];
l2_freq_tbl = l2_freq_tbl_8064;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8064);
} else if (cpu_is_msm8627()) {
@@ -1482,6 +1567,7 @@
} else {
BUG();
}
+ BUG_ON(!acpu_freq_tbl);
if (krait_needs_vmin())
kraitv2_apply_vmin(acpu_freq_tbl);
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 877c9fc..2009584 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -126,7 +126,6 @@
PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_30),
/* TABLA CODEC RESET */
PM8921_GPIO_OUTPUT(34, 1, MED),
- PM8921_GPIO_INPUT(31, PM_GPIO_PULL_NO),
PM8921_GPIO_OUTPUT(13, 0, HIGH), /* PCIE_CLK_PWR_EN */
};
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 08dacea..f7d5403 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -265,9 +265,6 @@
REGULATOR_SUPPLY("ext_ts_sw", NULL),
REGULATOR_SUPPLY("vdd_ana", "3-005b"),
};
-VREG_CONSUMERS(FRC_5V) = {
- REGULATOR_SUPPLY("frc_5v", NULL),
-};
VREG_CONSUMERS(AVC_1P2V) = {
REGULATOR_SUPPLY("avc_1p2v", NULL),
};
@@ -519,7 +516,6 @@
struct gpio_regulator_platform_data
mpq8064_gpio_regulator_pdata[] __devinitdata = {
- GPIO_VREG(FRC_5V, "frc_5v", "frc_5v_en", SX150X_GPIO(4, 10), NULL),
GPIO_VREG(AVC_1P2V, "avc_1p2v", "avc_1p2v_en", SX150X_GPIO(4, 2), NULL),
GPIO_VREG(AVC_1P8V, "avc_1p8v", "avc_1p8v_en", SX150X_GPIO(4, 4), NULL),
GPIO_VREG(AVC_2P2V, "avc_2p2v", "avc_2p2v_en",
@@ -532,15 +528,15 @@
/* SAW regulator constraints */
struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5 =
/* ID vreg_name min_uV max_uV */
- SAW_VREG_INIT(S5, "8921_s5", 950000, 1300000);
+ SAW_VREG_INIT(S5, "8921_s5", 850000, 1300000);
struct regulator_init_data msm8064_saw_regulator_pdata_8921_s6 =
- SAW_VREG_INIT(S6, "8921_s6", 950000, 1300000);
+ SAW_VREG_INIT(S6, "8921_s6", 850000, 1300000);
struct regulator_init_data msm8064_saw_regulator_pdata_8821_s0 =
/* ID vreg_name min_uV max_uV */
- SAW_VREG_INIT(8821_S0, "8821_s0", 950000, 1300000);
+ SAW_VREG_INIT(8821_S0, "8821_s0", 850000, 1300000);
struct regulator_init_data msm8064_saw_regulator_pdata_8821_s1 =
- SAW_VREG_INIT(8821_S1, "8821_s1", 950000, 1300000);
+ SAW_VREG_INIT(8821_S1, "8821_s1", 850000, 1300000);
/* PM8921 regulator constraints */
struct pm8xxx_regulator_platform_data
@@ -589,7 +585,7 @@
RPM_LDO(L22, 0, 1, 0, 2600000, 2600000, NULL, 0, 0),
RPM_LDO(L23, 0, 1, 0, 1800000, 1800000, NULL, 0, 0),
RPM_LDO(L24, 0, 1, 1, 750000, 1150000, "8921_s1", 10000, 10000),
- RPM_LDO(L25, 1, 1, 0, 1225000, 1225000, "8921_s1", 10000, 10000),
+ RPM_LDO(L25, 1, 1, 0, 1250000, 1250000, "8921_s1", 10000, 10000),
RPM_LDO(L27, 0, 1, 0, 1100000, 1100000, "8921_s7", 0, 0),
RPM_LDO(L28, 0, 1, 0, 1050000, 1050000, "8921_s7", 0, 0),
RPM_LDO(L29, 0, 1, 0, 2000000, 2000000, NULL, 0, 0),
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index fb507c7..5f74468 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -362,10 +362,29 @@
}
if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
machine_is_mpq8064_dtv()) {
+ int rc;
+ struct pm_gpio sd_card_det_init_cfg = {
+ .direction = PM_GPIO_DIR_IN,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .pull = PM_GPIO_PULL_UP_30,
+ .vin_sel = PM_GPIO_VIN_S4,
+ .out_strength = PM_GPIO_STRENGTH_NO,
+ .function = PM_GPIO_FUNC_NORMAL,
+ };
+
apq8064_sdc3_pdata->status_gpio =
PM8921_GPIO_PM_TO_SYS(31);
apq8064_sdc3_pdata->status_irq =
PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 31);
+ rc = pm8xxx_gpio_config(apq8064_sdc3_pdata->status_gpio,
+ &sd_card_det_init_cfg);
+ if (rc) {
+ pr_info("%s: SD_CARD_DET GPIO%d config "
+ "failed(%d)\n", __func__,
+ apq8064_sdc3_pdata->status_gpio, rc);
+ apq8064_sdc3_pdata->status_gpio = 0;
+ apq8064_sdc3_pdata->status_irq = 0;
+ }
}
apq8064_add_sdcc(3, apq8064_sdc3_pdata);
}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 72430e6..5f1a57d 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1027,13 +1027,13 @@
{
.name = "VDDD_CDC_D",
.min_uV = 1225000,
- .max_uV = 1225000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
},
{
.name = "CDC_VDDA_A_1P2V",
.min_uV = 1225000,
- .max_uV = 1225000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
},
},
@@ -1094,13 +1094,13 @@
{
.name = "VDDD_CDC_D",
.min_uV = 1225000,
- .max_uV = 1225000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
},
{
.name = "CDC_VDDA_A_1P2V",
.min_uV = 1225000,
- .max_uV = 1225000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
},
},
@@ -2190,6 +2190,7 @@
&apq_cpudai_slimbus_2_rx,
&apq_cpudai_slimbus_2_tx,
&apq_cpudai_slimbus_3_rx,
+ &apq_cpudai_slimbus_3_tx,
&apq8064_rpm_device,
&apq8064_rpm_log_device,
&apq8064_rpm_stat_device,
@@ -2248,16 +2249,6 @@
};
static struct platform_device
-mpq8064_device_ext_5v_frc_vreg __devinitdata = {
- .name = GPIO_REGULATOR_DEV_NAME,
- .id = SX150X_GPIO(4, 10),
- .dev = {
- .platform_data =
- &mpq8064_gpio_regulator_pdata[GPIO_VREG_ID_FRC_5V],
- },
-};
-
-static struct platform_device
mpq8064_device_ext_1p2_buck_vreg __devinitdata = {
.name = GPIO_REGULATOR_DEV_NAME,
.id = SX150X_GPIO(4, 2),
@@ -2346,7 +2337,6 @@
&msm_rotator_device,
#endif
&gpio_ir_recv_pdev,
- &mpq8064_device_ext_5v_frc_vreg,
&mpq8064_device_ext_1p2_buck_vreg,
&mpq8064_device_ext_1p8_buck_vreg,
&mpq8064_device_ext_2p2_buck_vreg,
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 39c367f..a241ab3 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -45,12 +45,11 @@
#define GPIO_VREG_ID_EXT_TS_SW 2
#define GPIO_VREG_ID_EXT_MPP8 3
-#define GPIO_VREG_ID_FRC_5V 0
-#define GPIO_VREG_ID_AVC_1P2V 1
-#define GPIO_VREG_ID_AVC_1P8V 2
-#define GPIO_VREG_ID_AVC_2P2V 3
-#define GPIO_VREG_ID_AVC_5V 4
-#define GPIO_VREG_ID_AVC_3P3V 5
+#define GPIO_VREG_ID_AVC_1P2V 0
+#define GPIO_VREG_ID_AVC_1P8V 1
+#define GPIO_VREG_ID_AVC_2P2V 2
+#define GPIO_VREG_ID_AVC_5V 3
+#define GPIO_VREG_ID_AVC_3P3V 4
#define APQ8064_EXT_3P3V_REG_EN_GPIO 77
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index c7ab260..000f080 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -624,6 +624,22 @@
},
};
+static struct gpiomux_setting sd_det_line = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm8930_sd_det_config[] __initdata = {
+ {
+ .gpio = 94, /* SD Card Detect Line */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &sd_det_line,
+ [GPIOMUX_ACTIVE] = &sd_det_line,
+ },
+ },
+};
+
int __init msm8930_init_gpiomux(void)
{
int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -687,5 +703,9 @@
msm_gpiomux_install(msm8960_mdp_vsync_configs,
ARRAY_SIZE(msm8960_mdp_vsync_configs));
+
+ msm_gpiomux_install(msm8930_sd_det_config,
+ ARRAY_SIZE(msm8930_sd_det_config));
+
return 0;
}
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 3c3843a..e23b76c 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -115,7 +115,7 @@
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
.pwrlevel = {
{
- .gpu_freq = 450000000,
+ .gpu_freq = 400000000,
.bus_freq = 3,
.io_fraction = 0,
},
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index 87143ff..bb35c95 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -53,7 +53,19 @@
.name = "sdc_vdd",
.high_vol_level = 2950000,
.low_vol_level = 2950000,
+ /*
+ * Normally this is not an always ON regulator. On this
+ * platform, unfortunately the sd detect line is connected
+ * to this via esd circuit and so turn this off/on while card
+ * is not present causes the sd detect line to toggle
+ * continuously. This is expected to be fixed in the newer
+ * hardware revisions - maybe once that is done, this can be
+ * reverted.
+ */
+ .always_on = 1,
+ .lpm_sup = 1,
.hpm_uA = 800000, /* 800mA */
+ .lpm_uA = 9000,
}
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 98d9f3a..712b520 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -126,6 +126,7 @@
#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define HOLE_SIZE 0x20000
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
@@ -138,7 +139,7 @@
#define MSM_ION_QSECOM_SIZE 0x600000 /* (6MB) */
#define MSM_ION_HEAP_NUM 8
#endif
-#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
+#define MSM_ION_MM_FW_SIZE (0x200000 - HOLE_SIZE) /* 2MB - 128Kb */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
@@ -146,10 +147,11 @@
#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 MSM_MM_FW_SIZE (0x200000 - HOLE_SIZE) /*2MB -128Kb */
+#define MSM8930_FIXED_AREA_START (0xa0000000 - (MSM_ION_MM_FW_SIZE + \
+ HOLE_SIZE))
#define MAX_FIXED_AREA_SIZE 0x10000000
-#define MSM_MM_FW_SIZE 0x200000
-#define MSM8930_FW_START (MSM8930_FIXED_AREA_START - MSM_MM_FW_SIZE)
+#define MSM8930_FW_START MSM8930_FIXED_AREA_START
#else
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
@@ -560,7 +562,8 @@
return;
if (msm8930_fmem_pdata.size) {
- msm8930_fmem_pdata.reserved_size_low = fixed_low_size;
+ msm8930_fmem_pdata.reserved_size_low = fixed_low_size +
+ HOLE_SIZE;
msm8930_fmem_pdata.reserved_size_high = fixed_high_size;
}
@@ -572,7 +575,7 @@
msm8930_reserve_fixed_area(fixed_size);
fixed_low_start = MSM8930_FIXED_AREA_START;
- fixed_middle_start = fixed_low_start + fixed_low_size;
+ fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
fixed_high_start = fixed_middle_start + fixed_middle_size;
for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
@@ -580,11 +583,13 @@
if (heap->extra_data) {
int fixed_position = NOT_FIXED;
+ struct ion_cp_heap_pdata *pdata = NULL;
switch (heap->type) {
case ION_HEAP_TYPE_CP:
- fixed_position = ((struct ion_cp_heap_pdata *)
- heap->extra_data)->fixed_position;
+ pdata =
+ (struct ion_cp_heap_pdata *)heap->extra_data;
+ fixed_position = pdata->fixed_position;
break;
case ION_HEAP_TYPE_CARVEOUT:
fixed_position = ((struct ion_co_heap_pdata *)
@@ -600,6 +605,9 @@
break;
case FIXED_MIDDLE:
heap->base = fixed_middle_start;
+ pdata->secure_base = fixed_middle_start
+ - HOLE_SIZE;
+ pdata->secure_size = HOLE_SIZE + heap->size;
break;
case FIXED_HIGH:
heap->base = fixed_high_start;
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 90ba66b..9c096b7 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -50,6 +50,7 @@
#include <asm/mach/mmc.h>
#include <mach/board.h>
+#include <mach/msm_tspp.h>
#include <mach/msm_iomap.h>
#include <mach/msm_spi.h>
#include <mach/msm_serial_hs.h>
@@ -144,6 +145,7 @@
#define MSM_HDMI_PRIM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define HOLE_SIZE 0x20000
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
@@ -156,7 +158,7 @@
#define MSM_ION_QSECOM_SIZE 0x600000 /* (6MB) */
#define MSM_ION_HEAP_NUM 8
#endif
-#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
+#define MSM_ION_MM_FW_SIZE (0x200000 - HOLE_SIZE) /* 128kb */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
@@ -164,10 +166,11 @@
#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE
#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE
-#define MSM8960_FIXED_AREA_START 0xa0000000
+#define MSM_MM_FW_SIZE (0x200000 - HOLE_SIZE) /* 2mb -128kb*/
+#define MSM8960_FIXED_AREA_START (0xa0000000 - (MSM_ION_MM_FW_SIZE + \
+ HOLE_SIZE))
#define MAX_FIXED_AREA_SIZE 0x10000000
-#define MSM_MM_FW_SIZE 0x200000
-#define MSM8960_FW_START (MSM8960_FIXED_AREA_START - MSM_MM_FW_SIZE)
+#define MSM8960_FW_START MSM8960_FIXED_AREA_START
static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
#else
@@ -640,7 +643,8 @@
return;
if (msm8960_fmem_pdata.size) {
- msm8960_fmem_pdata.reserved_size_low = fixed_low_size;
+ msm8960_fmem_pdata.reserved_size_low = fixed_low_size +
+ HOLE_SIZE;
msm8960_fmem_pdata.reserved_size_high = fixed_high_size;
}
@@ -652,7 +656,7 @@
msm8960_reserve_fixed_area(fixed_size);
fixed_low_start = MSM8960_FIXED_AREA_START;
- fixed_middle_start = fixed_low_start + fixed_low_size;
+ fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
fixed_high_start = fixed_middle_start + fixed_middle_size;
for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
@@ -660,11 +664,13 @@
if (heap->extra_data) {
int fixed_position = NOT_FIXED;
+ struct ion_cp_heap_pdata *pdata = NULL;
switch (heap->type) {
case ION_HEAP_TYPE_CP:
- fixed_position = ((struct ion_cp_heap_pdata *)
- heap->extra_data)->fixed_position;
+ pdata =
+ (struct ion_cp_heap_pdata *)heap->extra_data;
+ fixed_position = pdata->fixed_position;
break;
case ION_HEAP_TYPE_CARVEOUT:
fixed_position = ((struct ion_co_heap_pdata *)
@@ -680,6 +686,9 @@
break;
case FIXED_MIDDLE:
heap->base = fixed_middle_start;
+ pdata->secure_base = fixed_middle_start
+ - HOLE_SIZE;
+ pdata->secure_size = HOLE_SIZE + heap->size;
break;
case FIXED_HIGH:
heap->base = fixed_high_start;
@@ -1284,6 +1293,87 @@
.peripheral_platform_device = NULL,
};
+#define MSM_TSIF0_PHYS (0x18200000)
+#define MSM_TSIF1_PHYS (0x18201000)
+#define MSM_TSIF_SIZE (0x200)
+#define MSM_TSPP_PHYS (0x18202000)
+#define MSM_TSPP_SIZE (0x1000)
+#define MSM_TSPP_BAM_PHYS (0x18204000)
+#define MSM_TSPP_BAM_SIZE (0x2000)
+
+#define TSIF_0_CLK GPIO_CFG(75, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_EN GPIO_CFG(76, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_DATA GPIO_CFG(77, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_SYNC GPIO_CFG(82, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_CLK GPIO_CFG(79, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_EN GPIO_CFG(80, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_DATA GPIO_CFG(81, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_SYNC GPIO_CFG(78, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+
+static const struct msm_gpio tsif_gpios[] = {
+ { .gpio_cfg = TSIF_0_CLK, .label = "tsif0_clk", },
+ { .gpio_cfg = TSIF_0_EN, .label = "tsif0_en", },
+ { .gpio_cfg = TSIF_0_DATA, .label = "tsif0_data", },
+ { .gpio_cfg = TSIF_0_SYNC, .label = "tsif0_sync", },
+ { .gpio_cfg = TSIF_1_CLK, .label = "tsif1_clk", },
+ { .gpio_cfg = TSIF_1_EN, .label = "tsif1_en", },
+ { .gpio_cfg = TSIF_1_DATA, .label = "tsif1_data", },
+ { .gpio_cfg = TSIF_1_SYNC, .label = "tsif1_sync", },
+};
+
+static struct resource tspp_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ .start = TSIF_TSPP_IRQ,
+ .end = TSIF1_IRQ,
+ },
+ [1] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSIF0_PHYS,
+ .end = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
+ },
+ [2] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSIF1_PHYS,
+ .end = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
+ },
+ [3] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSPP_PHYS,
+ .end = MSM_TSPP_PHYS + MSM_TSPP_SIZE - 1,
+ },
+ [4] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSPP_BAM_PHYS,
+ .end = MSM_TSPP_BAM_PHYS + MSM_TSPP_BAM_SIZE - 1,
+ },
+};
+
+static struct msm_tspp_platform_data tspp_platform_data = {
+ .num_gpios = ARRAY_SIZE(tsif_gpios),
+ .gpios = tsif_gpios,
+ .tsif_pclk = "tsif_pclk",
+ .tsif_ref_clk = "tsif_ref_clk",
+};
+
+static struct platform_device msm_device_tspp = {
+ .name = "msm_tspp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(tspp_resources),
+ .resource = tspp_resources,
+ .dev = {
+ .platform_data = &tspp_platform_data
+ },
+};
+
#define MSM_SHARED_RAM_PHYS 0x80000000
static void __init msm8960_map_io(void)
@@ -2466,7 +2556,6 @@
&msm_device_vidc,
&msm_device_bam_dmux,
&msm_fm_platform_init,
-
#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
#ifdef CONFIG_MSM_USE_TSIF1
&msm_device_tsif[1],
@@ -2474,7 +2563,7 @@
&msm_device_tsif[0],
#endif
#endif
-
+ &msm_device_tspp,
#ifdef CONFIG_HW_RANDOM_MSM
&msm_device_rng,
#endif
@@ -2559,6 +2648,9 @@
#ifdef CONFIG_MSM_GEMINI
&msm8960_gemini_device,
#endif
+#ifdef CONFIG_MSM_MERCURY
+ &msm8960_mercury_device,
+#endif
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -2597,6 +2689,9 @@
#ifdef CONFIG_MSM_GEMINI
&msm8960_gemini_device,
#endif
+#ifdef CONFIG_MSM_MERCURY
+ &msm8960_mercury_device,
+#endif
&msm_voice,
&msm_voip,
&msm_lpa_pcm,
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index b771386..1122ed9 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -316,7 +316,7 @@
/* ID a_on pd ss min_uV max_uV supply sys_uA init_ip */
RPM_LDO(L2, 1, 1, 0, 1800000, 1800000, NULL, 0, 10000),
- RPM_LDO(L3, 0, 1, 0, 1800000, 1800000, NULL, 0, 0),
+ RPM_LDO(L3, 1, 1, 0, 1800000, 1800000, NULL, 0, 0),
RPM_LDO(L4, 0, 1, 0, 3075000, 3075000, NULL, 0, 0),
RPM_LDO(L5, 0, 1, 0, 2850000, 2850000, NULL, 0, 0),
RPM_LDO(L6, 0, 1, 0, 1800000, 2850000, NULL, 0, 0),
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index bada29c..dc376b5 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -900,6 +900,8 @@
&msm_pcm_afe,
&msm_cpudai_auxpcm_rx,
&msm_cpudai_auxpcm_tx,
+ &msm_cpudai_sec_auxpcm_rx,
+ &msm_cpudai_sec_auxpcm_tx,
#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 94d2543..2afefa6 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -497,6 +497,8 @@
"msm_sdcc.4", NULL),
OF_DEV_AUXDATA("qcom,pil-q6v5-lpass", 0xFE200000, \
"pil-q6v5-lpass", NULL),
+ OF_DEV_AUXDATA("qcom,pil-q6v5-mss", 0xFC880000, "pil-q6v5-mss", NULL),
+ OF_DEV_AUXDATA("qcom,pil-mba", 0xFC820000, "pil-mba", NULL),
OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
"pil_pronto", NULL),
OF_DEV_AUXDATA("qcom,msm-rng", 0xF9BFF000, \
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 8abcef0..7ac0c9a 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -95,15 +95,31 @@
#define MSM_PMEM_SF_SIZE 0x1700000
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
-#define MSM_FB_SIZE 0x780000
+#define MSM_FB_PRIM_BUF_SIZE (864 * 480 * 4 * 3) /* 4bpp * 3 Pages */
#else
-#define MSM_FB_SIZE 0x500000
+#define MSM_FB_PRIM_BUF_SIZE (864 * 480 * 4 * 2) /* 4bpp * 2 Pages */
#endif
/*
* Reserve space for double buffered full screen
* res V4L2 video overlay - i.e. 1280x720x1.5x2
*/
#define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 2764800
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+#define MSM_FB_EXT_BUF_SIZE (1280 * 720 * 2 * 1) /* 2 bpp x 1 page */
+#else
+#define MSM_FB_EXT_BUF_SIZE 0
+#endif
+
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+/* width x height x 3 bpp x 2 frame buffer */
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((864 * 480 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE 0
+#endif
+
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
+
#define MSM_PMEM_ADSP_SIZE 0x1E00000
#define MSM_FLUID_PMEM_ADSP_SIZE 0x2800000
#define PMEM_KERNEL_EBI0_SIZE 0x600000
@@ -4533,6 +4549,7 @@
.mdp_core_clk_table = mdp_core_clk_rate_table,
.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
.mdp_rev = MDP_REV_40,
+ .mem_hid = MEMTYPE_EBI0,
};
static int lcd_panel_spi_gpio_num[] = {
@@ -7095,7 +7112,7 @@
}
early_param("pmem_sf_size", pmem_sf_size_setup);
-static unsigned fb_size = MSM_FB_SIZE;
+static unsigned fb_size;
static int __init fb_size_setup(char *p)
{
fb_size = memparse(p, NULL);
@@ -7176,10 +7193,17 @@
#endif
}
+static void __init reserve_mdp_memory(void)
+{
+ mdp_pdata.ov0_wb_size = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
+ msm7x30_reserve_table[mdp_pdata.mem_hid].size += mdp_pdata.ov0_wb_size;
+}
+
static void __init msm7x30_calculate_reserve_sizes(void)
{
size_pmem_devices();
reserve_pmem_memory();
+ reserve_mdp_memory();
}
static int msm7x30_paddr_to_memtype(unsigned int paddr)
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 57f2077..73a900c 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2650,11 +2650,19 @@
#define USER_SMI_SIZE (MSM_SMI_SIZE - KERNEL_SMI_SIZE)
#define MSM_PMEM_SMIPOOL_SIZE USER_SMI_SIZE
+#define MSM_ION_HOLE_SIZE SZ_128K /* (128KB) */
+#define MSM_MM_FW_SIZE (0x200000 - MSM_ION_HOLE_SIZE) /*(2MB-128KB)*/
+#define MSM_ION_MM_SIZE 0x3800000 /* (56MB) */
+#define MSM_ION_MFC_SIZE SZ_8K
+
+#define MSM_MM_FW_BASE MSM_SMI_BASE
+#define MSM_ION_HOLE_BASE (MSM_MM_FW_BASE + MSM_MM_FW_SIZE)
+#define MSM_ION_MM_BASE (MSM_ION_HOLE_BASE + MSM_ION_HOLE_SIZE)
+#define MSM_ION_MFC_BASE (MSM_ION_MM_BASE + MSM_ION_MM_SIZE)
+
#define MSM_ION_SF_SIZE 0x4000000 /* 64MB */
#define MSM_ION_CAMERA_SIZE MSM_PMEM_ADSP_SIZE
-#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
-#define MSM_ION_MM_SIZE 0x3c00000 /* (60MB) Must be a multiple of 64K */
-#define MSM_ION_MFC_SIZE SZ_8K
+
#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
#define MSM_ION_WB_SIZE 0xC00000 /* 12MB */
#else
@@ -5289,6 +5297,8 @@
.request_region = request_smi_region,
.release_region = release_smi_region,
.setup_region = setup_smi_region,
+ .secure_base = MSM_ION_HOLE_BASE,
+ .secure_size = MSM_ION_HOLE_SIZE + MSM_ION_MM_SIZE,
.iommu_map_all = 1,
.iommu_2x_map_domain = VIDEO_DOMAIN,
};
@@ -5306,9 +5316,8 @@
.align = PAGE_SIZE,
};
-static struct ion_co_heap_pdata fw_co_ion_pdata = {
+static struct ion_co_heap_pdata hole_co_ion_pdata = {
.adjacent_mem_id = ION_CP_MM_HEAP_ID,
- .align = SZ_128K,
};
static struct ion_co_heap_pdata co_ion_pdata = {
@@ -5341,6 +5350,7 @@
.id = ION_CP_MM_HEAP_ID,
.type = ION_HEAP_TYPE_CP,
.name = ION_MM_HEAP_NAME,
+ .base = MSM_ION_MM_BASE,
.size = MSM_ION_MM_SIZE,
.memory_type = ION_SMI_TYPE,
.extra_data = (void *) &cp_mm_ion_pdata,
@@ -5349,14 +5359,16 @@
.id = ION_MM_FIRMWARE_HEAP_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_MM_FIRMWARE_HEAP_NAME,
- .size = MSM_ION_MM_FW_SIZE,
+ .base = MSM_ION_HOLE_BASE,
+ .size = MSM_ION_HOLE_SIZE,
.memory_type = ION_SMI_TYPE,
- .extra_data = (void *) &fw_co_ion_pdata,
+ .extra_data = (void *) &hole_co_ion_pdata,
},
{
.id = ION_CP_MFC_HEAP_ID,
.type = ION_HEAP_TYPE_CP,
.name = ION_MFC_HEAP_NAME,
+ .base = MSM_ION_MFC_BASE,
.size = MSM_ION_MFC_SIZE,
.memory_type = ION_SMI_TYPE,
.extra_data = (void *) &cp_mfc_ion_pdata,
@@ -5425,12 +5437,7 @@
.size = KERNEL_SMI_SIZE,
.flags = MEMTYPE_FLAGS_FIXED,
},
- /* User space SMI memory pool for video core */
- /* used for encoder, decoder input & output buffers */
[MEMTYPE_SMI] = {
- .start = USER_SMI_BASE,
- .limit = USER_SMI_SIZE,
- .flags = MEMTYPE_FLAGS_FIXED,
},
[MEMTYPE_EBI0] = {
.flags = MEMTYPE_FLAGS_1M_ALIGN,
@@ -5475,9 +5482,6 @@
}
msm8x60_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;
- msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_FW_SIZE;
- msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_SIZE;
- msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MFC_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_WB_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 7708310..761a3c9 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -32,6 +32,7 @@
#include <linux/input/ft5x06_ts.h>
#include <linux/msm_adc.h>
#include <linux/fmem.h>
+#include <linux/regulator/msm-gpio-regulator.h>
#include <asm/mach/mmc.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -631,6 +632,62 @@
.dev = { .platform_data = &fmem_pdata },
};
+#define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio, _active_low) \
+ [GPIO_VREG_ID_##_id] = { \
+ .init_data = { \
+ .constraints = { \
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS, \
+ }, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(vreg_consumers_##_id), \
+ .consumer_supplies = vreg_consumers_##_id, \
+ }, \
+ .regulator_name = _reg_name, \
+ .active_low = _active_low, \
+ .gpio_label = _gpio_label, \
+ .gpio = _gpio, \
+ }
+
+#define GPIO_VREG_ID_EXT_2P85V 0
+#define GPIO_VREG_ID_EXT_1P8V 1
+
+static struct regulator_consumer_supply vreg_consumers_EXT_2P85V[] = {
+ REGULATOR_SUPPLY("cam0_avdd", "0-006c"),
+ REGULATOR_SUPPLY("cam1_avdd", "0-0078"),
+ REGULATOR_SUPPLY("lcd_vdd", "mipi_dsi.1"),
+};
+
+static struct regulator_consumer_supply vreg_consumers_EXT_1P8V[] = {
+ REGULATOR_SUPPLY("cam0_vdd", "0-006c"),
+ REGULATOR_SUPPLY("cam1_vdd", "0-0078"),
+ REGULATOR_SUPPLY("lcd_vddi", "mipi_dsi.1"),
+};
+
+/* GPIO regulator constraints */
+static struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] = {
+ GPIO_VREG_INIT(EXT_2P85V, "ext_2p85v", "ext_2p85v_en", 35, 0),
+ GPIO_VREG_INIT(EXT_1P8V, "ext_1p8v", "ext_1p8v_en", 40, 0),
+};
+
+/* GPIO regulator */
+static struct platform_device qrd_msm8625_vreg_gpio_ext_2p85v __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 35,
+ .dev = {
+ .platform_data =
+ &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_2P85V],
+ },
+};
+
+static struct platform_device qrd_msm8625_vreg_gpio_ext_1p8v __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 40,
+ .dev = {
+ .platform_data =
+ &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_1P8V],
+ },
+};
+
static struct platform_device *common_devices[] __initdata = {
&android_usb_device,
&android_pmem_device,
@@ -672,6 +729,8 @@
&msm8625_device_otg,
&msm8625_device_gadget_peripheral,
&msm8625_kgsl_3d0,
+ &qrd_msm8625_vreg_gpio_ext_2p85v,
+ &qrd_msm8625_vreg_gpio_ext_1p8v,
};
static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
index 97225ac..4d7ce12 100644
--- a/arch/arm/mach-msm/cache_erp.c
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -35,6 +35,9 @@
/* Print a message for everything but TLB MH events */
#define CESR_PRINT_MASK 0x000000FF
+/* Log everything but TLB MH events */
+#define CESR_LOG_EVENT_MASK 0x000000FF
+
#define L2ESR_IND_ADDR 0x204
#define L2ESYNR0_IND_ADDR 0x208
#define L2ESYNR1_IND_ADDR 0x209
@@ -87,6 +90,9 @@
#define MODULE_NAME "msm_cache_erp"
+#define ERP_LOG_MAGIC_ADDR 0x748
+#define ERP_LOG_MAGIC 0x11C39893
+
struct msm_l1_err_stats {
unsigned int dctpe;
unsigned int dcdpe;
@@ -114,6 +120,10 @@
static int l1_erp_irq, l2_erp_irq;
static struct proc_dir_entry *procfs_entry;
+#ifdef CONFIG_MSM_L1_ERR_LOG
+static struct proc_dir_entry *procfs_log_entry;
+#endif
+
static inline unsigned int read_cesr(void)
{
unsigned int cesr;
@@ -192,6 +202,48 @@
return len;
}
+#ifdef CONFIG_MSM_L1_ERR_LOG
+static int proc_read_log(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ char *p = page;
+ int len, log_value;
+ log_value = __raw_readl(MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR) ==
+ ERP_LOG_MAGIC ? 1 : 0;
+
+ p += snprintf(p, PAGE_SIZE, "%d\n", log_value);
+
+ len = (p - page) - off;
+ if (len < 0)
+ len = 0;
+
+ *eof = (len <= count) ? 1 : 0;
+ *start = page + off;
+
+ return len;
+}
+
+static void log_cpu_event(void)
+{
+ __raw_writel(ERP_LOG_MAGIC, MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR);
+ mb();
+}
+
+static int procfs_event_log_init(void)
+{
+ procfs_log_entry = create_proc_entry("cpu/msm_erp_log", S_IRUGO, NULL);
+
+ if (!procfs_log_entry)
+ return -ENODEV;
+ procfs_log_entry->read_proc = proc_read_log;
+ return 0;
+}
+
+#else
+static inline void log_cpu_event(void) { }
+static inline int procfs_event_log_init(void) { return 0; }
+#endif
+
static irqreturn_t msm_l1_erp_irq(int irq, void *dev_id)
{
struct msm_l1_err_stats *l1_stats = dev_id;
@@ -199,6 +251,7 @@
unsigned int i_cesynr, d_cesynr;
unsigned int cpu = smp_processor_id();
int print_regs = cesr & CESR_PRINT_MASK;
+ int log_event = cesr & CESR_LOG_EVENT_MASK;
void *const saw_bases[] = {
MSM_SAW0_BASE,
@@ -271,6 +324,9 @@
pr_alert("D-side CESYNR = 0x%08x\n", d_cesynr);
}
+ if (log_event)
+ log_cpu_event();
+
/* Clear the interrupt bits we processed */
write_cesr(cesr);
@@ -459,6 +515,11 @@
put_online_cpus();
procfs_entry->read_proc = proc_read_status;
+
+ ret = procfs_event_log_init();
+ if (ret)
+ pr_err("Failed to create procfs node for ERP log access\n");
+
return 0;
fail_l2:
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 7b4ca29..c4ada1e 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -4605,6 +4605,11 @@
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_acpu_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_msmbus_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_acpu_a_clk, &afab_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_msmbus_a_clk, &afab_a_clk.c, LONG_MAX);
+
#ifdef CONFIG_DEBUG_FS
struct measure_sel {
u32 test_vector;
@@ -5030,8 +5035,25 @@
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("bus_clk", afab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_a_clk.c, ""),
+
CLK_LOOKUP("bus_clk", afab_clk.c, "msm_apps_fab"),
- CLK_LOOKUP("bus_a_clk", afab_a_clk.c, "msm_apps_fab"),
+ CLK_LOOKUP("bus_a_clk", afab_msmbus_a_clk.c, "msm_apps_fab"),
CLK_LOOKUP("bus_clk", cfpb_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
@@ -5041,7 +5063,7 @@
CLK_LOOKUP("bus_clk", mmfab_clk.c, "msm_mm_fab"),
CLK_LOOKUP("bus_a_clk", mmfab_a_clk.c, "msm_mm_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
- CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
@@ -5313,6 +5335,8 @@
CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c, "pil_vidc"),
CLK_LOOKUP("mem_clk", ebi1_adm_clk.c, "msm_dmov"),
+ CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
CLK_LOOKUP("l2_mclk", l2_m_clk, ""),
CLK_LOOKUP("krait0_mclk", krait0_m_clk, ""),
@@ -5336,8 +5360,25 @@
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("bus_clk", afab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_a_clk.c, ""),
+
CLK_LOOKUP("bus_clk", afab_clk.c, "msm_apps_fab"),
- CLK_LOOKUP("bus_a_clk", afab_a_clk.c, "msm_apps_fab"),
+ CLK_LOOKUP("bus_a_clk", afab_msmbus_a_clk.c, "msm_apps_fab"),
CLK_LOOKUP("bus_clk", cfpb_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
@@ -5347,7 +5388,7 @@
CLK_LOOKUP("bus_clk", mmfab_clk.c, "msm_mm_fab"),
CLK_LOOKUP("bus_a_clk", mmfab_a_clk.c, "msm_mm_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
- CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
@@ -5486,7 +5527,8 @@
CLK_LOOKUP("mem_clk", imem_axi_clk.c, "msm_gemini.0"),
CLK_LOOKUP("core_clk", ijpeg_clk.c, "msm_gemini.0"),
CLK_LOOKUP("core_clk", ijpeg_clk.c, "footswitch-8x60.3"),
- CLK_LOOKUP("core_clk", jpegd_clk.c, ""),
+ CLK_LOOKUP("core_clk", jpegd_clk.c, "msm_mercury.0"),
+ CLK_LOOKUP("iface_clk", jpegd_p_clk.c, "msm_mercury.0"),
CLK_LOOKUP("core_clk", mdp_clk.c, "mdp.0"),
CLK_LOOKUP("core_clk", mdp_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("vsync_clk", mdp_vsync_clk.c, "mdp.0"),
@@ -5611,6 +5653,8 @@
CLK_LOOKUP("bus_clk", dfab_tzcom_clk.c, "tzcom"),
CLK_LOOKUP("mem_clk", ebi1_adm_clk.c, "msm_dmov"),
+ CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
CLK_LOOKUP("l2_mclk", l2_m_clk, ""),
CLK_LOOKUP("krait0_mclk", krait0_m_clk, ""),
@@ -5633,8 +5677,25 @@
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("bus_clk", afab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_a_clk.c, ""),
+
CLK_LOOKUP("bus_clk", afab_clk.c, "msm_apps_fab"),
- CLK_LOOKUP("bus_a_clk", afab_a_clk.c, "msm_apps_fab"),
+ CLK_LOOKUP("bus_a_clk", afab_msmbus_a_clk.c, "msm_apps_fab"),
CLK_LOOKUP("bus_clk", cfpb_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
@@ -5644,7 +5705,7 @@
CLK_LOOKUP("bus_clk", mmfab_clk.c, "msm_mm_fab"),
CLK_LOOKUP("bus_a_clk", mmfab_a_clk.c, "msm_mm_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
- CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
@@ -5885,6 +5946,8 @@
CLK_LOOKUP("bus_clk", dfab_qseecom_clk.c, "qseecom"),
CLK_LOOKUP("mem_clk", ebi1_adm_clk.c, "msm_dmov"),
+ CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
CLK_LOOKUP("l2_mclk", l2_m_clk, ""),
CLK_LOOKUP("krait0_mclk", krait0_m_clk, ""),
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 7aed579..975587d 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3117,6 +3117,11 @@
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ebi1_adm0_clk, &ebi1_clk.c, 0);
static DEFINE_CLK_VOTER(ebi1_adm1_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_acpu_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_msmbus_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_acpu_a_clk, &afab_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_msmbus_a_clk, &afab_a_clk.c, LONG_MAX);
+
static DEFINE_CLK_MEASURE(sc0_m_clk);
static DEFINE_CLK_MEASURE(sc1_m_clk);
static DEFINE_CLK_MEASURE(l2_m_clk);
@@ -3479,8 +3484,27 @@
CLK_LOOKUP("pll4", pll4_clk.c, "pil_qdsp6v3"),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("bus_clk", afab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", smi_clk.c, ""),
+ CLK_LOOKUP("mem_clk", smi_a_clk.c, ""),
+
CLK_LOOKUP("bus_clk", afab_clk.c, "msm_apps_fab"),
- CLK_LOOKUP("bus_a_clk", afab_a_clk.c, "msm_apps_fab"),
+ CLK_LOOKUP("bus_a_clk", afab_msmbus_a_clk.c, "msm_apps_fab"),
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
CLK_LOOKUP("bus_a_clk", sfab_a_clk.c, "msm_sys_fab"),
CLK_LOOKUP("bus_clk", sfpb_clk.c, "msm_sys_fpb"),
@@ -3490,16 +3514,10 @@
CLK_LOOKUP("bus_clk", cfpb_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
- CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("smi_clk", smi_clk.c, "msm_bus"),
CLK_LOOKUP("smi_a_clk", smi_a_clk.c, "msm_bus"),
- CLK_LOOKUP("ebi1_clk", ebi1_clk.c, NULL),
- CLK_LOOKUP("dfab_clk", dfab_clk.c, NULL),
- CLK_LOOKUP("dfab_a_clk", dfab_a_clk.c, NULL),
- CLK_LOOKUP("mmfpb_clk", mmfpb_clk.c, NULL),
- CLK_LOOKUP("mmfpb_a_clk", mmfpb_a_clk.c, NULL),
-
CLK_LOOKUP("core_clk", gp0_clk.c, ""),
CLK_LOOKUP("core_clk", gp1_clk.c, ""),
CLK_LOOKUP("core_clk", gp2_clk.c, ""),
@@ -3713,6 +3731,8 @@
CLK_LOOKUP("mem_clk", ebi1_adm0_clk.c, "msm_dmov.0"),
CLK_LOOKUP("mem_clk", ebi1_adm1_clk.c, "msm_dmov.1"),
+ CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
CLK_LOOKUP("sc0_mclk", sc0_m_clk, ""),
CLK_LOOKUP("sc1_mclk", sc1_m_clk, ""),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 66d849a..834deb6 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -135,6 +135,9 @@
#define LCC_PCM_MD_REG REG_LPA(0x0058)
#define LCC_PCM_NS_REG REG_LPA(0x0054)
#define LCC_PCM_STATUS_REG REG_LPA(0x005C)
+#define LCC_SEC_PCM_MD_REG REG_LPA(0x00F4)
+#define LCC_SEC_PCM_NS_REG REG_LPA(0x00F0)
+#define LCC_SEC_PCM_STATUS_REG REG_LPA(0x00F8)
#define LCC_PLL0_STATUS_REG REG_LPA(0x0018)
#define LCC_SPARE_I2S_MIC_MD_REG REG_LPA(0x007C)
#define LCC_SPARE_I2S_MIC_NS_REG REG_LPA(0x0078)
@@ -1267,6 +1270,32 @@
},
};
+static struct rcg_clk sec_pcm_clk = {
+ .b = {
+ .ctl_reg = LCC_SEC_PCM_NS_REG,
+ .en_mask = BIT(11),
+ .reset_reg = LCC_SEC_PCM_NS_REG,
+ .reset_mask = BIT(13),
+ .halt_reg = LCC_SEC_PCM_STATUS_REG,
+ .halt_check = ENABLE,
+ .halt_bit = 0,
+ },
+ .ns_reg = LCC_SEC_PCM_NS_REG,
+ .md_reg = LCC_SEC_PCM_MD_REG,
+ .root_en_mask = BIT(9),
+ .ns_mask = BM(31, 16) | BIT(10) | BM(6, 0),
+ .mnd_en_mask = BIT(8),
+ .set_rate = set_rate_mnd,
+ .freq_tbl = clk_tbl_pcm,
+ .current_freq = &rcg_dummy_freq,
+ .c = {
+ .dbg_name = "sec_pcm_clk",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 24576000),
+ CLK_INIT(sec_pcm_clk.c),
+ },
+};
+
static struct rcg_clk audio_slimbus_clk = {
.b = {
.ctl_reg = LCC_SLIMBUS_NS_REG,
@@ -1338,7 +1367,11 @@
static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c, 0);
static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c, 0);
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_msmbus_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_acpu_a_clk, &ebi1_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(sfab_msmbus_a_clk, &sfab_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(sfab_acpu_a_clk, &sfab_a_clk.c, LONG_MAX);
#ifdef CONFIG_DEBUG_FS
struct measure_sel {
@@ -1588,19 +1621,24 @@
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("bus_clk", cfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_a_clk.c, ""),
+
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
- CLK_LOOKUP("bus_a_clk", sfab_a_clk.c, "msm_sys_fab"),
+ CLK_LOOKUP("bus_a_clk", sfab_msmbus_a_clk.c, "msm_sys_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
- CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
- CLK_LOOKUP("bus_clk", sfpb_clk.c, NULL),
- CLK_LOOKUP("bus_a_clk", sfpb_a_clk.c, NULL),
- CLK_LOOKUP("bus_clk", cfpb_clk.c, NULL),
- CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, NULL),
- CLK_LOOKUP("ebi1_clk", ebi1_clk.c, NULL),
-
CLK_LOOKUP("core_clk", gp0_clk.c, ""),
CLK_LOOKUP("core_clk", gp1_clk.c, ""),
CLK_LOOKUP("core_clk", gp2_clk.c, ""),
@@ -1673,6 +1711,8 @@
"msm-dai-q6.4"),
CLK_LOOKUP("pcm_clk", pcm_clk.c, "msm-dai-q6.2"),
CLK_LOOKUP("pcm_clk", pcm_clk.c, "msm-dai-q6.3"),
+ CLK_LOOKUP("sec_pcm_clk", sec_pcm_clk.c, "msm-dai-q6.12"),
+ CLK_LOOKUP("sec_pcm_clk", sec_pcm_clk.c, "msm-dai-q6.13"),
CLK_LOOKUP("sps_slimbus_clk", sps_slimbus_clk.c, NULL),
CLK_LOOKUP("core_clk", audio_slimbus_clk.c, "msm_slim_ctrl.1"),
@@ -1682,6 +1722,8 @@
CLK_LOOKUP("dfab_clk", dfab_sps_clk.c, "msm_sps"),
CLK_LOOKUP("bus_clk", dfab_bam_dmux_clk.c, "BAM_RMNT"),
CLK_LOOKUP("mem_clk", ebi1_adm_clk.c, "msm_dmov"),
+ CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_acpu_a_clk.c, ""),
CLK_LOOKUP("iface_clk", ce1_p_clk.c, "qce.0"),
CLK_LOOKUP("iface_clk", ce1_p_clk.c, "qcrypto.0"),
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index dd7967d..778301b 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -4577,6 +4577,8 @@
static struct clk_lookup msm_clocks_copper[] = {
CLK_LOOKUP("xo", cxo_clk_src.c, "msm_otg"),
CLK_LOOKUP("xo", cxo_clk_src.c, "pil-q6v5-lpass"),
+ CLK_LOOKUP("xo", cxo_clk_src.c, "pil-q6v5-mss"),
+ CLK_LOOKUP("xo", cxo_clk_src.c, "pil-mba"),
CLK_LOOKUP("xo", cxo_clk_src.c, "pil_pronto"),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
@@ -4773,12 +4775,12 @@
CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", mss_xo_q6_clk.c, ""),
- CLK_LOOKUP("bus_clk", mss_bus_q6_clk.c, ""),
+ CLK_LOOKUP("core_clk", mss_xo_q6_clk.c, "pil-q6v5-mss"),
+ CLK_LOOKUP("bus_clk", mss_bus_q6_clk.c, "pil-q6v5-mss"),
+ CLK_LOOKUP("bus_clk", gcc_mss_cfg_ahb_clk.c, ""),
+ CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "pil-q6v5-mss"),
CLK_LOOKUP("core_clk", q6ss_xo_clk.c, "pil-q6v5-lpass"),
CLK_LOOKUP("bus_clk", q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
- CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
- CLK_LOOKUP("bus_clk", gcc_mss_cfg_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
/* TODO: Remove dummy clocks as soon as they become unnecessary */
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 6401722..b9617f3 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -623,6 +623,11 @@
.id = 0x4006,
};
+struct platform_device apq_cpudai_slimbus_3_tx = {
+ .name = "msm-dai-q6",
+ .id = 0x4007,
+};
+
static struct resource resources_ssbi_pmic1[] = {
{
.start = MSM_PMIC1_SSBI_CMD_PHYS,
@@ -1668,6 +1673,21 @@
.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
};
+static struct fs_driver_data mdp_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { .name = "vsync_clk" },
+ { .name = "lut_clk" },
+ { .name = "tv_src_clk" },
+ { .name = "tv_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
+ .bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
+};
+
static struct fs_driver_data rot_fs_data = {
.clks = (struct fs_clk_data[]){
{ .name = "core_clk" },
@@ -1720,6 +1740,7 @@
};
struct platform_device *apq8064_footswitch[] __initdata = {
+ FS_8X60(FS_MDP, "vdd", "mdp.0", &mdp_fs_data),
FS_8X60(FS_ROT, "vdd", "msm_rotator.0", &rot_fs_data),
FS_8X60(FS_IJPEG, "vdd", "msm_gemini.0", &ijpeg_fs_data),
FS_8X60(FS_VFE, "fs_vfe", NULL, &vfe_fs_data),
@@ -2023,6 +2044,16 @@
/* Sensors DSPS platform data */
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
+#define PPSS_DSPS_PIPE_BASE 0x12800000
+#define PPSS_DSPS_PIPE_SIZE 0x4000
+#define PPSS_DSPS_DDR_BASE 0x8fe00000
+#define PPSS_DSPS_DDR_SIZE 0x100000
+#define PPSS_SMEM_BASE 0x80000000
+#define PPSS_SMEM_SIZE 0x200000
#define PPSS_REG_PHYS_BASE 0x12080000
static struct dsps_clk_info dsps_clks[] = {};
@@ -2041,6 +2072,16 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.dsps_pwr_ctl_en = 1,
+ .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
+ .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
+ .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
+ .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
+ .pipe_start = PPSS_DSPS_PIPE_BASE,
+ .pipe_size = PPSS_DSPS_PIPE_SIZE,
+ .ddr_start = PPSS_DSPS_DDR_BASE,
+ .ddr_size = PPSS_DSPS_DDR_SIZE,
+ .smem_start = PPSS_SMEM_BASE,
+ .smem_size = PPSS_SMEM_SIZE,
.signature = DSPS_SIGNATURE,
};
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 14ddd96..db55d14 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -577,6 +577,58 @@
.ib = 10000000,
},
};
+static struct msm_bus_vectors vidc_venc_1080p_turbo_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 222298112,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 330301440,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 700000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 10000000,
+ },
+};
+static struct msm_bus_vectors vidc_vdec_1080p_turbo_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 222298112,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 330301440,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 700000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 10000000,
+ },
+};
static struct msm_bus_paths vidc_bus_client_config[] = {
{
@@ -607,6 +659,14 @@
ARRAY_SIZE(vidc_vdec_1080p_vectors),
vidc_vdec_1080p_vectors,
},
+ {
+ ARRAY_SIZE(vidc_venc_1080p_turbo_vectors),
+ vidc_vdec_1080p_turbo_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_vdec_1080p_turbo_vectors),
+ vidc_vdec_1080p_turbo_vectors,
+ },
};
static struct msm_bus_scale_pdata vidc_bus_client_data = {
@@ -2944,6 +3004,27 @@
};
#endif
+#ifdef CONFIG_MSM_MERCURY
+static struct resource msm_mercury_resources[] = {
+ {
+ .start = 0x05000000,
+ .end = 0x05000000 + SZ_1M - 1,
+ .name = "mercury_resource_base",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = JPEGD_IRQ,
+ .end = JPEGD_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+struct platform_device msm8960_mercury_device = {
+ .name = "msm_mercury",
+ .resource = msm_mercury_resources,
+ .num_resources = ARRAY_SIZE(msm_mercury_resources),
+};
+#endif
+
struct msm_rpm_platform_data msm8960_rpm_data __initdata = {
.reg_base_addrs = {
[MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
@@ -3251,6 +3332,16 @@
/* Sensors DSPS platform data */
#ifdef CONFIG_MSM_DSPS
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
+#define PPSS_DSPS_PIPE_BASE 0x12800000
+#define PPSS_DSPS_PIPE_SIZE 0x4000
+#define PPSS_DSPS_DDR_BASE 0x8fe00000
+#define PPSS_DSPS_DDR_SIZE 0x100000
+#define PPSS_SMEM_BASE 0x80000000
+#define PPSS_SMEM_SIZE 0x200000
#define PPSS_REG_PHYS_BASE 0x12080000
static struct dsps_clk_info dsps_clks[] = {};
@@ -3269,6 +3360,16 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.dsps_pwr_ctl_en = 1,
+ .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
+ .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
+ .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
+ .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
+ .pipe_start = PPSS_DSPS_PIPE_BASE,
+ .pipe_size = PPSS_DSPS_PIPE_SIZE,
+ .ddr_start = PPSS_DSPS_DDR_BASE,
+ .ddr_size = PPSS_DSPS_DDR_SIZE,
+ .smem_start = PPSS_SMEM_BASE,
+ .smem_size = PPSS_SMEM_SIZE,
.signature = DSPS_SIGNATURE,
};
@@ -3279,7 +3380,6 @@
.name = "ppss_reg",
.flags = IORESOURCE_MEM,
},
-
{
.start = PPSS_WDOG_TIMER_IRQ,
.end = PPSS_WDOG_TIMER_IRQ,
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 85d00eb..4677a1c 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -492,6 +492,44 @@
},
};
+struct msm_dai_auxpcm_pdata sec_auxpcm_pdata = {
+ .clk = "sec_pcm_clk",
+ .mode_8k = {
+ .mode = AFE_PCM_CFG_MODE_PCM,
+ .sync = AFE_PCM_CFG_SYNC_INT,
+ .frame = AFE_PCM_CFG_FRM_256BPF,
+ .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+ .slot = 0,
+ .data = AFE_PCM_CFG_CDATAOE_MASTER,
+ .pcm_clk_rate = 2048000,
+ },
+ .mode_16k = {
+ .mode = AFE_PCM_CFG_MODE_PCM,
+ .sync = AFE_PCM_CFG_SYNC_INT,
+ .frame = AFE_PCM_CFG_FRM_256BPF,
+ .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+ .slot = 0,
+ .data = AFE_PCM_CFG_CDATAOE_MASTER,
+ .pcm_clk_rate = 4096000,
+ }
+};
+
+struct platform_device msm_cpudai_sec_auxpcm_rx = {
+ .name = "msm-dai-q6",
+ .id = 12,
+ .dev = {
+ .platform_data = &sec_auxpcm_pdata,
+ },
+};
+
+struct platform_device msm_cpudai_sec_auxpcm_tx = {
+ .name = "msm-dai-q6",
+ .id = 13,
+ .dev = {
+ .platform_data = &sec_auxpcm_pdata,
+ },
+};
+
struct platform_device msm_cpu_fe = {
.name = "msm-dai-fe",
.id = -1,
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index d622af2..37844c1 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1568,6 +1568,16 @@
/* Sensors DSPS platform data */
#ifdef CONFIG_MSM_DSPS
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
+#define PPSS_DSPS_PIPE_BASE 0x12800000
+#define PPSS_DSPS_PIPE_SIZE 0x0 /* 8660 V2 does not use PIPE memory */
+#define PPSS_DSPS_DDR_BASE 0x8fe00000
+#define PPSS_DSPS_DDR_SIZE 0x0 /* 8660 V2 does not use DDR memory */
+#define PPSS_SMEM_BASE 0x40000000
+#define PPSS_SMEM_SIZE 0x4000
#define PPSS_REG_PHYS_BASE 0x12080000
#define MHZ (1000*1000)
@@ -1631,6 +1641,16 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.init = dsps_init1,
+ .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
+ .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
+ .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
+ .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
+ .pipe_start = PPSS_DSPS_PIPE_BASE,
+ .pipe_size = PPSS_DSPS_PIPE_SIZE,
+ .ddr_start = PPSS_DSPS_DDR_BASE,
+ .ddr_size = PPSS_DSPS_DDR_SIZE,
+ .smem_start = PPSS_SMEM_BASE,
+ .smem_size = PPSS_SMEM_SIZE,
.signature = DSPS_SIGNATURE,
};
@@ -2266,7 +2286,8 @@
#endif
.disable_dmx = 0,
.disable_fullhd = 0,
- .cont_mode_dpb_count = 8
+ .cont_mode_dpb_count = 8,
+ .disable_turbo = 1,
};
struct platform_device msm_device_vidc = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 0b59c00..f1d7aa0 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -65,6 +65,7 @@
extern struct platform_device msm8960_device_qup_i2c_gsbi12;
extern struct platform_device msm8960_device_qup_spi_gsbi1;
extern struct platform_device msm8960_gemini_device;
+extern struct platform_device msm8960_mercury_device;
extern struct platform_device msm8960_device_i2c_mux_gsbi4;
extern struct platform_device msm8960_device_csiphy0;
extern struct platform_device msm8960_device_csiphy1;
@@ -211,6 +212,8 @@
extern struct platform_device msm_cpudai_fm_tx;
extern struct platform_device msm_cpudai_auxpcm_rx;
extern struct platform_device msm_cpudai_auxpcm_tx;
+extern struct platform_device msm_cpudai_sec_auxpcm_rx;
+extern struct platform_device msm_cpudai_sec_auxpcm_tx;
extern struct platform_device msm_cpu_fe;
extern struct platform_device msm_stub_codec;
extern struct platform_device msm_voice;
@@ -271,6 +274,7 @@
extern struct platform_device apq_cpudai_slimbus_2_rx;
extern struct platform_device apq_cpudai_slimbus_2_tx;
extern struct platform_device apq_cpudai_slimbus_3_rx;
+extern struct platform_device apq_cpudai_slimbus_3_tx;
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/board.h b/arch/arm/mach-msm/include/mach/board.h
index 5e2eaf1..bae5cbc 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -524,6 +524,7 @@
struct msm_bus_scale_pdata *vidc_bus_client_pdata;
#endif
int cont_mode_dpb_count;
+ int disable_turbo;
};
struct vcap_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index fdf6786..d630799 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -41,7 +41,7 @@
#define NR_MSM_IRQS 288
#define NR_GPIO_IRQS 152
#define NR_PM8921_IRQS 256
-#define NR_PM8821_IRQS 64
+#define NR_PM8821_IRQS 112
#define NR_WCD9XXX_IRQS 49
#define NR_TABLA_IRQS NR_WCD9XXX_IRQS
#define NR_GPIO_EXPANDER_IRQS 64
diff --git a/arch/arm/mach-msm/include/mach/msm_dsps.h b/arch/arm/mach-msm/include/mach/msm_dsps.h
index cfb2024..32a4f15 100644
--- a/arch/arm/mach-msm/include/mach/msm_dsps.h
+++ b/arch/arm/mach-msm/include/mach/msm_dsps.h
@@ -75,6 +75,16 @@
* @regs_num - number of regulators.
* @dsps_pwr_ctl_en - to enable DSPS to do power control if set 1
* otherwise the apps will do power control
+ * @tcm_code_start - start of the TCM code region as physical address
+ * @tcm_code_size - size of the TCM code region in bytes
+ * @tcm_buf_start - start of the TCM buf region as physical address
+ * @tcm_buf_size - size of the TCM buf region in bytes
+ * @pipe_start - start of the PIPE region as physical address
+ * @pipe_size - size of the PIPE region in bytes
+ * @ddr_start - start of the DDR region as physical address
+ * @ddr_size - size of the DDR region in bytes
+ * @smem_start - start of the smem region as physical address
+ * @smem_size - size of the smem region in bytes
* @signature - signature for validity check.
*/
struct msm_dsps_platform_data {
@@ -87,6 +97,16 @@
int regs_num;
int dsps_pwr_ctl_en;
void (*init)(struct msm_dsps_platform_data *data);
+ int tcm_code_start;
+ int tcm_code_size;
+ int tcm_buf_start;
+ int tcm_buf_size;
+ int pipe_start;
+ int pipe_size;
+ int ddr_start;
+ int ddr_size;
+ int smem_start;
+ int smem_size;
u32 signature;
};
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index daf32a5..dd3a318 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -78,4 +78,8 @@
int free_head(struct ocmem_zone *, unsigned long, unsigned long);
unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
int free_tail(struct ocmem_zone *, unsigned long, unsigned long);
+
+int ocmem_notifier_init(void);
+int check_notifier(int);
+int dispatch_notification(int, enum ocmem_notif_type, struct ocmem_buf *);
#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index bd303b2..f747a80 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -68,12 +68,23 @@
#define USF_POINT_EPOS_FORMAT 0
#define USF_RAW_FORMAT 1
+/* Indexes of event types, produced by the calculators */
+#define USF_TSC_EVENT_IND 0
+#define USF_TSC_PTR_EVENT_IND 1
+#define USF_MOUSE_EVENT_IND 2
+#define USF_KEYBOARD_EVENT_IND 3
+#define USF_MAX_EVENT_IND 4
+
/* Types of events, produced by the calculators */
#define USF_NO_EVENT 0
-#define USF_TSC_EVENT 1
-#define USF_MOUSE_EVENT 2
-#define USF_KEYBOARD_EVENT 4
-#define USF_ALL_EVENTS (USF_TSC_EVENT | USF_MOUSE_EVENT | USF_KEYBOARD_EVENT)
+#define USF_TSC_EVENT (1 << USF_TSC_EVENT_IND)
+#define USF_TSC_PTR_EVENT (1 << USF_TSC_PTR_EVENT_IND)
+#define USF_MOUSE_EVENT (1 << USF_MOUSE_EVENT_IND)
+#define USF_KEYBOARD_EVENT (1 << USF_KEYBOARD_EVENT_IND)
+#define USF_ALL_EVENTS (USF_TSC_EVENT |\
+ USF_TSC_PTR_EVENT |\
+ USF_MOUSE_EVENT |\
+ USF_KEYBOARD_EVENT)
/* min, max array dimension */
#define MIN_MAX_DIM 2
@@ -152,9 +163,6 @@
/* Info specific for RX*/
};
-
-#define USF_PIX_COORDINATE 0 /* unit is pixel */
-#define USF_CMM_COORDINATE 1 /* unit is 0.01 mm */
struct point_event_type {
/* Pen coordinates (x, y, z) in units, defined by <coordinates_type> */
int coordinates[COORDINATES_DIM];
@@ -162,8 +170,6 @@
int inclinations[TILTS_DIM];
/* [0-1023] (10bits); 0 - pen up */
uint32_t pressure;
-/* 0 - mapped in the display pixel. 1 - raw in 0.01 mm (only for log); */
- uint8_t coordinates_type;
};
/* Mouse buttons, supported by USF */
@@ -189,8 +195,8 @@
uint32_t seq_num;
/* Event generation system time */
uint32_t timestamp;
-/* Destination input event type (e.g. touch screen, mouse, key) */
- uint16_t event_type;
+/* Destination input event type index (e.g. touch screen, mouse, key) */
+ uint16_t event_type_ind;
union {
struct point_event_type point_event;
struct mouse_event_type mouse_event;
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 4922007..5d02bda 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -63,6 +63,12 @@
wmb();
}
+static void restart_modem(void)
+{
+ log_modem_sfr();
+ subsystem_restart("modem");
+}
+
static void modem_wdog_check(struct work_struct *work)
{
void __iomem *q6_sw_wdog_addr;
@@ -75,8 +81,7 @@
regval = readl_relaxed(q6_sw_wdog_addr);
if (!regval) {
pr_err("modem-8960: Modem watchdog wasn't activated!. Restarting the modem now.\n");
- log_modem_sfr();
- subsystem_restart("modem");
+ restart_modem();
}
iounmap(q6_sw_wdog_addr);
@@ -84,47 +89,6 @@
static DECLARE_DELAYED_WORK(modem_wdog_check_work, modem_wdog_check);
-static void modem_sw_fatal_fn(struct work_struct *work)
-{
- uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
- uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
- SMSM_SYSTEM_PWRDWN_USR;
- uint32_t modem_state;
-
- pr_err("Watchdog bite received from modem SW!\n");
-
- modem_state = smsm_get_state(SMSM_MODEM_STATE);
-
- if (modem_state & panic_smsm_states) {
-
- pr_err("Modem SMSM state changed to SMSM_RESET.\n"
- "Probable err_fatal on the modem. "
- "Calling subsystem restart...\n");
- log_modem_sfr();
- subsystem_restart("modem");
-
- } else if (modem_state & reset_smsm_states) {
-
- pr_err("%s: User-invoked system reset/powerdown. "
- "Resetting the SoC now.\n",
- __func__);
- kernel_restart(NULL);
- } else {
- log_modem_sfr();
- subsystem_restart("modem");
- }
-}
-
-static void modem_fw_fatal_fn(struct work_struct *work)
-{
- pr_err("Watchdog bite received from modem FW!\n");
- log_modem_sfr();
- subsystem_restart("modem");
-}
-
-static DECLARE_WORK(modem_sw_fatal_work, modem_sw_fatal_fn);
-static DECLARE_WORK(modem_fw_fatal_work, modem_fw_fatal_fn);
-
static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
{
/* Ignore if we're the one that set SMSM_RESET */
@@ -133,8 +97,7 @@
if (new_state & SMSM_RESET) {
pr_err("Probable fatal error on the modem.\n");
- log_modem_sfr();
- subsystem_restart("modem");
+ restart_modem();
}
}
@@ -252,19 +215,15 @@
static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
{
- int ret;
-
switch (irq) {
case Q6SW_WDOG_EXPIRED_IRQ:
- ret = schedule_work(&modem_sw_fatal_work);
- disable_irq_nosync(Q6SW_WDOG_EXPIRED_IRQ);
- disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
+ pr_err("Watchdog bite received from modem software!\n");
+ restart_modem();
break;
case Q6FW_WDOG_EXPIRED_IRQ:
- ret = schedule_work(&modem_fw_fatal_work);
- disable_irq_nosync(Q6SW_WDOG_EXPIRED_IRQ);
- disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
+ pr_err("Watchdog bite received from modem firmware!\n");
+ restart_modem();
break;
break;
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 057665b..eda22e1 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -15,6 +15,8 @@
*
*/
+#include <asm/atomic.h>
+
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -39,10 +41,11 @@
#include <mach/subsystem_restart.h>
#include <mach/subsystem_notif.h>
+#include "ramdump.h"
#include "timer.h"
#define DRV_NAME "msm_dsps"
-#define DRV_VERSION "3.02"
+#define DRV_VERSION "4.01"
#define PPSS_PAUSE_REG 0x1804
@@ -58,8 +61,14 @@
* @cdev - character device for user interface.
* @pdata - platform data.
* @pil - handle to DSPS Firmware loader.
+ * @dspsfw_ramdump_dev - handle to ramdump device for DSPS
+ * @dspsfw_ramdump_segments - Ramdump segment information for DSPS
+ * @smem_ramdump_dev - handle to ramdump device for smem
+ * @smem_ramdump_segments - Ramdump segment information for smem
* @is_on - DSPS is on.
* @ref_count - open/close reference count.
+ * @wdog_irq - DSPS Watchdog IRQ
+ * @crash_in_progress - 1 if crash recovery is in progress
* @ppss_base - ppss registers virtual base address.
*/
struct dsps_drv {
@@ -73,9 +82,17 @@
void *pil;
+ void *dspsfw_ramdump_dev;
+ struct ramdump_segment dspsfw_ramdump_segments[4];
+
+ void *smem_ramdump_dev;
+ struct ramdump_segment smem_ramdump_segments[1];
+
int is_on;
int ref_count;
+ int wdog_irq;
+ atomic_t crash_in_progress;
void __iomem *ppss_base;
};
@@ -89,8 +106,7 @@
*/
static int dsps_crash_shutdown_g;
-
-static void dsps_fatal_handler(struct work_struct *work);
+static void dsps_restart_handler(void);
/**
* Load DSPS Firmware.
@@ -210,7 +226,7 @@
}
- ret = clk_enable(clock);
+ ret = clk_prepare_enable(clock);
if (ret) {
pr_err("%s: enable clk %s err %d.",
__func__, name, ret);
@@ -299,7 +315,7 @@
if (clock == NULL)
continue;
- clk_disable(clock);
+ clk_disable_unprepare(clock);
}
return -ENODEV;
@@ -329,7 +345,7 @@
const char *name = drv->pdata->clks[i].name;
pr_debug("%s: set clk %s off.", __func__, name);
- clk_disable(drv->pdata->clks[i].clock);
+ clk_disable_unprepare(drv->pdata->clks[i].clock);
}
for (i = 0; i < drv->pdata->regs_num; i++)
@@ -360,7 +376,28 @@
return 0;
}
-static DECLARE_WORK(dsps_fatal_work, dsps_fatal_handler);
+/**
+ *
+ * Log subsystem restart failure reason
+ */
+static void dsps_log_sfr(void)
+{
+ const char dflt_reason[] = "Died too early due to unknown reason";
+ char *smem_reset_reason;
+ unsigned smem_reset_size;
+
+ smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_DSPS0,
+ &smem_reset_size);
+ if (smem_reset_reason != NULL && smem_reset_reason[0] != 0) {
+ smem_reset_reason[smem_reset_size-1] = 0;
+ pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
+ __func__, smem_reset_reason);
+ memset(smem_reset_reason, 0, smem_reset_size);
+ wmb();
+ } else
+ pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
+ __func__, dflt_reason);
+}
/**
* Watchdog interrupt handler
@@ -368,9 +405,9 @@
*/
static irqreturn_t dsps_wdog_bite_irq(int irq, void *dev_id)
{
- pr_debug("%s\n", __func__);
- (void)schedule_work(&dsps_fatal_work);
- disable_irq_nosync(irq);
+ pr_err("%s\n", __func__);
+ dsps_log_sfr();
+ dsps_restart_handler();
return IRQ_HANDLED;
}
@@ -406,7 +443,9 @@
ret = put_user(val, (u32 __user *) arg);
break;
case DSPS_IOCTL_RESET:
- dsps_fatal_handler(NULL);
+ pr_err("%s: User-initiated DSPS reset.\nResetting DSPS\n",
+ __func__);
+ dsps_restart_handler();
ret = 0;
break;
default:
@@ -498,21 +537,52 @@
ppss_wdog = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
"ppss_wdog");
if (ppss_wdog) {
- ret = request_irq(ppss_wdog->start, dsps_wdog_bite_irq,
+ drv->wdog_irq = ppss_wdog->start;
+ ret = request_irq(drv->wdog_irq, dsps_wdog_bite_irq,
IRQF_TRIGGER_RISING, "dsps_wdog", NULL);
if (ret) {
pr_err("%s: request_irq fail %d\n", __func__, ret);
goto request_irq_err;
}
} else {
+ drv->wdog_irq = -1;
pr_debug("%s: ppss_wdog not supported.\n", __func__);
}
+ drv->dspsfw_ramdump_segments[0].address = drv->pdata->tcm_code_start;
+ drv->dspsfw_ramdump_segments[0].size = drv->pdata->tcm_code_size;
+ drv->dspsfw_ramdump_segments[1].address = drv->pdata->tcm_buf_start;
+ drv->dspsfw_ramdump_segments[1].size = drv->pdata->tcm_buf_size;
+ drv->dspsfw_ramdump_segments[2].address = drv->pdata->pipe_start;
+ drv->dspsfw_ramdump_segments[2].size = drv->pdata->pipe_size;
+ drv->dspsfw_ramdump_segments[3].address = drv->pdata->ddr_start;
+ drv->dspsfw_ramdump_segments[3].size = drv->pdata->ddr_size;
+
+ drv->dspsfw_ramdump_dev = create_ramdump_device("dsps");
+ if (!drv->dspsfw_ramdump_dev) {
+ pr_err("%s: create_ramdump_device(\"dsps\") fail\n",
+ __func__);
+ goto create_ramdump_err;
+ }
+
+ drv->smem_ramdump_segments[0].address = drv->pdata->smem_start;
+ drv->smem_ramdump_segments[0].size = drv->pdata->smem_size;
+ drv->smem_ramdump_dev = create_ramdump_device("smem");
+ if (!drv->smem_ramdump_dev) {
+ pr_err("%s: create_ramdump_device(\"smem\") fail\n",
+ __func__);
+ goto create_ramdump_err;
+ }
+
if (drv->pdata->init)
drv->pdata->init(drv->pdata);
return 0;
+create_ramdump_err:
+ disable_irq_nosync(drv->wdog_irq);
+ free_irq(drv->wdog_irq, NULL);
+
request_irq_err:
iounmap(drv->ppss_base);
@@ -600,6 +670,8 @@
}
}
+ free_irq(drv->wdog_irq, NULL);
+
iounmap(drv->ppss_base);
}
@@ -646,22 +718,16 @@
* Fatal error handler
* Resets DSPS.
*/
-static void dsps_fatal_handler(struct work_struct *work)
+static void dsps_restart_handler(void)
{
- uint32_t dsps_state;
+ pr_debug("%s: Restart lvl %d\n",
+ __func__, get_restart_level());
- dsps_state = smsm_get_state(SMSM_DSPS_STATE);
-
- pr_debug("%s: DSPS state 0x%x\n", __func__, dsps_state);
-
- if (dsps_state & SMSM_RESET) {
- pr_err("%s: DSPS fatal error detected. Resetting\n",
- __func__);
- panic("DSPS fatal error detected.");
+ if (atomic_add_return(1, &drv->crash_in_progress) > 1) {
+ pr_err("%s: DSPS already resetting. Count %d\n", __func__,
+ atomic_read(&drv->crash_in_progress));
} else {
- pr_debug("%s: User-initiated DSPS reset. Resetting\n",
- __func__);
- panic("User-initiated DSPS reset.");
+ subsystem_restart("dsps");
}
}
@@ -680,12 +746,9 @@
dsps_crash_shutdown_g = 0;
return;
}
-
if (new_state & SMSM_RESET) {
- pr_err
- ("%s: SMSM_RESET state detected. restarting the DSPS\n",
- __func__);
- panic("SMSM_RESET state detected.");
+ dsps_log_sfr();
+ dsps_restart_handler();
}
}
@@ -697,7 +760,10 @@
static int dsps_shutdown(const struct subsys_data *subsys)
{
pr_debug("%s\n", __func__);
- dsps_unload();
+ disable_irq_nosync(drv->wdog_irq);
+ dsps_suspend();
+ pil_force_shutdown(drv->pdata->pil_name);
+ dsps_power_off_handler();
return 0;
}
@@ -709,11 +775,11 @@
static int dsps_powerup(const struct subsys_data *subsys)
{
pr_debug("%s\n", __func__);
- if (dsps_load(drv->pdata->pil_name) != 0) {
- pr_err("%s: fail to restart DSPS after reboot\n",
- __func__);
- return 1;
- }
+ dsps_power_on_handler();
+ pil_force_boot(drv->pdata->pil_name);
+ atomic_set(&drv->crash_in_progress, 0);
+ enable_irq(drv->wdog_irq);
+ dsps_resume();
return 0;
}
@@ -736,8 +802,34 @@
*/
static int dsps_ramdump(int enable, const struct subsys_data *subsys)
{
+ int ret = 0;
pr_debug("%s\n", __func__);
- return 0;
+
+ if (enable) {
+ if (drv->dspsfw_ramdump_dev != NULL) {
+ ret = do_ramdump(drv->dspsfw_ramdump_dev,
+ drv->dspsfw_ramdump_segments,
+ ARRAY_SIZE(drv->dspsfw_ramdump_segments));
+ if (ret < 0) {
+ pr_err("%s: Unable to dump DSPS memory (rc = %d).\n",
+ __func__, ret);
+ goto dsps_ramdump_out;
+ }
+ }
+ if (drv->smem_ramdump_dev != NULL) {
+ ret = do_ramdump(drv->smem_ramdump_dev,
+ drv->smem_ramdump_segments,
+ ARRAY_SIZE(drv->smem_ramdump_segments));
+ if (ret < 0) {
+ pr_err("%s: Unable to dump smem memory (rc = %d).\n",
+ __func__, ret);
+ goto dsps_ramdump_out;
+ }
+ }
+ }
+
+dsps_ramdump_out:
+ return ret;
}
static struct subsys_data dsps_ssrops = {
@@ -768,6 +860,8 @@
pr_err("%s: kzalloc fail.\n", __func__);
goto alloc_err;
}
+ atomic_set(&drv->crash_in_progress, 0);
+
drv->pdata = pdev->dev.platform_data;
drv->dev_class = class_create(THIS_MODULE, DRV_NAME);
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index 2cff7f0..7ac3f74 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -247,29 +247,6 @@
schedule_delayed_work_on(0, &dogwork_struct, delay_time);
}
-static int msm_watchdog_remove(struct platform_device *pdev)
-{
- if (enable) {
- __raw_writel(0, msm_tmr0_base + WDT0_EN);
- mb();
- if (has_vic) {
- free_irq(WDT0_ACCSCSSNBARK_INT, 0);
- } else {
- disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
- if (!appsbark_fiq) {
- free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
- percpu_pdata);
- free_percpu(percpu_pdata);
- }
- }
- enable = 0;
- /* In case we got suspended mid-exit */
- __raw_writel(0, msm_tmr0_base + WDT0_EN);
- }
- printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n");
- return 0;
-}
-
static irqreturn_t wdog_bark_handler(int irq, void *dev_id)
{
unsigned long nanosec_rem;
@@ -445,7 +422,6 @@
static struct platform_driver msm_watchdog_driver = {
.probe = msm_watchdog_probe,
- .remove = msm_watchdog_remove,
.driver = {
.name = MODULE_NAME,
.owner = THIS_MODULE,
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 69e39df..ddfc906 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -273,6 +273,9 @@
if (ocmem_zone_init(pdev))
return -EBUSY;
+ if (ocmem_notifier_init())
+ return -EBUSY;
+
dev_info(dev, "initialized successfully\n");
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_notifier.c b/arch/arm/mach-msm/ocmem_notifier.c
new file mode 100644
index 0000000..58ad3d9
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_notifier.c
@@ -0,0 +1,137 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <mach/ocmem_priv.h>
+#include <linux/hardirq.h>
+
+static unsigned notifier_threshold;
+
+/* Protect the notifier structure below */
+DEFINE_MUTEX(nc_lock);
+
+struct ocmem_notifier {
+ int owner;
+ struct atomic_notifier_head nc;
+ unsigned listeners;
+} notifiers[OCMEM_CLIENT_MAX];
+
+static int check_id(int id)
+{
+ return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
+}
+
+int check_notifier(int id)
+{
+ int ret = 0;
+
+ if (!check_id(id))
+ return 0;
+
+ mutex_lock(&nc_lock);
+ ret = notifiers[id].listeners;
+ mutex_unlock(&nc_lock);
+ return ret;
+}
+
+int ocmem_notifier_init(void)
+{
+ int id;
+ /* Maximum notifiers for each subsystem */
+ notifier_threshold = 1;
+ mutex_lock(&nc_lock);
+ for (id = 0; id < OCMEM_CLIENT_MAX; id++) {
+ notifiers[id].owner = id;
+ ATOMIC_INIT_NOTIFIER_HEAD(¬ifiers[id].nc);
+ notifiers[id].listeners = 0;
+ }
+ mutex_unlock(&nc_lock);
+ return 0;
+}
+
+/* Broadcast a notification to listeners */
+int dispatch_notification(int id, enum ocmem_notif_type notif,
+ struct ocmem_buf *buf)
+{
+ int ret = 0;
+ struct ocmem_notifier *nc_hndl = NULL;
+ mutex_lock(&nc_lock);
+ nc_hndl = ¬ifiers[id];
+ if (nc_hndl->listeners == 0) {
+ /* Send an error so that the scheduler can clean up */
+ mutex_unlock(&nc_lock);
+ return -EINVAL;
+ }
+ ret = atomic_notifier_call_chain(¬ifiers[id].nc, notif, buf);
+ mutex_unlock(&nc_lock);
+ return ret;
+}
+
+void *ocmem_notifier_register(int client_id, struct notifier_block *nb)
+{
+
+ int ret = 0;
+ struct ocmem_notifier *nc_hndl = NULL;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid Client id\n");
+ return NULL;
+ }
+
+ if (!nb) {
+ pr_err("ocmem: Invalid Notifier Block\n");
+ return NULL;
+ }
+
+ mutex_lock(&nc_lock);
+
+ nc_hndl = ¬ifiers[client_id];
+
+ if (nc_hndl->listeners >= notifier_threshold) {
+ pr_err("ocmem: Max notifiers already registered\n");
+ mutex_unlock(&nc_lock);
+ return NULL;
+ }
+
+ ret = atomic_notifier_chain_register(&nc_hndl->nc, nb);
+
+ if (ret < 0) {
+ mutex_unlock(&nc_lock);
+ return NULL;
+ }
+
+ nc_hndl->listeners++;
+ pr_info("ocmem: Notifier registered for %d\n", client_id);
+ mutex_unlock(&nc_lock);
+ return nc_hndl;
+}
+EXPORT_SYMBOL(ocmem_notifier_register);
+
+int ocmem_notifier_unregister(void *hndl, struct notifier_block *nb)
+{
+
+ int ret = 0;
+
+ struct ocmem_notifier *nc_hndl = (struct ocmem_notifier *) hndl;
+
+ if (!nc_hndl) {
+ pr_err("ocmem: Invalid notification handle\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&nc_lock);
+ ret = atomic_notifier_chain_unregister(&nc_hndl->nc, nb);
+ nc_hndl->listeners--;
+ mutex_unlock(&nc_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(ocmem_notifier_unregister);
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
new file mode 100644
index 0000000..7405ab9
--- /dev/null
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+
+#include "peripheral-loader.h"
+
+#define RMB_MBA_COMMAND 0x08
+#define RMB_MBA_STATUS 0x0C
+#define RMB_PMI_META_DATA 0x10
+#define RMB_PMI_CODE_START 0x14
+#define RMB_PMI_CODE_LENGTH 0x18
+
+#define CMD_META_DATA_READY 0x1
+#define CMD_LOAD_READY 0x2
+
+#define STATUS_META_DATA_AUTH_SUCCESS 0x3
+#define STATUS_AUTH_COMPLETE 0x4
+#define STATUS_ERROR_MASK BIT(31)
+
+#define AUTH_TIMEOUT_US 10000000
+#define PROXY_TIMEOUT_MS 10000
+#define POLL_INTERVAL_US 50
+
+struct mba_data {
+ void __iomem *reg_base;
+ void __iomem *metadata_base;
+ unsigned long metadata_phys;
+ struct pil_device *pil;
+ struct clk *xo;
+ u32 img_length;
+};
+
+static int pil_mba_make_proxy_votes(struct pil_desc *pil)
+{
+ int ret;
+ struct mba_data *drv = dev_get_drvdata(pil->dev);
+
+ ret = clk_prepare_enable(drv->xo);
+ if (ret) {
+ dev_err(pil->dev, "Failed to enable XO\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void pil_mba_remove_proxy_votes(struct pil_desc *pil)
+{
+ struct mba_data *drv = dev_get_drvdata(pil->dev);
+ clk_disable_unprepare(drv->xo);
+}
+
+static int pil_mba_init_image(struct pil_desc *pil,
+ const u8 *metadata, size_t size)
+{
+ struct mba_data *drv = dev_get_drvdata(pil->dev);
+ u32 status;
+ int ret;
+
+ /* Copy metadata to assigned shared buffer location */
+ memcpy(drv->metadata_base, metadata, size);
+
+ /* Initialize length counter to 0 */
+ writel_relaxed(0, drv->reg_base + RMB_PMI_CODE_LENGTH);
+ drv->img_length = 0;
+
+ /* Pass address of meta-data to the MBA and perform authentication */
+ writel_relaxed(drv->metadata_phys, drv->reg_base + RMB_PMI_META_DATA);
+ writel_relaxed(CMD_META_DATA_READY, drv->reg_base + RMB_MBA_COMMAND);
+ ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
+ status == STATUS_META_DATA_AUTH_SUCCESS,
+ POLL_INTERVAL_US, AUTH_TIMEOUT_US);
+ if (ret)
+ dev_err(pil->dev, "MBA authentication timed out\n");
+
+ return ret;
+}
+
+static int pil_mba_verify_blob(struct pil_desc *pil, u32 phy_addr,
+ size_t size)
+{
+ struct mba_data *drv = dev_get_drvdata(pil->dev);
+
+ /* Begin image authentication */
+ if (drv->img_length == 0) {
+ writel_relaxed(phy_addr, drv->reg_base + RMB_PMI_CODE_START);
+ writel_relaxed(CMD_LOAD_READY, drv->reg_base + RMB_MBA_COMMAND);
+ }
+ /* Increment length counter */
+ drv->img_length += size;
+ writel_relaxed(drv->img_length, drv->reg_base + RMB_PMI_CODE_LENGTH);
+
+ return readl_relaxed(drv->reg_base + RMB_MBA_STATUS)
+ & STATUS_ERROR_MASK;
+}
+
+static int pil_mba_auth(struct pil_desc *pil)
+{
+ struct mba_data *drv = dev_get_drvdata(pil->dev);
+ int ret;
+ u32 status;
+
+ /* Wait for all segments to be authenticated or an error to occur */
+ ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
+ status == STATUS_AUTH_COMPLETE ||
+ status & STATUS_ERROR_MASK,
+ 50, AUTH_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ if (status & STATUS_ERROR_MASK)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int pil_mba_shutdown(struct pil_desc *pil)
+{
+ return 0;
+}
+
+static struct pil_reset_ops pil_mba_ops = {
+ .init_image = pil_mba_init_image,
+ .proxy_vote = pil_mba_make_proxy_votes,
+ .proxy_unvote = pil_mba_remove_proxy_votes,
+ .verify_blob = pil_mba_verify_blob,
+ .auth_and_reset = pil_mba_auth,
+ .shutdown = pil_mba_shutdown,
+};
+
+static int __devinit pil_mba_driver_probe(struct platform_device *pdev)
+{
+ struct mba_data *drv;
+ struct resource *res;
+ struct pil_desc *desc;
+ int ret;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+ drv->reg_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->reg_base)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res) {
+ drv->metadata_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->metadata_base)
+ return -ENOMEM;
+ drv->metadata_phys = res->start;
+ }
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+ &desc->name);
+ if (ret)
+ return ret;
+
+ of_property_read_string(pdev->dev.of_node, "qcom,depends-on",
+ &desc->depends_on);
+
+ drv->xo = devm_clk_get(&pdev->dev, "xo");
+ if (IS_ERR(drv->xo))
+ return PTR_ERR(drv->xo);
+
+ desc->dev = &pdev->dev;
+ desc->ops = &pil_mba_ops;
+ desc->owner = THIS_MODULE;
+ desc->proxy_timeout = PROXY_TIMEOUT_MS;
+
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+
+ return 0;
+}
+
+static int __devexit pil_mba_driver_exit(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct of_device_id mba_match_table[] = {
+ { .compatible = "qcom,pil-mba" },
+ {}
+};
+
+struct platform_driver pil_mba_driver = {
+ .probe = pil_mba_driver_probe,
+ .remove = __devexit_p(pil_mba_driver_exit),
+ .driver = {
+ .name = "pil-mba",
+ .of_match_table = mba_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_mba_init(void)
+{
+ return platform_driver_register(&pil_mba_driver);
+}
+module_init(pil_mba_init);
+
+static void __exit pil_mba_exit(void)
+{
+ platform_driver_unregister(&pil_mba_driver);
+}
+module_exit(pil_mba_exit);
+
+MODULE_DESCRIPTION("Support for modem boot using the Modem Boot Authenticator");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
new file mode 100644
index 0000000..e279f99
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/clk.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v5.h"
+
+/* Q6 Register Offsets */
+#define QDSP6SS_RST_EVB 0x010
+
+/* AXI Halting Registers */
+#define MSS_Q6_HALT_BASE 0x180
+#define MSS_MODEM_HALT_BASE 0x200
+#define MSS_NC_HALT_BASE 0x280
+
+/* RMB Status Register Values */
+#define STATUS_PBL_SUCCESS 0x1
+#define STATUS_XPU_UNLOCKED 0x1
+#define STATUS_XPU_UNLOCKED_SCRIBBLED 0x2
+
+/* PBL/MBA interface registers */
+#define RMB_MBA_IMAGE 0x00
+#define RMB_PBL_STATUS 0x04
+#define RMB_MBA_STATUS 0x0C
+
+#define PBL_MBA_WAIT_TIMEOUT_US 100000
+#define PROXY_TIMEOUT_MS 10000
+#define POLL_INTERVAL_US 50
+
+static int pil_mss_power_up(struct device *dev)
+{
+ int ret;
+ struct q6v5_data *drv = dev_get_drvdata(dev);
+
+ ret = regulator_enable(drv->vreg);
+ if (ret)
+ dev_err(dev, "Failed to enable regulator.\n");
+
+ return ret;
+}
+
+static int pil_mss_power_down(struct device *dev)
+{
+ struct q6v5_data *drv = dev_get_drvdata(dev);
+
+ return regulator_disable(drv->vreg);
+}
+
+static int wait_for_mba_ready(struct device *dev)
+{
+ struct q6v5_data *drv = dev_get_drvdata(dev);
+ int ret;
+ u32 status;
+
+ /* Wait for PBL completion. */
+ ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
+ status != 0, POLL_INTERVAL_US, PBL_MBA_WAIT_TIMEOUT_US);
+ if (ret) {
+ dev_err(dev, "PBL boot timed out\n");
+ return ret;
+ }
+ if (status != STATUS_PBL_SUCCESS) {
+ dev_err(dev, "PBL returned unexpected status %d\n", status);
+ return -EINVAL;
+ }
+
+ /* Wait for MBA completion. */
+ ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+ status != 0, POLL_INTERVAL_US, PBL_MBA_WAIT_TIMEOUT_US);
+ if (ret) {
+ dev_err(dev, "MBA boot timed out\n");
+ return ret;
+ }
+ if (status != STATUS_XPU_UNLOCKED &&
+ status != STATUS_XPU_UNLOCKED_SCRIBBLED) {
+ dev_err(dev, "MBA returned unexpected status %d\n", status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pil_mss_shutdown(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_Q6_HALT_BASE);
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_MODEM_HALT_BASE);
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_NC_HALT_BASE);
+
+ /*
+ * If the shutdown function is called before the reset function, clocks
+ * and power will not be enabled yet. Enable them here so that register
+ * writes performed during the shutdown succeed.
+ */
+ if (drv->is_booted == false) {
+ pil_mss_power_up(pil->dev);
+ pil_q6v5_enable_clks(pil);
+ }
+ pil_q6v5_shutdown(pil);
+
+ pil_q6v5_disable_clks(pil);
+ pil_mss_power_down(pil->dev);
+
+ writel_relaxed(1, drv->restart_reg);
+
+ drv->is_booted = false;
+
+ return 0;
+}
+
+static int pil_mss_reset(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ int ret;
+
+ writel_relaxed(0, drv->restart_reg);
+ mb();
+
+ /*
+ * Bring subsystem out of reset and enable required
+ * regulators and clocks.
+ */
+ ret = pil_mss_power_up(pil->dev);
+ if (ret)
+ goto err_power;
+
+ ret = pil_q6v5_enable_clks(pil);
+ if (ret)
+ goto err_clks;
+
+ /* Program Image Address */
+ if (drv->self_auth)
+ writel_relaxed(drv->start_addr, drv->rmb_base + RMB_MBA_IMAGE);
+ else
+ writel_relaxed((drv->start_addr >> 4) & 0x0FFFFFF0,
+ drv->reg_base + QDSP6SS_RST_EVB);
+
+ ret = pil_q6v5_reset(pil);
+ if (ret)
+ goto err_q6v5_reset;
+
+ /* Wait for MBA to start. Check for PBL and MBA errors while waiting. */
+ if (drv->self_auth) {
+ ret = wait_for_mba_ready(pil->dev);
+ if (ret)
+ goto err_auth;
+ }
+
+ drv->is_booted = true;
+
+ return 0;
+
+err_auth:
+ pil_q6v5_shutdown(pil);
+err_q6v5_reset:
+ pil_q6v5_disable_clks(pil);
+err_clks:
+ pil_mss_power_down(pil->dev);
+err_power:
+ return ret;
+}
+
+static struct pil_reset_ops pil_mss_ops = {
+ .init_image = pil_q6v5_init_image,
+ .proxy_vote = pil_q6v5_make_proxy_votes,
+ .proxy_unvote = pil_q6v5_remove_proxy_votes,
+ .auth_and_reset = pil_mss_reset,
+ .shutdown = pil_mss_shutdown,
+};
+
+static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
+{
+ struct q6v5_data *drv;
+ struct pil_desc *desc;
+ struct resource *res;
+ int ret;
+
+ desc = pil_q6v5_init(pdev);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+ drv = platform_get_drvdata(pdev);
+ if (drv == NULL)
+ return -ENODEV;
+
+ desc->ops = &pil_mss_ops;
+ desc->owner = THIS_MODULE;
+ desc->proxy_timeout = PROXY_TIMEOUT_MS;
+
+ of_property_read_u32(pdev->dev.of_node, "qcom,pil-self-auth",
+ &drv->self_auth);
+ if (drv->self_auth) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ drv->rmb_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->rmb_base)
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ drv->restart_reg = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->restart_reg)
+ return -ENOMEM;
+
+ drv->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
+ if (IS_ERR(drv->vreg))
+ return PTR_ERR(drv->vreg);
+
+ ret = regulator_set_voltage(drv->vreg, 1150000, 1150000);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
+
+ ret = regulator_set_optimum_mode(drv->vreg, 100000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
+ return ret;
+ }
+
+ drv->mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
+ if (IS_ERR(drv->mem_clk))
+ return PTR_ERR(drv->mem_clk);
+
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+
+ return 0;
+}
+
+static int __devexit pil_mss_driver_exit(struct platform_device *pdev)
+{
+ struct q6v5_data *drv = platform_get_drvdata(pdev);
+ msm_pil_unregister(drv->pil);
+ return 0;
+}
+
+static struct of_device_id mss_match_table[] = {
+ { .compatible = "qcom,pil-q6v5-mss" },
+ {}
+};
+
+static struct platform_driver pil_mss_driver = {
+ .probe = pil_mss_driver_probe,
+ .remove = __devexit_p(pil_mss_driver_exit),
+ .driver = {
+ .name = "pil-q6v5-mss",
+ .of_match_table = mss_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_mss_init(void)
+{
+ return platform_driver_register(&pil_mss_driver);
+}
+module_init(pil_mss_init);
+
+static void __exit pil_mss_exit(void)
+{
+ platform_driver_unregister(&pil_mss_driver);
+}
+module_exit(pil_mss_exit);
+
+MODULE_DESCRIPTION("Support for booting modem subsystems with QDSP6v5 Hexagon processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 6a96990..a362a7e3 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -121,9 +121,16 @@
ret = clk_prepare_enable(drv->bus_clk);
if (ret)
goto err_bus_clk;
+ if (drv->mem_clk) {
+ ret = clk_prepare_enable(drv->mem_clk);
+ if (ret)
+ goto err_mem_clk;
+ }
return 0;
+err_mem_clk:
+ clk_disable_unprepare(drv->bus_clk);
err_bus_clk:
clk_disable_unprepare(drv->core_clk);
err_core_clk:
@@ -139,6 +146,7 @@
clk_disable_unprepare(drv->bus_clk);
clk_disable_unprepare(drv->core_clk);
+ clk_disable_unprepare(drv->mem_clk);
clk_reset(drv->core_clk, CLK_RESET_ASSERT);
}
EXPORT_SYMBOL(pil_q6v5_disable_clks);
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index a9a8d07..e0d7a20 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -24,8 +24,10 @@
struct clk *xo;
struct clk *bus_clk;
struct clk *core_clk;
+ struct clk *mem_clk;
void __iomem *axi_halt_base;
void __iomem *rmb_base;
+ void __iomem *restart_reg;
unsigned long start_addr;
struct regulator *vreg;
bool is_booted;
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index f6105af1..079ed9c 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -41,7 +41,7 @@
}
#ifdef CONFIG_MSM_SCM
-static int __init msm_pm_tz_boot_init(void)
+static int __devinit msm_pm_tz_boot_init(void)
{
int flag = 0;
if (num_possible_cpus() == 1)
@@ -72,7 +72,7 @@
unsigned long entry) {}
#endif
-static int __init msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
+static int __devinit msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
{
if (!reset_vector)
return -ENODEV;
@@ -110,7 +110,7 @@
}
#define BOOT_REMAP_ENABLE BIT(0)
-int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
+int __devinit msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
{
int ret = 0;
unsigned long entry;
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 6f5ccbf..b485058 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -865,7 +865,8 @@
unsigned msg_id;
unsigned msg_length;
#ifdef CONFIG_DEBUG_FS
- uint16_t *ptr;
+ uint16_t *ptr16;
+ uint32_t *ptr32;
int ii;
#endif /* CONFIG_DEBUG_FS */
void (*func)(void *, size_t);
@@ -909,12 +910,20 @@
return 0;
}
#ifdef CONFIG_DEBUG_FS
- if (rdump > 0) {
- ptr = read_event_addr;
+ if (rdump > 0 &&
+ (dsp_addr >= (void *)(MSM_AD5_BASE + QDSP_RAMC_OFFSET))) {
+ ptr32 = read_event_addr;
+ pr_info("D->A\n");
+ pr_info("m_id = %x id = %x\n", module->id, msg_id);
+ for (ii = 0; ii < msg_length/4; ii++)
+ pr_info("%x ", ptr32[ii]);
+ pr_info("\n");
+ } else if (rdump > 0) {
+ ptr16 = read_event_addr;
pr_info("D->A\n");
pr_info("m_id = %x id = %x\n", module->id, msg_id);
for (ii = 0; ii < msg_length/2; ii++)
- pr_info("%x ", ptr[ii]);
+ pr_info("%x ", ptr16[ii]);
pr_info("\n");
}
#endif /* CONFIG_DEBUG_FS */
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index 2011c42..03dd295 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -387,9 +387,10 @@
msm_rpc_setup_req(&rhdr, audio->rpc_prog, audio->rpc_ver,
SND_VOC_REC_STOP_PROC);
rc = msm_rpc_write(audio->sndept, &rhdr, sizeof(rhdr));
- wait_event_timeout(audio->wait, audio->stopped == 0,
+ rc = wait_event_timeout(audio->wait, audio->stopped == 1,
1 * HZ);
- audio->stopped = 1;
+ if (rc == 0)
+ audio->stopped = 1;
wake_up(&audio->read_wait);
audmgr_disable(&audio->audmgr);
audio->enabled = 0;
@@ -456,7 +457,9 @@
if ((rec_status == RPC_VOC_REC_STAT_DATA) ||
(rec_status == RPC_VOC_REC_STAT_DONE)) {
if (datacb_data->pkt.fw_data.fw_ptr_status &&
- be32_to_cpu(datacb_data->pkt.fw_data.rec_length)) {
+ be32_to_cpu(datacb_data->pkt.fw_data.rec_length) &&
+ be32_to_cpu(datacb_data->pkt.fw_data.rec_length)
+ <= MAX_FRAME_SIZE) {
MM_DBG("Copy FW link:rec_buf_size \
= 0x%08x, rec_length=0x%08x\n",
@@ -479,7 +482,10 @@
datacb_data->pkt.fw_data.rec_num_frames);
mutex_unlock(&audio->dsp_lock);
} else if (datacb_data->pkt.rw_data.rw_ptr_status &&
- be32_to_cpu(datacb_data->pkt.rw_data.rec_length)) {
+ be32_to_cpu(datacb_data->pkt.rw_data.rec_length) &&
+ be32_to_cpu(datacb_data->pkt.rw_data.rec_length)
+ <= MAX_FRAME_SIZE) {
+
MM_DBG("Copy RW link:rec_buf_size \
=0x%08x, rec_length=0x%08x\n",
be32_to_cpu( \
@@ -500,6 +506,15 @@
be32_to_cpu(
datacb_data->pkt.rw_data.rec_num_frames);
mutex_unlock(&audio->dsp_lock);
+ } else {
+ MM_ERR("FW: ptr_status %d, rec_length=0x%08x,"
+ "RW: ptr_status %d, rec_length=0x%08x\n",
+ datacb_data->pkt.rw_data.fw_ptr_status, \
+ be32_to_cpu( \
+ datacb_data->pkt.fw_data.rec_length), \
+ datacb_data->pkt.rw_data.fw_ptr_status, \
+ be32_to_cpu( \
+ datacb_data->pkt.fw_data.rec_length));
}
if (rec_status != RPC_VOC_REC_STAT_DONE) {
/* Not end of record */
@@ -521,6 +536,7 @@
} else {
/* Indication record stopped gracefully */
MM_DBG("End Of Voice Record\n");
+ audio->stopped = 1;
wake_up(&audio->wait);
}
} else if (rec_status == RPC_VOC_REC_STAT_PAUSED) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
index db0a96e..0591a71 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -840,6 +840,10 @@
.step = SOFT_VOLUME_STEP,
.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
};
+ if (softpause.rampingcurve == SOFT_PAUSE_CURVE_LINEAR)
+ softpause.step = SOFT_PAUSE_STEP_LINEAR;
+ if (softvol.rampingcurve == SOFT_VOLUME_CURVE_LINEAR)
+ softvol.step = SOFT_VOLUME_STEP_LINEAR;
audio->out_enabled = 1;
audio->out_needed = 1;
rc = q6asm_set_volume(audio->ac, audio->volume);
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
index f75af16..0b38ec2 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
@@ -220,7 +220,7 @@
goto err_clk;
}
- clk_enable(drv->ecodec_clk);
+ clk_prepare_enable(drv->ecodec_clk);
clk_reset(drv->ecodec_clk, CLK_RESET_DEASSERT);
@@ -260,7 +260,7 @@
pr_info("%s: closing all devices\n", __func__);
- clk_disable(drv->ecodec_clk);
+ clk_disable_unprepare(drv->ecodec_clk);
aux_pcm_gpios_free();
afe_close(PCM_RX);
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
index 41ef88c..e266d7a 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
@@ -325,7 +325,7 @@
goto error_invalid_freq;
}
- clk_enable(drv->rx_osrclk);
+ clk_prepare_enable(drv->rx_osrclk);
drv->rx_bitclk = clk_get_sys(NULL, "i2s_spkr_bit_clk");
if (IS_ERR(drv->rx_bitclk))
pr_err("%s clock Error\n", __func__);
@@ -345,7 +345,7 @@
pr_err("ERROR setting m clock1\n");
goto error_adie;
}
- clk_enable(drv->rx_bitclk);
+ clk_prepare_enable(drv->rx_bitclk);
if (icodec->data->voltage_on)
icodec->data->voltage_on();
@@ -412,7 +412,7 @@
error_pamp:
error_adie:
- clk_disable(drv->rx_osrclk);
+ clk_disable_unprepare(drv->rx_osrclk);
error_invalid_freq:
pr_err("%s: encounter error\n", __func__);
@@ -455,7 +455,7 @@
goto error_invalid_freq;
}
- clk_enable(drv->tx_osrclk);
+ clk_prepare_enable(drv->tx_osrclk);
drv->tx_bitclk = clk_get_sys(NULL, "i2s_mic_bit_clk");
if (IS_ERR(drv->tx_bitclk))
pr_err("%s clock Error\n", __func__);
@@ -471,7 +471,7 @@
} else
trc = clk_set_rate(drv->tx_bitclk, 8);
- clk_enable(drv->tx_bitclk);
+ clk_prepare_enable(drv->tx_bitclk);
/* Enable ADIE */
trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
@@ -580,8 +580,8 @@
if (icodec->data->voltage_off)
icodec->data->voltage_off();
- clk_disable(drv->rx_bitclk);
- clk_disable(drv->rx_osrclk);
+ clk_disable_unprepare(drv->rx_bitclk);
+ clk_disable_unprepare(drv->rx_osrclk);
msm_snddev_rx_mclk_free();
@@ -611,8 +611,8 @@
afe_close(icodec->data->copp_id);
- clk_disable(drv->tx_bitclk);
- clk_disable(drv->tx_osrclk);
+ clk_disable_unprepare(drv->tx_bitclk);
+ clk_disable_unprepare(drv->tx_osrclk);
msm_snddev_tx_mclk_free();
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
index 75a7411..4cf18b3 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
@@ -194,7 +194,7 @@
pr_err("ERROR setting osr clock\n");
return -ENODEV;
}
- clk_enable(drv->tx_osrclk);
+ clk_prepare_enable(drv->tx_osrclk);
/* set up bit clk */
drv->tx_bitclk = clk_get_sys(NULL, "mi2s_bit_clk");
@@ -204,10 +204,10 @@
rc = clk_set_rate(drv->tx_bitclk, 8);
if (IS_ERR_VALUE(rc)) {
pr_err("ERROR setting bit clock\n");
- clk_disable(drv->tx_osrclk);
+ clk_disable_unprepare(drv->tx_osrclk);
return -ENODEV;
}
- clk_enable(drv->tx_bitclk);
+ clk_prepare_enable(drv->tx_bitclk);
afe_config.mi2s.bitwidth = 16;
@@ -336,8 +336,8 @@
error_invalid_data:
- clk_disable(drv->tx_bitclk);
- clk_disable(drv->tx_osrclk);
+ clk_disable_unprepare(drv->tx_bitclk);
+ clk_disable_unprepare(drv->tx_osrclk);
return -EINVAL;
}
@@ -358,8 +358,8 @@
return -EIO;
}
afe_close(snddev_mi2s_data->copp_id);
- clk_disable(mi2s_drv->tx_bitclk);
- clk_disable(mi2s_drv->tx_osrclk);
+ clk_disable_unprepare(mi2s_drv->tx_bitclk);
+ clk_disable_unprepare(mi2s_drv->tx_osrclk);
mi2s_gpios_free();
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 614339b..a8773ea 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -27,7 +27,8 @@
#include "usfcdev.h"
/* The driver version*/
-#define DRV_VERSION "1.3.1"
+#define DRV_VERSION "1.4.0"
+#define USF_VERSION_ID 0x0140
/* Standard timeout in the asynchronous ops */
#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
@@ -108,8 +109,8 @@
uint16_t dev_ind;
/* Event types, supported by device */
uint16_t event_types;
- /* The device is "input" module registered client */
- struct input_dev *input_if;
+ /* The input devices are "input" module registered clients */
+ struct input_dev *input_ifs[USF_MAX_EVENT_IND];
/* The event source */
int event_src;
/* Bitmap of types of events, conflicting to USF's ones */
@@ -118,6 +119,23 @@
uint16_t conflicting_event_filters;
};
+struct usf_input_dev_type {
+ /* Input event type, supported by the input device */
+ uint16_t event_type;
+ /* Input device name */
+ const char *input_dev_name;
+ /* Input device registration function */
+ int (*prepare_dev)(uint16_t, struct usf_type *,
+ struct us_input_info_type *,
+ const char *);
+ /* Input event notification function */
+ void (*notify_event)(struct usf_type *,
+ uint16_t,
+ struct usf_event_type *
+ );
+};
+
+
/* The MAX number of the supported devices */
#define MAX_DEVS_NUMBER 1
@@ -131,9 +149,197 @@
/* The opened devices container */
static int s_opened_devs[MAX_DEVS_NUMBER];
-#define USF_NAME_PREFIX "USF_"
+#define USF_NAME_PREFIX "usf_"
#define USF_NAME_PREFIX_SIZE 4
+
+static struct input_dev *allocate_dev(uint16_t ind, const char *name)
+{
+ struct input_dev *in_dev = input_allocate_device();
+
+ if (in_dev == NULL) {
+ pr_err("%s: input_allocate_device() failed\n", __func__);
+ } else {
+ /* Common part configuration */
+ in_dev->name = name;
+ in_dev->phys = NULL;
+ in_dev->id.bustype = BUS_HOST;
+ in_dev->id.vendor = 0x0001;
+ in_dev->id.product = 0x0001;
+ in_dev->id.version = USF_VERSION_ID;
+ }
+ return in_dev;
+}
+
+static int prepare_tsc_input_device(uint16_t ind,
+ struct usf_type *usf_info,
+ struct us_input_info_type *input_info,
+ const char *name)
+{
+ struct input_dev *in_dev = allocate_dev(ind, name);
+
+ if (in_dev == NULL)
+ return -ENOMEM;
+
+ usf_info->input_ifs[ind] = in_dev;
+ in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_abs_params(in_dev, ABS_X,
+ input_info->tsc_x_dim[MIN_IND],
+ input_info->tsc_x_dim[MAX_IND],
+ 0, 0);
+ input_set_abs_params(in_dev, ABS_Y,
+ input_info->tsc_y_dim[MIN_IND],
+ input_info->tsc_y_dim[MAX_IND],
+ 0, 0);
+ input_set_abs_params(in_dev, ABS_DISTANCE,
+ input_info->tsc_z_dim[MIN_IND],
+ input_info->tsc_z_dim[MAX_IND],
+ 0, 0);
+
+ input_set_abs_params(in_dev, ABS_PRESSURE,
+ input_info->tsc_pressure[MIN_IND],
+ input_info->tsc_pressure[MAX_IND],
+ 0, 0);
+
+ input_set_abs_params(in_dev, ABS_TILT_X,
+ input_info->tsc_x_tilt[MIN_IND],
+ input_info->tsc_x_tilt[MAX_IND],
+ 0, 0);
+ input_set_abs_params(in_dev, ABS_TILT_Y,
+ input_info->tsc_y_tilt[MIN_IND],
+ input_info->tsc_y_tilt[MAX_IND],
+ 0, 0);
+
+ return 0;
+}
+
+static int prepare_mouse_input_device(uint16_t ind, struct usf_type *usf_info,
+ struct us_input_info_type *input_info,
+ const char *name)
+{
+ struct input_dev *in_dev = allocate_dev(ind, name);
+
+ if (in_dev == NULL)
+ return -ENOMEM;
+
+ usf_info->input_ifs[ind] = in_dev;
+ in_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+
+ in_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT) |
+ BIT_MASK(BTN_MIDDLE);
+ in_dev->relbit[0] = BIT_MASK(REL_X) |
+ BIT_MASK(REL_Y) |
+ BIT_MASK(REL_Z);
+
+ return 0;
+}
+
+static int prepare_keyboard_input_device(
+ uint16_t ind,
+ struct usf_type *usf_info,
+ struct us_input_info_type *input_info,
+ const char *name)
+{
+ struct input_dev *in_dev = allocate_dev(ind, name);
+
+ if (in_dev == NULL)
+ return -ENOMEM;
+
+ usf_info->input_ifs[ind] = in_dev;
+ in_dev->evbit[0] |= BIT_MASK(EV_KEY);
+ /* All keys are permitted */
+ memset(in_dev->keybit, 0xff, sizeof(in_dev->keybit));
+
+ return 0;
+}
+
+static void notify_tsc_event(struct usf_type *usf_info,
+ uint16_t if_ind,
+ struct usf_event_type *event)
+
+{
+ struct input_dev *input_if = usf_info->input_ifs[if_ind];
+ struct point_event_type *pe = &(event->event_data.point_event);
+
+ input_report_abs(input_if, ABS_X, pe->coordinates[X_IND]);
+ input_report_abs(input_if, ABS_Y, pe->coordinates[Y_IND]);
+ input_report_abs(input_if, ABS_DISTANCE, pe->coordinates[Z_IND]);
+
+ input_report_abs(input_if, ABS_TILT_X, pe->inclinations[X_IND]);
+ input_report_abs(input_if, ABS_TILT_Y, pe->inclinations[Y_IND]);
+
+ input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
+ input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
+
+ if (usf_info->event_src)
+ input_report_key(input_if, usf_info->event_src, 1);
+
+ input_sync(input_if);
+
+ pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
+ __func__,
+ pe->coordinates[X_IND],
+ pe->coordinates[Y_IND],
+ pe->coordinates[Z_IND],
+ pe->inclinations[X_IND],
+ pe->inclinations[Y_IND],
+ pe->pressure);
+}
+
+static void notify_mouse_event(struct usf_type *usf_info,
+ uint16_t if_ind,
+ struct usf_event_type *event)
+{
+ struct input_dev *input_if = usf_info->input_ifs[if_ind];
+ struct mouse_event_type *me = &(event->event_data.mouse_event);
+
+ input_report_rel(input_if, REL_X, me->rels[X_IND]);
+ input_report_rel(input_if, REL_Y, me->rels[Y_IND]);
+ input_report_rel(input_if, REL_Z, me->rels[Z_IND]);
+
+ input_report_key(input_if, BTN_LEFT,
+ me->buttons_states & USF_BUTTON_LEFT_MASK);
+ input_report_key(input_if, BTN_MIDDLE,
+ me->buttons_states & USF_BUTTON_MIDDLE_MASK);
+ input_report_key(input_if, BTN_RIGHT,
+ me->buttons_states & USF_BUTTON_RIGHT_MASK);
+
+ input_sync(input_if);
+
+ pr_debug("%s: mouse event: dx[%d], dy[%d], buttons_states[%d]\n",
+ __func__, me->rels[X_IND],
+ me->rels[Y_IND], me->buttons_states);
+}
+
+static void notify_key_event(struct usf_type *usf_info,
+ uint16_t if_ind,
+ struct usf_event_type *event)
+{
+ struct input_dev *input_if = usf_info->input_ifs[if_ind];
+ struct key_event_type *ke = &(event->event_data.key_event);
+
+ input_report_key(input_if, ke->key, ke->key_state);
+ input_sync(input_if);
+ pr_debug("%s: key event: key[%d], state[%d]\n",
+ __func__,
+ ke->key,
+ ke->key_state);
+
+}
+
+static struct usf_input_dev_type s_usf_input_devs[] = {
+ {USF_TSC_EVENT, "usf_tsc",
+ prepare_tsc_input_device, notify_tsc_event},
+ {USF_TSC_PTR_EVENT, "usf_tsc_ptr",
+ prepare_tsc_input_device, notify_tsc_event},
+ {USF_MOUSE_EVENT, "usf_mouse",
+ prepare_mouse_input_device, notify_mouse_event},
+ {USF_KEYBOARD_EVENT, "usf_kb",
+ prepare_keyboard_input_device, notify_key_event},
+};
+
static void usf_rx_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
@@ -386,8 +592,8 @@
struct us_input_info_type *input_info)
{
int rc = 0;
- struct input_dev *input_dev = NULL;
bool ret = true;
+ uint16_t ind = 0;
if ((usf_info == NULL) ||
(input_info == NULL) ||
@@ -396,194 +602,75 @@
return -EINVAL;
}
- if (usf_info->input_if != NULL) {
- pr_err("%s: input_if is already allocated\n", __func__);
- return -EFAULT;
- }
-
- input_dev = input_allocate_device();
- if (input_dev == NULL) {
- pr_err("%s: input_allocate_device() failed\n", __func__);
- return -ENOMEM;
- }
-
- /* Common part configuration */
- input_dev->name = (const char *)(usf_info->usf_tx.client_name);
- input_dev->phys = NULL;
- input_dev->id.bustype = BUS_HOST;
- input_dev->id.vendor = 0x0001;
- input_dev->id.product = 0x0001;
- input_dev->id.version = 0x0001;
-
- if (input_info->event_types & USF_TSC_EVENT) {
- /* TSC part configuration */
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X,
- input_info->tsc_x_dim[MIN_IND],
- input_info->tsc_x_dim[MAX_IND],
- 0, 0);
- input_set_abs_params(input_dev, ABS_Y,
- input_info->tsc_y_dim[MIN_IND],
- input_info->tsc_y_dim[MAX_IND],
- 0, 0);
- input_set_abs_params(input_dev, ABS_DISTANCE,
- input_info->tsc_z_dim[MIN_IND],
- input_info->tsc_z_dim[MAX_IND],
- 0, 0);
-
- input_set_abs_params(input_dev, ABS_PRESSURE,
- input_info->tsc_pressure[MIN_IND],
- input_info->tsc_pressure[MAX_IND], 0, 0);
-
- input_set_abs_params(input_dev, ABS_TILT_X,
- input_info->tsc_x_tilt[MIN_IND],
- input_info->tsc_x_tilt[MAX_IND],
- 0, 0);
- input_set_abs_params(input_dev, ABS_TILT_Y,
- input_info->tsc_y_tilt[MIN_IND],
- input_info->tsc_y_tilt[MAX_IND],
- 0, 0);
- }
-
- if (input_info->event_types & USF_MOUSE_EVENT) {
- /* Mouse part configuration */
- input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-
- input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
- BIT_MASK(BTN_RIGHT) |
- BIT_MASK(BTN_MIDDLE);
- input_dev->relbit[0] = BIT_MASK(REL_X) |
- BIT_MASK(REL_Y) |
- BIT_MASK(REL_Z);
- }
-
- if (input_info->event_types & USF_KEYBOARD_EVENT) {
- /* Keyboard part configuration */
- input_dev->evbit[0] |= BIT_MASK(EV_KEY);
-
- /* All keys are permitted */
- memset(input_dev->keybit, 0xff, sizeof(input_dev->keybit));
- }
-
if (input_info->event_src < ARRAY_SIZE(s_event_src_map))
- usf_info->event_src = s_event_src_map[input_info->event_src];
+ usf_info->event_src =
+ s_event_src_map[input_info->event_src];
else
usf_info->event_src = 0;
- if (usf_info->event_src)
- input_set_capability(input_dev, EV_KEY, usf_info->event_src);
+ for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
+ if (usf_info->input_ifs[ind] != NULL) {
+ pr_err("%s: input_if[%d] is already allocated\n",
+ __func__, ind);
+ return -EFAULT;
+ }
+ if ((input_info->event_types &
+ s_usf_input_devs[ind].event_type) &&
+ s_usf_input_devs[ind].prepare_dev) {
+ rc = (*s_usf_input_devs[ind].prepare_dev)(
+ ind,
+ usf_info,
+ input_info,
+ s_usf_input_devs[ind].input_dev_name);
+ if (rc)
+ return rc;
- rc = input_register_device(input_dev);
- if (rc) {
- pr_err("%s: input_register_device() failed; rc=%d\n",
- __func__, rc);
- input_free_device(input_dev);
- } else {
- usf_info->input_if = input_dev;
- usf_info->event_types = input_info->event_types;
- pr_debug("%s: input device[%s] was registered\n",
- __func__, input_dev->name);
- ret = usf_register_conflicting_events(
- input_info->conflicting_event_types);
- if (ret)
- usf_info->conflicting_event_types =
- input_info->conflicting_event_types;
- }
- return rc;
+ if (usf_info->event_src)
+ input_set_capability(usf_info->input_ifs[ind],
+ EV_KEY,
+ usf_info->event_src);
+
+ rc = input_register_device(usf_info->input_ifs[ind]);
+ if (rc) {
+ pr_err("%s: input_reg_dev() failed; rc=%d\n",
+ __func__, rc);
+ input_free_device(usf_info->input_ifs[ind]);
+ usf_info->input_ifs[ind] = NULL;
+ } else {
+ usf_info->event_types |=
+ s_usf_input_devs[ind].event_type;
+ pr_debug("%s: input device[%s] was registered\n",
+ __func__,
+ s_usf_input_devs[ind].input_dev_name);
+ }
+ } /* supported event */
+ } /* event types loop */
+
+ ret = usf_register_conflicting_events(
+ input_info->conflicting_event_types);
+ if (ret)
+ usf_info->conflicting_event_types =
+ input_info->conflicting_event_types;
+
+ return 0;
}
-static void notify_tsc_event(struct usf_type *usf_info,
- struct point_event_type *pe)
-{
- struct input_dev *input_if = usf_info->input_if;
-
- input_report_abs(input_if, ABS_X, pe->coordinates[X_IND]);
- input_report_abs(input_if, ABS_Y, pe->coordinates[Y_IND]);
- input_report_abs(input_if, ABS_DISTANCE, pe->coordinates[Z_IND]);
-
- input_report_abs(input_if, ABS_TILT_X, pe->inclinations[X_IND]);
- input_report_abs(input_if, ABS_TILT_Y, pe->inclinations[Y_IND]);
-
- input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
- input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
-
- if (usf_info->event_src)
- input_report_key(input_if, usf_info->event_src, 1);
-
- input_sync(input_if);
-
- pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
- __func__,
- pe->coordinates[X_IND],
- pe->coordinates[Y_IND],
- pe->coordinates[Z_IND],
- pe->inclinations[X_IND],
- pe->inclinations[Y_IND],
- pe->pressure);
-}
-
-static void notify_mouse_event(struct input_dev *input_if,
- struct mouse_event_type *me)
-{
- if (me == NULL) {
- pr_err("%s: mouse event is NULL\n", __func__);
- return;
- }
-
- input_report_rel(input_if, REL_X, me->rels[X_IND]);
- input_report_rel(input_if, REL_Y, me->rels[Y_IND]);
- input_report_rel(input_if, REL_Z, me->rels[Z_IND]);
-
- input_report_key(input_if, BTN_LEFT,
- me->buttons_states & USF_BUTTON_LEFT_MASK);
- input_report_key(input_if, BTN_MIDDLE,
- me->buttons_states & USF_BUTTON_MIDDLE_MASK);
- input_report_key(input_if, BTN_RIGHT,
- me->buttons_states & USF_BUTTON_RIGHT_MASK);
-
- input_sync(input_if);
-
- pr_debug("%s: mouse event: dx[%d], dy[%d], buttons_states[%d]\n",
- __func__, me->rels[X_IND],
- me->rels[Y_IND], me->buttons_states);
-}
-
-static void notify_key_event(struct input_dev *input_if,
- struct key_event_type *ke)
-{
- if (ke == NULL) {
- pr_err("%s: key event is NULL\n", __func__);
- return;
- }
-
- input_report_key(input_if, ke->key, ke->key_state);
- input_sync(input_if);
- pr_debug("%s: key event: key[%d], state[%d]\n",
- __func__,
- ke->key,
- ke->key_state);
-
-}
static void handle_input_event(struct usf_type *usf_info,
uint16_t event_counter,
struct usf_event_type *event)
{
- struct input_dev *input_if = NULL;
uint16_t ind = 0;
uint16_t events_num = 0;
struct usf_event_type usf_events[USF_EVENTS_PORTION_SIZE];
int rc = 0;
- if ((usf_info == NULL) || (usf_info->input_if == NULL) ||
+ if ((usf_info == NULL) ||
(event == NULL) || (!event_counter)) {
return;
}
- input_if = usf_info->input_if;
-
while (event_counter > 0) {
if (event_counter > USF_EVENTS_PORTION_SIZE) {
events_num = USF_EVENTS_PORTION_SIZE;
@@ -602,26 +689,17 @@
}
for (ind = 0; ind < events_num; ++ind) {
struct usf_event_type *p_event = &usf_events[ind];
- if (p_event->event_type & USF_TSC_EVENT) {
- struct point_event_type *pe =
- &(p_event->event_data.point_event);
- if (pe->coordinates_type ==
- USF_PIX_COORDINATE)
- notify_tsc_event(usf_info, pe);
- else
- pr_debug("%s: wrong coord type: %d",
- __func__,
- pe->coordinates_type);
- continue;
- }
- if (p_event->event_type & USF_MOUSE_EVENT) {
- notify_mouse_event(input_if,
- &(p_event->event_data.mouse_event));
- continue;
- }
- if (p_event->event_type & USF_KEYBOARD_EVENT)
- notify_key_event(input_if,
- &(p_event->event_data.key_event));
+ uint16_t if_ind = p_event->event_type_ind;
+
+ if ((if_ind >= USF_MAX_EVENT_IND) ||
+ (usf_info->input_ifs[if_ind] == NULL))
+ continue; /* event isn't supported */
+
+ if (s_usf_input_devs[if_ind].notify_event)
+ (*s_usf_input_devs[if_ind].notify_event)(
+ usf_info,
+ if_ind,
+ p_event);
} /* loop in the portion */
} /* all events loop */
}
@@ -1051,13 +1129,20 @@
static void usf_release_input(struct usf_type *usf)
{
- if (usf->input_if != NULL) {
+ uint16_t ind = 0;
+
+ for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
+ if (usf->input_ifs[ind] == NULL)
+ continue;
+
usf_unregister_conflicting_events(
usf->conflicting_event_types);
usf->conflicting_event_types = 0;
- input_unregister_device(usf->input_if);
- usf->input_if = NULL;
- pr_debug("%s input_unregister_device\n", __func__);
+ input_unregister_device(usf->input_ifs[ind]);
+ usf->input_ifs[ind] = NULL;
+ pr_debug("%s input_unregister_device[%s]\n",
+ __func__,
+ s_usf_input_devs[ind].input_dev_name);
}
} /* usf_release_input */
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 90948ea..266c8b4 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -28,6 +28,7 @@
#include "ramdump.h"
#define MODULE_NAME "wcnss_8960"
+#define MAX_BUF_SIZE 0x51
static void riva_smsm_cb_fn(struct work_struct *);
static DECLARE_WORK(riva_smsm_cb_work, riva_smsm_cb_fn);
@@ -52,12 +53,37 @@
static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
uint32_t new_state)
{
+ char *smem_reset_reason;
+ char buffer[MAX_BUF_SIZE];
+ unsigned smem_reset_size;
+ unsigned size;
+
if (!(new_state & SMSM_RESET))
return;
riva_crash = true;
pr_err("%s: smsm state changed to smsm reset\n", MODULE_NAME);
+ smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
+ &smem_reset_size);
+
+ if (!smem_reset_reason || !smem_reset_size) {
+ pr_err("%s: wcnss subsystem failure reason: %s\n", __func__,
+ "(unknown, smem_get_entry failed)");
+ } else if (!smem_reset_reason[0]) {
+ pr_err("%s: wcnss subsystem failure reason: %s\n", __func__,
+ "(unknown, init string found)");
+ } else {
+ size = smem_reset_size < MAX_BUF_SIZE ? smem_reset_size :
+ (MAX_BUF_SIZE - 1);
+ memcpy(buffer, smem_reset_reason, size);
+ buffer[size] = '\0';
+ pr_err("%s: wcnss subsystem failure reason: %s\n", __func__,
+ buffer);
+ memset(smem_reset_reason, 0, smem_reset_size);
+ wmb();
+ }
+
if (ss_restart_inprogress) {
pr_err("%s: Ignoring smsm reset req, restart in progress\n",
MODULE_NAME);
diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig
index 53df29b..8f8707f2e 100644
--- a/drivers/char/diag/Kconfig
+++ b/drivers/char/diag/Kconfig
@@ -32,10 +32,10 @@
menu "HSIC support for DIAG"
-config DIAG_HSIC_PIPE
+config DIAG_BRIDGE_CODE
depends on USB_QCOM_DIAG_BRIDGE
default y
- bool "Enable 9K DIAG traffic over HSIC"
+ bool "Enable QSC/9K DIAG traffic over SMUX/HSIC"
help
- HSIC Transport Layer for DIAG Router
+ SMUX/HSIC Transport Layer for DIAG Router
endmenu
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index 3181d29..ea75ffd 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_DIAG_CHAR) := diagchar.o
obj-$(CONFIG_DIAG_SDIO_PIPE) += diagfwd_sdio.o
-obj-$(CONFIG_DIAG_HSIC_PIPE) += diagfwd_hsic.o
+obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_hsic.o
+obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_smux.o
diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o diag_dci.o
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 49d687d..7e7b514 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -41,6 +41,7 @@
#define SDIO_DATA 4
#define WCNSS_DATA 5
#define HSIC_DATA 6
+#define SMUX_DATA 7
#define MODEM_PROC 0
#define APPS_PROC 1
#define QDSP_PROC 2
@@ -254,24 +255,30 @@
struct diag_request *usb_read_mdm_ptr;
struct diag_request *write_ptr_mdm;
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ /* SGLTE variables */
+ int lcid;
+ unsigned char *buf_in_smux;
+ int in_busy_smux;
+ int diag_smux_enabled;
+ /* HSIC variables */
unsigned char *buf_in_hsic;
- unsigned char *usb_buf_mdm_out;
- int hsic_initialized;
int hsic_ch;
int hsic_device_enabled;
int hsic_device_opened;
int hsic_suspend;
- int read_len_mdm;
int in_busy_hsic_read_on_device;
int in_busy_hsic_write_on_device;
int in_busy_hsic_write;
int in_busy_hsic_read;
- int usb_mdm_connected;
- struct usb_diag_ch *mdm_ch;
- struct workqueue_struct *diag_hsic_wq;
- struct work_struct diag_read_mdm_work;
struct work_struct diag_read_hsic_work;
+ /* USB MDM channel variables */
+ int usb_mdm_connected;
+ int read_len_mdm;
+ unsigned char *usb_buf_mdm_out;
+ struct usb_diag_ch *mdm_ch;
+ struct workqueue_struct *diag_bridge_wq;
+ struct work_struct diag_read_mdm_work;
struct work_struct diag_disconnect_work;
struct work_struct diag_usb_read_complete_work;
struct diag_request *usb_read_mdm_ptr;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 58a8676..d6a6e66 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -32,8 +32,9 @@
#ifdef CONFIG_DIAG_SDIO_PIPE
#include "diagfwd_sdio.h"
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
#include "diagfwd_hsic.h"
+#include "diagfwd_smux.h"
#endif
#include <linux/timer.h>
@@ -234,9 +235,9 @@
if (driver->logging_process_id == current->tgid) {
driver->logging_mode = USB_MODE;
diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
diagfwd_cancel_hsic();
- diagfwd_connect_hsic(0);
+ diagfwd_connect_bridge(0);
#endif
}
#endif /* DIAG over USB */
@@ -481,8 +482,8 @@
#ifdef CONFIG_DIAG_SDIO_PIPE
driver->in_busy_sdio = 1;
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_disconnect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ diagfwd_disconnect_bridge(0);
#endif
} else if (temp == NO_LOGGING_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
@@ -509,22 +510,22 @@
queue_work(driver->diag_sdio_wq,
&(driver->diag_read_sdio_work));
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_connect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ diagfwd_connect_bridge(0);
#endif
}
#ifdef CONFIG_DIAG_OVER_USB
else if (temp == USB_MODE && driver->logging_mode
== NO_LOGGING_MODE) {
diagfwd_disconnect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_disconnect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ diagfwd_disconnect_bridge(0);
#endif
} else if (temp == NO_LOGGING_MODE && driver->logging_mode
== USB_MODE) {
diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_connect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ diagfwd_connect_bridge(0);
#endif
} else if (temp == USB_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
@@ -552,16 +553,16 @@
queue_work(driver->diag_sdio_wq,
&(driver->diag_read_sdio_work));
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
diagfwd_cancel_hsic();
- diagfwd_connect_hsic(0);
+ diagfwd_connect_bridge(0);
#endif
} else if (temp == MEMORY_DEVICE_MODE &&
driver->logging_mode == USB_MODE) {
diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
diagfwd_cancel_hsic();
- diagfwd_connect_hsic(0);
+ diagfwd_connect_bridge(0);
#endif
}
#endif /* DIAG over USB */
@@ -720,7 +721,7 @@
driver->in_busy_sdio = 0;
}
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
pr_debug("diag: Copy data to user space %d\n",
driver->in_busy_hsic_write_on_device);
if (driver->in_busy_hsic_write_on_device == 1) {
@@ -898,7 +899,7 @@
}
}
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
/* send masks to 9k too */
if (driver->hsic_ch && (payload_size > 0)) {
/* wait sending mask updates if HSIC ch not ready */
@@ -1199,6 +1200,18 @@
inline void diag_sdio_fn(int type) {}
#endif
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diag_bridge_fn(int type)
+{
+ if (type == INIT)
+ diagfwd_bridge_init();
+ else if (type == EXIT)
+ diagfwd_bridge_exit();
+}
+#else
+inline void diag_bridge_fn(int type) {}
+#endif
+
static int __init diagchar_init(void)
{
dev_t dev;
@@ -1243,9 +1256,7 @@
diagfwd_cntl_init();
driver->dci_state = diag_dci_init();
diag_sdio_fn(INIT);
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_hsic_init();
-#endif
+ diag_bridge_fn(INIT);
pr_debug("diagchar initializing ..\n");
driver->num = 1;
driver->name = ((void *)driver) + sizeof(struct diagchar_dev);
@@ -1279,9 +1290,7 @@
diagfwd_exit();
diagfwd_cntl_exit();
diag_sdio_fn(EXIT);
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_hsic_exit();
-#endif
+ diag_bridge_fn(EXIT);
return -1;
}
@@ -1294,9 +1303,7 @@
diagfwd_exit();
diagfwd_cntl_exit();
diag_sdio_fn(EXIT);
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_hsic_exit();
-#endif
+ diag_bridge_fn(EXIT);
diag_debugfs_cleanup();
diagchar_cleanup();
printk(KERN_INFO "done diagchar exit\n");
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 4ac2643..83d65b1 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -49,7 +49,7 @@
unsigned char diag_debug_buf[1024];
static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
struct diag_master_table entry;
-smd_channel_t *ch_temp, *chqdsp_temp, *ch_wcnss_temp;
+smd_channel_t *ch_temp = NULL, *chqdsp_temp = NULL, *ch_wcnss_temp = NULL;
int diag_event_num_bytes;
int diag_event_config;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
@@ -300,12 +300,12 @@
&(driver->diag_read_sdio_work));
}
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
else if (proc_num == HSIC_DATA) {
driver->in_busy_hsic_read = 0;
driver->in_busy_hsic_write_on_device = 0;
if (driver->hsic_ch)
- queue_work(driver->diag_hsic_wq,
+ queue_work(driver->diag_bridge_wq,
&(driver->diag_read_hsic_work));
}
#endif
@@ -352,7 +352,7 @@
"while USB write\n");
}
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
else if (proc_num == HSIC_DATA) {
if (driver->hsic_device_enabled) {
write_ptr->buf = buf;
@@ -360,6 +360,10 @@
} else
pr_err("diag: Incorrect hsic data "
"while USB write\n");
+ } else if (proc_num == SMUX_DATA) {
+ write_ptr->buf = buf;
+ pr_debug("diag: writing SMUX data\n");
+ err = usb_diag_write(driver->mdm_ch, write_ptr);
}
#endif
APPEND_DEBUG('d');
@@ -922,8 +926,10 @@
{
uint16_t subsys_cmd_code;
int subsys_id, ssid_first, ssid_last, ssid_range;
- int packet_type = 1, i, cmd_code, rt_mask;
+ int packet_type = 1, i, cmd_code;
+ int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
unsigned char *temp = buf;
+ uint8_t *rt_mask_ptr;
int data_type;
#if defined(CONFIG_DIAG_OVER_USB)
int payload_length;
@@ -983,6 +989,38 @@
return 0;
}
#endif
+ } /* Get runtime message mask */
+ else if ((*buf == 0x7d) && (*(buf+1) == 0x3)) {
+ ssid_first = *(uint16_t *)(buf + 2);
+ ssid_last = *(uint16_t *)(buf + 4);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (!(driver->ch) && chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x7d;
+ driver->apps_rsp_buf[1] = 0x3;
+ *(uint16_t *)(driver->apps_rsp_buf+2) = ssid_first;
+ *(uint16_t *)(driver->apps_rsp_buf+4) = ssid_last;
+ driver->apps_rsp_buf[6] = 0x1; /* Success Status */
+ driver->apps_rsp_buf[7] = 0x0;
+ rt_mask_ptr = driver->msg_masks;
+ while (*(uint32_t *)(rt_mask_ptr + 4)) {
+ rt_first_ssid = *(uint32_t *)rt_mask_ptr;
+ rt_mask_ptr += 4;
+ rt_last_ssid = *(uint32_t *)rt_mask_ptr;
+ rt_mask_ptr += 4;
+ if (ssid_first == rt_first_ssid && ssid_last ==
+ rt_last_ssid) {
+ rt_mask_size = 4 * (rt_last_ssid -
+ rt_first_ssid + 1);
+ memcpy(driver->apps_rsp_buf+8,
+ rt_mask_ptr, rt_mask_size);
+ ENCODE_RSP_AND_SEND(8+rt_mask_size-1);
+ return 0;
+ }
+ ptr += MAX_SSID_PER_RANGE*4;
+ }
+ } else
+ buf = temp;
+#endif
} /* Set runtime message mask */
else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
ssid_first = *(uint16_t *)(buf + 2);
@@ -1695,7 +1733,8 @@
driver->ch = 0;
return;
} else if (event == SMD_EVENT_OPEN) {
- driver->ch = ch_temp;
+ if (ch_temp)
+ driver->ch = ch_temp;
}
queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
}
@@ -1709,7 +1748,8 @@
driver->chqdsp = 0;
return;
} else if (event == SMD_EVENT_OPEN) {
- driver->chqdsp = chqdsp_temp;
+ if (chqdsp_temp)
+ driver->chqdsp = chqdsp_temp;
}
queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
}
@@ -1723,7 +1763,8 @@
driver->ch_wcnss = 0;
return;
} else if (event == SMD_EVENT_OPEN) {
- driver->ch_wcnss = ch_wcnss_temp;
+ if (ch_wcnss_temp)
+ driver->ch_wcnss = ch_wcnss_temp;
}
queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
}
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index a3c6f26..d54d3dc 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -19,6 +19,7 @@
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
+#include <linux/smux.h>
#include <asm/current.h>
#ifdef CONFIG_DIAG_OVER_USB
#include <mach/usbdiag.h>
@@ -28,6 +29,7 @@
#include "diagchar.h"
#include "diagfwd.h"
#include "diagfwd_hsic.h"
+#include "diagfwd_smux.h"
static void diag_read_hsic_work_fn(struct work_struct *work)
{
@@ -71,7 +73,8 @@
* the next read
*/
if (!driver->in_busy_hsic_read)
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_hsic_work);
}
static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
@@ -114,7 +117,8 @@
if (!driver->in_busy_hsic_write_on_device && ((driver->logging_mode
== MEMORY_DEVICE_MODE) || (driver->usb_mdm_connected &&
!driver->hsic_suspend)))
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_hsic_work);
}
static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
@@ -132,7 +136,7 @@
pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
if (driver->usb_mdm_connected)
- queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+ queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
}
static int diag_hsic_suspend(void *ctxt)
@@ -157,7 +161,8 @@
if (!driver->in_busy_hsic_write_on_device && (driver->logging_mode
== MEMORY_DEVICE_MODE || driver->usb_mdm_connected))
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_hsic_work);
}
static struct diag_bridge_ops hsic_diag_bridge_ops = {
@@ -209,42 +214,48 @@
return 0;
}
-/* diagfwd_connect_hsic is called when the USB mdm channel is connected */
-int diagfwd_connect_hsic(int process_cable)
+/* diagfwd_connect_bridge is called when the USB mdm channel is connected */
+int diagfwd_connect_bridge(int process_cable)
{
int err;
- pr_debug("DIAG in %s\n", __func__);
+ pr_debug("diag: in %s\n", __func__);
/* If the usb cable is being connected */
if (process_cable) {
err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE,
N_MDM_READ);
if (err)
- pr_err("DIAG: unable to alloc USB req on mdm"
+ pr_err("diag: unable to alloc USB req on mdm"
" ch err:%d\n", err);
driver->usb_mdm_connected = 1;
}
- driver->in_busy_hsic_write_on_device = 0;
- driver->in_busy_hsic_read_on_device = 0;
- driver->in_busy_hsic_write = 0;
- driver->in_busy_hsic_read = 0;
+ if (driver->hsic_device_enabled) {
+ driver->in_busy_hsic_write_on_device = 0;
+ driver->in_busy_hsic_read_on_device = 0;
+ driver->in_busy_hsic_write = 0;
+ driver->in_busy_hsic_read = 0;
+ } else if (driver->diag_smux_enabled) {
+ driver->in_busy_smux = 0;
+ diagfwd_connect_smux();
+ return 0;
+ }
/* If the hsic (diag_bridge) platform device is not open */
if (driver->hsic_device_enabled) {
if (!driver->hsic_device_opened) {
err = diag_bridge_open(&hsic_diag_bridge_ops);
if (err) {
- pr_err("DIAG: HSIC channel open error: %d\n",
+ pr_err("diag: HSIC channel open error: %d\n",
err);
} else {
- pr_debug("DIAG: opened HSIC channel\n");
+ pr_debug("diag: opened HSIC channel\n");
driver->hsic_device_opened = 1;
}
} else {
- pr_debug("DIAG: HSIC channel already open\n");
+ pr_debug("diag: HSIC channel already open\n");
}
/*
@@ -256,24 +267,25 @@
/* Poll USB mdm channel to check for data */
if (driver->logging_mode == USB_MODE)
- queue_work(driver->diag_hsic_wq,
+ queue_work(driver->diag_bridge_wq,
&driver->diag_read_mdm_work);
/* Poll HSIC channel to check for data */
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_hsic_work);
} else {
/* The hsic device driver has not yet been enabled */
- pr_info("DIAG: HSIC channel not yet enabled\n");
+ pr_info("diag: HSIC channel not yet enabled\n");
}
return 0;
}
/*
- * diagfwd_disconnect_hsic is called when the USB mdm channel
+ * diagfwd_disconnect_bridge is called when the USB mdm channel
* is disconnected
*/
-int diagfwd_disconnect_hsic(int process_cable)
+int diagfwd_disconnect_bridge(int process_cable)
{
pr_debug("DIAG in %s\n", __func__);
@@ -284,12 +296,19 @@
}
if (driver->logging_mode != MEMORY_DEVICE_MODE) {
- driver->in_busy_hsic_write_on_device = 1;
- driver->in_busy_hsic_read_on_device = 1;
- driver->in_busy_hsic_write = 1;
- driver->in_busy_hsic_read = 1;
- /* Turn off communication over usb mdm and hsic */
- return diag_hsic_close();
+ if (driver->hsic_device_enabled) {
+ driver->in_busy_hsic_write_on_device = 1;
+ driver->in_busy_hsic_read_on_device = 1;
+ driver->in_busy_hsic_write = 1;
+ driver->in_busy_hsic_read = 1;
+ /* Turn off communication over usb mdm and hsic */
+ return diag_hsic_close();
+ } else if (driver->diag_smux_enabled) {
+ driver->in_busy_smux = 1;
+ driver->lcid = LCID_INVALID;
+ /* Turn off communication over usb mdm and smux */
+ msm_smux_close(LCID_VALID);
+ }
}
return 0;
}
@@ -313,18 +332,23 @@
APPEND_DEBUG('q');
/* Read data from the hsic */
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq, &driver->diag_read_hsic_work);
return 0;
}
/* Called after the asychronous usb_diag_read() on mdm channel is complete */
-static int diagfwd_read_complete_hsic(struct diag_request *diag_read_ptr)
+static int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr)
{
/* The read of the usb driver on the mdm (not hsic) has completed */
driver->in_busy_hsic_read_on_device = 0;
driver->read_len_mdm = diag_read_ptr->actual;
+ if (driver->diag_smux_enabled) {
+ diagfwd_read_complete_smux();
+ return 0;
+ }
+ /* If SMUX not enabled, check for HSIC */
if (!driver->hsic_ch) {
pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
return 0;
@@ -366,30 +390,34 @@
* hsic channel
*/
if (!driver->in_busy_hsic_write)
- queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+ queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
return 0;
}
-static void diagfwd_hsic_notifier(void *priv, unsigned event,
+static void diagfwd_bridge_notifier(void *priv, unsigned event,
struct diag_request *d_req)
{
switch (event) {
case USB_DIAG_CONNECT:
- diagfwd_connect_hsic(1);
+ diagfwd_connect_bridge(1);
break;
case USB_DIAG_DISCONNECT:
- queue_work(driver->diag_hsic_wq, &driver->diag_disconnect_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_disconnect_work);
break;
case USB_DIAG_READ_DONE:
- queue_work(driver->diag_hsic_wq,
+ queue_work(driver->diag_bridge_wq,
&driver->diag_usb_read_complete_work);
break;
case USB_DIAG_WRITE_DONE:
- diagfwd_write_complete_hsic();
+ if (driver->hsic_device_enabled)
+ diagfwd_write_complete_hsic();
+ else if (driver->diag_smux_enabled)
+ diagfwd_write_complete_smux();
break;
default:
- pr_err("DIAG in %s: Unknown event from USB diag:%u\n",
+ pr_err("diag: in %s: Unknown event from USB diag:%u\n",
__func__, event);
break;
}
@@ -397,16 +425,33 @@
static void diag_usb_read_complete_fn(struct work_struct *w)
{
- diagfwd_read_complete_hsic(driver->usb_read_mdm_ptr);
+ diagfwd_read_complete_bridge(driver->usb_read_mdm_ptr);
}
static void diag_disconnect_work_fn(struct work_struct *w)
{
- diagfwd_disconnect_hsic(1);
+ diagfwd_disconnect_bridge(1);
}
static void diag_read_mdm_work_fn(struct work_struct *work)
{
+ int ret;
+ if (driver->diag_smux_enabled) {
+ if (driver->lcid && driver->usb_buf_mdm_out &&
+ (driver->read_len_mdm > 0)) {
+ ret = msm_smux_write(driver->lcid, NULL,
+ driver->usb_buf_mdm_out, driver->read_len_mdm);
+ if (ret)
+ pr_err("diag: writing to SMUX ch, r = %d,"
+ "lcid = %d\n", ret, driver->lcid);
+ }
+ driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
+ driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
+ usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
+ return;
+ }
+
+ /* if SMUX not enabled, check for HSIC */
if (!driver->hsic_ch) {
pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
return;
@@ -434,7 +479,8 @@
* queue up the reading of data from the mdm channel
*/
if (!driver->in_busy_hsic_read_on_device)
- queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_mdm_work);
}
static int diag_hsic_probe(struct platform_device *pdev)
@@ -442,31 +488,10 @@
int err = 0;
pr_debug("diag: in %s\n", __func__);
if (!driver->hsic_device_enabled) {
- driver->read_len_mdm = 0;
if (driver->buf_in_hsic == NULL)
driver->buf_in_hsic = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_hsic == NULL)
- goto err;
- if (driver->usb_buf_mdm_out == NULL)
- driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
- GFP_KERNEL);
- if (driver->usb_buf_mdm_out == NULL)
- goto err;
- if (driver->write_ptr_mdm == NULL)
- driver->write_ptr_mdm = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_mdm == NULL)
- goto err;
- if (driver->usb_read_mdm_ptr == NULL)
- driver->usb_read_mdm_ptr = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->usb_read_mdm_ptr == NULL)
- goto err;
-#ifdef CONFIG_DIAG_OVER_USB
- INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
-#endif
INIT_WORK(&(driver->diag_read_hsic_work),
- diag_read_hsic_work_fn);
+ diag_read_hsic_work_fn);
driver->hsic_device_enabled = 1;
}
@@ -495,25 +520,16 @@
if (driver->usb_mdm_connected) {
/* Poll USB mdm channel to check for data */
- queue_work(driver->diag_hsic_wq,
+ queue_work(driver->diag_bridge_wq,
&driver->diag_read_mdm_work);
}
/* Poll HSIC channel to check for data */
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_hsic_work);
}
return err;
-err:
- pr_err("DIAG could not initialize buf for HSIC\n");
- kfree(driver->buf_in_hsic);
- kfree(driver->usb_buf_mdm_out);
- kfree(driver->write_ptr_mdm);
- kfree(driver->usb_read_mdm_ptr);
- if (driver->diag_hsic_wq)
- destroy_workqueue(driver->diag_hsic_wq);
-
- return -ENOMEM;
}
static int diag_hsic_remove(struct platform_device *pdev)
@@ -550,55 +566,93 @@
},
};
-void diagfwd_hsic_init(void)
+void diagfwd_bridge_init(void)
{
int ret;
- pr_debug("DIAG in %s\n", __func__);
+ pr_debug("diag: in %s\n", __func__);
+ driver->diag_bridge_wq = create_singlethread_workqueue(
+ "diag_bridge_wq");
+ driver->read_len_mdm = 0;
+ if (driver->usb_buf_mdm_out == NULL)
+ driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
+ GFP_KERNEL);
+ if (driver->usb_buf_mdm_out == NULL)
+ goto err;
+ if (driver->write_ptr_mdm == NULL)
+ driver->write_ptr_mdm = kzalloc(
+ sizeof(struct diag_request), GFP_KERNEL);
+ if (driver->write_ptr_mdm == NULL)
+ goto err;
+ if (driver->usb_read_mdm_ptr == NULL)
+ driver->usb_read_mdm_ptr = kzalloc(
+ sizeof(struct diag_request), GFP_KERNEL);
+ if (driver->usb_read_mdm_ptr == NULL)
+ goto err;
- driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
+#ifdef CONFIG_DIAG_OVER_USB
+ INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
+#endif
INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
INIT_WORK(&(driver->diag_usb_read_complete_work),
diag_usb_read_complete_fn);
-
#ifdef CONFIG_DIAG_OVER_USB
- driver->mdm_ch = usb_diag_open(DIAG_MDM, driver, diagfwd_hsic_notifier);
+ driver->mdm_ch = usb_diag_open(DIAG_MDM, driver,
+ diagfwd_bridge_notifier);
if (IS_ERR(driver->mdm_ch)) {
- pr_err("DIAG Unable to open USB diag MDM channel\n");
+ pr_err("diag: Unable to open USB diag MDM channel\n");
goto err;
}
#endif
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
+ INIT_WORK(&(driver->diag_usb_read_complete_work),
+ diag_usb_read_complete_fn);
+ /* register HSIC device */
ret = platform_driver_register(&msm_hsic_ch_driver);
if (ret)
- pr_err("DIAG could not register HSIC device, ret: %d\n", ret);
- else
- driver->hsic_initialized = 1;
-
+ pr_err("diag: could not register HSIC device, ret: %d\n", ret);
+ /* register SMUX device */
+ ret = platform_driver_register(&msm_diagfwd_smux_driver);
+ if (ret)
+ pr_err("diag: could not register SMUX device, ret: %d\n", ret);
+#endif
return;
err:
- pr_err("DIAG could not initialize for HSIC execution\n");
-}
-
-void diagfwd_hsic_exit(void)
-{
- pr_debug("DIAG in %s\n", __func__);
-
- if (driver->hsic_initialized)
- diag_hsic_close();
-
-#ifdef CONFIG_DIAG_OVER_USB
- if (driver->usb_mdm_connected)
- usb_diag_free_req(driver->mdm_ch);
-#endif
- platform_driver_unregister(&msm_hsic_ch_driver);
-#ifdef CONFIG_DIAG_OVER_USB
- usb_diag_close(driver->mdm_ch);
-#endif
- kfree(driver->buf_in_hsic);
+ pr_err("diag: Could not initialize for bridge forwarding\n");
kfree(driver->usb_buf_mdm_out);
kfree(driver->write_ptr_mdm);
kfree(driver->usb_read_mdm_ptr);
- destroy_workqueue(driver->diag_hsic_wq);
+ if (driver->diag_bridge_wq)
+ destroy_workqueue(driver->diag_bridge_wq);
- driver->hsic_device_enabled = 0;
+ return;
+}
+
+void diagfwd_bridge_exit(void)
+{
+ pr_debug("diag: in %s\n", __func__);
+
+ if (driver->hsic_device_enabled) {
+ diag_hsic_close();
+ kfree(driver->buf_in_hsic);
+ driver->hsic_device_enabled = 0;
+ }
+ if (driver->diag_smux_enabled) {
+ driver->lcid = LCID_INVALID;
+ kfree(driver->buf_in_smux);
+ driver->diag_smux_enabled = 0;
+ }
+ platform_driver_unregister(&msm_hsic_ch_driver);
+ platform_driver_unregister(&msm_diagfwd_smux_driver);
+ /* destroy USB MDM specific variables */
+#ifdef CONFIG_DIAG_OVER_USB
+ if (driver->usb_mdm_connected)
+ usb_diag_free_req(driver->mdm_ch);
+ usb_diag_close(driver->mdm_ch);
+#endif
+ kfree(driver->usb_buf_mdm_out);
+ kfree(driver->write_ptr_mdm);
+ kfree(driver->usb_read_mdm_ptr);
+ destroy_workqueue(driver->diag_bridge_wq);
}
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
index a47ee26..b189c94 100644
--- a/drivers/char/diag/diagfwd_hsic.h
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -17,11 +17,11 @@
#define N_MDM_WRITE 1 /* Upgrade to 2 with ping pong buffer */
#define N_MDM_READ 1
-void __init diagfwd_hsic_init(void);
-int diagfwd_connect_hsic(int);
-int diagfwd_disconnect_hsic(int);
+int diagfwd_connect_bridge(int);
+int diagfwd_disconnect_bridge(int);
int diagfwd_write_complete_hsic(void);
int diagfwd_cancel_hsic(void);
-void diagfwd_hsic_exit(void);
+void diagfwd_bridge_init(void);
+void diagfwd_bridge_exit(void);
#endif
diff --git a/drivers/char/diag/diagfwd_smux.c b/drivers/char/diag/diagfwd_smux.c
new file mode 100644
index 0000000..8bbc67ea
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smux.c
@@ -0,0 +1,156 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/termios.h>
+#include <linux/slab.h>
+#include <linux/diagchar.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <mach/usbdiag.h>
+#include "diagchar.h"
+#include "diagfwd.h"
+#include "diagfwd_smux.h"
+
+void diag_smux_event(void *priv, int event_type, const void *metadata)
+{
+ unsigned char *rx_buf;
+ int len;
+
+ switch (event_type) {
+ case SMUX_CONNECTED:
+ pr_debug("diag: SMUX_CONNECTED received\n");
+ driver->in_busy_smux = 0;
+ /* read data from USB MDM channel & Initiate first write */
+ queue_work(driver->diag_bridge_wq,
+ &(driver->diag_read_mdm_work));
+ break;
+ case SMUX_DISCONNECTED:
+ pr_info("diag: SMUX_DISCONNECTED received\n");
+ break;
+ case SMUX_WRITE_DONE:
+ pr_debug("diag: SMUX Write done\n");
+ break;
+ case SMUX_WRITE_FAIL:
+ pr_info("diag: SMUX Write Failed\n");
+ break;
+ case SMUX_READ_FAIL:
+ pr_info("diag: SMUX Read Failed\n");
+ break;
+ case SMUX_READ_DONE:
+ len = ((struct smux_meta_read *)metadata)->len;
+ rx_buf = ((struct smux_meta_read *)metadata)->buffer;
+ driver->write_ptr_mdm->length = len;
+ diag_device_write(driver->buf_in_smux, SMUX_DATA,
+ driver->write_ptr_mdm);
+ break;
+ };
+}
+
+int diagfwd_write_complete_smux(void)
+{
+ pr_debug("diag: clear in_busy_smux\n");
+ driver->in_busy_smux = 0;
+ return 0;
+}
+
+int diagfwd_read_complete_smux(void)
+{
+ queue_work(driver->diag_bridge_wq, &(driver->diag_read_mdm_work));
+ return 0;
+}
+
+int diag_get_rx_buffer(void *priv, void **pkt_priv, void **buffer, int size)
+{
+ if (!driver->in_busy_smux) {
+ *pkt_priv = (void *)0x1234;
+ *buffer = driver->buf_in_smux;
+ pr_debug("diag: set in_busy_smux as 1\n");
+ driver->in_busy_smux = 1;
+ } else {
+ pr_debug("diag: read buffer for SMUX is BUSY\n");
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static int diagfwd_smux_runtime_suspend(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: suspending...\n");
+ return 0;
+}
+
+static int diagfwd_smux_runtime_resume(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: resuming...\n");
+ return 0;
+}
+
+static const struct dev_pm_ops diagfwd_smux_dev_pm_ops = {
+ .runtime_suspend = diagfwd_smux_runtime_suspend,
+ .runtime_resume = diagfwd_smux_runtime_resume,
+};
+
+int diagfwd_connect_smux(void)
+{
+ void *priv = NULL;
+ int ret = 0;
+
+ if (driver->lcid == LCID_INVALID) {
+ ret = msm_smux_open(LCID_VALID, priv, diag_smux_event,
+ diag_get_rx_buffer);
+ if (!ret) {
+ driver->lcid = LCID_VALID;
+ msm_smux_tiocm_set(driver->lcid, TIOCM_DTR, 0);
+ pr_info("diag: open SMUX ch, r = %d\n", ret);
+ } else {
+ pr_err("diag: failed to open SMUX ch, r = %d\n", ret);
+ }
+ }
+ /* Poll USB channel to check for data*/
+ queue_work(driver->diag_bridge_wq, &(driver->diag_read_mdm_work));
+ return ret;
+}
+
+static int diagfwd_smux_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ pr_info("diag: SMUX probe called\n");
+ driver->lcid = LCID_INVALID;
+ driver->diag_smux_enabled = 1;
+ if (driver->buf_in_smux == NULL) {
+ driver->buf_in_smux = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ if (driver->buf_in_smux == NULL)
+ goto err;
+ }
+ /* Only required for Local loopback test
+ * ret = msm_smux_set_ch_option(LCID_VALID,
+ SMUX_CH_OPTION_LOCAL_LOOPBACK, 0);
+ * if (ret)
+ * pr_err("diag: error setting SMUX ch option, r = %d\n", ret);
+ */
+ ret = diagfwd_connect_smux();
+ return ret;
+
+err:
+ pr_err("diag: Could not initialize SMUX buffer\n");
+ kfree(driver->buf_in_smux);
+ return ret;
+}
+
+struct platform_driver msm_diagfwd_smux_driver = {
+ .probe = diagfwd_smux_probe,
+ .driver = {
+ .name = "SMUX_DIAG",
+ .owner = THIS_MODULE,
+ .pm = &diagfwd_smux_dev_pm_ops,
+ },
+};
diff --git a/drivers/char/diag/diagfwd_smux.h b/drivers/char/diag/diagfwd_smux.h
new file mode 100644
index 0000000..e78b7ed9
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smux.h
@@ -0,0 +1,25 @@
+/* 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 DIAGFWD_SMUX_H
+#define DIAGFWD_SMUX_H
+
+#include <linux/smux.h>
+#define LCID_VALID SMUX_USB_DIAG_0
+#define LCID_INVALID 0
+
+int diagfwd_read_complete_smux(void);
+int diagfwd_write_complete_smux(void);
+int diagfwd_connect_smux(void);
+extern struct platform_driver msm_diagfwd_smux_driver;
+
+#endif
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 35af06e..0a71982 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -248,10 +248,6 @@
#define A3XX_VBIF_ARB_CTL 0x303C
#define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E
#define A3XX_VBIF_OUT_AXI_AOOO 0x305F
-#define A3XX_VBIF_ERR_PENDING 0x3064
-#define A3XX_VBIF_ERR_MASK 0x3066
-#define A3XX_VBIF_ERR_CLEAR 0x3067
-#define A3XX_VBIF_ERR_INFO 0x3068
/* Bit flags for RBBM_CTL */
#define RBBM_RBBM_CTL_RESET_PWR_CTR1 (1 << 1)
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 66baee1..6041cd8 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -254,7 +254,7 @@
int sizedwords = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_memdesc **reg_map_desc;
- void *reg_map_array;
+ void *reg_map_array = NULL;
int num_iommu_units, i;
if (!adreno_dev->drawctxt_active)
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 09eae17..1902f50 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2336,39 +2336,6 @@
adreno_ringbuffer_submit(rb);
}
-#define VBIF_MAX_CLIENTS 6
-
-static void a3xx_vbif_callback(struct adreno_device *adreno_dev,
- unsigned int status)
-{
- struct kgsl_device *device = &adreno_dev->dev;
- int i;
- char str[80], *ptr = str;
- int slen = sizeof(str) - 1;
-
- KGSL_DRV_INFO(device, "VBIF error | status=%X\n",
- status);
-
- for (i = 0; i < VBIF_MAX_CLIENTS; i++) {
- if (status & (1 << i)) {
- unsigned int err;
- int ret;
-
- adreno_regwrite(device, A3XX_VBIF_ERR_INFO, i);
- adreno_regread(device, A3XX_VBIF_ERR_INFO, &err);
-
- ret = snprintf(ptr, slen, "%d:%8.8X ", i, err);
- ptr += ret;
- slen -= ret;
- }
- }
-
- KGSL_DRV_INFO(device, "%s\n", str);
-
- /* Clear the errors */
- adreno_regwrite(device, A3XX_VBIF_ERR_CLEAR, status);
-}
-
static void a3xx_err_callback(struct adreno_device *adreno_dev, int bit)
{
struct kgsl_device *device = &adreno_dev->dev;
@@ -2472,7 +2439,6 @@
#define A3XX_INT_MASK \
((1 << A3XX_INT_RBBM_AHB_ERROR) | \
- (1 << A3XX_INT_RBBM_REG_TIMEOUT) | \
(1 << A3XX_INT_RBBM_ATB_BUS_OVERFLOW) | \
(1 << A3XX_INT_CP_T0_PACKET_IN_IB) | \
(1 << A3XX_INT_CP_OPCODE_ERROR) | \
@@ -2545,15 +2511,6 @@
if (status)
adreno_regwrite(&adreno_dev->dev, A3XX_RBBM_INT_CLEAR_CMD,
status);
-
- /* Check for VBIF errors */
- adreno_regread(&adreno_dev->dev, A3XX_VBIF_ERR_PENDING, &status);
-
- if (status) {
- a3xx_vbif_callback(adreno_dev, status);
- ret = IRQ_HANDLED;
- }
-
return ret;
}
@@ -2561,17 +2518,10 @@
{
struct kgsl_device *device = &adreno_dev->dev;
- if (state) {
+ if (state)
adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK);
-
- /* Enable VBIF interrupts - write 0 to enable them all */
- adreno_regwrite(device, A3XX_VBIF_ERR_MASK, 0);
- /* Clear outstanding VBIF errors */
- adreno_regwrite(device, A3XX_VBIF_ERR_CLEAR, 0x3F);
- } else {
+ else
adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
- adreno_regwrite(device, A3XX_VBIF_ERR_MASK, 0xFFFFFFFF);
- }
}
static unsigned int a3xx_busy_cycles(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index a0907d7..5572695 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -674,6 +674,12 @@
adreno_find_ctxtmem(device, ptbase, ibaddr,
ibsize);
+ /* IOMMU uses a NOP IB placed in setsate memory */
+ if (NULL == memdesc)
+ if (kgsl_gpuaddr_in_memdesc(
+ &device->mmu.setstate_memory,
+ ibaddr, ibsize))
+ memdesc = &device->mmu.setstate_memory;
/*
* The IB from CP_IB1_BASE and the IBs for legacy
* context switch go into the snapshot all
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index ff9f0b8..5216b34 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -761,7 +761,7 @@
return 0;
spin_lock(&pt->lock);
- if (pt->tlb_flags && (1<<id)) {
+ if (pt->tlb_flags & (1<<id)) {
result = KGSL_MMUFLAGS_TLBFLUSH;
pt->tlb_flags &= ~(1<<id);
}
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index 5d3a948..964218f 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -248,6 +248,12 @@
---help---
Enable support for Gemini Jpeg Engine
+config MSM_MERCURY
+ tristate "Qualcomm MSM Mercury Jpeg Decoder Engine support"
+ depends on MSM_CAMERA && ARCH_MSM8960
+ ---help---
+ Enable support for Mercury Jpeg Engine
+
config MSM_VPE
tristate "Qualcomm MSM Video Pre-processing Engine support"
depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60)
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index e4d4081..67da5ea 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -18,7 +18,7 @@
else
obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
endif
-obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/
+obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/ mercury/
obj-$(CONFIG_MSM_CAMERA_FLASH) += flash.o
obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.h b/drivers/media/video/msm/gemini/msm_gemini_platform.h
index 4542129..eb6b9f0 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.h
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/ion.h>
+#include <linux/iommu.h>
void msm_gemini_platform_p2v(struct file *file,
struct ion_handle **ionhandle);
uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file,
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index fe7c99f..b55ec18 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.c
@@ -453,6 +453,7 @@
{
struct msm_gemini_core_buf *buf_p;
struct msm_gemini_buf buf_cmd;
+ int rc = 0;
if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
@@ -469,17 +470,25 @@
(int) buf_cmd.vaddr, buf_cmd.y_len);
if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
- buf_p->y_buffer_addr = buf_cmd.y_off;
+ rc = msm_iommu_map_contig_buffer(
+ (unsigned long)buf_cmd.y_off, CAMERA_DOMAIN, GEN_POOL,
+ ((buf_cmd.y_len + buf_cmd.cbcr_len + 4095) & (~4095)),
+ SZ_4K, IOMMU_WRITE | IOMMU_READ,
+ (unsigned long *)&buf_p->y_buffer_addr);
+ if (rc < 0) {
+ pr_err("%s iommu mapping failed with error %d\n",
+ __func__, rc);
+ kfree(buf_p);
+ return rc;
+ }
} else {
buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
&buf_p->handle) + buf_cmd.offset;
}
buf_p->y_len = buf_cmd.y_len;
-
buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
buf_p->cbcr_len = buf_cmd.cbcr_len;
-
buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
buf_p->y_buffer_addr, buf_p->y_len, buf_p->cbcr_buffer_addr,
diff --git a/drivers/media/video/msm/mercury/Makefile b/drivers/media/video/msm/mercury/Makefile
new file mode 100644
index 0000000..ce4c86d
--- /dev/null
+++ b/drivers/media/video/msm/mercury/Makefile
@@ -0,0 +1,3 @@
+GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+EXTRA_CFLAGS += -Idrivers/media/video/msm
+obj-$(CONFIG_MSM_MERCURY) += msm_mercury_dev.o msm_mercury_core.o msm_mercury_hw.o msm_mercury_platform.o msm_mercury_sync.o
diff --git a/drivers/media/video/msm/mercury/msm_mercury_common.h b/drivers/media/video/msm/mercury/msm_mercury_common.h
new file mode 100644
index 0000000..f5939c1
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_common.h
@@ -0,0 +1,24 @@
+/* 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 MSM_MERCURY_COMMON_H
+#define MSM_MERCURY_COMMON_H
+
+#define MSM_MERCURY_DEBUG
+#ifdef MSM_MERCURY_DEBUG
+#define MCR_DBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define MCR_DBG(fmt, args...) do { } while (0)
+#endif
+
+#define MCR_PR_ERR pr_err
+#endif /* MSM_MERCURY_COMMON_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_core.c b/drivers/media/video/msm/mercury/msm_mercury_core.c
new file mode 100644
index 0000000..a91c257
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_core.c
@@ -0,0 +1,136 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include "msm_mercury_hw.h"
+#include "msm_mercury_core.h"
+#include "msm_mercury_platform.h"
+#include "msm_mercury_common.h"
+
+static int reset_done_ack;
+static spinlock_t reset_lock;
+static wait_queue_head_t reset_wait;
+
+int mercury_core_reset(void)
+{
+ struct clk *clk = NULL;
+
+ /*Resettting MMSS Fabric*/
+
+ clk = clk_get(NULL, "jpegd_clk");
+
+ if (!IS_ERR(clk))
+ clk_enable(clk);
+
+ msm_bus_axi_porthalt(MSM_BUS_MASTER_JPEG_DEC);
+ clk_reset(clk, CLK_RESET_ASSERT);
+
+ /*need to have some delay here, there is no
+ other way to know if hardware reset is complete*/
+ usleep_range(1000, 1200);
+
+ msm_bus_axi_portunhalt(MSM_BUS_MASTER_JPEG_DEC);
+ clk_reset(clk, CLK_RESET_DEASSERT);
+
+ return 0;
+}
+
+int msm_mercury_core_reset(void)
+{
+ unsigned long flags;
+ int rc = 0;
+ int tm = 500;/*500ms*/
+ MCR_DBG("\n%s\n(%d)%s()\n", __FILE__, __LINE__, __func__);
+
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 0;
+ spin_unlock_irqrestore(&reset_lock, flags);
+
+ msm_mercury_hw_reset();
+ rc = wait_event_interruptible_timeout(reset_wait,
+ reset_done_ack,
+ msecs_to_jiffies(tm));
+
+ if (!reset_done_ack) {
+ MCR_DBG("%s: reset ACK failed %d", __func__, rc);
+ return -EBUSY;
+ }
+
+ MCR_DBG("(%d)%s() reset_done_ack rc %d\n\n", __LINE__, __func__, rc);
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 0;
+ spin_unlock_irqrestore(&reset_lock, flags);
+
+ return 0;
+}
+
+void msm_mercury_core_init(void)
+{
+ init_waitqueue_head(&reset_wait);
+ spin_lock_init(&reset_lock);
+}
+
+static int (*msm_mercury_irq_handler) (int, void *, void *);
+
+irqreturn_t msm_mercury_core_irq(int irq_num, void *context)
+{
+ void *data = NULL;
+ unsigned long flags;
+ uint16_t mcr_rd_irq;
+ uint16_t mcr_wr_irq;
+ uint32_t jpeg_status;
+
+ MCR_DBG("\n(%d)%s() irq_number = %d", __LINE__, __func__, irq_num);
+
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 1;
+ spin_unlock_irqrestore(&reset_lock, flags);
+
+ msm_mercury_hw_irq_get_status(&mcr_rd_irq, &mcr_wr_irq);
+ msm_mercury_hw_get_jpeg_status(&jpeg_status);
+ MCR_DBG("mercury_rd_irq = 0x%08X\n", mcr_rd_irq);
+ MCR_DBG("mercury_wr_irq = 0x%08X\n", mcr_wr_irq);
+ MCR_DBG("jpeg_status = 0x%08X\n", jpeg_status);
+ if (mcr_wr_irq & MSM_MERCURY_HW_IRQ_SW_RESET_ACK) {
+ MCR_DBG("*** SW Reset IRQ received ***\n");
+ wake_up(&reset_wait);
+ msm_mercury_hw_wr_irq_clear(MSM_MERCURY_HW_IRQ_SW_RESET_ACK);
+ }
+ if (mcr_wr_irq & MSM_MERCURY_HW_IRQ_WR_ERR_ACK) {
+ MCR_DBG(" *** Error IRQ received ***\n");
+ msm_mercury_irq_handler(MSM_MERCURY_HW_IRQ_WR_ERR_ACK,
+ context, data);
+ }
+ if (mcr_wr_irq & MSM_MERCURY_HW_IRQ_WR_EOI_ACK) {
+ MCR_DBG(" *** WE_EOI IRQ received ***\n");
+ msm_mercury_irq_handler(MSM_MERCURY_HW_IRQ_WR_EOI_ACK,
+ context, data);
+ }
+ return IRQ_HANDLED;
+}
+
+void msm_mercury_core_irq_install(int (*irq_handler) (int, void *, void *))
+{
+ msm_mercury_irq_handler = irq_handler;
+}
+
+void msm_mercury_core_irq_remove(void)
+{
+ msm_mercury_irq_handler = NULL;
+}
diff --git a/drivers/media/video/msm/mercury/msm_mercury_core.h b/drivers/media/video/msm/mercury/msm_mercury_core.h
new file mode 100644
index 0000000..e374cee
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_core.h
@@ -0,0 +1,29 @@
+/* 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 MSM_MERCURY_CORE_H
+#define MSM_MERCURY_CORE_H
+
+#include <linux/interrupt.h>
+#include "msm_mercury_hw.h"
+
+#define msm_mercury_core_buf msm_mercury_hw_buf
+
+irqreturn_t msm_mercury_core_irq(int irq_num, void *context);
+
+void msm_mercury_core_irq_install(int (*irq_handler) (int, void *, void *));
+void msm_mercury_core_irq_remove(void);
+
+int msm_mercury_core_reset(void);
+void msm_mercury_core_init(void);
+
+#endif /* MSM_MERCURY_CORE_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_dev.c b/drivers/media/video/msm/mercury/msm_mercury_dev.c
new file mode 100644
index 0000000..df32b26
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_dev.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_mercury.h>
+#include <mach/board.h>
+#include "msm_mercury_sync.h"
+#include "msm_mercury_common.h"
+#include "msm.h"
+
+#define MSM_MERCURY_NAME "mercury"
+
+static int msm_mercury_open(struct inode *inode, struct file *filp)
+{
+ int rc;
+
+ struct msm_mercury_device *pmercury_dev = container_of(inode->i_cdev,
+ struct msm_mercury_device, cdev);
+ filp->private_data = pmercury_dev;
+
+ MCR_DBG("\n---(%d)%s()\n", __LINE__, __func__);
+
+ rc = __msm_mercury_open(pmercury_dev);
+
+ MCR_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+ filp->f_path.dentry->d_name.name, pmercury_dev->open_count);
+
+ return rc;
+}
+
+static int msm_mercury_release(struct inode *inode, struct file *filp)
+{
+ int rc;
+
+ struct msm_mercury_device *pmercury_dev = filp->private_data;
+
+ MCR_DBG("\n---(%d)%s()\n", __LINE__, __func__);
+
+ rc = __msm_mercury_release(pmercury_dev);
+
+ MCR_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+ filp->f_path.dentry->d_name.name, pmercury_dev->open_count);
+ return rc;
+}
+
+static long msm_mercury_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg) {
+ int rc;
+ struct msm_mercury_device *pmercury_dev = filp->private_data;
+ rc = __msm_mercury_ioctl(pmercury_dev, cmd, arg);
+ return rc;
+}
+
+static const struct file_operations msm_mercury_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_mercury_open,
+ .release = msm_mercury_release,
+ .unlocked_ioctl = msm_mercury_ioctl,
+};
+
+static struct class *msm_mercury_class;
+static dev_t msm_mercury_devno;
+static struct msm_mercury_device *msm_mercury_device_p;
+
+int msm_mercury_subdev_init(struct v4l2_subdev *mercury_sd)
+{
+ int rc;
+ struct msm_mercury_device *pgmn_dev =
+ (struct msm_mercury_device *)mercury_sd->host_priv;
+
+ MCR_DBG("%s:%d: mercury_sd=0x%x pgmn_dev=0x%x\n",
+ __func__, __LINE__, (uint32_t)mercury_sd, (uint32_t)pgmn_dev);
+ rc = __msm_mercury_open(pgmn_dev);
+ MCR_DBG("%s:%d: rc=%d\n",
+ __func__, __LINE__, rc);
+ return rc;
+}
+
+static long msm_mercury_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ long rc;
+ struct msm_mercury_device *pgmn_dev =
+ (struct msm_mercury_device *)sd->host_priv;
+
+ MCR_DBG("%s: cmd=%d\n", __func__, cmd);
+
+ MCR_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev);
+
+ MCR_DBG("%s: Calling __msm_mercury_ioctl\n", __func__);
+
+ rc = __msm_mercury_ioctl(pgmn_dev, cmd, (unsigned long)arg);
+ pr_debug("%s: X\n", __func__);
+ return rc;
+}
+
+void msm_mercury_subdev_release(struct v4l2_subdev *mercury_sd)
+{
+ int rc;
+ struct msm_mercury_device *pgmn_dev =
+ (struct msm_mercury_device *)mercury_sd->host_priv;
+ MCR_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev);
+ rc = __msm_mercury_release(pgmn_dev);
+ MCR_DBG("%s:rc=%d", __func__, rc);
+}
+
+static const struct v4l2_subdev_core_ops msm_mercury_subdev_core_ops = {
+ .ioctl = msm_mercury_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_mercury_subdev_ops = {
+ .core = &msm_mercury_subdev_core_ops,
+};
+
+static int msm_mercury_init(struct platform_device *pdev)
+{
+ int rc = -1;
+ struct device *dev;
+
+ MCR_DBG("%s:\n", __func__);
+ msm_mercury_device_p = __msm_mercury_init(pdev);
+ if (msm_mercury_device_p == NULL) {
+ MCR_PR_ERR("%s: initialization failed\n", __func__);
+ goto fail;
+ }
+
+ v4l2_subdev_init(&msm_mercury_device_p->subdev,
+ &msm_mercury_subdev_ops);
+ v4l2_set_subdev_hostdata(&msm_mercury_device_p->subdev,
+ msm_mercury_device_p);
+ pr_debug("%s: msm_mercury_device_p 0x%x", __func__,
+ (uint32_t)msm_mercury_device_p);
+ MCR_DBG("%s:mercury: platform_set_drvdata\n", __func__);
+ platform_set_drvdata(pdev, &msm_mercury_device_p->subdev);
+
+ rc = alloc_chrdev_region(&msm_mercury_devno, 0, 1, MSM_MERCURY_NAME);
+ if (rc < 0) {
+ MCR_PR_ERR("%s: failed to allocate chrdev\n", __func__);
+ goto fail_1;
+ }
+
+ if (!msm_mercury_class) {
+ msm_mercury_class = class_create(THIS_MODULE, MSM_MERCURY_NAME);
+ if (IS_ERR(msm_mercury_class)) {
+ rc = PTR_ERR(msm_mercury_class);
+ MCR_PR_ERR("%s: create device class failed\n",
+ __func__);
+ goto fail_2;
+ }
+ }
+
+ dev = device_create(msm_mercury_class, NULL,
+ MKDEV(MAJOR(msm_mercury_devno), MINOR(msm_mercury_devno)), NULL,
+ "%s%d", MSM_MERCURY_NAME, 0);
+
+ if (IS_ERR(dev)) {
+ MCR_PR_ERR("%s: error creating device\n", __func__);
+ rc = -ENODEV;
+ goto fail_3;
+ }
+
+ cdev_init(&msm_mercury_device_p->cdev, &msm_mercury_fops);
+ msm_mercury_device_p->cdev.owner = THIS_MODULE;
+ msm_mercury_device_p->cdev.ops =
+ (const struct file_operations *) &msm_mercury_fops;
+ rc = cdev_add(&msm_mercury_device_p->cdev, msm_mercury_devno, 1);
+ if (rc < 0) {
+ MCR_PR_ERR("%s: error adding cdev\n", __func__);
+ rc = -ENODEV;
+ goto fail_4;
+ }
+
+ MCR_DBG("%s %s: success\n", __func__, MSM_MERCURY_NAME);
+
+ return rc;
+
+fail_4:
+ device_destroy(msm_mercury_class, msm_mercury_devno);
+
+fail_3:
+ class_destroy(msm_mercury_class);
+
+fail_2:
+ unregister_chrdev_region(msm_mercury_devno, 1);
+
+fail_1:
+ __msm_mercury_exit(msm_mercury_device_p);
+
+fail:
+ return rc;
+}
+
+static void msm_mercury_exit(void)
+{
+ cdev_del(&msm_mercury_device_p->cdev);
+ device_destroy(msm_mercury_class, msm_mercury_devno);
+ class_destroy(msm_mercury_class);
+ unregister_chrdev_region(msm_mercury_devno, 1);
+
+ __msm_mercury_exit(msm_mercury_device_p);
+}
+
+static int __msm_mercury_probe(struct platform_device *pdev)
+{
+ return msm_mercury_init(pdev);
+}
+
+static int __msm_mercury_remove(struct platform_device *pdev)
+{
+ msm_mercury_exit();
+ return 0;
+}
+
+static struct platform_driver msm_mercury_driver = {
+ .probe = __msm_mercury_probe,
+ .remove = __msm_mercury_remove,
+ .driver = {
+ .name = MSM_MERCURY_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_mercury_driver_init(void)
+{
+ int rc;
+ rc = platform_driver_register(&msm_mercury_driver);
+ return rc;
+}
+
+static void __exit msm_mercury_driver_exit(void)
+{
+ platform_driver_unregister(&msm_mercury_driver);
+}
+
+MODULE_DESCRIPTION("msm mercury jpeg driver");
+
+module_init(msm_mercury_driver_init);
+module_exit(msm_mercury_driver_exit);
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw.c b/drivers/media/video/msm/mercury/msm_mercury_hw.c
new file mode 100644
index 0000000..7bc4abe
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include "msm_mercury_hw.h"
+#include "msm_mercury_common.h"
+#include "msm_mercury_hw_reg.h"
+#include "msm_mercury_macros.h"
+
+static void *mercury_region_base;
+static uint32_t mercury_region_size;
+
+
+void msm_mercury_hw_write(struct msm_mercury_hw_cmd *hw_cmd_p)
+{
+ uint32_t *paddr;
+ uint32_t old_data, new_data;
+
+ paddr = mercury_region_base + hw_cmd_p->offset;
+
+ if (hw_cmd_p->mask == 0xffffffff) {
+ old_data = 0;
+ } else {
+ old_data = readl_relaxed(paddr);
+ old_data &= ~hw_cmd_p->mask;
+ }
+
+ new_data = hw_cmd_p->data & hw_cmd_p->mask;
+ new_data |= old_data;
+ writel_relaxed(new_data, paddr);
+}
+
+uint32_t msm_mercury_hw_read(struct msm_mercury_hw_cmd *hw_cmd_p)
+{
+ uint32_t *paddr;
+ uint32_t data;
+
+ paddr = mercury_region_base + hw_cmd_p->offset;
+
+ data = readl_relaxed(paddr);
+ data &= hw_cmd_p->mask;
+
+ MCR_DBG("MERCURY_READ: offset=0x%04X data=0x%08X\n",
+ hw_cmd_p->offset, data);
+
+ return data;
+}
+
+void msm_mercury_hw_start_decode(void)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kread(JPEG_STATUS);
+ mercury_kread(RTDMA_JPEG_RD_STA_ACK);
+ mercury_kread(RTDMA_JPEG_WR_STA_ACK);
+ mercury_kread(RTDMA_JPEG_RD_BUF_Y_PNTR);
+ mercury_kread(RTDMA_JPEG_WR_BUF_Y_PNTR);
+ mercury_kread(RTDMA_JPEG_WR_BUF_U_PNTR);
+ mercury_kwrite(RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO, (7<<2));
+ return;
+}
+
+void msm_mercury_hw_bitstream_buf_cfg(uint32_t bitstream_buf_addr)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_RD_BUF_Y_PNTR, bitstream_buf_addr);
+ return;
+}
+
+
+void msm_mercury_hw_output_y_buf_cfg(uint32_t y_buf_addr)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_WR_BUF_Y_PNTR, y_buf_addr);
+ return;
+}
+
+void msm_mercury_hw_output_u_buf_cfg(uint32_t u_buf_addr)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_WR_BUF_U_PNTR, u_buf_addr);
+ return;
+}
+
+void msm_mercury_hw_output_v_buf_cfg(uint32_t v_buf_addr)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_WR_BUF_V_PNTR, v_buf_addr);
+ return;
+}
+
+int msm_mercury_hw_wait(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us)
+{
+ int tm = hw_cmd_p->n;
+ uint32_t data;
+ uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
+
+ data = msm_mercury_hw_read(hw_cmd_p);
+ if (data != wait_data) {
+ while (tm) {
+ udelay(m_us);
+ data = msm_mercury_hw_read(hw_cmd_p);
+ if (data == wait_data)
+ break;
+ tm--;
+ }
+ }
+ hw_cmd_p->data = data;
+ return tm;
+}
+
+void msm_mercury_hw_irq_get_status(uint16_t *rd_irq, uint16_t *wr_irq)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+ rmb();
+ mercury_kread(RTDMA_JPEG_RD_STA_ACK);
+ *rd_irq = hw_cmd.data;
+
+ mercury_kread(RTDMA_JPEG_WR_STA_ACK);
+ *wr_irq = hw_cmd.data;
+ rmb();
+}
+
+void msm_mercury_hw_get_jpeg_status(uint32_t *jpeg_status)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ rmb();
+ mercury_kread(JPEG_STATUS);
+ *jpeg_status = hw_cmd.data;
+ rmb();
+}
+
+uint32_t msm_mercury_get_restartInterval(void)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ rmb();
+ mercury_kread(JPEG_DRI);
+ rmb();
+ return hw_cmd.data;
+
+}
+
+void msm_mercury_hw_rd_irq_clear(uint32_t val)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+ mercury_kwrite(RTDMA_JPEG_RD_STA_ACK, val);
+}
+
+void msm_mercury_hw_wr_irq_clear(uint32_t val)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_WR_STA_ACK, val);
+}
+
+void msm_mercury_hw_set_rd_irq_mask(uint32_t val)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_RD_INT_EN, val);
+}
+
+void msm_mercury_hw_set_wr_irq_mask(uint32_t val)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_WR_INT_EN, val);
+}
+
+void msm_mercury_set_jpeg_ctl_common(uint32_t val)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(JPEG_CTRL_COMMON, val);
+}
+
+void msm_mercury_hw_reset(void)
+{
+ uint32_t val;
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ wmb();
+ /* disable all interrupts*/
+ mercury_kwrite(RTDMA_JPEG_RD_INT_EN, 0);
+
+ mercury_kwrite(RTDMA_JPEG_WR_INT_EN, 0);
+
+ /* clear pending interrupts*/
+ val = 0;
+ MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK,
+ SW_RESET_ABORT_RDY_ACK,
+ ERR_ACK, 1, 1);
+ MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+ mercury_kwrite(RTDMA_JPEG_WR_STA_ACK, val);
+
+ val = 0;
+ MEM_OUTF2(&val, RTDMA_JPEG_RD_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+ mercury_kwrite(RTDMA_JPEG_RD_STA_ACK, val);
+
+ /* enable SWResetAbortRdyInt for core reset*/
+ val = 0;
+ MEM_OUTF(&val, RTDMA_JPEG_WR_INT_EN, SW_RESET_ABORT_RDY_EN, 1);
+ mercury_kwrite(RTDMA_JPEG_WR_INT_EN, val);
+
+ /* Reset Core from MMSS Fabric*/
+ mercury_core_reset();
+
+ /* disable all interrupts*/
+ mercury_kwrite(RTDMA_JPEG_WR_INT_EN, 0);
+
+ /* clear pending interrupts*/
+ val = 0;
+ MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK,
+ SW_RESET_ABORT_RDY_ACK,
+ ERR_ACK, 1, 1);
+ MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+ mercury_kwrite(RTDMA_JPEG_WR_STA_ACK, val);
+
+ val = 0;
+ MEM_OUTF2(&val, RTDMA_JPEG_RD_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+ mercury_kwrite(RTDMA_JPEG_RD_STA_ACK, val);
+
+ /* enable neccessary interrupt source*/
+ val = 0;
+ MEM_OUTF2(&val, RTDMA_JPEG_WR_INT_EN, EOF_EN, ERR_EN, 1, 1);
+ MEM_OUTF(&val, RTDMA_JPEG_WR_INT_EN, SW_RESET_ABORT_RDY_EN, 1);
+ mercury_kwrite(RTDMA_JPEG_WR_INT_EN, val);
+
+ wmb();
+
+}
+
+void msm_mercury_hw_init(void *base, int size)
+{
+ mercury_region_base = base;
+ mercury_region_size = size;
+}
+
+
+void msm_mercury_hw_delay(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us)
+{
+ int tm = hw_cmd_p->n;
+ while (tm) {
+ udelay(m_us);
+ tm--;
+ }
+}
+
+int msm_mercury_hw_exec_cmds(struct msm_mercury_hw_cmd *hw_cmd_p, int m_cmds)
+{
+ int is_copy_to_user = -1;
+ uint32_t data;
+ if (m_cmds > 1)
+ MCR_DBG("m_cmds = %d\n", m_cmds);
+
+ while (m_cmds--) {
+ if (hw_cmd_p->offset > mercury_region_size) {
+ MCR_PR_ERR("%s:%d] %d exceed hw region %d\n",
+ __func__, __LINE__, hw_cmd_p->offset,
+ mercury_region_size);
+ return -EFAULT;
+ }
+
+ switch (hw_cmd_p->type) {
+ case MSM_MERCURY_HW_CMD_TYPE_READ:
+ hw_cmd_p->data = msm_mercury_hw_read(hw_cmd_p);
+ is_copy_to_user = 1;
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_WRITE:
+ msm_mercury_hw_write(hw_cmd_p);
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_WRITE_OR:
+ data = msm_mercury_hw_read(hw_cmd_p);
+ hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
+ data;
+ msm_mercury_hw_write(hw_cmd_p);
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_UWAIT:
+ msm_mercury_hw_wait(hw_cmd_p, 1);
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_MWAIT:
+ msm_mercury_hw_wait(hw_cmd_p, 1000);
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_UDELAY:
+ msm_mercury_hw_delay(hw_cmd_p, 1);
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_MDELAY:
+ msm_mercury_hw_delay(hw_cmd_p, 1000);
+ break;
+
+ default:
+ MCR_DBG("wrong hw command type\n");
+ break;
+ }
+
+ hw_cmd_p++;
+ }
+ return is_copy_to_user;
+}
+
+void msm_mercury_hw_region_dump(int size)
+{
+ uint32_t *p;
+ uint8_t *p8;
+
+ MCR_DBG("(%d)%s()\n", __LINE__, __func__);
+ if (size > mercury_region_size)
+ MCR_DBG("%s:%d] wrong region dump size\n",
+ __func__, __LINE__);
+
+ p = (uint32_t *) mercury_region_base;
+ while (size >= 16) {
+ MCR_DBG("0x%08X] %08X %08X %08X %08X\n",
+ mercury_region_size - size,
+ readl_relaxed(p), readl_relaxed(p+1),
+ readl_relaxed(p+2), readl_relaxed(p+3));
+ p += 4;
+ size -= 16;
+ }
+
+ if (size > 0) {
+ uint32_t d;
+ MCR_DBG("0x%08X] ", mercury_region_size - size);
+ while (size >= 4) {
+ MCR_DBG("%08X ", readl_relaxed(p++));
+ size -= 4;
+ }
+
+ d = readl_relaxed(p);
+ p8 = (uint8_t *) &d;
+ while (size) {
+ MCR_DBG("%02X", *p8++);
+ size--;
+ }
+
+ MCR_DBG("\n");
+ }
+}
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw.h b/drivers/media/video/msm/mercury/msm_mercury_hw.h
new file mode 100644
index 0000000..f6e3e49
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw.h
@@ -0,0 +1,70 @@
+/* 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 MSM_MERCURY_HW_H
+#define MSM_MERCURY_HW_H
+
+#include <media/msm_mercury.h>
+
+/*number of pel per block (horiz/vert)*/
+#define JPEGDEC_BLOCK_SIZE (8)
+/* Hardware alignment*/
+#define JPEGDEC_HW_ALIGN (8)
+#define JPEGDEC_HW_SAMPLING_RATIO_MAX (4)
+
+#define MSM_MERCURY_HW_IRQ_SW_RESET_ACK (1<<3)
+#define MSM_MERCURY_HW_IRQ_WR_ERR_ACK (1<<2)
+#define MSM_MERCURY_HW_IRQ_WR_EOI_ACK (1<<1)
+#define MSM_MERCURY_HW_IRQ_WR_SOF_ACK (1<<0)
+
+#define MSM_MERCURY_HW_IRQ_RD_EOF_ACK (1<<1)
+#define MSM_MERCURY_HW_IRQ_RD_SOF_ACK (1<<0)
+
+extern int mercury_core_reset(void);
+
+struct msm_mercury_hw_buf {
+ struct msm_mercury_buf vbuf;
+ struct file *file;
+ uint32_t framedone_len;
+ uint32_t y_buffer_addr;
+ uint32_t y_len;
+ uint32_t cbcr_buffer_addr;
+ uint32_t cbcr_len;
+ uint32_t num_of_mcu_rows;
+ struct msm_mapped_buffer *msm_buffer;
+ int *subsystem_id;
+ struct ion_handle *handle;
+};
+
+
+void msm_mercury_hw_reset(void);
+void msm_mercury_hw_init(void *base, int size);
+void msm_mercury_hw_rd_irq_clear(uint32_t val);
+void msm_mercury_hw_wr_irq_clear(uint32_t val);
+
+uint32_t msm_mercury_hw_read(struct msm_mercury_hw_cmd *hw_cmd_p);
+void msm_mercury_hw_write(struct msm_mercury_hw_cmd *hw_cmd_p);
+int msm_mercury_hw_wait(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us);
+void msm_mercury_hw_delay(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us);
+int msm_mercury_hw_exec_cmds(struct msm_mercury_hw_cmd *hw_cmd_p, int m_cmds);
+void msm_mercury_hw_region_dump(int size);
+
+
+void msm_mercury_hw_irq_get_status(uint16_t *rd_irq, uint16_t *wr_irq);
+void msm_mercury_hw_start_decode(void);
+void msm_mercury_hw_get_jpeg_status(uint32_t *jpeg_status);
+void msm_mercury_hw_output_y_buf_cfg(uint32_t y_buf_addr);
+void msm_mercury_hw_output_u_buf_cfg(uint32_t u_buf_addr);
+void msm_mercury_hw_output_v_buf_cfg(uint32_t v_buf_addr);
+void msm_mercury_hw_bitstream_buf_cfg(uint32_t bitstream_buf_addr);
+
+#endif /* MSM_MERCURY_HW_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw_reg.h b/drivers/media/video/msm/mercury/msm_mercury_hw_reg.h
new file mode 100644
index 0000000..671bc66
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw_reg.h
@@ -0,0 +1,715 @@
+/* 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 MSM_MERCURY_HW_REG_H
+#define MSM_MERCURY_HW_REG_H
+
+
+#define JPEGD_BASE 0x00000000
+
+/* Register ADDR, RMSK, and SHFT*/
+/* RW */
+#define JPEG_CTRL_COMMON JPEG_CTRL_COMMON
+#define HWIO_JPEG_CTRL_COMMON_ADDR (JPEGD_BASE+0x00000000)
+#define HWIO_JPEG_CTRL_COMMON__POR 0x00000000
+#define HWIO_JPEG_CTRL_COMMON__RMSK 0x0000001F
+#define HWIO_JPEG_CTRL_COMMON__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_ZZ_OVERRIDE_EN__BMSK 0x00000010
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_ZZ_OVERRIDE_EN__SHFT 4
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_MODE__BMSK 0x0000000F
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_MODE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+/* RW */
+#define JPEG_CTRL_ENCODE JPEG_CTRL_ENCODE
+#define HWIO_JPEG_CTRL_ENCODE_ADDR (JPEGD_BASE+0x00000008)
+#define HWIO_JPEG_CTRL_ENCODE__POR 0x00000000
+#define HWIO_JPEG_CTRL_ENCODE__RMSK 0x00000010
+#define HWIO_JPEG_CTRL_ENCODE__SHFT 4
+/* Register Element MIN and MAX*/
+#define HWIO_JPEG_CTRL_ENCODE___S 4
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_CTRL_ENCODE__JPEG_CTRL_ENCODE_EOI_MARKER_EN__BMSK 0x00000010
+#define HWIO_JPEG_CTRL_ENCODE__JPEG_CTRL_ENCODE_EOI_MARKER_EN__SHFT 4
+
+/* Register Field FMSK and SHFT*/
+#define JPEG_STATUS JPEG_STATUS
+#define HWIO_JPEG_STATUS_ADDR (JPEGD_BASE+0x00000010)
+#define HWIO_JPEG_STATUS__POR 0x00000000
+#define HWIO_JPEG_STATUS__RMSK 0x00003FF0
+#define HWIO_JPEG_STATUS__SHFT 4
+/* Register Element MIN and MAX*/
+#define HWIO_JPEG_STATUS___S 4
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_STATUS__JPEG_STATUS_REGISTER_TIMEOUT__BMSK 0x00002000
+#define HWIO_JPEG_STATUS__JPEG_STATUS_REGISTER_TIMEOUT__SHFT 13
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_EOI__BMSK 0x00001000
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_EOI__SHFT 12
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_UNESCAPED_FF__BMSK 0x00000800
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_UNESCAPED_FF__SHFT 11
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_HUFFCODE__BMSK 0x00000400
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_HUFFCODE__SHFT 10
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_MARKER__BMSK 0x00000200
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_MARKER__SHFT 9
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_SEQ__BMSK 0x00000100
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_SEQ__SHFT 8
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_OVRFLW__BMSK 0x00000080
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_OVRFLW__SHFT 7
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_UNDFLW__BMSK 0x00000040
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_UNDFLW__SHFT 6
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_OVRFLW__BMSK 0x00000020
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_OVRFLW__SHFT 5
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_UNDFLW__BMSK 0x00000010
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_UNDFLW__SHFT 4
+
+/* Register ADDR, RMSK, and SHFT*/
+/* R */
+#define JPEG_SOF_REG_0 JPEG_SOF_REG_0
+#define HWIO_JPEG_SOF_REG_0_ADDR /* RW */ (JPEGD_BASE+0x00000014)
+#define HWIO_JPEG_SOF_REG_0__POR 0x00000000
+#define HWIO_JPEG_SOF_REG_0__RMSK 0x000000FF
+#define HWIO_JPEG_SOF_REG_0__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOF_REG_0__JPEG_SOF_REG_0_NF__BMSK 0x000000FF
+#define HWIO_JPEG_SOF_REG_0__JPEG_SOF_REG_0_NF__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOF_REG_1 JPEG_SOF_REG_1
+#define HWIO_JPEG_SOF_REG_1_ADDR /* RW */ (JPEGD_BASE+0x00000018)
+#define HWIO_JPEG_SOF_REG_1__POR 0x00000000
+#define HWIO_JPEG_SOF_REG_1__RMSK 0x00FFFFFF
+#define HWIO_JPEG_SOF_REG_1__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_C__BMSK 0x00FF0000
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_C__SHFT 16
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_H__BMSK 0x0000F000
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_H__SHFT 12
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_V__BMSK 0x00000F00
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_V__SHFT 8
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_TQ__BMSK 0x000000FF
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_TQ__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOF_REG_2 JPEG_SOF_REG_2
+#define HWIO_JPEG_SOF_REG_2_ADDR /* RW */ (JPEGD_BASE+0x0000001C)
+#define HWIO_JPEG_SOF_REG_2__POR 0x00000000
+#define HWIO_JPEG_SOF_REG_2__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_SOF_REG_2__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_Y__BMSK 0xFFFF0000
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_Y__SHFT 16
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_X__BMSK 0x0000FFFF
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_X__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOS_REG_0 JPEG_SOS_REG_0
+#define HWIO_JPEG_SOS_REG_0_ADDR /* RW */ (JPEGD_BASE+0x00000020)
+#define HWIO_JPEG_SOS_REG_0__POR 0x00000000
+#define HWIO_JPEG_SOS_REG_0__RMSK 0xFF000000
+#define HWIO_JPEG_SOS_REG_0__SHFT 24
+/*Register Element MIN and MAX*/
+#define HWIO_JPEG_SOS_REG_0___S 24
+#define HWIO_JPEG_SOS_REG_0___S 24
+#define HWIO_JPEG_SOS_REG_0___S 24
+#define HWIO_JPEG_SOS_REG_0___S 24
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOS_REG_0__JPEG_SOS_REG_0_NS__BMSK 0xFF000000
+#define HWIO_JPEG_SOS_REG_0__JPEG_SOS_REG_0_NS__SHFT 24
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOS_REG_1 JPEG_SOS_REG_1
+#define HWIO_JPEG_SOS_REG_1_ADDR /* RW */ (JPEGD_BASE+0x00000024)
+#define HWIO_JPEG_SOS_REG_1__POR 0x00000000
+#define HWIO_JPEG_SOS_REG_1__RMSK 0x0000FFFF
+#define HWIO_JPEG_SOS_REG_1__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_CS__BMSK 0x0000FF00
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_CS__SHFT 8
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TD__BMSK 0x000000F0
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TD__SHFT 4
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TA__BMSK 0x0000000F
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TA__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_QT_IDX JPEG_QT_IDX
+#define HWIO_JPEG_QT_IDX_ADDR (JPEGD_BASE+0x00000030)
+#define HWIO_JPEG_QT_IDX__POR 0x00000000
+#define HWIO_JPEG_QT_IDX__RMSK 0x0000FFFF
+#define HWIO_JPEG_QT_IDX__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_1__BMSK 0x0000FF00
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_1__SHFT 8
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_0__BMSK 0x000000FF
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_0__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DQT JPEG_DQT
+#define HWIO_JPEG_DQT_ADDR /* RW */ (JPEGD_BASE+0x00000034)
+#define HWIO_JPEG_DQT__POR 0x00000000
+#define HWIO_JPEG_DQT__RMSK 0x0F00FFFF
+#define HWIO_JPEG_DQT__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DQT__JPEG_DQT_TQ__BMSK 0x0F000000
+#define HWIO_JPEG_DQT__JPEG_DQT_TQ__SHFT 24
+#define HWIO_JPEG_DQT__JPEG_DQT_QK__BMSK 0x0000FFFF
+#define HWIO_JPEG_DQT__JPEG_DQT_QK__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DRI JPEG_DRI
+#define HWIO_JPEG_DRI_ADDR /* RW */ (JPEGD_BASE+0x00000040)
+#define HWIO_JPEG_DRI__POR 0x00000000
+#define HWIO_JPEG_DRI__RMSK 0x0000FFFF
+#define HWIO_JPEG_DRI__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DRI__JPEG_DRI_RI__BMSK 0x0000FFFF
+#define HWIO_JPEG_DRI__JPEG_DRI_RI__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_REG_0 JPEG_DHT_REG_0
+#define HWIO_JPEG_DHT_REG_0_ADDR /* RW */ (JPEGD_BASE+0x00000050)
+#define HWIO_JPEG_DHT_REG_0__POR 0x00000000
+#define HWIO_JPEG_DHT_REG_0__RMSK 0x000000FF
+#define HWIO_JPEG_DHT_REG_0__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TH__BMSK 0x000000F0
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TH__SHFT 4
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TC__BMSK 0x0000000F
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TC__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_IDX JPEG_DHT_IDX
+#define HWIO_JPEG_DHT_IDX_ADDR /* RW */ (JPEGD_BASE+0x00000054)
+#define HWIO_JPEG_DHT_IDX__POR 0x00000000
+#define HWIO_JPEG_DHT_IDX__RMSK 0x00000FFF
+#define HWIO_JPEG_DHT_IDX__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_CCC_MAX__BMSK 0x00000F00
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_CCC_MAX__SHFT 8
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_VIJ__BMSK 0x000000FF
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_VIJ__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_REG_1 JPEG_DHT_REG_1
+#define HWIO_JPEG_DHT_REG_1_ADDR /* RW */ (JPEGD_BASE+0x00000058)
+#define HWIO_JPEG_DHT_REG_1__POR 0x00000000
+#define HWIO_JPEG_DHT_REG_1__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_DHT_REG_1__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_0__BMSK 0xFF000000
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_0__SHFT 24
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_1__BMSK 0x00FF0000
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_1__SHFT 16
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_2__BMSK 0x0000FF00
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_2__SHFT 8
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_3__BMSK 0x000000FF
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_3__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_CCC_MAX JPEG_DHT_CCC_MAX
+#define HWIO_JPEG_DHT_CCC_MAX_ADDR /* RW */ (JPEGD_BASE+0x0000005C)
+#define HWIO_JPEG_DHT_CCC_MAX__POR 0x00000000
+#define HWIO_JPEG_DHT_CCC_MAX__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_DHT_CCC_MAX__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__BMSK 0xFFFF0000
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__SHFT 16
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__BMSK 0x0000FFFF
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__BMSK 0xFFFF0000
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__SHFT 16
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__BMSK 0x0000FFFF
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__SHFT 0
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_LI__BMSK 0x000000FF
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_LI__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DEC_SCALE JPEG_DEC_SCALE
+#define HWIO_JPEG_DEC_SCALE_ADDR /* RW */ (JPEGD_BASE+0x00000060)
+#define HWIO_JPEG_DEC_SCALE__POR 0x00000000
+#define HWIO_JPEG_DEC_SCALE__RMSK 0x00000003
+#define HWIO_JPEG_DEC_SCALE__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DEC_SCALE__JPEG_DEC_SCALE_RATIO__BMSK 0x00000003
+#define HWIO_JPEG_DEC_SCALE__JPEG_DEC_SCALE_RATIO__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_CONVERT JPEG_CONVERT
+#define HWIO_JPEG_CONVERT_ADDR /* RW */ (JPEGD_BASE+0x00000064)
+#define HWIO_JPEG_CONVERT__POR 0x00000000
+#define HWIO_JPEG_CONVERT__RMSK 0xFFFF13FF
+#define HWIO_JPEG_CONVERT__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CB_VALUE__BMSK 0xFF000000
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CB_VALUE__SHFT 24
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CR_VALUE__BMSK 0x00FF0000
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CR_VALUE__SHFT 16
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CLAMP_EN__BMSK 0x00001000
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CLAMP_EN__SHFT 12
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CBCR_SWITCH__BMSK 0x00000200
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CBCR_SWITCH__SHFT 9
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONOCHROME_EN__BMSK 0x00000100
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONOCHROME_EN__SHFT 8
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MEM_ORG__BMSK 0x000000C0
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MEM_ORG__SHFT 6
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_422_MCU_TYPE__BMSK 0x00000030
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_422_MCU_TYPE__SHFT 4
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_OUTPUT_FORMAT__BMSK 0x0000000C
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_OUTPUT_FORMAT__SHFT 2
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_INPUT_FORMAT__BMSK 0x00000003
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_INPUT_FORMAT__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_ENC_BYTE_CNT JPEG_ENC_BYTE_CNT
+#define HWIO_JPEG_ENC_BYTE_CNT_ADDR /* RW */ (JPEGD_BASE+0x00000070)
+#define HWIO_JPEG_ENC_BYTE_CNT__POR 0x00000000
+#define HWIO_JPEG_ENC_BYTE_CNT__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_ENC_BYTE_CNT__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_ENC_BYTE_CNT__JPEG_ENC_BYTE_CNT_TOT__BMSK 0xFFFFFFFF
+#define HWIO_JPEG_ENC_BYTE_CNT__JPEG_ENC_BYTE_CNT_TOT__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DEBUG JPEG_DEBUG
+#define HWIO_JPEG_DEBUG_ADDR /* RW */ (JPEGD_BASE+0x00000080)
+#define HWIO_JPEG_DEBUG__POR 0x4A504547
+#define HWIO_JPEG_DEBUG__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_DEBUG__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DEBUG__JPEG_DEBUG__BMSK 0xFFFFFFFF
+#define HWIO_JPEG_DEBUG__JPEG_DEBUG__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SPARE JPEG_SPARE
+#define HWIO_JPEG_SPARE_ADDR /* RW */ (JPEGD_BASE+0x00000084)
+#define HWIO_JPEG_SPARE__POR 0x00000000
+#define HWIO_JPEG_SPARE__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_SPARE__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SPARE__JPEG_SPARE_00__BMSK 0xFFFFFFFF
+#define HWIO_JPEG_SPARE__JPEG_SPARE_00__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_REGISTER_TIMEOUT JPEG_REGISTER_TIMEOUT
+#define HWIO_JPEG_REGISTER_TIMEOUT_ADDR (JPEGD_BASE+0x00000088)
+#define HWIO_JPEG_REGISTER_TIMEOUT__POR 0x0000FFFF
+#define HWIO_JPEG_REGISTER_TIMEOUT__RMSK 0x0000FFFF
+#define HWIO_JPEG_REGISTER_TIMEOUT__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_REGISTER_TIMEOUT__JPEG_TIMEOUT_VALUE__BMSK 0x0000FFFF
+#define HWIO_JPEG_REGISTER_TIMEOUT__JPEG_TIMEOUT_VALUE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEGD_STATUS_BUS_DATA JPEGD_STATUS_BUS_DATA
+#define HWIO_JPEGD_STATUS_BUS_DATA_ADDR /* RW */ (JPEGD_BASE+0x00000258)
+#define HWIO_JPEGD_STATUS_BUS_DATA__POR 0x00000000
+#define HWIO_JPEGD_STATUS_BUS_DATA__RMSK 0xFFFFFFFF
+#define HWIO_JPEGD_STATUS_BUS_DATA__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEGD_STATUS_BUS_DATA__STATUS_BUS_DATA__BMSK 0xFFFFFFFF
+#define HWIO_JPEGD_STATUS_BUS_DATA__STATUS_BUS_DATA__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEGD_STATUS_BUS_CONFIG JPEGD_STATUS_BUS_CONFIG
+#define HWIO_JPEGD_STATUS_BUS_CONFIG_ADDR /* RW */ (JPEGD_BASE+0x0000025C)
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__POR 0x00000000
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__RMSK 0x0000001F
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__STATUS_BUS_SEL__BMSK 0x0000001F
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__STATUS_BUS_SEL__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_AXI_CONFIG RTDMA_JPEG_AXI_CONFIG
+#define HWIO_RTDMA_JPEG_AXI_CONFIG_ADDR /* RW */ (JPEGD_BASE+0x00000260)
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__POR 0x00000024
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__RMSK 0x00000FFF
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_WR__BMSK 0x00000800
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_WR__SHFT 11
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_RD__BMSK 0x00000400
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_RD__SHFT 10
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__BOUND_LIMIT__BMSK 0x00000300
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__BOUND_LIMIT__SHFT 8
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_TIMEOUT__BMSK 0x000000F0
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_TIMEOUT__SHFT 4
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_MAX_BLEN__BMSK 0x0000000F
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_MAX_BLEN__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEGD_CLK_CONTROL JPEGD_CLK_CONTROL
+#define HWIO_JPEGD_CLK_CONTROL_ADDR /* RW */ (JPEGD_BASE+0x00000264)
+#define HWIO_JPEGD_CLK_CONTROL__POR 0x00000005
+#define HWIO_JPEGD_CLK_CONTROL__RMSK 0x0000000F
+#define HWIO_JPEGD_CLK_CONTROL__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKIDLE__BMSK 0x00000008
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKIDLE__SHFT 3
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKON__BMSK 0x00000004
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKON__SHFT 2
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKIDLE__BMSK 0x00000002
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKIDLE__SHFT 1
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKON__BMSK 0x00000001
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKON__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_CONFIG RTDMA_JPEG_WR_BUF_CONFIG
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG_ADDR /* RW */ (JPEGD_BASE+0x00000200)
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__RMSK 0x0000001F
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__BUF_FORMAT__BMSK 0x0000001C
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__BUF_FORMAT__SHFT 2
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__NUM_OF_PLANES__BMSK 0x00000003
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__NUM_OF_PLANES__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_OP RTDMA_JPEG_WR_OP
+#define HWIO_RTDMA_JPEG_WR_OP_ADDR /* RW */ (JPEGD_BASE+0x00000204)
+#define HWIO_RTDMA_JPEG_WR_OP__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_OP__RMSK 0x00000013
+#define HWIO_RTDMA_JPEG_WR_OP__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_OP__ALIGN__BMSK 0x00000010
+#define HWIO_RTDMA_JPEG_WR_OP__ALIGN__SHFT 4
+#define HWIO_RTDMA_JPEG_WR_OP__FLIP__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_WR_OP__FLIP__SHFT 1
+#define HWIO_RTDMA_JPEG_WR_OP__MIRROR__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_WR_OP__MIRROR__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_Y_PNTR RTDMA_JPEG_WR_BUF_Y_PNTR
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR_ADDR (JPEGD_BASE+0x00000208)
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__SHFT 3
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_U_PNTR RTDMA_JPEG_WR_BUF_U_PNTR
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR_ADDR /* RW */ (JPEGD_BASE+0x0000020C)
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_V_PNTR RTDMA_JPEG_WR_BUF_V_PNTR
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR_ADDR (JPEGD_BASE+0x00000210)
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_PITCH RTDMA_JPEG_WR_BUF_PITCH
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH_ADDR /* RW */ (JPEGD_BASE+0x00000214)
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__RMSK 0x00003FF8
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__PITCH__BMSK 0x00003FF8
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__PITCH__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_PLANE_SIZE RTDMA_JPEG_WR_PLANE_SIZE
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE_ADDR /* RW */ (JPEGD_BASE+0x00000218)
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__RMSK 0x1FFF1FFF
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_VSIZE__BMSK 0x1FFF0000
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_VSIZE__SHFT 16
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_HSIZE__BMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_HSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BLOCK_SIZE RTDMA_JPEG_WR_BLOCK_SIZE
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE_ADDR /* RW */ (JPEGD_BASE+0x0000021C)
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__RMSK 0x00000FFF
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_VSIZE__BMSK 0x00000FC0
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_VSIZE__SHFT 6
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_HSIZE__BMSK 0x0000003F
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_HSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUFFER_SIZE RTDMA_JPEG_WR_BUFFER_SIZE
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE_ADDR /* RW */ (JPEGD_BASE+0x00000220)
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__RMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__BUFFER_VSIZE__BMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__BUFFER_VSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_STA_ACK RTDMA_JPEG_WR_STA_ACK
+#define HWIO_RTDMA_JPEG_WR_STA_ACK_ADDR /* RW */ (JPEGD_BASE+0x00000224)
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__RMSK 0x0000000F
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S 3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S 3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S 3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_STA__BMSK 0x00000008
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_STA__SHFT 3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_ACK__BMSK 0x00000008
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_ACK__SHFT 3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_STA__BMSK 0x00000004
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_STA__SHFT 2
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_ACK__BMSK 0x00000004
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_ACK__SHFT 2
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_STA__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_STA__SHFT 1
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_ACK__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_ACK__SHFT 1
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_STA__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_STA__SHFT 0
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_ACK__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_ACK__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_INT_EN RTDMA_JPEG_WR_INT_EN
+#define HWIO_RTDMA_JPEG_WR_INT_EN_ADDR /* W */ (JPEGD_BASE+0x00000228)
+#define HWIO_RTDMA_JPEG_WR_INT_EN__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_INT_EN__RMSK 0x0000000F
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SW_RESET_ABORT_RDY_EN__BMSK 0x00000008
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SW_RESET_ABORT_RDY_EN__SHFT 3
+#define HWIO_RTDMA_JPEG_WR_INT_EN__ERR_EN__BMSK 0x00000004
+#define HWIO_RTDMA_JPEG_WR_INT_EN__ERR_EN__SHFT 2
+#define HWIO_RTDMA_JPEG_WR_INT_EN__EOF_EN__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_WR_INT_EN__EOF_EN__SHFT 1
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SOF_EN__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SOF_EN__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_CONFIG RTDMA_JPEG_RD_BUF_CONFIG
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG_ADDR /* RW */ (JPEGD_BASE+0x00000100)
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__RMSK 0x0000001F
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__BUF_FORMAT__BMSK 0x0000001C
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__BUF_FORMAT__SHFT 2
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__NUM_OF_PLANES__BMSK 0x00000003
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__NUM_OF_PLANES__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT, W */
+#define RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO_ADDR (JPEGD_BASE+0x00000104)
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__RMSK 0x0000001C
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__SHFT 2
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S 2
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S 2
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S 2
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S 2
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_APPLY__BMSK 0x00000010
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_APPLY__SHFT 4
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_EOF__BMSK 0x00000008
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_EOF__SHFT 3
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_SOF__BMSK 0x00000004
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_SOF__SHFT 2
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_Y_PNTR RTDMA_JPEG_RD_BUF_Y_PNTR
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR_ADDR /* RW */ (JPEGD_BASE+0x0000010C)
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_U_PNTR RTDMA_JPEG_RD_BUF_U_PNTR
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR_ADDR /* RW */ (JPEGD_BASE+0x00000110)
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_V_PNTR RTDMA_JPEG_RD_BUF_V_PNTR
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR_ADDR /* RW */ (JPEGD_BASE+0x00000114)
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_PITCH RTDMA_JPEG_RD_BUF_PITCH
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH_ADDR /* RW */ (JPEGD_BASE+0x00000118)
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__RMSK 0x00003FF8
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__PITCH__BMSK 0x00003FF8
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__PITCH__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_PLANE_SIZE RTDMA_JPEG_RD_PLANE_SIZE
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE_ADDR /* RW */ (JPEGD_BASE+0x0000011C)
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__RMSK 0x1FFF1FFF
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_VSIZE__BMSK 0x1FFF0000
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_VSIZE__SHFT 16
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_HSIZE__BMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_HSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BLOCK_SIZE RTDMA_JPEG_RD_BLOCK_SIZE
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE_ADDR /* RW */ (JPEGD_BASE+0x00000120)
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__POR 0x000003CF
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__RMSK 0x00000FFF
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_VSIZE__BMSK 0x00000FC0
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_VSIZE__SHFT 6
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_HSIZE__BMSK 0x0000003F
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_HSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUFFER_SIZE RTDMA_JPEG_RD_BUFFER_SIZE
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE_ADDR (JPEGD_BASE+0x00000124)
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__RMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__BUFFER_VSIZE__BMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__BUFFER_VSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_STA_ACK RTDMA_JPEG_RD_STA_ACK
+#define HWIO_RTDMA_JPEG_RD_STA_ACK_ADDR (JPEGD_BASE+0x00000128)
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__RMSK 0x00000003
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_STA__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_STA__SHFT 1
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_STA__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_STA__SHFT 0
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_ACK__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_ACK__SHFT 1
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_ACK__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_ACK__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_INT_EN RTDMA_JPEG_RD_INT_EN
+#define HWIO_RTDMA_JPEG_RD_INT_EN_ADDR /* W */ (JPEGD_BASE+0x0000012C)
+#define HWIO_RTDMA_JPEG_RD_INT_EN__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_INT_EN__RMSK 0x00000003
+#define HWIO_RTDMA_JPEG_RD_INT_EN__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_INT_EN__EOF_EN__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_RD_INT_EN__EOF_EN__SHFT 1
+#define HWIO_RTDMA_JPEG_RD_INT_EN__SOF_EN__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_RD_INT_EN__SOF_EN__SHFT 0
+
+#endif /* MSM_MERCURY_HW_REG_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_macros.h b/drivers/media/video/msm/mercury/msm_mercury_macros.h
new file mode 100644
index 0000000..33c4f9a
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_macros.h
@@ -0,0 +1,118 @@
+/* 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 MSM_MERCURY_MACROS_H
+#define MSM_MERCURY_MACROS_H
+
+#include <media/msm_mercury.h>
+
+#define mercury_kread(reg) \
+ hw_cmd.type = MSM_MERCURY_HW_CMD_TYPE_READ; \
+ hw_cmd.n = 1; \
+ hw_cmd.offset = HWIO_##reg##_ADDR; \
+ hw_cmd.mask = HWIO_##reg##__RMSK; \
+ hw_cmd.data = 0x0; \
+ msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+
+#define mercury_kwrite(reg, val) \
+ hw_cmd.offset = HWIO_##reg##_ADDR; \
+ hw_cmd.mask = HWIO_##reg##__RMSK; \
+ hw_cmd.type = MSM_MERCURY_HW_CMD_TYPE_WRITE; \
+ hw_cmd.n = 1; \
+ hw_cmd.data = val; \
+ msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+
+#define GET_FVAL(val, reg, field) ((val & HWIO_FMSK(reg, field)) >> \
+ HWIO_SHFT(reg, field))
+
+#define byte unsigned char
+#define word unsigned short
+#define dword unsigned long
+
+#define inp(port) (*((dword *) (port)))
+#define inpb(port) (*((byte *) (port)))
+#define inpw(port) (*((word *) (port)))
+#define inpdw(port) (*((dword *)(port)))
+
+#define outp(port, val) (*((dword *) (port)) = ((dword) (val)))
+#define outpb(port, val) (*((byte *) (port)) = ((byte) (val)))
+#define outpw(port, val) (*((word *) (port)) = ((word) (val)))
+#define outpdw(port, val) (*((dword *) (port)) = ((dword) (val)))
+
+
+#define in_byte(addr) (inp(addr))
+#define in_byte_masked(addr, mask) (inp(addr) & (byte)mask)
+#define out_byte(addr, val) outp(addr, val)
+#define in_word(addr) (inpw(addr))
+#define in_word_masked(addr, mask) (inpw(addr) & (word)mask)
+#define out_word(addr, val) outpw(addr, val)
+#define in_dword(addr) (inpdw(addr))
+#define in_dword_masked(addr, mask) (inpdw(addr) & mask)
+#define out_dword(addr, val) outpdw(addr, val)
+
+/* shadowed, masked output for write-only registers */
+#define out_byte_masked(io, mask, val, shadow) \
+ do { \
+ shadow = (shadow & (word)(~(mask))) | \
+ ((word)((val) & (mask))); \
+ (void) out_byte(io, shadow);\
+ } while (0);
+
+#define out_word_masked(io, mask, val, shadow) \
+ do { \
+ shadow = (shadow & (word)(~(mask))) | \
+ ((word)((val) & (mask))); \
+ (void) out_word(io, shadow); \
+ } while (0);
+
+#define out_dword_masked(io, mask, val, shadow) \
+ do { \
+ shadow = (shadow & (dword)(~(mask))) | \
+ ((dword)((val) & (mask))); \
+ (void) out_dword(io, shadow);\
+ } while (0);
+
+#define out_byte_masked_ns(io, mask, val, current_reg_content) \
+ (void) out_byte(io, ((current_reg_content & \
+ (word)(~(mask))) | ((word)((val) & (mask)))))
+
+#define out_word_masked_ns(io, mask, val, current_reg_content) \
+ (void) out_word(io, ((current_reg_content & \
+ (word)(~(mask))) | ((word)((val) & (mask)))))
+
+#define out_dword_masked_ns(io, mask, val, current_reg_content) \
+ (void) out_dword(io, ((current_reg_content & \
+ (dword)(~(mask))) | ((dword)((val) & (mask)))))
+
+#define MEM_INF(val, reg, field) ((val & HWIO_FMSK(reg, field)) >> \
+ HWIO_SHFT(reg, field))
+
+#define MEM_OUTF(mem, reg, field, val)\
+ out_dword_masked_ns(mem, HWIO_FMSK(reg, field), \
+ (unsigned int)val<<HWIO_SHFT(reg, field), in_dword(mem))
+
+#define MEM_OUTF2(mem, reg, field2, field1, val2, val1) \
+ out_dword_masked_ns(mem, (HWIO_FMSK(reg, field2)| \
+ HWIO_FMSK(reg, field1)), \
+ (((unsigned int)val2<<HWIO_SHFT(reg, field2))| \
+ ((unsigned int)val1<<HWIO_SHFT(reg, field1))), in_dword(mem))
+
+#define MEM_OUTF3(mem, reg, fld3, fld2, fld1, val3, val2, val1) \
+ out_dword_masked_ns(mem, (HWIO_FMSK(reg, fld3)| \
+ HWIO_FMSK(reg, fld2)|HWIO_FMSK(reg, fld1)), \
+ (((unsigned int)val3<<HWIO_SHFT(reg, fld3))| \
+ ((unsigned int)val2<<HWIO_SHFT(reg, fld2))| \
+ ((unsigned int)val1<<HWIO_SHFT(reg, fld1))), in_dword(mem))
+
+#define HWIO_FMSK(reg, field) HWIO_##reg##__##field##__BMSK
+#define HWIO_SHFT(reg, field) HWIO_##reg##__##field##__SHFT
+#endif
diff --git a/drivers/media/video/msm/mercury/msm_mercury_platform.c b/drivers/media/video/msm/mercury/msm_mercury_platform.c
new file mode 100644
index 0000000..9366ef3
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_platform.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/pm_qos_params.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <mach/clk.h>
+#include <mach/camera.h>
+#include <mach/msm_subsystem_map.h>
+
+#include "msm_mercury_platform.h"
+#include "msm_mercury_sync.h"
+#include "msm_mercury_common.h"
+#include "msm_mercury_hw.h"
+
+
+struct ion_client *mercury_client;
+
+static struct msm_cam_clk_info mercury_jpegd_clk_info[] = {
+ {"core_clk", 200000000},
+ {"iface_clk", -1}
+};
+
+void msm_mercury_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle)
+{
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(mercury_client, *ionhandle, CAMERA_DOMAIN,
+ GEN_POOL);
+ ion_free(mercury_client, *ionhandle);
+ *ionhandle = NULL;
+#elif CONFIG_ANDROID_PMEM
+ put_pmem_file(file);
+#endif
+}
+
+uint32_t msm_mercury_platform_v2p(int fd, uint32_t len,
+ struct file **file_p,
+ struct ion_handle **ionhandle)
+{
+ unsigned long paddr;
+ unsigned long size;
+ int rc;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ *ionhandle = ion_import_fd(mercury_client, fd);
+ if (IS_ERR_OR_NULL(*ionhandle))
+ return 0;
+
+ rc = ion_map_iommu(mercury_client, *ionhandle, CAMERA_DOMAIN,
+ GEN_POOL, SZ_4K, 0, &paddr,
+ (unsigned long *)&size, UNCACHED, 0);
+#elif CONFIG_ANDROID_PMEM
+ unsigned long kvstart;
+ rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
+#else
+ rc = 0;
+ paddr = 0;
+ size = 0;
+#endif
+ if (rc < 0) {
+ MCR_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
+ rc);
+ goto error1;
+ }
+
+ /* validate user input */
+ if (len > size) {
+ MCR_PR_ERR("%s: invalid offset + len\n", __func__);
+ goto error1;
+ }
+
+ return paddr;
+error1:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_free(mercury_client, *ionhandle);
+#endif
+ return 0;
+}
+
+int msm_mercury_platform_init(struct platform_device *pdev,
+ struct resource **mem,
+ void **base,
+ int *irq,
+ irqreturn_t (*handler) (int, void *),
+ void *context)
+{
+ int rc = 0;
+ int mercury_irq;
+ struct resource *mercury_mem, *mercury_io, *mercury_irq_res;
+ void *mercury_base;
+ struct msm_mercury_device *pmercury_dev =
+ (struct msm_mercury_device *) context;
+
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+
+ mercury_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mercury_mem) {
+ MCR_PR_ERR("%s: no mem resource?\n", __func__);
+ return -ENODEV;
+ }
+
+ mercury_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!mercury_irq_res) {
+ MCR_PR_ERR("no irq resource?\n");
+ return -ENODEV;
+ }
+ mercury_irq = mercury_irq_res->start;
+
+ mercury_io = request_mem_region(mercury_mem->start,
+ resource_size(mercury_mem), pdev->name);
+ if (!mercury_io) {
+ MCR_PR_ERR("%s: region already claimed\n", __func__);
+ return -EBUSY;
+ }
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ mercury_base = ioremap(mercury_mem->start,
+ resource_size(mercury_mem));
+ if (!mercury_base) {
+ rc = -ENOMEM;
+ MCR_PR_ERR("%s: ioremap failed\n", __func__);
+ goto fail1;
+ }
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+
+ rc = msm_cam_clk_enable(&pmercury_dev->pdev->dev,
+ mercury_jpegd_clk_info, pmercury_dev->mercury_clk,
+ ARRAY_SIZE(mercury_jpegd_clk_info), 1);
+ if (rc < 0)
+ MCR_PR_ERR("%s:%d] rc = %d\n", __func__, __LINE__, rc);
+
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ msm_mercury_hw_init(mercury_base, resource_size(mercury_mem));
+ rc = request_irq(mercury_irq, handler, IRQF_TRIGGER_RISING,
+ "mercury", context);
+ if (rc) {
+ MCR_PR_ERR("%s: request_irq failed, %d\n", __func__,
+ mercury_irq);
+ goto fail3;
+ }
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ *mem = mercury_mem;
+ *base = mercury_base;
+ *irq = mercury_irq;
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ mercury_client = msm_ion_client_create(-1, "camera/mercury");
+#endif
+ MCR_PR_ERR("%s:%d] success\n", __func__, __LINE__);
+ return rc;
+fail3:
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ msm_cam_clk_enable(&pmercury_dev->pdev->dev, mercury_jpegd_clk_info,
+ pmercury_dev->mercury_clk,
+ ARRAY_SIZE(mercury_jpegd_clk_info), 0);
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ iounmap(mercury_base);
+fail1:
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ release_mem_region(mercury_mem->start, resource_size(mercury_mem));
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ return rc;
+}
+
+int msm_mercury_platform_release(struct resource *mem, void *base,
+ int irq, void *context)
+{
+ int result = 0;
+ struct msm_mercury_device *pmercury_dev =
+ (struct msm_mercury_device *) context;
+
+ free_irq(irq, context);
+ msm_cam_clk_enable(&pmercury_dev->pdev->dev, mercury_jpegd_clk_info,
+ pmercury_dev->mercury_clk, ARRAY_SIZE(mercury_jpegd_clk_info),
+ 0);
+ iounmap(base);
+ release_mem_region(mem->start, resource_size(mem));
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_client_destroy(mercury_client);
+#endif
+ MCR_DBG("%s:%d] success\n", __func__, __LINE__);
+ return result;
+}
+
diff --git a/drivers/media/video/msm/mercury/msm_mercury_platform.h b/drivers/media/video/msm/mercury/msm_mercury_platform.h
new file mode 100644
index 0000000..8f4a7e3
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_platform.h
@@ -0,0 +1,39 @@
+/* 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 MSM_MERCURY_PLATFORM_H
+#define MSM_MERCURY_PLATFORM_H
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/ion.h>
+
+int msm_mercury_platform_clk_enable(void);
+int msm_mercury_platform_clk_disable(void);
+
+void msm_mercury_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle);
+
+uint32_t msm_mercury_platform_v2p(int fd, uint32_t len, struct file **file,
+ struct ion_handle **ionhandle);
+
+int msm_mercury_platform_init(struct platform_device *pdev,
+ struct resource **mem,
+ void **base,
+ int *irq,
+ irqreturn_t (*handler) (int, void *),
+ void *context);
+
+int msm_mercury_platform_release(struct resource *mem, void *base, int irq,
+ void *context);
+
+#endif /* MSM_MERCURY_PLATFORM_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_sync.c b/drivers/media/video/msm/mercury/msm_mercury_sync.c
new file mode 100644
index 0000000..31fb8b4
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_sync.c
@@ -0,0 +1,614 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <media/msm_mercury.h>
+
+#include "msm_mercury_sync.h"
+#include "msm_mercury_core.h"
+#include "msm_mercury_platform.h"
+#include "msm_mercury_common.h"
+#include "msm_mercury_macros.h"
+#include "msm_mercury_hw_reg.h"
+
+static struct msm_mercury_core_buf out_buf_local;
+static struct msm_mercury_core_buf in_buf_local;
+
+/*************** queue helper ****************/
+inline void msm_mercury_q_init(char const *name, struct msm_mercury_q *q_p)
+{
+ MCR_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+ q_p->name = name;
+ spin_lock_init(&q_p->lck);
+ INIT_LIST_HEAD(&q_p->q);
+ init_waitqueue_head(&q_p->wait);
+ q_p->unblck = 0;
+}
+
+inline void *msm_mercury_q_out(struct msm_mercury_q *q_p)
+{
+ unsigned long flags;
+ struct msm_mercury_q_entry *q_entry_p = NULL;
+ void *data = NULL;
+
+ MCR_DBG("(%d)%s() %s\n", __LINE__, __func__, q_p->name);
+ spin_lock_irqsave(&q_p->lck, flags);
+ if (!list_empty(&q_p->q)) {
+ q_entry_p = list_first_entry(&q_p->q,
+ struct msm_mercury_q_entry,
+ list);
+ list_del_init(&q_entry_p->list);
+ }
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ if (q_entry_p) {
+ data = q_entry_p->data;
+ kfree(q_entry_p);
+ } else {
+ MCR_DBG("%s:%d] %s no entry\n", __func__, __LINE__, q_p->name);
+ }
+
+ return data;
+}
+
+inline int msm_mercury_q_in(struct msm_mercury_q *q_p, void *data)
+{
+ unsigned long flags;
+
+ struct msm_mercury_q_entry *q_entry_p;
+
+ MCR_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+ q_entry_p = kmalloc(sizeof(struct msm_mercury_q_entry), GFP_ATOMIC);
+ if (!q_entry_p) {
+ MCR_PR_ERR("%s: no mem\n", __func__);
+ return -EFAULT;
+ }
+ q_entry_p->data = data;
+
+ spin_lock_irqsave(&q_p->lck, flags);
+ list_add_tail(&q_entry_p->list, &q_p->q);
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ return 0;
+}
+
+inline int msm_mercury_q_in_buf(struct msm_mercury_q *q_p,
+ struct msm_mercury_core_buf *buf)
+{
+ struct msm_mercury_core_buf *buf_p;
+
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ buf_p = kmalloc(sizeof(struct msm_mercury_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ MCR_PR_ERR("%s: no mem\n", __func__);
+ return -EFAULT;
+ }
+
+ memcpy(buf_p, buf, sizeof(struct msm_mercury_core_buf));
+
+ msm_mercury_q_in(q_p, buf_p);
+ return 0;
+}
+
+inline int msm_mercury_q_wait(struct msm_mercury_q *q_p)
+{
+ int tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */
+ int rc;
+
+ MCR_DBG("%s:%d %s wait\n", __func__, __LINE__, q_p->name);
+ rc = wait_event_interruptible_timeout(q_p->wait,
+ (!list_empty_careful(&q_p->q) || q_p->unblck),
+ msecs_to_jiffies(tm));
+
+ MCR_DBG("%s:%d %s wait done (rc=%d)\n", __func__,
+ __LINE__, q_p->name, rc);
+ if (list_empty_careful(&q_p->q)) {
+ if (rc == 0) {
+ rc = -ETIMEDOUT;
+ MCR_PR_ERR("%s:%d] %s timeout\n", __func__,
+ __LINE__, q_p->name);
+ } else if (q_p->unblck) {
+ MCR_DBG("%s:%d %s unblock is true", __func__,
+ __LINE__, q_p->name);
+ rc = q_p->unblck;
+ q_p->unblck = 0;
+ } else if (rc < 0) {
+ MCR_PR_ERR("%s:%d %s rc %d\n", __func__, __LINE__,
+ q_p->name, rc);
+ }
+ }
+ return rc;
+}
+
+inline int msm_mercury_q_wakeup(struct msm_mercury_q *q_p)
+{
+ MCR_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline int msm_mercury_q_wr_eoi(struct msm_mercury_q *q_p)
+{
+ MCR_DBG("%s:%d] Wake up %s\n", __func__, __LINE__, q_p->name);
+ q_p->unblck = MSM_MERCURY_EVT_FRAMEDONE;
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline int msm_mercury_q_wr_err(struct msm_mercury_q *q_p)
+{
+ MCR_DBG("%s:%d] Wake up %s\n", __func__, __LINE__, q_p->name);
+ q_p->unblck = MSM_MERCURY_EVT_ERR;
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline int msm_mercury_q_unblock(struct msm_mercury_q *q_p)
+{
+ MCR_DBG("%s:%d] Wake up %s\n", __func__, __LINE__, q_p->name);
+ q_p->unblck = MSM_MERCURY_EVT_UNBLOCK;
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline void msm_mercury_q_cleanup(struct msm_mercury_q *q_p)
+{
+ void *data;
+ MCR_DBG("\n%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ do {
+ data = msm_mercury_q_out(q_p);
+ if (data) {
+ MCR_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ kfree(data);
+ }
+ } while (data);
+ q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+int msm_mercury_framedone_irq(struct msm_mercury_device *pmercury_dev)
+{
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_mercury_q_unblock(&pmercury_dev->evt_q);
+
+ MCR_DBG("%s:%d] Exit\n", __func__, __LINE__);
+ return 0;
+}
+
+int msm_mercury_evt_get(struct msm_mercury_device *pmercury_dev,
+ void __user *arg)
+{
+ struct msm_mercury_ctrl_cmd ctrl_cmd;
+ int rc = 0;
+
+ MCR_DBG("(%d)%s() Enter\n", __LINE__, __func__);
+ ctrl_cmd.type = (uint32_t)msm_mercury_q_wait(&pmercury_dev->evt_q);
+
+ rc = copy_to_user(arg, &ctrl_cmd, sizeof(ctrl_cmd));
+
+ if (rc) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_mercury_evt_get_unblock(struct msm_mercury_device *pmercury_dev)
+{
+ MCR_DBG("--(%d)%s() Enter\n", __LINE__, __func__);
+ msm_mercury_q_unblock(&pmercury_dev->evt_q);
+ return 0;
+}
+
+int msm_mercury_output_buf_cfg(struct msm_mercury_device *pmercury_dev,
+ void __user *arg)
+{
+ struct msm_mercury_buf buf_cmd;
+
+
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_mercury_buf))) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ out_buf_local.y_buffer_addr = msm_mercury_platform_v2p(buf_cmd.fd,
+ buf_cmd.y_len, &out_buf_local.file, &out_buf_local.handle);
+ out_buf_local.cbcr_buffer_addr = out_buf_local.y_buffer_addr +
+ buf_cmd.y_len;
+
+ if (!out_buf_local.y_buffer_addr) {
+ MCR_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ msm_mercury_hw_output_y_buf_cfg(out_buf_local.y_buffer_addr);
+ msm_mercury_hw_output_u_buf_cfg(out_buf_local.cbcr_buffer_addr);
+
+ MCR_DBG("(%d)%s()\n y_buf=0x%08X, y_len=0x%08X, vaddr=0x%08X\n"
+ " u_buf=0x%08X, u_len=0x%08X\n\n", __LINE__, __func__,
+ out_buf_local.y_buffer_addr, buf_cmd.y_len, (int) buf_cmd.vaddr,
+ out_buf_local.cbcr_buffer_addr, buf_cmd.cbcr_len);
+
+ return 0;
+}
+
+int msm_mercury_input_buf_cfg(struct msm_mercury_device *pmercury_dev,
+ void __user *arg)
+{
+ struct msm_mercury_buf buf_cmd;
+
+
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_mercury_buf))) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ in_buf_local.y_buffer_addr = msm_mercury_platform_v2p(buf_cmd.fd,
+ buf_cmd.y_len, &in_buf_local.file, &in_buf_local.handle);
+
+ if (!in_buf_local.y_buffer_addr) {
+ MCR_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ msm_mercury_hw_bitstream_buf_cfg(in_buf_local.y_buffer_addr);
+
+ MCR_DBG("(%d)%s()\n bitstream_buf=0x%08X, len=0x%08X, vaddr=0x%08X\n",
+ __LINE__, __func__, in_buf_local.y_buffer_addr, buf_cmd.y_len,
+ (int) buf_cmd.vaddr);
+
+ return 0;
+}
+
+int msm_mercury_output_get(struct msm_mercury_device *pmercury_dev,
+ void __user *to)
+{
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_mercury_platform_p2v(out_buf_local.file, &out_buf_local.handle);
+ return 0;
+}
+
+int msm_mercury_input_get(struct msm_mercury_device *pmercury_dev,
+ void __user *to)
+{
+
+
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_mercury_platform_p2v(in_buf_local.file, &in_buf_local.handle);
+ return 0;
+}
+
+int msm_mercury_ioctl_dump_regs(void)
+{
+ uint32_t mercury_regs[] = {
+ 0x0000, 0x0008, 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0x0024,
+ 0x0030, 0x0034, 0x0040, 0x0050, 0x0054, 0x0058, 0x005C, 0x0060,
+ 0x0064, 0x0070, 0x0080, 0x0084, 0x0088, 0x0258, 0x025C, 0x0260,
+ 0x0264, 0x0200, 0x0204, 0x0208, 0x020C, 0x0210, 0x0214, 0x0218,
+ 0x021C, 0x0220, 0x0224, 0x0228, 0x0100, 0x0104, 0x010C, 0x0110,
+ 0x0114, 0x0118, 0x011C, 0x0120, 0x0124, 0x0128, 0x012C};
+
+ struct msm_mercury_hw_cmd hw_cmd;
+ int len = sizeof(mercury_regs)/4;
+ int i;
+
+ MCR_DBG("\n%s\n (%d)%s()\n", __FILE__, __LINE__, __func__);
+
+ hw_cmd.mask = 0xFFFFFFFF;
+ hw_cmd.type = MSM_MERCURY_HW_CMD_TYPE_READ;
+ hw_cmd.n = 1;
+
+ for (i = 0; i < len; i++) {
+ hw_cmd.offset = mercury_regs[i];
+ msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+ }
+
+ return 0;
+}
+
+int msm_mercury_ioctl_magic_code(struct msm_mercury_device *pmercury_dev,
+ void * __user arg)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+ int rc = 0;
+
+ rc = copy_from_user(&hw_cmd, arg, sizeof(struct msm_mercury_hw_cmd));
+ if (rc) {
+ printk(KERN_ERR "%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ hw_cmd.data = 0x600D600D;
+ rc = copy_to_user(arg, &hw_cmd, sizeof(hw_cmd));
+
+ if (rc) {
+ printk(KERN_ERR "%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_mercury_irq(int event, void *context, void *data)
+{
+ struct msm_mercury_device *pmercury_dev =
+ (struct msm_mercury_device *) context;
+
+ switch (event) {
+ case MSM_MERCURY_HW_IRQ_SW_RESET_ACK:
+ /* wake up evt_q*/
+ MCR_DBG("(%d)%s Wake up event q from Reset IRQ\n", __LINE__,
+ __func__);
+ msm_mercury_q_wakeup(&pmercury_dev->evt_q);
+ break;
+ case MSM_MERCURY_HW_IRQ_WR_EOI_ACK:
+ /*wake up evt_q*/
+ MCR_DBG("%d%s Wake up eventq from WR_EOI IRQ\n", __LINE__,
+ __func__);
+ msm_mercury_q_wr_eoi(&pmercury_dev->evt_q);
+ break;
+ case MSM_MERCURY_HW_IRQ_WR_ERR_ACK:
+ MCR_DBG("(%d)%s Wake up eventq from WR_ERR IRQ\n",
+ __LINE__, __func__);
+ msm_mercury_q_wr_err(&pmercury_dev->evt_q);
+ break;
+ default:
+ MCR_DBG("(%d)%s (default) Wake up event q from WR_ERR IRQ\n",
+ __LINE__, __func__);
+ msm_mercury_q_wr_err(&pmercury_dev->evt_q);
+ }
+ return 0;
+}
+
+int __msm_mercury_open(struct msm_mercury_device *pmercury_dev)
+{
+ int rc = 0;
+
+ mutex_lock(&pmercury_dev->lock);
+ if (pmercury_dev->open_count) {
+ /* only open once */
+ MCR_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+ mutex_unlock(&pmercury_dev->lock);
+ return -EBUSY;
+ }
+ pmercury_dev->open_count++;
+ mutex_unlock(&pmercury_dev->lock);
+
+ msm_mercury_core_irq_install(msm_mercury_irq);
+
+ rc = msm_mercury_platform_init(pmercury_dev->pdev,
+ &pmercury_dev->mem, &pmercury_dev->base,
+ &pmercury_dev->irq, msm_mercury_core_irq, pmercury_dev);
+ if (rc) {
+ MCR_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+ __LINE__, rc);
+ return rc;
+ }
+
+ MCR_DBG("\n%s:%d] platform resources - mem 0x%p, base 0x%p, irq %d\n",
+ __func__, __LINE__, pmercury_dev->mem, pmercury_dev->base,
+ pmercury_dev->irq);
+
+ msm_mercury_q_cleanup(&pmercury_dev->evt_q);
+ msm_mercury_core_init();
+
+ MCR_DBG("\n%s:%d] success\n", __func__, __LINE__);
+ return rc;
+}
+
+int __msm_mercury_release(struct msm_mercury_device *pmercury_dev)
+{
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ mutex_lock(&pmercury_dev->lock);
+ if (!pmercury_dev->open_count) {
+ MCR_PR_ERR(KERN_ERR "%s: not opened\n", __func__);
+ mutex_unlock(&pmercury_dev->lock);
+ return -EINVAL;
+ }
+ pmercury_dev->open_count--;
+ mutex_unlock(&pmercury_dev->lock);
+
+ msm_mercury_q_cleanup(&pmercury_dev->evt_q);
+
+ if (pmercury_dev->open_count)
+ MCR_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+ if (pmercury_dev->open_count)
+ MCR_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+
+ msm_mercury_platform_release(pmercury_dev->mem, pmercury_dev->base,
+ pmercury_dev->irq, pmercury_dev);
+
+ return 0;
+}
+
+int msm_mercury_ioctl_hw_cmd(struct msm_mercury_device *pmercury_dev,
+ void * __user arg)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+ int is_copy_to_user;
+ int rc = 0;
+
+ rc = copy_from_user(&hw_cmd, arg, sizeof(struct msm_mercury_hw_cmd));
+ if (rc) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ is_copy_to_user = msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+ if (is_copy_to_user >= 0) {
+ rc = copy_to_user(arg, &hw_cmd, sizeof(hw_cmd));
+
+ if (rc) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+int msm_mercury_ioctl_hw_cmds(struct msm_mercury_device *pmercury_dev,
+ void * __user arg)
+{
+ int is_copy_to_user;
+ int len;
+ uint32_t m;
+ struct msm_mercury_hw_cmds *hw_cmds_p;
+ struct msm_mercury_hw_cmd *hw_cmd_p;
+
+ if (copy_from_user(&m, arg, sizeof(m))) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ len = sizeof(struct msm_mercury_hw_cmds) +
+ sizeof(struct msm_mercury_hw_cmd) * (m - 1);
+ hw_cmds_p = kmalloc(len, GFP_KERNEL);
+ if (!hw_cmds_p) {
+ MCR_PR_ERR("[%d]%s() no mem %d\n", __LINE__, __func__, len);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(hw_cmds_p, arg, len)) {
+ MCR_PR_ERR("[%d]%s Fail to copy hw_cmds of len %d from user\n",
+ __LINE__, __func__, len);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+
+ hw_cmd_p = (struct msm_mercury_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+ is_copy_to_user = msm_mercury_hw_exec_cmds(hw_cmd_p, m);
+
+ if (is_copy_to_user >= 0) {
+ if (copy_to_user(arg, hw_cmds_p, len)) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+ }
+ kfree(hw_cmds_p);
+ return 0;
+}
+
+int msm_mercury_ioctl_reset(struct msm_mercury_device *pmercury_dev,
+ void * __user arg)
+{
+ int rc = 0;
+
+ MCR_DBG("(%d)%s() Enter\n", __LINE__, __func__);
+ rc = msm_mercury_core_reset();
+
+ return rc;
+}
+
+long __msm_mercury_ioctl(struct msm_mercury_device *pmercury_dev,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+
+ switch (cmd) {
+ case MSM_MCR_IOCTL_GET_HW_VERSION:
+ rc = msm_mercury_ioctl_magic_code(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_RESET:
+ rc = msm_mercury_ioctl_reset(pmercury_dev, (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_EVT_GET:
+ rc = msm_mercury_evt_get(pmercury_dev, (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_EVT_GET_UNBLOCK:
+ rc = msm_mercury_evt_get_unblock(pmercury_dev);
+ break;
+
+ case MSM_MCR_IOCTL_HW_CMD:
+ rc = msm_mercury_ioctl_hw_cmd(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_HW_CMDS:
+ rc = msm_mercury_ioctl_hw_cmds(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_INPUT_BUF_CFG:
+ rc = msm_mercury_input_buf_cfg(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_OUTPUT_BUF_CFG:
+ rc = msm_mercury_output_buf_cfg(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_OUTPUT_GET:
+ rc = msm_mercury_output_get(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_INPUT_GET:
+ rc = msm_mercury_input_get(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_TEST_DUMP_REGION:
+ rc = msm_mercury_ioctl_dump_regs();
+ break;
+
+ default:
+ printk(KERN_ERR "(%d)%s() cmd = %d not supported\n",
+ __LINE__, __func__, _IOC_NR(cmd));
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+struct msm_mercury_device *__msm_mercury_init(struct platform_device *pdev)
+{
+ struct msm_mercury_device *pmercury_dev;
+ pmercury_dev = kzalloc(sizeof(struct msm_mercury_device), GFP_ATOMIC);
+ if (!pmercury_dev) {
+ printk(KERN_ERR "%s:%d]no mem\n", __func__, __LINE__);
+ return NULL;
+ }
+
+ mutex_init(&pmercury_dev->lock);
+
+ pmercury_dev->pdev = pdev;
+
+ msm_mercury_q_init("evt_q", &pmercury_dev->evt_q);
+
+ return pmercury_dev;
+}
+
+int __msm_mercury_exit(struct msm_mercury_device *pmercury_dev)
+{
+ mutex_destroy(&pmercury_dev->lock);
+ kfree(pmercury_dev);
+ return 0;
+}
+
diff --git a/drivers/media/video/msm/mercury/msm_mercury_sync.h b/drivers/media/video/msm/mercury/msm_mercury_sync.h
new file mode 100644
index 0000000..f392907
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_sync.h
@@ -0,0 +1,67 @@
+/* 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 MSM_MERCURY_SYNC_H
+#define MSM_MERCURY_SYNC_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_mercury_core.h"
+
+struct msm_mercury_q {
+ char const *name;
+ struct list_head q;
+ spinlock_t lck;
+ wait_queue_head_t wait;
+ int unblck;
+};
+
+struct msm_mercury_q_entry {
+ struct list_head list;
+ void *data;
+};
+
+struct msm_mercury_device {
+ struct platform_device *pdev;
+ struct resource *mem;
+ int irq;
+ void *base;
+ struct clk *mercury_clk[2];
+ struct device *device;
+ struct cdev cdev;
+ struct mutex lock;
+ char open_count;
+ uint8_t op_mode;
+
+ /* event queue including frame done & err indications*/
+ struct msm_mercury_q evt_q;
+ struct v4l2_subdev subdev;
+
+};
+
+int __msm_mercury_open(struct msm_mercury_device *pmcry_dev);
+int __msm_mercury_release(struct msm_mercury_device *pmcry_dev);
+
+long __msm_mercury_ioctl(struct msm_mercury_device *pmcry_dev,
+ unsigned int cmd, unsigned long arg);
+
+struct msm_mercury_device *__msm_mercury_init(struct platform_device *pdev);
+int __msm_mercury_exit(struct msm_mercury_device *pmcry_dev);
+int msm_mercury_ioctl_hw_cmds(struct msm_mercury_device *pmcry_dev,
+ void * __user arg);
+int msm_mercury_ioctl_hw_cmds_wo(struct msm_mercury_device *pmcry_dev,
+ void * __user arg);
+#endif /* MSM_MERCURY_SYNC_H */
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 8500d47..caa2d32 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -20,6 +20,7 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <linux/pm_qos.h>
+#include <linux/wakelock.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
@@ -32,6 +33,7 @@
#include <mach/camera.h>
#include <media/msm_isp.h>
#include <linux/ion.h>
+#include <linux/iommu.h>
#include <media/msm_gestures.h>
#define MSM_V4L2_DIMENSION_SIZE 96
@@ -49,6 +51,7 @@
#define MSM_VFE_DRV_NAME "msm_vfe"
#define MSM_VPE_DRV_NAME "msm_vpe"
#define MSM_GEMINI_DRV_NAME "msm_gemini"
+#define MSM_MERCURY_DRV_NAME "msm_mercury"
#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
#define MAX_NUM_CSIPHY_DEV 3
@@ -258,7 +261,7 @@
uint8_t opencnt; /*mctl ref count*/
const char *apps_id; /*ID for app that open this session*/
struct mutex lock;
- struct pm_qos_request idle_pm_qos; /*avoid low power mode when active*/
+ struct wake_lock wake_lock; /*avoid low power mode when active*/
struct pm_qos_request pm_qos_req_list;
struct msm_mctl_pp_info pp_info;
struct msm_mctl_stats_t stats_info; /*stats pmem info*/
@@ -271,6 +274,12 @@
/*sensor info*/
struct msm_camera_sensor_info *sdata;
+
+ /*IOMMU mapped IMEM addresses*/
+ uint32_t ping_imem_y;
+ uint32_t ping_imem_cbcr;
+ uint32_t pong_imem_y;
+ uint32_t pong_imem_cbcr;
};
/* abstract camera device represents a VFE and connected sensor */
@@ -284,7 +293,8 @@
unsigned int cmd, unsigned long arg);
int (*isp_notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
- void (*isp_release)(struct v4l2_subdev *sd);
+ void (*isp_release)(struct msm_cam_media_controller *mctl,
+ struct v4l2_subdev *sd);
int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
struct msm_mctl_pp_cmd, void *data);
diff --git a/drivers/media/video/msm/msm_camera.c b/drivers/media/video/msm/msm_camera.c
index ec1e253..624fe9b 100644
--- a/drivers/media/video/msm/msm_camera.c
+++ b/drivers/media/video/msm/msm_camera.c
@@ -36,7 +36,6 @@
#include <linux/hrtimer.h>
#include <linux/ion.h>
-#include <mach/cpuidle.h>
DEFINE_MUTEX(ctrl_cmd_lock);
#define CAMERA_STOP_VIDEO 58
@@ -3086,7 +3085,7 @@
msm_queue_drain(&sync->pict_q, list_pict);
msm_queue_drain(&sync->event_q, list_config);
- pm_qos_update_request(&sync->idle_pm_qos, PM_QOS_DEFAULT_VALUE);
+ wake_unlock(&sync->wake_lock);
sync->apps_id = NULL;
sync->core_powered_on = 0;
}
@@ -3746,8 +3745,7 @@
sync->apps_id = apps_id;
if (!sync->core_powered_on && !is_controlnode) {
- pm_qos_update_request(&sync->idle_pm_qos,
- msm_cpuidle_get_deep_idle_latency());
+ wake_lock(&sync->wake_lock);
msm_camvfe_fn_init(&sync->vfefn, sync);
if (sync->vfefn.vfe_init) {
@@ -3961,12 +3959,11 @@
msm_queue_init(&sync->pict_q, "pict");
msm_queue_init(&sync->vpe_q, "vpe");
- pm_qos_add_request(&sync->idle_pm_qos, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ wake_lock_init(&sync->wake_lock, WAKE_LOCK_SUSPEND, "msm_camera");
rc = msm_camio_probe_on(pdev);
if (rc < 0) {
- pm_qos_remove_request(&sync->idle_pm_qos);
+ wake_lock_destroy(&sync->wake_lock);
return rc;
}
rc = sensor_probe(sync->sdata, &sctrl);
@@ -3979,7 +3976,7 @@
pr_err("%s: failed to initialize %s\n",
__func__,
sync->sdata->sensor_name);
- pm_qos_remove_request(&sync->idle_pm_qos);
+ wake_lock_destroy(&sync->wake_lock);
return rc;
}
@@ -3998,7 +3995,7 @@
static int msm_sync_destroy(struct msm_sync *sync)
{
- pm_qos_remove_request(&sync->idle_pm_qos);
+ wake_lock_destroy(&sync->wake_lock);
return 0;
}
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 148f8b5..848beda 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -211,9 +211,9 @@
case VFE_MSG_V32_JPEG_CAPTURE:
D("%s:VFE_MSG_V32_JPEG_CAPTURE vdata->type %d\n", __func__,
vdata->type);
- free_buf.num_planes = 1;
- free_buf.ch_paddr[0] = IMEM_Y_PING_OFFSET;
- free_buf.ch_paddr[1] = IMEM_CBCR_PING_OFFSET;
+ free_buf.num_planes = 2;
+ free_buf.ch_paddr[0] = pmctl->ping_imem_y;
+ free_buf.ch_paddr[1] = pmctl->ping_imem_cbcr;
cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
cfgcmd.value = &vfe_id;
vfe_params.vfe_cfg = &cfgcmd;
@@ -222,8 +222,8 @@
__func__, free_buf.ch_paddr[0], free_buf.ch_paddr[1]);
rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
/* Write the same buffer into PONG */
- free_buf.ch_paddr[0] = IMEM_Y_PONG_OFFSET;
- free_buf.ch_paddr[1] = IMEM_CBCR_PONG_OFFSET;
+ free_buf.ch_paddr[0] = pmctl->pong_imem_y;
+ free_buf.ch_paddr[1] = pmctl->pong_imem_cbcr;
cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR;
cfgcmd.value = &vfe_id;
vfe_params.vfe_cfg = &cfgcmd;
@@ -467,19 +467,54 @@
return -EINVAL;
}
+ rc = msm_iommu_map_contig_buffer(
+ (unsigned long)IMEM_Y_PING_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
+ SZ_4K, IOMMU_WRITE | IOMMU_READ,
+ (unsigned long *)&mctl->ping_imem_y);
+ mctl->ping_imem_cbcr = mctl->ping_imem_y + IMEM_Y_SIZE;
+ if (rc < 0) {
+ pr_err("%s: ping iommu mapping returned error %d\n",
+ __func__, rc);
+ mctl->ping_imem_y = 0;
+ mctl->ping_imem_cbcr = 0;
+ }
+ msm_iommu_map_contig_buffer(
+ (unsigned long)IMEM_Y_PONG_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
+ SZ_4K, IOMMU_WRITE | IOMMU_READ,
+ (unsigned long *)&mctl->pong_imem_y);
+ mctl->pong_imem_cbcr = mctl->pong_imem_y + IMEM_Y_SIZE;
+ if (rc < 0) {
+ pr_err("%s: pong iommu mapping returned error %d\n",
+ __func__, rc);
+ mctl->pong_imem_y = 0;
+ mctl->pong_imem_cbcr = 0;
+ }
+
rc = msm_vfe_subdev_init(sd, mctl);
if (rc < 0) {
pr_err("%s: vfe_init failed at %d\n",
- __func__, rc);
+ __func__, rc);
}
return rc;
}
-static void msm_isp_release(
+static void msm_isp_release(struct msm_cam_media_controller *mctl,
struct v4l2_subdev *sd)
{
D("%s\n", __func__);
msm_vfe_subdev_release(sd);
+ msm_iommu_unmap_contig_buffer(mctl->ping_imem_y,
+ CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
+ msm_iommu_unmap_contig_buffer(mctl->pong_imem_y,
+ CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
+ mctl->ping_imem_y = 0;
+ mctl->ping_imem_cbcr = 0;
+ mctl->pong_imem_y = 0;
+ mctl->pong_imem_cbcr = 0;
}
static int msm_config_vfe(struct v4l2_subdev *sd,
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 716575a..e6523cd 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -20,6 +20,7 @@
#include <linux/videodev2.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
+#include <linux/wakelock.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
@@ -27,8 +28,6 @@
#include <linux/android_pmem.h>
-#include <mach/cpuidle.h>
-
#include "msm.h"
#include "msm_cam_server.h"
#include "msm_csid.h"
@@ -570,8 +569,7 @@
/* open sub devices - once only*/
if (!p_mctl->opencnt) {
uint32_t csid_version;
- pm_qos_update_request(&p_mctl->idle_pm_qos,
- msm_cpuidle_get_deep_idle_latency());
+ wake_lock(&p_mctl->wake_lock);
csid_core = camdev->csid_core;
rc = msm_mctl_register_subdevs(p_mctl, csid_core);
@@ -667,12 +665,11 @@
}
}
- 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_update_request(&p_mctl->pm_qos_req_list,
- MSM_V4L2_SWFI_LATENCY);
- }
+ pm_qos_add_request(&p_mctl->pm_qos_req_list,
+ PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+ pm_qos_update_request(&p_mctl->pm_qos_req_list,
+ MSM_V4L2_SWFI_LATENCY);
+
p_mctl->apps_id = apps_id;
p_mctl->opencnt++;
} else {
@@ -694,7 +691,7 @@
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);
+ p_mctl->isp_sdev->isp_release(p_mctl, p_mctl->isp_sdev->sd);
isp_open_failed:
if (camdev->is_csic)
if (v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
@@ -720,7 +717,7 @@
pr_err("%s: sensor powerdown failed: %d\n", __func__, rc);
sensor_sdev_failed:
register_sdev_failed:
- pm_qos_update_request(&p_mctl->idle_pm_qos, PM_QOS_DEFAULT_VALUE);
+ wake_unlock(&p_mctl->wake_lock);
mutex_unlock(&p_mctl->lock);
return rc;
}
@@ -757,7 +754,7 @@
}
if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
- p_mctl->isp_sdev->isp_release(
+ p_mctl->isp_sdev->isp_release(p_mctl,
p_mctl->isp_sdev->sd);
if (camdev->is_csid) {
@@ -770,18 +767,16 @@
VIDIOC_MSM_CSIPHY_RELEASE, NULL);
}
- if (camdev->is_ispif) {
- pm_qos_update_request(&p_mctl->pm_qos_req_list,
- PM_QOS_DEFAULT_VALUE);
- pm_qos_remove_request(&p_mctl->pm_qos_req_list);
- }
-
if (p_mctl->act_sdev)
v4l2_subdev_call(p_mctl->act_sdev, core, s_power, 0);
v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
- pm_qos_update_request(&p_mctl->idle_pm_qos, PM_QOS_DEFAULT_VALUE);
+ pm_qos_update_request(&p_mctl->pm_qos_req_list,
+ PM_QOS_DEFAULT_VALUE);
+ pm_qos_remove_request(&p_mctl->pm_qos_req_list);
+
+ wake_unlock(&p_mctl->wake_lock);
return rc;
}
@@ -865,8 +860,7 @@
return -EINVAL;
}
- pm_qos_add_request(&pmctl->idle_pm_qos, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ wake_lock_init(&pmctl->wake_lock, WAKE_LOCK_SUSPEND, "msm_camera");
mutex_init(&pmctl->lock);
pmctl->opencnt = 0;
@@ -906,7 +900,7 @@
}
mutex_destroy(&pmctl->lock);
- pm_qos_remove_request(&pmctl->idle_pm_qos);
+ wake_lock_destroy(&pmctl->wake_lock);
msm_cam_server_free_mctl(pcam->mctl_handle);
return rc;
}
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index aac2f2b..9dfbf8d 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -458,7 +458,7 @@
CDBG(KERN_ERR "snapshot exposure seting 0x%x, 0x%x, %d"
, gain, line, line);
s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
- if (line > 1964 && line <= 1968) {
+ if (line > 1964) {
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->frame_length_lines,
(uint8_t)((line+4) >> 8),
@@ -556,10 +556,10 @@
static int32_t ov5647_write_prev_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
uint16_t gain, uint32_t line)
{
-
- static uint16_t max_line = 984;
u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
uint8_t gain_lsb, gain_hsb;
+ uint32_t fl_lines = s_ctrl->curr_frame_length_lines;
+ uint8_t offset = s_ctrl->sensor_exp_gain_info->vert_offset;
CDBG(KERN_ERR "preview exposure setting 0x%x, 0x%x, %d",
gain, line, line);
@@ -567,33 +567,23 @@
gain_lsb = (uint8_t) (gain);
gain_hsb = (uint8_t)((gain & 0x300)>>8);
+ fl_lines = (fl_lines * s_ctrl->fps_divider) / Q10;
+
s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
/* adjust frame rate */
- if (line > 980 && line <= 984) {
- msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ if (line > (fl_lines - offset))
+ fl_lines = line + offset;
+
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->frame_length_lines,
- (uint8_t)((line+4) >> 8),
+ (uint8_t)(fl_lines >> 8),
MSM_CAMERA_I2C_BYTE_DATA);
- msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
- (uint8_t)((line+4) & 0x00FF),
+ (uint8_t)(fl_lines & 0x00FF),
MSM_CAMERA_I2C_BYTE_DATA);
- max_line = line + 4;
- } else if (max_line > 984) {
-
- msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_output_reg_addr->frame_length_lines,
- (uint8_t)(984 >> 8),
- MSM_CAMERA_I2C_BYTE_DATA);
-
- msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_output_reg_addr->frame_length_lines + 1 ,
- (uint8_t)(984 & 0x00FF),
- MSM_CAMERA_I2C_BYTE_DATA);
- max_line = 984;
- }
line = line<<4;
/* ov5647 need this operation */
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index c94fa13..a5f2634 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -1297,17 +1297,33 @@
return rc;
}
static long venc_set_max_perf_level(struct video_client_ctx *client_ctx,
- int val)
+ __s32 value)
{
int rc = 0;
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_perf_level perf;
+ int level = 0;
+
+ switch (value) {
+ case V4L2_CID_MPEG_QCOM_PERF_LEVEL_PERFORMANCE:
+ level = VCD_PERF_LEVEL2;
+ break;
+ case V4L2_CID_MPEG_QCOM_PERF_LEVEL_TURBO:
+ level = VCD_PERF_LEVEL_TURBO;
+ break;
+ default:
+ WFD_MSG_ERR("Unknown performance level: %d\n", value);
+ rc = -ENOTSUPP;
+ goto err_set_perf_level;
+ }
+
vcd_property_hdr.prop_id = VCD_REQ_PERF_LEVEL;
vcd_property_hdr.sz =
sizeof(struct vcd_property_perf_level);
- perf.level = VCD_PERF_LEVEL2;
+ perf.level = level;
rc = vcd_set_property(client_ctx->vcd_handle,
&vcd_property_hdr, &perf);
+err_set_perf_level:
return rc;
}
static long venc_set_header_mode(struct video_client_ctx *client_ctx,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 7c61bf3..f4e7fda 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -936,6 +936,14 @@
This is required to use certain other PM 8xxx features, such as GPIO
and MPP.
+config MFD_PM8821_IRQ
+ bool "Support for Qualcomm PM8821 IRQ features"
+ default y if MFD_PM8821_CORE
+ help
+ This is the IRQ driver for Qualcomm PM 8821 PMIC chips.
+
+ This is required to use certain other PM 8821 features, such as MPPs.
+
config TPS65911_COMPARATOR
tristate
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e81e4b1..099e45f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -137,6 +137,7 @@
obj-$(CONFIG_MFD_PM8018_CORE) += pm8018-core.o
obj-$(CONFIG_MFD_PM8038_CORE) += pm8038-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
+obj-$(CONFIG_MFD_PM8821_IRQ) += pm8821-irq.o
obj-$(CONFIG_MFD_PM8XXX_DEBUG) += pm8xxx-debug.o
obj-$(CONFIG_MFD_PM8XXX_PWM) += pm8xxx-pwm.o
obj-$(CONFIG_MFD_PM8XXX_MISC) += pm8xxx-misc.o
diff --git a/drivers/mfd/marimba-tsadc.c b/drivers/mfd/marimba-tsadc.c
index 8a7b781..32b93e1 100644
--- a/drivers/mfd/marimba-tsadc.c
+++ b/drivers/mfd/marimba-tsadc.c
@@ -437,7 +437,7 @@
struct marimba_tsadc *tsadc = dev_get_drvdata(dev);
if (tsadc->clk_enabled == true) {
- clk_disable(tsadc->codec_ssbi);
+ clk_disable_unprepare(tsadc->codec_ssbi);
tsadc->clk_enabled = false;
}
@@ -462,7 +462,7 @@
marimba_tsadc_configure(tsadc_dev);
fail_shutdown:
if (tsadc->clk_enabled == false) {
- ret = clk_enable(tsadc->codec_ssbi);
+ ret = clk_prepare_enable(tsadc->codec_ssbi);
if (ret == 0)
tsadc->clk_enabled = true;
}
@@ -475,7 +475,7 @@
struct marimba_tsadc *tsadc = dev_get_drvdata(dev);
if (tsadc->clk_enabled == false) {
- rc = clk_enable(tsadc->codec_ssbi);
+ rc = clk_prepare_enable(tsadc->codec_ssbi);
if (rc != 0) {
pr_err("%s: Clk enable failed\n", __func__);
return rc;
@@ -515,7 +515,7 @@
tsadc->pdata->marimba_tsadc_power(0);
fail_tsadc_power:
if (tsadc->clk_enabled == true) {
- clk_disable(tsadc->codec_ssbi);
+ clk_disable_unprepare(tsadc->codec_ssbi);
tsadc->clk_enabled = false;
}
return rc;
@@ -591,7 +591,7 @@
rc = PTR_ERR(tsadc->codec_ssbi);
goto fail_clk_get;
}
- rc = clk_enable(tsadc->codec_ssbi);
+ rc = clk_prepare_enable(tsadc->codec_ssbi);
if (rc != 0)
goto fail_clk_enable;
@@ -623,7 +623,7 @@
return rc;
fail_add_subdev:
- clk_disable(tsadc->codec_ssbi);
+ clk_disable_unprepare(tsadc->codec_ssbi);
fail_clk_enable:
clk_put(tsadc->codec_ssbi);
@@ -647,7 +647,7 @@
device_init_wakeup(&pdev->dev, 0);
if (tsadc->clk_enabled == true)
- clk_disable(tsadc->codec_ssbi);
+ clk_disable_unprepare(tsadc->codec_ssbi);
clk_put(tsadc->codec_ssbi);
diff --git a/drivers/mfd/pm8821-core.c b/drivers/mfd/pm8821-core.c
index df9d2e1..1d3c927a 100644
--- a/drivers/mfd/pm8821-core.c
+++ b/drivers/mfd/pm8821-core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -27,7 +27,7 @@
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
#define REG_MPP_BASE 0x050
-#define REG_IRQ_BASE 0x1BB
+#define REG_IRQ_BASE 0x100
#define PM8821_VERSION_MASK 0xFFF0
#define PM8821_VERSION_VALUE 0x0BF0
@@ -86,7 +86,7 @@
const struct pm8xxx_drvdata *pm8821_drvdata = dev_get_drvdata(dev);
const struct pm8821 *pmic = pm8821_drvdata->pm_chip_data;
- return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
+ return pm8821_get_irq_stat(pmic->irq_chip, irq);
}
static enum pm8xxx_version pm8821_get_version(const struct device *dev)
@@ -154,7 +154,7 @@
pdata->irq_pdata->irq_cdata.nirqs = PM8821_NR_IRQS;
pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
irq_base = pdata->irq_pdata->irq_base;
- irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
+ irq_chip = pm8821_irq_init(pmic->dev, pdata->irq_pdata);
if (IS_ERR(irq_chip)) {
pr_err("Failed to init interrupts ret=%ld\n",
@@ -186,7 +186,7 @@
return 0;
bail:
if (pmic->irq_chip) {
- pm8xxx_irq_exit(pmic->irq_chip);
+ pm8821_irq_exit(pmic->irq_chip);
pmic->irq_chip = NULL;
}
return ret;
@@ -281,7 +281,7 @@
if (pmic)
mfd_remove_devices(pmic->dev);
if (pmic->irq_chip) {
- pm8xxx_irq_exit(pmic->irq_chip);
+ pm8821_irq_exit(pmic->irq_chip);
pmic->irq_chip = NULL;
}
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/mfd/pm8821-irq.c b/drivers/mfd/pm8821-irq.c
new file mode 100644
index 0000000..2dcc792
--- /dev/null
+++ b/drivers/mfd/pm8821-irq.c
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/pm8821-irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define PM8821_TOTAL_IRQ_MASTERS 2
+#define PM8821_BLOCKS_PER_MASTER 7
+#define PM8821_IRQ_MASTER1_SET 0x01
+#define PM8821_IRQ_CLEAR_OFFSET 0x01
+#define PM8821_IRQ_RT_STATUS_OFFSET 0x0F
+#define PM8821_IRQ_MASK_REG_OFFSET 0x08
+#define SSBI_REG_ADDR_IRQ_MASTER0 0x30
+#define SSBI_REG_ADDR_IRQ_MASTER1 0xB0
+
+#define SSBI_REG_ADDR_IRQ_IT_STATUS(master_base, block) (master_base + block)
+
+/*
+ * Block 0 does not exist in PM8821 IRQ SSBI address space,
+ * IRQ0 is assigned to bit0 of block1.
+ */
+#define SSBI_REG_ADDR_IRQ_IT_CLEAR(master_base, block) \
+ (master_base + PM8821_IRQ_CLEAR_OFFSET + block)
+
+#define SSBI_REG_ADDR_IRQ_RT_STATUS(master_base, block) \
+ (master_base + PM8821_IRQ_RT_STATUS_OFFSET + block)
+
+#define SSBI_REG_ADDR_IRQ_MASK(master_base, block) \
+ (master_base + PM8821_IRQ_MASK_REG_OFFSET + block)
+
+struct pm_irq_chip {
+ struct device *dev;
+ spinlock_t pm_irq_lock;
+ unsigned int base_addr;
+ unsigned int devirq;
+ unsigned int irq_base;
+ unsigned int num_irqs;
+ int masters[PM8821_TOTAL_IRQ_MASTERS];
+};
+
+static int pm8821_irq_masked_write(struct pm_irq_chip *chip, u16 addr,
+ u8 mask, u8 val)
+{
+ int rc;
+ u8 reg;
+
+ rc = pm8xxx_readb(chip->dev, addr, ®);
+ if (rc) {
+ pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
+ return rc;
+ }
+
+ reg &= ~mask;
+ reg |= val & mask;
+
+ rc = pm8xxx_writeb(chip->dev, addr, reg);
+ if (rc) {
+ pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int pm8821_read_master_irq(const struct pm_irq_chip *chip,
+ int m, u8 *master)
+{
+ return pm8xxx_readb(chip->dev, chip->masters[m], master);
+}
+
+static int pm8821_read_block_irq(struct pm_irq_chip *chip, int master,
+ u8 block, u8 *bits)
+{
+ int rc;
+
+ spin_lock(&chip->pm_irq_lock);
+
+ rc = pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_IT_STATUS(chip->masters[master], block), bits);
+ if (rc)
+ pr_err("Failed Reading Status rc=%d\n", rc);
+
+ spin_unlock(&chip->pm_irq_lock);
+ return rc;
+}
+
+
+static int pm8821_irq_block_handler(struct pm_irq_chip *chip,
+ int master_number, int block)
+{
+ int pmirq, irq, i, ret;
+ u8 bits;
+
+ ret = pm8821_read_block_irq(chip, master_number, block, &bits);
+ if (ret) {
+ pr_err("Failed reading %d block ret=%d", block, ret);
+ return ret;
+ }
+ if (!bits) {
+ pr_err("block bit set in master but no irqs: %d", block);
+ return 0;
+ }
+
+ /* Convert block offset to global block number */
+ block += (master_number * PM8821_BLOCKS_PER_MASTER) - 1;
+
+ /* Check IRQ bits */
+ for (i = 0; i < 8; i++) {
+ if (bits & BIT(i)) {
+ pmirq = (block << 3) + i;
+ irq = pmirq + chip->irq_base;
+ generic_handle_irq(irq);
+ }
+ }
+ return 0;
+}
+
+static int pm8821_irq_read_master(struct pm_irq_chip *chip,
+ int master_number, u8 master_val)
+{
+ int ret = 0;
+ int block;
+
+ for (block = 1; block < 8; block++) {
+ if (master_val & BIT(block)) {
+ ret |= pm8821_irq_block_handler(chip,
+ master_number, block);
+ }
+ }
+
+ return ret;
+}
+
+static irqreturn_t pm8821_irq_handler(int irq, void *data)
+{
+ struct pm_irq_chip *chip = data;
+ int ret;
+ u8 master;
+
+ ret = pm8821_read_master_irq(chip, 0, &master);
+ if (ret) {
+ pr_err("Failed to read master 0 ret=%d\n", ret);
+ return ret;
+ }
+
+ if (master & ~PM8821_IRQ_MASTER1_SET)
+ pm8821_irq_read_master(chip, 0, master);
+
+ if (!(master & PM8821_IRQ_MASTER1_SET))
+ goto done;
+
+ ret = pm8821_read_master_irq(chip, 1, &master);
+ if (ret) {
+ pr_err("Failed to read master 1 ret=%d\n", ret);
+ return ret;
+ }
+
+ pm8821_irq_read_master(chip, 1, master);
+
+done:
+ return IRQ_HANDLED;
+}
+
+static void pm8821_irq_mask(struct irq_data *d)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+ unsigned int pmirq = d->irq - chip->irq_base;
+ int irq_bit, rc;
+ u8 block, master;
+
+ block = pmirq >> 3;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ irq_bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ spin_lock(&chip->pm_irq_lock);
+
+ rc = pm8821_irq_masked_write(chip,
+ SSBI_REG_ADDR_IRQ_MASK(chip->masters[master], block),
+ BIT(irq_bit), BIT(irq_bit));
+
+ if (rc)
+ pr_err("Failed to read/write mask IRQ:%d rc=%d\n", pmirq, rc);
+
+ spin_unlock(&chip->pm_irq_lock);
+}
+
+static void pm8821_irq_mask_ack(struct irq_data *d)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+ unsigned int pmirq = d->irq - chip->irq_base;
+ int irq_bit, rc;
+ u8 block, master;
+
+ block = pmirq >> 3;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ irq_bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ spin_lock(&chip->pm_irq_lock);
+
+ rc = pm8821_irq_masked_write(chip,
+ SSBI_REG_ADDR_IRQ_MASK(chip->masters[master], block),
+ BIT(irq_bit), BIT(irq_bit));
+
+ if (rc) {
+ pr_err("Failed to read/write mask IRQ:%d rc=%d\n", pmirq, rc);
+ goto fail;
+ }
+
+ rc = pm8821_irq_masked_write(chip,
+ SSBI_REG_ADDR_IRQ_IT_CLEAR(chip->masters[master], block),
+ BIT(irq_bit), BIT(irq_bit));
+
+ if (rc) {
+ pr_err("Failed to read/write IT_CLEAR IRQ:%d rc=%d\n",
+ pmirq, rc);
+ }
+
+fail:
+ spin_unlock(&chip->pm_irq_lock);
+}
+
+static void pm8821_irq_unmask(struct irq_data *d)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+ unsigned int pmirq = d->irq - chip->irq_base;
+ int irq_bit, rc;
+ u8 block, master;
+
+ block = pmirq >> 3;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ irq_bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ spin_lock(&chip->pm_irq_lock);
+
+ rc = pm8821_irq_masked_write(chip,
+ SSBI_REG_ADDR_IRQ_MASK(chip->masters[master], block),
+ BIT(irq_bit), ~BIT(irq_bit));
+
+ if (rc)
+ pr_err("Failed to read/write unmask IRQ:%d rc=%d\n", pmirq, rc);
+
+ spin_unlock(&chip->pm_irq_lock);
+}
+
+static int pm8821_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ /*
+ * PM8821 IRQ controller does not have explicit software support for
+ * IRQ flow type.
+ */
+ return 0;
+}
+
+static int pm8821_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ return 0;
+}
+
+static int pm8821_irq_read_line(struct irq_data *d)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+
+ return pm8821_get_irq_stat(chip, d->irq);
+}
+
+static struct irq_chip pm_irq_chip = {
+ .name = "pm8821-irq",
+ .irq_mask = pm8821_irq_mask,
+ .irq_mask_ack = pm8821_irq_mask_ack,
+ .irq_unmask = pm8821_irq_unmask,
+ .irq_set_type = pm8821_irq_set_type,
+ .irq_set_wake = pm8821_irq_set_wake,
+ .irq_read_line = pm8821_irq_read_line,
+ .flags = IRQCHIP_MASK_ON_SUSPEND,
+};
+
+/**
+ * pm8821_get_irq_stat - get the status of the irq line
+ * @chip: pointer to identify a pmic irq controller
+ * @irq: the irq number
+ *
+ * The pm8821 gpio and mpp rely on the interrupt block to read
+ * the values on their pins. This function is to facilitate reading
+ * the status of a gpio or an mpp line. The caller has to convert the
+ * gpio number to irq number.
+ *
+ * RETURNS:
+ * an int indicating the value read on that line
+ */
+int pm8821_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+ int pmirq, rc;
+ u8 block, bits, bit, master;
+ unsigned long flags;
+
+ if (chip == NULL || irq < chip->irq_base
+ || irq >= chip->irq_base + chip->num_irqs)
+ return -EINVAL;
+
+ pmirq = irq - chip->irq_base;
+
+ block = pmirq >> 3;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ spin_lock_irqsave(&chip->pm_irq_lock, flags);
+
+ rc = pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_RT_STATUS(chip->masters[master], block),
+ &bits);
+ if (rc) {
+ pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
+ irq, pmirq, block, rc);
+ goto bail_out;
+ }
+
+ rc = (bits & BIT(bit)) ? 1 : 0;
+
+bail_out:
+ spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pm8821_get_irq_stat);
+
+struct pm_irq_chip * __devinit pm8821_irq_init(struct device *dev,
+ const struct pm8xxx_irq_platform_data *pdata)
+{
+ struct pm_irq_chip *chip;
+ int devirq, rc, blocks, masters;
+ unsigned int pmirq;
+
+ if (!pdata) {
+ pr_err("No platform data\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ devirq = pdata->devirq;
+ if (devirq < 0) {
+ pr_err("missing devirq\n");
+ rc = devirq;
+ return ERR_PTR(-EINVAL);
+ }
+
+ chip = kzalloc(sizeof(struct pm_irq_chip)
+ + sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
+ if (!chip) {
+ pr_err("Cannot alloc pm_irq_chip struct\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ chip->dev = dev;
+ chip->devirq = devirq;
+ chip->irq_base = pdata->irq_base;
+ chip->num_irqs = pdata->irq_cdata.nirqs;
+ chip->base_addr = pdata->irq_cdata.base_addr;
+ blocks = DIV_ROUND_UP(pdata->irq_cdata.nirqs, 8);
+ masters = DIV_ROUND_UP(blocks, PM8821_BLOCKS_PER_MASTER);
+ chip->masters[0] = chip->base_addr + SSBI_REG_ADDR_IRQ_MASTER0;
+ chip->masters[1] = chip->base_addr + SSBI_REG_ADDR_IRQ_MASTER1;
+
+ if (masters != PM8821_TOTAL_IRQ_MASTERS) {
+ pr_err("Unequal number of masters, passed: %d, "
+ "should have been: %d\n", masters, PM8821_TOTAL_IRQ_MASTERS);
+ kfree(chip);
+ return ERR_PTR(-EINVAL);
+ }
+
+ spin_lock_init(&chip->pm_irq_lock);
+
+ for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) {
+ irq_set_chip_and_handler(chip->irq_base + pmirq,
+ &pm_irq_chip, handle_level_irq);
+ irq_set_chip_data(chip->irq_base + pmirq, chip);
+#ifdef CONFIG_ARM
+ set_irq_flags(chip->irq_base + pmirq, IRQF_VALID);
+#else
+ irq_set_noprobe(chip->irq_base + pmirq);
+#endif
+ }
+
+ if (devirq != 0) {
+ rc = request_irq(devirq, pm8821_irq_handler,
+ pdata->irq_trigger_flag, "pm8821_sec_irq", chip);
+ if (rc) {
+ pr_err("failed to request_irq for %d rc=%d\n",
+ devirq, rc);
+ kfree(chip);
+ return ERR_PTR(rc);
+ } else
+ irq_set_irq_wake(devirq, 1);
+ }
+
+ return chip;
+}
+
+int pm8821_irq_exit(struct pm_irq_chip *chip)
+{
+ irq_set_chained_handler(chip->devirq, NULL);
+ kfree(chip);
+ return 0;
+}
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 538ca7c..705a57b 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -510,7 +510,6 @@
sph[i] = tx[idx].sph;
grph = tx[idx].grph;
}
-
/* slim_control_ch (REMOVE) */
ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
if (ret < 0) {
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 02d1581..e7838f5 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -376,8 +376,8 @@
{
host->curr.data = NULL;
host->curr.got_dataend = 0;
- host->curr.wait_for_auto_prog_done = 0;
- host->curr.got_auto_prog_done = 0;
+ host->curr.wait_for_auto_prog_done = false;
+ host->curr.got_auto_prog_done = false;
writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
(~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
@@ -1118,7 +1118,7 @@
host->curr.xfer_remain = host->curr.xfer_size;
host->curr.data_xfered = 0;
host->curr.got_dataend = 0;
- host->curr.got_auto_prog_done = 0;
+ host->curr.got_auto_prog_done = false;
datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
@@ -1644,7 +1644,7 @@
host->curr.cmd = cmd;
} else {
host->prog_enable = 0;
- host->curr.wait_for_auto_prog_done = 0;
+ host->curr.wait_for_auto_prog_done = false;
if (host->dummy_52_needed)
host->dummy_52_needed = 0;
if (cmd->data && cmd->error)
@@ -1808,7 +1808,7 @@
/* Check for prog done */
if (host->curr.wait_for_auto_prog_done &&
(status & MCI_PROGDONE))
- host->curr.got_auto_prog_done = 1;
+ host->curr.got_auto_prog_done = true;
/* Check for data done */
if (!host->curr.got_dataend && (status & MCI_DATAEND))
@@ -2026,35 +2026,26 @@
msecs_to_jiffies(host->curr.req_tout_ms)));
host->curr.mrq = mrq;
+ if (mrq->sbc) {
+ mrq->sbc->mrq = mrq;
+ mrq->sbc->data = mrq->data;
+ }
+
if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
- if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
- mrq->cmd->opcode == 54) {
- if (!host->sdcc_version)
+ if (host->sdcc_version) {
+ if (!mrq->stop)
+ host->curr.wait_for_auto_prog_done = true;
+ } else {
+ if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
+ (mrq->cmd->opcode == 54))
host->dummy_52_needed = 1;
- else
- /*
- * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
- * write operations using CMD53 and CMD54.
- * Setting this bit with CMD53 would
- * automatically triggers PROG_DONE interrupt
- * without the need of sending dummy CMD52.
- */
- host->curr.wait_for_auto_prog_done = 1;
- } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
- host->sdcc_version) {
- host->curr.wait_for_auto_prog_done = 1;
}
+
if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
(mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
host->curr.use_wr_data_pend = true;
}
- if (mrq->data && mrq->sbc) {
- mrq->sbc->mrq = mrq;
- mrq->sbc->data = mrq->data;
- if (mrq->data->flags & MMC_DATA_WRITE)
- host->curr.wait_for_auto_prog_done = 1;
- }
msmsdcc_request_start(host, mrq);
spin_unlock_irqrestore(&host->lock, flags);
@@ -4363,7 +4354,7 @@
}
static ssize_t
-set_polling(struct device *dev, struct device_attribute *attr,
+store_polling(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -4387,9 +4378,6 @@
return count;
}
-static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
- show_polling, set_polling);
-
static ssize_t
show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -4402,7 +4390,7 @@
}
static ssize_t
-set_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -4419,20 +4407,6 @@
return count;
}
-static DEVICE_ATTR(max_bus_bw, S_IRUGO | S_IWUSR,
- show_sdcc_to_mem_max_bus_bw, set_sdcc_to_mem_max_bus_bw);
-
-static struct attribute *dev_attrs[] = {
- &dev_attr_max_bus_bw.attr,
- /* if polling is enabled, this will be filled with dev_attr_polling */
- NULL,
- NULL,
-};
-
-static struct attribute_group dev_attr_grp = {
- .attrs = dev_attrs,
-};
-
#ifdef CONFIG_HAS_EARLYSUSPEND
static void msmsdcc_early_suspend(struct early_suspend *h)
{
@@ -4568,7 +4542,7 @@
}
} else {
host->prog_enable = 0;
- host->curr.wait_for_auto_prog_done = 0;
+ host->curr.wait_for_auto_prog_done = false;
msmsdcc_reset_and_restore(host);
msmsdcc_request_end(host, mrq);
}
@@ -5189,14 +5163,30 @@
#if defined(CONFIG_DEBUG_FS)
msmsdcc_dbg_createhost(host);
#endif
- if (!plat->status_irq)
- dev_attrs[1] = &dev_attr_polling.attr;
- ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
+ host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
+ host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
+ sysfs_attr_init(&host->max_bus_bw.attr);
+ host->max_bus_bw.attr.name = "max_bus_bw";
+ host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(&pdev->dev, &host->max_bus_bw);
if (ret)
goto platform_irq_free;
+
+ if (!plat->status_irq) {
+ host->polling.show = show_polling;
+ host->polling.store = store_polling;
+ sysfs_attr_init(&host->polling.attr);
+ host->polling.attr.name = "polling";
+ host->polling.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(&pdev->dev, &host->polling);
+ if (ret)
+ goto remove_max_bus_bw_file;
+ }
return 0;
+ remove_max_bus_bw_file:
+ device_remove_file(&pdev->dev, &host->max_bus_bw);
platform_irq_free:
del_timer_sync(&host->req_tout_timer);
pm_runtime_disable(&(pdev)->dev);
@@ -5273,8 +5263,9 @@
DBG(host, "Removing SDCC device = %d\n", pdev->id);
plat = host->plat;
+ device_remove_file(&pdev->dev, &host->max_bus_bw);
if (!plat->status_irq)
- sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
+ device_remove_file(&pdev->dev, &host->polling);
del_timer_sync(&host->req_tout_timer);
tasklet_kill(&host->dma_tlet);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index ecf4950..1fe5129 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -293,8 +293,8 @@
unsigned int xfer_remain; /* Bytes remaining to send */
unsigned int data_xfered; /* Bytes acked by BLKEND irq */
int got_dataend;
- int wait_for_auto_prog_done;
- int got_auto_prog_done;
+ bool wait_for_auto_prog_done;
+ bool got_auto_prog_done;
bool use_wr_data_pend;
int user_pages;
u32 req_tout_ms;
@@ -411,6 +411,8 @@
struct mutex clk_mutex;
bool pending_resume;
struct msmsdcc_msm_bus_vote msm_bus_vote;
+ struct device_attribute max_bus_bw;
+ struct device_attribute polling;
};
int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 3f63532..0342b97 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/spmi.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
struct spmii_boardinfo {
struct list_head list;
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index df335d2..65bcb08 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -25,13 +25,14 @@
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
#include <mach/msm_serial_hs.h>
#include "smux_private.h"
#include "smux_loopback.h"
#define SMUX_NOTIFY_FIFO_SIZE 128
#define SMUX_TX_QUEUE_SIZE 256
-#define SMUX_GET_RX_BUFF_MAX_RETRY_CNT 2
#define SMUX_WM_LOW 2
#define SMUX_WM_HIGH 4
#define SMUX_PKT_LOG_SIZE 80
@@ -49,6 +50,10 @@
/* inactivity timeout for no rx/tx activity */
#define SMUX_INACTIVITY_TIMEOUT_MS 1000
+/* RX get_rx_buffer retry timeout values */
+#define SMUX_RX_RETRY_MIN_MS (1 << 0) /* 1 ms */
+#define SMUX_RX_RETRY_MAX_MS (1 << 10) /* 1024 ms */
+
enum {
MSM_SMUX_DEBUG = 1U << 0,
MSM_SMUX_INFO = 1U << 1,
@@ -175,6 +180,11 @@
int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
int size);
+ /* RX Info */
+ struct list_head rx_retry_queue;
+ unsigned rx_retry_queue_cnt;
+ struct delayed_work rx_retry_work;
+
/* TX Info */
spinlock_t tx_lock_lhb2;
struct list_head tx_queue;
@@ -198,25 +208,54 @@
};
/**
+ * Get RX Buffer Retry structure.
+ *
+ * This is used for clients that are unable to provide an RX buffer
+ * immediately. This temporary structure will be used to temporarily hold the
+ * data and perform a retry.
+ */
+struct smux_rx_pkt_retry {
+ struct smux_pkt_t *pkt;
+ struct list_head rx_retry_list;
+ unsigned timeout_in_ms;
+};
+
+/**
+ * Receive worker data structure.
+ *
+ * One instance is created for every call to smux_rx_state_machine.
+ */
+struct smux_rx_worker_data {
+ const unsigned char *data;
+ int len;
+ int flag;
+
+ struct work_struct work;
+ struct completion work_complete;
+};
+
+/**
* Line discipline and module structure.
*
* Only one instance since multiple instances of line discipline are not
* allowed.
*/
struct smux_ldisc_t {
- spinlock_t lock_lha0;
+ struct mutex mutex_lha0;
int is_initialized;
int in_reset;
int ld_open_count;
struct tty_struct *tty;
- /* RX State Machine */
- spinlock_t rx_lock_lha1;
+ /* RX State Machine (singled-threaded access by smux_rx_wq) */
unsigned char recv_buf[SMUX_MAX_PKT_SIZE];
unsigned int recv_len;
unsigned int pkt_remain;
unsigned rx_state;
+
+ /* RX Activity - accessed by multiple threads */
+ spinlock_t rx_lock_lha1;
unsigned rx_activity_flag;
/* TX / Power */
@@ -226,6 +265,7 @@
unsigned pwr_wakeup_delay_us;
unsigned tx_activity_flag;
unsigned powerdown_enabled;
+ struct list_head power_queue;
};
@@ -259,10 +299,13 @@
static DEFINE_SPINLOCK(notify_lock_lhc1);
static struct workqueue_struct *smux_tx_wq;
+static struct workqueue_struct *smux_rx_wq;
static void smux_tx_worker(struct work_struct *work);
static DECLARE_WORK(smux_tx_work, smux_tx_worker);
static void smux_wakeup_worker(struct work_struct *work);
+static void smux_rx_retry_worker(struct work_struct *work);
+static void smux_rx_worker(struct work_struct *work);
static DECLARE_WORK(smux_wakeup_work, smux_wakeup_worker);
static DECLARE_DELAYED_WORK(smux_wakeup_delayed_work, smux_wakeup_worker);
@@ -275,6 +318,13 @@
static void list_channel(struct smux_lch_t *ch);
static int smux_send_status_cmd(struct smux_lch_t *ch);
static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt);
+static void smux_flush_tty(void);
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch);
+static int schedule_notify(uint8_t lcid, int event,
+ const union notifier_metadata *metadata);
+static int ssr_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data);
/**
* Convert TTY Error Flags to string for logging purposes.
@@ -321,6 +371,7 @@
smux_notify_wq = create_singlethread_workqueue("smux_notify_wq");
smux_tx_wq = create_singlethread_workqueue("smux_tx_wq");
+ smux_rx_wq = create_singlethread_workqueue("smux_rx_wq");
if (IS_ERR(smux_notify_wq) || IS_ERR(smux_tx_wq)) {
SMUX_DBG("%s: create_singlethread_workqueue ENOMEM\n",
@@ -354,6 +405,10 @@
ch->notify = 0;
ch->get_rx_buffer = 0;
+ INIT_LIST_HEAD(&ch->rx_retry_queue);
+ ch->rx_retry_queue_cnt = 0;
+ INIT_DELAYED_WORK(&ch->rx_retry_work, smux_rx_retry_worker);
+
spin_lock_init(&ch->tx_lock_lhb2);
INIT_LIST_HEAD(&ch->tx_queue);
INIT_LIST_HEAD(&ch->tx_ready_list);
@@ -364,6 +419,82 @@
return 0;
}
+/**
+ * Empty and cleanup all SMUX logical channels for subsystem restart or line
+ * discipline disconnect.
+ */
+static void smux_lch_purge(void)
+{
+ struct smux_lch_t *ch;
+ unsigned long flags;
+ int i;
+
+ /* Empty TX ready list */
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ while (!list_empty(&smux.lch_tx_ready_list)) {
+ SMUX_DBG("%s: emptying ready list %p\n",
+ __func__, smux.lch_tx_ready_list.next);
+ ch = list_first_entry(&smux.lch_tx_ready_list,
+ struct smux_lch_t,
+ tx_ready_list);
+ list_del(&ch->tx_ready_list);
+ INIT_LIST_HEAD(&ch->tx_ready_list);
+ }
+
+ /* Purge Power Queue */
+ while (!list_empty(&smux.power_queue)) {
+ struct smux_pkt_t *pkt;
+
+ pkt = list_first_entry(&smux.power_queue,
+ struct smux_pkt_t,
+ list);
+ SMUX_DBG("%s: emptying power queue pkt=%p\n",
+ __func__, pkt);
+ smux_free_pkt(pkt);
+ }
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ /* Close all ports */
+ for (i = 0 ; i < SMUX_NUM_LOGICAL_CHANNELS; i++) {
+ ch = &smux_lch[i];
+ SMUX_DBG("%s: cleaning up lcid %d\n", __func__, i);
+
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+
+ /* Purge TX queue */
+ spin_lock(&ch->tx_lock_lhb2);
+ smux_purge_ch_tx_queue(ch);
+ spin_unlock(&ch->tx_lock_lhb2);
+
+ /* Notify user of disconnect and reset channel state */
+ if (ch->local_state == SMUX_LCH_LOCAL_OPENED ||
+ ch->local_state == SMUX_LCH_LOCAL_CLOSING) {
+ union notifier_metadata meta;
+
+ meta.disconnected.is_ssr = smux.in_reset;
+ schedule_notify(ch->lcid, SMUX_DISCONNECTED, &meta);
+ }
+
+ ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+ ch->local_mode = SMUX_LCH_MODE_NORMAL;
+ ch->remote_state = SMUX_LCH_REMOTE_CLOSED;
+ ch->remote_mode = SMUX_LCH_MODE_NORMAL;
+ ch->tx_flow_control = 0;
+
+ /* Purge RX retry queue */
+ if (ch->rx_retry_queue_cnt)
+ queue_delayed_work(smux_rx_wq, &ch->rx_retry_work, 0);
+
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+ }
+
+ /* Flush TX/RX workqueues */
+ SMUX_DBG("%s: flushing tx wq\n", __func__);
+ flush_workqueue(smux_tx_wq);
+ SMUX_DBG("%s: flushing rx wq\n", __func__);
+ flush_workqueue(smux_rx_wq);
+}
+
int smux_assert_lch_id(uint32_t lcid)
{
if (lcid >= SMUX_NUM_LOGICAL_CHANNELS)
@@ -785,7 +916,7 @@
if (!data)
return 0;
- while (len > 0) {
+ while (len > 0 && !smux.in_reset) {
data_written = smux.tty->ops->write(smux.tty, data, len);
if (data_written >= 0) {
len -= data_written;
@@ -799,8 +930,6 @@
if (len)
tty_wait_until_sent(smux.tty,
msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
-
- /* FUTURE - add SSR logic */
}
return 0;
}
@@ -866,19 +995,20 @@
*/
static void smux_send_byte(char ch)
{
- struct smux_pkt_t pkt;
+ struct smux_pkt_t *pkt;
- smux_init_pkt(&pkt);
+ pkt = smux_alloc_pkt();
+ if (!pkt) {
+ pr_err("%s: alloc failure for byte %x\n", __func__, ch);
+ return;
+ }
+ pkt->hdr.cmd = SMUX_CMD_BYTE;
+ pkt->hdr.flags = ch;
+ pkt->hdr.lcid = SMUX_BROADCAST_LCID;
+ pkt->hdr.flags = ch;
- pkt.hdr.cmd = SMUX_CMD_BYTE;
- pkt.hdr.flags = ch;
- pkt.hdr.lcid = 0;
- pkt.hdr.flags = ch;
- SMUX_LOG_PKT_TX(&pkt);
- if (!smux_byte_loopback)
- smux_tx_tty(&pkt);
- else
- smux_tx_loopback(&pkt);
+ list_add_tail(&pkt->list, &smux.power_queue);
+ queue_work(smux_tx_wq, &smux_tx_work);
}
/**
@@ -888,8 +1018,6 @@
* @lcid Logical channel ID for packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 locked.
*/
static int smux_receive_byte(char ch, int lcid)
{
@@ -931,8 +1059,6 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_open_ack(struct smux_pkt_t *pkt)
{
@@ -1021,8 +1147,6 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_open_cmd(struct smux_pkt_t *pkt)
{
@@ -1030,6 +1154,7 @@
int ret;
struct smux_lch_t *ch;
struct smux_pkt_t *ack_pkt;
+ unsigned long flags;
int tx_ready = 0;
int enable_powerdown = 0;
@@ -1039,7 +1164,7 @@
lcid = pkt->hdr.lcid;
ch = &smux_lch[lcid];
- spin_lock(&ch->state_lock_lhb1);
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED) {
SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
@@ -1100,13 +1225,16 @@
}
out:
- spin_unlock(&ch->state_lock_lhb1);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
if (enable_powerdown) {
- spin_lock(&smux.tx_lock_lha2);
- smux.powerdown_enabled = 1;
- SMUX_DBG("%s: enabling power-collapse support\n", __func__);
- spin_unlock(&smux.tx_lock_lha2);
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ if (!smux.powerdown_enabled) {
+ smux.powerdown_enabled = 1;
+ SMUX_DBG("%s: enabling power-collapse support\n",
+ __func__);
+ }
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
}
if (tx_ready)
@@ -1121,8 +1249,6 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_close_cmd(struct smux_pkt_t *pkt)
{
@@ -1131,6 +1257,7 @@
struct smux_lch_t *ch;
struct smux_pkt_t *ack_pkt;
union notifier_metadata meta_disconnected;
+ unsigned long flags;
int tx_ready = 0;
if (pkt->hdr.flags & SMUX_CMD_CLOSE_ACK)
@@ -1140,7 +1267,7 @@
ch = &smux_lch[lcid];
meta_disconnected.disconnected.is_ssr = 0;
- spin_lock(&ch->state_lock_lhb1);
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
SMUX_LCH_REMOTE_OPENED,
@@ -1191,7 +1318,7 @@
ret = -EINVAL;
}
out:
- spin_unlock(&ch->state_lock_lhb1);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
if (tx_ready)
list_channel(ch);
@@ -1204,25 +1331,30 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_data_cmd(struct smux_pkt_t *pkt)
{
uint8_t lcid;
- int ret;
- int i;
+ int ret = 0;
+ int do_retry = 0;
int tmp;
int rx_len;
struct smux_lch_t *ch;
union notifier_metadata metadata;
int remote_loopback;
- int tx_ready = 0;
struct smux_pkt_t *ack_pkt;
unsigned long flags;
- if (!pkt || smux_assert_lch_id(pkt->hdr.lcid))
- return -ENXIO;
+ if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ rx_len = pkt->hdr.payload_len;
+ if (rx_len == 0) {
+ ret = -EINVAL;
+ goto out;
+ }
lcid = pkt->hdr.lcid;
ch = &smux_lch[lcid];
@@ -1234,6 +1366,7 @@
pr_err("smux: ch %d error data on local state 0x%x",
lcid, ch->local_state);
ret = -EIO;
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
goto out;
}
@@ -1241,69 +1374,110 @@
pr_err("smux: ch %d error data on remote state 0x%x",
lcid, ch->remote_state);
ret = -EIO;
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
goto out;
}
- rx_len = pkt->hdr.payload_len;
- if (rx_len == 0) {
- ret = -EINVAL;
- goto out;
+ if (!list_empty(&ch->rx_retry_queue)) {
+ do_retry = 1;
+ if ((ch->rx_retry_queue_cnt + 1) > SMUX_RX_RETRY_MAX_PKTS) {
+ /* retry queue full */
+ schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+ ret = -ENOMEM;
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+ goto out;
+ }
}
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
- for (i = 0; i < SMUX_GET_RX_BUFF_MAX_RETRY_CNT; ++i) {
+ if (remote_loopback) {
+ /* Echo the data back to the remote client. */
+ ack_pkt = smux_alloc_pkt();
+ if (ack_pkt) {
+ ack_pkt->hdr.lcid = lcid;
+ ack_pkt->hdr.cmd = SMUX_CMD_DATA;
+ ack_pkt->hdr.flags = 0;
+ ack_pkt->hdr.payload_len = pkt->hdr.payload_len;
+ if (ack_pkt->hdr.payload_len) {
+ smux_alloc_pkt_payload(ack_pkt);
+ memcpy(ack_pkt->payload, pkt->payload,
+ ack_pkt->hdr.payload_len);
+ }
+ ack_pkt->hdr.pad_len = pkt->hdr.pad_len;
+ smux_tx_queue(ack_pkt, ch, 0);
+ list_channel(ch);
+ } else {
+ pr_err("%s: Remote loopack allocation failure\n",
+ __func__);
+ }
+ } else if (!do_retry) {
+ /* request buffer from client */
metadata.read.pkt_priv = 0;
metadata.read.buffer = 0;
+ tmp = ch->get_rx_buffer(ch->priv,
+ (void **)&metadata.read.pkt_priv,
+ (void **)&metadata.read.buffer,
+ rx_len);
- if (!remote_loopback) {
- tmp = ch->get_rx_buffer(ch->priv,
- (void **)&metadata.read.pkt_priv,
- (void **)&metadata.read.buffer,
+ if (tmp == 0 && metadata.read.buffer) {
+ /* place data into RX buffer */
+ memcpy(metadata.read.buffer, pkt->payload,
rx_len);
- if (tmp == 0 && metadata.read.buffer) {
- /* place data into RX buffer */
- memcpy(metadata.read.buffer, pkt->payload,
- rx_len);
- metadata.read.len = rx_len;
- schedule_notify(lcid, SMUX_READ_DONE,
- &metadata);
- ret = 0;
- break;
- } else if (tmp == -EAGAIN) {
- ret = -ENOMEM;
- } else if (tmp < 0) {
- schedule_notify(lcid, SMUX_READ_FAIL, NULL);
- ret = -ENOMEM;
- break;
- } else if (!metadata.read.buffer) {
- pr_err("%s: get_rx_buffer() buffer is NULL\n",
- __func__);
- ret = -ENOMEM;
- }
- } else {
- /* Echo the data back to the remote client. */
- ack_pkt = smux_alloc_pkt();
- if (ack_pkt) {
- ack_pkt->hdr.lcid = lcid;
- ack_pkt->hdr.cmd = SMUX_CMD_DATA;
- ack_pkt->hdr.flags = 0;
- ack_pkt->hdr.payload_len = pkt->hdr.payload_len;
- ack_pkt->payload = pkt->payload;
- ack_pkt->hdr.pad_len = pkt->hdr.pad_len;
- smux_tx_queue(ack_pkt, ch, 0);
- tx_ready = 1;
- } else {
- pr_err("%s: Remote loopack allocation failure\n",
- __func__);
- }
+ metadata.read.len = rx_len;
+ schedule_notify(lcid, SMUX_READ_DONE,
+ &metadata);
+ } else if (tmp == -EAGAIN ||
+ (tmp == 0 && !metadata.read.buffer)) {
+ /* buffer allocation failed - add to retry queue */
+ do_retry = 1;
+ } else if (tmp < 0) {
+ schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+ ret = -ENOMEM;
}
}
+ if (do_retry) {
+ struct smux_rx_pkt_retry *retry;
+
+ retry = kmalloc(sizeof(struct smux_rx_pkt_retry), GFP_KERNEL);
+ if (!retry) {
+ pr_err("%s: retry alloc failure\n", __func__);
+ ret = -ENOMEM;
+ schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+ goto out;
+ }
+ INIT_LIST_HEAD(&retry->rx_retry_list);
+ retry->timeout_in_ms = SMUX_RX_RETRY_MIN_MS;
+
+ /* copy packet */
+ retry->pkt = smux_alloc_pkt();
+ if (!retry->pkt) {
+ kfree(retry);
+ pr_err("%s: pkt alloc failure\n", __func__);
+ ret = -ENOMEM;
+ schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+ goto out;
+ }
+ retry->pkt->hdr.lcid = lcid;
+ retry->pkt->hdr.payload_len = pkt->hdr.payload_len;
+ retry->pkt->hdr.pad_len = pkt->hdr.pad_len;
+ if (retry->pkt->hdr.payload_len) {
+ smux_alloc_pkt_payload(retry->pkt);
+ memcpy(retry->pkt->payload, pkt->payload,
+ retry->pkt->hdr.payload_len);
+ }
+
+ /* add to retry queue */
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ list_add_tail(&retry->rx_retry_list, &ch->rx_retry_queue);
+ ++ch->rx_retry_queue_cnt;
+ if (ch->rx_retry_queue_cnt == 1)
+ queue_delayed_work(smux_rx_wq, &ch->rx_retry_work,
+ msecs_to_jiffies(retry->timeout_in_ms));
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+ }
+
out:
- spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
-
- if (tx_ready)
- list_channel(ch);
-
return ret;
}
@@ -1322,8 +1496,10 @@
union notifier_metadata metadata;
unsigned long flags;
- if (!pkt || smux_assert_lch_id(pkt->hdr.lcid))
+ if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
+ pr_err("%s: invalid packet or channel id\n", __func__);
return -ENXIO;
+ }
lcid = pkt->hdr.lcid;
ch = &smux_lch[lcid];
@@ -1359,8 +1535,6 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_status_cmd(struct smux_pkt_t *pkt)
{
@@ -1416,15 +1590,13 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_power_cmd(struct smux_pkt_t *pkt)
{
- int tx_ready = 0;
struct smux_pkt_t *ack_pkt = NULL;
+ unsigned long flags;
- spin_lock(&smux.tx_lock_lha2);
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (pkt->hdr.flags & SMUX_CMD_PWR_CTL_ACK) {
/* local sleep request ack */
if (smux.power_state == SMUX_PWR_TURNING_OFF) {
@@ -1438,7 +1610,17 @@
__func__, smux.power_state);
}
} else {
- /* remote sleep request */
+ /*
+ * Remote sleep request
+ *
+ * Even if we have data pending, we need to transition to the
+ * POWER_OFF state and then perform a wakeup since the remote
+ * side has requested a power-down.
+ *
+ * The state here is set to SMUX_PWR_TURNING_OFF_FLUSH and
+ * the TX thread will set the state to SMUX_PWR_TURNING_OFF
+ * when it sends the packet.
+ */
if (smux.power_state == SMUX_PWR_ON
|| smux.power_state == SMUX_PWR_TURNING_OFF) {
ack_pkt = smux_alloc_pkt();
@@ -1447,28 +1629,22 @@
smux.power_state,
SMUX_PWR_TURNING_OFF_FLUSH);
- /* send power-down request */
+ smux.power_state = SMUX_PWR_TURNING_OFF_FLUSH;
+
+ /* send power-down ack */
ack_pkt->hdr.cmd = SMUX_CMD_PWR_CTL;
ack_pkt->hdr.flags = SMUX_CMD_PWR_CTL_ACK;
- ack_pkt->hdr.lcid = pkt->hdr.lcid;
- smux_tx_queue(ack_pkt,
- &smux_lch[ack_pkt->hdr.lcid], 0);
- tx_ready = 1;
- smux.power_state = SMUX_PWR_TURNING_OFF_FLUSH;
- queue_delayed_work(smux_tx_wq,
- &smux_delayed_inactivity_work,
- msecs_to_jiffies(
- SMUX_INACTIVITY_TIMEOUT_MS));
+ ack_pkt->hdr.lcid = SMUX_BROADCAST_LCID;
+ list_add_tail(&ack_pkt->list,
+ &smux.power_queue);
+ queue_work(smux_tx_wq, &smux_tx_work);
}
} else {
pr_err("%s: sleep request invalid in state %d\n",
__func__, smux.power_state);
}
}
- spin_unlock(&smux.tx_lock_lha2);
-
- if (tx_ready)
- list_channel(&smux_lch[ack_pkt->hdr.lcid]);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
return 0;
}
@@ -1479,8 +1655,6 @@
* @pkt Packet to process
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt)
{
@@ -1527,8 +1701,6 @@
* @len Length of the data
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_deserialize(unsigned char *data, int len)
{
@@ -1562,12 +1734,12 @@
/**
* Handle wakeup request byte.
- *
- * Called with rx_lock_lha1 already locked.
*/
static void smux_handle_wakeup_req(void)
{
- spin_lock(&smux.tx_lock_lha2);
+ unsigned long flags;
+
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_OFF
|| smux.power_state == SMUX_PWR_TURNING_ON) {
/* wakeup system */
@@ -1582,17 +1754,17 @@
} else {
smux_send_byte(SMUX_WAKEUP_ACK);
}
- spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
}
/**
* Handle wakeup request ack.
- *
- * Called with rx_lock_lha1 already locked.
*/
static void smux_handle_wakeup_ack(void)
{
- spin_lock(&smux.tx_lock_lha2);
+ unsigned long flags;
+
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_TURNING_ON) {
/* received response to wakeup request */
SMUX_DBG("%s: Power %d->%d\n", __func__,
@@ -1607,7 +1779,7 @@
pr_err("%s: wakeup request ack invalid in state %d\n",
__func__, smux.power_state);
}
- spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
}
/**
@@ -1617,8 +1789,6 @@
* @len Length of the data
* @used Return value of length processed
* @flag Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
*/
static void smux_rx_handle_idle(const unsigned char *data,
int len, int *used, int flag)
@@ -1666,8 +1836,6 @@
* @len Length of the data
* @used Return value of length processed
* @flag Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
*/
static void smux_rx_handle_magic(const unsigned char *data,
int len, int *used, int flag)
@@ -1707,8 +1875,6 @@
* @len Length of the data
* @used Return value of length processed
* @flag Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
*/
static void smux_rx_handle_hdr(const unsigned char *data,
int len, int *used, int flag)
@@ -1744,8 +1910,6 @@
* @len Length of the data
* @used Return value of length processed
* @flag Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
*/
static void smux_rx_handle_pkt_payload(const unsigned char *data,
int len, int *used, int flag)
@@ -1784,47 +1948,20 @@
* @data Pointer to data block
* @len Length of data
* @flag TTY_NORMAL (0) for no error, otherwise TTY Error Flag
- *
- * Called with rx_lock_lha1 locked.
*/
void smux_rx_state_machine(const unsigned char *data,
int len, int flag)
{
- unsigned long flags;
- int used;
- int initial_rx_state;
+ struct smux_rx_worker_data work;
+ work.data = data;
+ work.len = len;
+ work.flag = flag;
+ INIT_WORK_ONSTACK(&work.work, smux_rx_worker);
+ work.work_complete = COMPLETION_INITIALIZER_ONSTACK(work.work_complete);
- SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
- spin_lock_irqsave(&smux.rx_lock_lha1, flags);
- used = 0;
- smux.rx_activity_flag = 1;
- do {
- SMUX_DBG("%s: state %d; %d of %d\n",
- __func__, smux.rx_state, used, len);
- initial_rx_state = smux.rx_state;
-
- switch (smux.rx_state) {
- case SMUX_RX_IDLE:
- smux_rx_handle_idle(data, len, &used, flag);
- break;
- case SMUX_RX_MAGIC:
- smux_rx_handle_magic(data, len, &used, flag);
- break;
- case SMUX_RX_HDR:
- smux_rx_handle_hdr(data, len, &used, flag);
- break;
- case SMUX_RX_PAYLOAD:
- smux_rx_handle_pkt_payload(data, len, &used, flag);
- break;
- default:
- SMUX_DBG("%s: invalid state %d\n",
- __func__, smux.rx_state);
- smux.rx_state = SMUX_RX_IDLE;
- break;
- }
- } while (used < len || smux.rx_state != initial_rx_state);
- spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+ queue_work(smux_rx_wq, &work.work);
+ wait_for_completion(&work.work_complete);
}
/**
@@ -1889,6 +2026,67 @@
}
/**
+ * Flush pending TTY TX data.
+ */
+static void smux_flush_tty(void)
+{
+ if (!smux.tty) {
+ pr_err("%s: ldisc not loaded\n", __func__);
+ return;
+ }
+
+ tty_wait_until_sent(smux.tty,
+ msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
+
+ if (tty_chars_in_buffer(smux.tty) > 0)
+ pr_err("%s: unable to flush UART queue\n", __func__);
+}
+
+/**
+ * Purge TX queue for logical channel.
+ *
+ * @ch Logical channel pointer
+ *
+ * Must be called with the following spinlocks locked:
+ * state_lock_lhb1
+ * tx_lock_lhb2
+ */
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch)
+{
+ struct smux_pkt_t *pkt;
+ int send_disconnect = 0;
+
+ while (!list_empty(&ch->tx_queue)) {
+ pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
+ list);
+ list_del(&pkt->list);
+
+ if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
+ /* Open was never sent, just force to closed state */
+ ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+ send_disconnect = 1;
+ } else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
+ /* Notify client of failed write */
+ union notifier_metadata meta_write;
+
+ meta_write.write.pkt_priv = pkt->priv;
+ meta_write.write.buffer = pkt->payload;
+ meta_write.write.len = pkt->hdr.payload_len;
+ schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
+ }
+ smux_free_pkt(pkt);
+ }
+
+ if (send_disconnect) {
+ union notifier_metadata meta_disconnected;
+
+ meta_disconnected.disconnected.is_ssr = smux.in_reset;
+ schedule_notify(ch->lcid, SMUX_DISCONNECTED,
+ &meta_disconnected);
+ }
+}
+
+/**
* Power-up the UART.
*/
static void smux_uart_power_on(void)
@@ -1934,7 +2132,7 @@
unsigned wakeup_delay;
int complete = 0;
- for (;;) {
+ while (!smux.in_reset) {
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_ON) {
/* wakeup complete */
@@ -1990,7 +2188,6 @@
*/
static void smux_inactivity_worker(struct work_struct *work)
{
- int tx_ready = 0;
struct smux_pkt_t *pkt;
unsigned long flags;
@@ -2012,11 +2209,13 @@
/* send power-down request */
pkt->hdr.cmd = SMUX_CMD_PWR_CTL;
pkt->hdr.flags = 0;
- pkt->hdr.lcid = 0;
- smux_tx_queue(pkt,
- &smux_lch[SMUX_TEST_LCID],
- 0);
- tx_ready = 1;
+ pkt->hdr.lcid = SMUX_BROADCAST_LCID;
+ list_add_tail(&pkt->list,
+ &smux.power_queue);
+ queue_work(smux_tx_wq, &smux_tx_work);
+ } else {
+ pr_err("%s: packet alloc failed\n",
+ __func__);
}
}
} else {
@@ -2027,21 +2226,26 @@
smux.tx_activity_flag = 0;
smux.rx_activity_flag = 0;
- spin_unlock(&smux.tx_lock_lha2);
- spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
-
- if (tx_ready)
- list_channel(&smux_lch[SMUX_TEST_LCID]);
-
- if ((smux.power_state == SMUX_PWR_OFF_FLUSH) ||
- (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH)) {
+ if (smux.power_state == SMUX_PWR_OFF_FLUSH) {
/* ready to power-down the UART */
+ smux.power_state = SMUX_PWR_OFF;
SMUX_DBG("%s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_OFF);
+
+ /* if data is pending, schedule a new wakeup */
+ if (!list_empty(&smux.lch_tx_ready_list) ||
+ !list_empty(&smux.power_queue))
+ queue_work(smux_tx_wq, &smux_tx_work);
+
+ spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+
+ /* flush UART output queue and power down */
+ smux_flush_tty();
smux_uart_power_off();
- spin_lock_irqsave(&smux.tx_lock_lha2, flags);
- smux.power_state = SMUX_PWR_OFF;
- spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+ } else {
+ spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
}
/* reschedule inactivity worker */
@@ -2051,6 +2255,167 @@
}
/**
+ * Remove RX retry packet from channel and free it.
+ *
+ * Must be called with state_lock_lhb1 locked.
+ *
+ * @ch Channel for retry packet
+ * @retry Retry packet to remove
+ */
+void smux_remove_rx_retry(struct smux_lch_t *ch,
+ struct smux_rx_pkt_retry *retry)
+{
+ list_del(&retry->rx_retry_list);
+ --ch->rx_retry_queue_cnt;
+ smux_free_pkt(retry->pkt);
+ kfree(retry);
+}
+
+/**
+ * RX worker handles all receive operations.
+ *
+ * @work Work structure contained in TBD structure
+ */
+static void smux_rx_worker(struct work_struct *work)
+{
+ unsigned long flags;
+ int used;
+ int initial_rx_state;
+ struct smux_rx_worker_data *w;
+ const unsigned char *data;
+ int len;
+ int flag;
+
+ w = container_of(work, struct smux_rx_worker_data, work);
+ data = w->data;
+ len = w->len;
+ flag = w->flag;
+
+ spin_lock_irqsave(&smux.rx_lock_lha1, flags);
+ smux.rx_activity_flag = 1;
+ spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+
+ SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
+ used = 0;
+ do {
+ SMUX_DBG("%s: state %d; %d of %d\n",
+ __func__, smux.rx_state, used, len);
+ initial_rx_state = smux.rx_state;
+
+ switch (smux.rx_state) {
+ case SMUX_RX_IDLE:
+ smux_rx_handle_idle(data, len, &used, flag);
+ break;
+ case SMUX_RX_MAGIC:
+ smux_rx_handle_magic(data, len, &used, flag);
+ break;
+ case SMUX_RX_HDR:
+ smux_rx_handle_hdr(data, len, &used, flag);
+ break;
+ case SMUX_RX_PAYLOAD:
+ smux_rx_handle_pkt_payload(data, len, &used, flag);
+ break;
+ default:
+ SMUX_DBG("%s: invalid state %d\n",
+ __func__, smux.rx_state);
+ smux.rx_state = SMUX_RX_IDLE;
+ break;
+ }
+ } while (used < len || smux.rx_state != initial_rx_state);
+
+ complete(&w->work_complete);
+}
+
+/**
+ * RX Retry worker handles retrying get_rx_buffer calls that previously failed
+ * because the client was not ready (-EAGAIN).
+ *
+ * @work Work structure contained in smux_lch_t structure
+ */
+static void smux_rx_retry_worker(struct work_struct *work)
+{
+ struct smux_lch_t *ch;
+ struct smux_rx_pkt_retry *retry;
+ union notifier_metadata metadata;
+ int tmp;
+ unsigned long flags;
+
+ ch = container_of(work, struct smux_lch_t, rx_retry_work.work);
+
+ /* get next retry packet */
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ if (ch->local_state != SMUX_LCH_LOCAL_OPENED) {
+ /* port has been closed - remove all retries */
+ while (!list_empty(&ch->rx_retry_queue)) {
+ retry = list_first_entry(&ch->rx_retry_queue,
+ struct smux_rx_pkt_retry,
+ rx_retry_list);
+ smux_remove_rx_retry(ch, retry);
+ }
+ }
+
+ if (list_empty(&ch->rx_retry_queue)) {
+ SMUX_DBG("%s: retry list empty for channel %d\n",
+ __func__, ch->lcid);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+ return;
+ }
+ retry = list_first_entry(&ch->rx_retry_queue,
+ struct smux_rx_pkt_retry,
+ rx_retry_list);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+ SMUX_DBG("%s: retrying rx pkt %p\n", __func__, retry);
+ metadata.read.pkt_priv = 0;
+ metadata.read.buffer = 0;
+ tmp = ch->get_rx_buffer(ch->priv,
+ (void **)&metadata.read.pkt_priv,
+ (void **)&metadata.read.buffer,
+ retry->pkt->hdr.payload_len);
+ if (tmp == 0 && metadata.read.buffer) {
+ /* have valid RX buffer */
+ memcpy(metadata.read.buffer, retry->pkt->payload,
+ retry->pkt->hdr.payload_len);
+ metadata.read.len = retry->pkt->hdr.payload_len;
+
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ smux_remove_rx_retry(ch, retry);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+ schedule_notify(ch->lcid, SMUX_READ_DONE, &metadata);
+ } else if (tmp == -EAGAIN ||
+ (tmp == 0 && !metadata.read.buffer)) {
+ /* retry again */
+ retry->timeout_in_ms <<= 1;
+ if (retry->timeout_in_ms > SMUX_RX_RETRY_MAX_MS) {
+ /* timed out */
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ smux_remove_rx_retry(ch, retry);
+ schedule_notify(ch->lcid, SMUX_READ_FAIL, NULL);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+ }
+ } else {
+ /* client error - drop packet */
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ smux_remove_rx_retry(ch, retry);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+ schedule_notify(ch->lcid, SMUX_READ_FAIL, NULL);
+ }
+
+ /* schedule next retry */
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ if (!list_empty(&ch->rx_retry_queue)) {
+ retry = list_first_entry(&ch->rx_retry_queue,
+ struct smux_rx_pkt_retry,
+ rx_retry_list);
+ queue_delayed_work(smux_rx_wq, &ch->rx_retry_work,
+ msecs_to_jiffies(retry->timeout_in_ms));
+ }
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+}
+
+/**
* Transmit worker handles serializing and transmitting packets onto the
* underlying transport.
*
@@ -2078,27 +2443,17 @@
* inserting after the tail. The locks can then be released
* while the packet is processed.
*/
- for (;;) {
+ while (!smux.in_reset) {
pkt = NULL;
low_wm_notif = 0;
- /* get the next ready channel */
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
- if (list_empty(&smux.lch_tx_ready_list)) {
- /* no ready channels */
- SMUX_DBG("%s: no more ready channels, exiting\n",
- __func__);
- spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
- break;
- }
- smux.tx_activity_flag = 1;
- if (smux.power_state != SMUX_PWR_ON
- && smux.power_state != SMUX_PWR_TURNING_OFF
- && smux.power_state != SMUX_PWR_TURNING_OFF_FLUSH) {
- /* Link isn't ready to transmit */
- if (smux.power_state == SMUX_PWR_OFF) {
- /* link is off, trigger wakeup */
+ /* handle wakeup if needed */
+ if (smux.power_state == SMUX_PWR_OFF) {
+ if (!list_empty(&smux.lch_tx_ready_list) ||
+ !list_empty(&smux.power_queue)) {
+ /* data to transmit, do wakeup */
smux.pwr_wakeup_delay_us = 1;
SMUX_DBG("%s: Power %d->%d\n", __func__,
smux.power_state,
@@ -2109,15 +2464,65 @@
smux_uart_power_on();
queue_work(smux_tx_wq, &smux_wakeup_work);
} else {
- SMUX_DBG("%s: can not tx with power state %d\n",
- __func__,
- smux.power_state);
+ /* no activity -- stay asleep */
spin_unlock_irqrestore(&smux.tx_lock_lha2,
flags);
}
break;
}
+ /* process any pending power packets */
+ if (!list_empty(&smux.power_queue)) {
+ pkt = list_first_entry(&smux.power_queue,
+ struct smux_pkt_t, list);
+ list_del(&pkt->list);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ /* send the packet */
+ SMUX_LOG_PKT_TX(pkt);
+ if (!smux_byte_loopback) {
+ smux_tx_tty(pkt);
+ smux_flush_tty();
+ } else {
+ smux_tx_loopback(pkt);
+ }
+
+ /* Adjust power state if this is a flush command */
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ if (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH &&
+ pkt->hdr.cmd == SMUX_CMD_PWR_CTL &&
+ (pkt->hdr.flags & SMUX_CMD_PWR_CTL_ACK)) {
+ SMUX_DBG("%s: Power %d->%d\n", __func__,
+ smux.power_state,
+ SMUX_PWR_OFF_FLUSH);
+ smux.power_state = SMUX_PWR_OFF_FLUSH;
+ queue_work(smux_tx_wq, &smux_inactivity_work);
+ }
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ smux_free_pkt(pkt);
+ continue;
+ }
+
+ /* get the next ready channel */
+ if (list_empty(&smux.lch_tx_ready_list)) {
+ /* no ready channels */
+ SMUX_DBG("%s: no more ready channels, exiting\n",
+ __func__);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+ break;
+ }
+ smux.tx_activity_flag = 1;
+
+ if (smux.power_state != SMUX_PWR_ON) {
+ /* channel not ready to transmit */
+ SMUX_DBG("%s: can not tx with power state %d\n",
+ __func__,
+ smux.power_state);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+ break;
+ }
+
/* get the next packet to send and rotate channel list */
ch = list_first_entry(&smux.lch_tx_ready_list,
struct smux_lch_t,
@@ -2355,30 +2760,7 @@
/* Purge TX queue */
spin_lock(&ch->tx_lock_lhb2);
- while (!list_empty(&ch->tx_queue)) {
- pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
- list);
- list_del(&pkt->list);
-
- if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
- /* Open was never sent, just force to closed state */
- union notifier_metadata meta_disconnected;
-
- ch->local_state = SMUX_LCH_LOCAL_CLOSED;
- meta_disconnected.disconnected.is_ssr = 0;
- schedule_notify(lcid, SMUX_DISCONNECTED,
- &meta_disconnected);
- } else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
- /* Notify client of failed write */
- union notifier_metadata meta_write;
-
- meta_write.write.pkt_priv = pkt->priv;
- meta_write.write.buffer = pkt->payload;
- meta_write.write.len = pkt->hdr.payload_len;
- schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
- }
- smux_free_pkt(pkt);
- }
+ smux_purge_ch_tx_queue(ch);
spin_unlock(&ch->tx_lock_lhb2);
/* Send Close Command */
@@ -2402,6 +2784,10 @@
pr_err("%s: pkt allocation failed\n", __func__);
ret = -ENOMEM;
}
+
+ /* Purge RX retry queue */
+ if (ch->rx_retry_queue_cnt)
+ queue_delayed_work(smux_rx_wq, &ch->rx_retry_work, 0);
}
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -2700,8 +3086,59 @@
}
/**********************************************************************/
+/* Subsystem Restart */
+/**********************************************************************/
+static struct notifier_block ssr_notifier = {
+ .notifier_call = ssr_notifier_cb,
+};
+
+/**
+ * Handle Subsystem Restart (SSR) notifications.
+ *
+ * @this Pointer to ssr_notifier
+ * @code SSR Code
+ * @data Data pointer (not used)
+ */
+static int ssr_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data)
+{
+ unsigned long flags;
+ int power_off_uart = 0;
+
+ if (code != SUBSYS_AFTER_SHUTDOWN)
+ return NOTIFY_DONE;
+
+ /* Cleanup channels */
+ smux_lch_purge();
+
+ /* Power-down UART */
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ if (smux.power_state != SMUX_PWR_OFF) {
+ SMUX_DBG("%s: SSR - turning off UART\n", __func__);
+ smux.power_state = SMUX_PWR_OFF;
+ power_off_uart = 1;
+ }
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ if (power_off_uart)
+ smux_uart_power_off();
+
+ return NOTIFY_DONE;
+}
+
+/**********************************************************************/
/* Line Discipline Interface */
/**********************************************************************/
+static void smux_pdev_release(struct device *dev)
+{
+ struct platform_device *pdev;
+
+ pdev = container_of(dev, struct platform_device, dev);
+ SMUX_DBG("%s: releasing pdev %p '%s'\n", __func__, pdev, pdev->name);
+ memset(&pdev->dev, 0x0, sizeof(pdev->dev));
+}
+
static int smuxld_open(struct tty_struct *tty)
{
int i;
@@ -2711,66 +3148,94 @@
if (!smux.is_initialized)
return -ENODEV;
- spin_lock_irqsave(&smux.lock_lha0, flags);
+ mutex_lock(&smux.mutex_lha0);
if (smux.ld_open_count) {
pr_err("%s: %p multiple instances not supported\n",
__func__, tty);
- spin_unlock_irqrestore(&smux.lock_lha0, flags);
+ mutex_unlock(&smux.mutex_lha0);
return -EEXIST;
}
- ++smux.ld_open_count;
if (tty->ops->write == NULL) {
- spin_unlock_irqrestore(&smux.lock_lha0, flags);
+ pr_err("%s: tty->ops->write already NULL\n", __func__);
+ mutex_unlock(&smux.mutex_lha0);
return -EINVAL;
}
/* connect to TTY */
+ ++smux.ld_open_count;
+ smux.in_reset = 0;
smux.tty = tty;
tty->disc_data = &smux;
tty->receive_room = TTY_RECEIVE_ROOM;
tty_driver_flush_buffer(tty);
/* power-down the UART if we are idle */
- spin_lock(&smux.tx_lock_lha2);
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_OFF) {
SMUX_DBG("%s: powering off uart\n", __func__);
smux.power_state = SMUX_PWR_OFF_FLUSH;
- spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
queue_work(smux_tx_wq, &smux_inactivity_work);
} else {
- spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
}
- spin_unlock_irqrestore(&smux.lock_lha0, flags);
/* register platform devices */
for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+ SMUX_DBG("%s: register pdev '%s'\n",
+ __func__, smux_devs[i].name);
+ smux_devs[i].dev.release = smux_pdev_release;
tmp = platform_device_register(&smux_devs[i]);
if (tmp)
pr_err("%s: error %d registering device %s\n",
__func__, tmp, smux_devs[i].name);
}
+ mutex_unlock(&smux.mutex_lha0);
return 0;
}
static void smuxld_close(struct tty_struct *tty)
{
unsigned long flags;
+ int power_up_uart = 0;
int i;
- spin_lock_irqsave(&smux.lock_lha0, flags);
+ SMUX_DBG("%s: ldisc unload\n", __func__);
+ mutex_lock(&smux.mutex_lha0);
if (smux.ld_open_count <= 0) {
pr_err("%s: invalid ld count %d\n", __func__,
smux.ld_open_count);
- spin_unlock_irqrestore(&smux.lock_lha0, flags);
+ mutex_unlock(&smux.mutex_lha0);
return;
}
- spin_unlock_irqrestore(&smux.lock_lha0, flags);
-
- for (i = 0; i < ARRAY_SIZE(smux_devs); ++i)
- platform_device_unregister(&smux_devs[i]);
-
+ smux.in_reset = 1;
--smux.ld_open_count;
+
+ /* Cleanup channels */
+ smux_lch_purge();
+
+ /* Unregister platform devices */
+ for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+ SMUX_DBG("%s: unregister pdev '%s'\n",
+ __func__, smux_devs[i].name);
+ platform_device_unregister(&smux_devs[i]);
+ }
+
+ /* Schedule UART power-up if it's down */
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ if (smux.power_state == SMUX_PWR_OFF)
+ power_up_uart = 1;
+ smux.power_state = SMUX_PWR_OFF;
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ if (power_up_uart)
+ smux_uart_power_on();
+
+ /* Disconnect from TTY */
+ smux.tty = NULL;
+ mutex_unlock(&smux.mutex_lha0);
+ SMUX_DBG("%s: ldisc complete\n", __func__);
}
/**
@@ -2879,13 +3344,14 @@
{
int ret;
- spin_lock_init(&smux.lock_lha0);
+ mutex_init(&smux.mutex_lha0);
spin_lock_init(&smux.rx_lock_lha1);
smux.rx_state = SMUX_RX_IDLE;
smux.power_state = SMUX_PWR_OFF;
smux.pwr_wakeup_delay_us = 1;
smux.powerdown_enabled = 0;
+ INIT_LIST_HEAD(&smux.power_queue);
smux.rx_activity_flag = 0;
smux.tx_activity_flag = 0;
smux.recv_len = 0;
@@ -2905,6 +3371,8 @@
return ret;
}
+ subsys_notif_register_notifier("qsc", &ssr_notifier);
+
ret = lch_init();
if (ret != 0) {
pr_err("%s: lch_init failed\n", __func__);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 59104ed..4a65177 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -1220,6 +1220,9 @@
msm_hsl_write(port, CR_PROTECTION_EN, regmap[vid][UARTDM_CR]);
msm_hsl_write(port, UARTDM_CR_TX_EN_BMSK, regmap[vid][UARTDM_CR]);
+ msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
+ msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
+
printk(KERN_INFO "msm_serial_hsl: console setup on port #%d\n",
port->line);
diff --git a/drivers/tty/smux_private.h b/drivers/tty/smux_private.h
index 6bd9713..f644ff0 100644
--- a/drivers/tty/smux_private.h
+++ b/drivers/tty/smux_private.h
@@ -16,6 +16,7 @@
#define SMUX_PRIVATE_H
#define SMUX_MAX_PKT_SIZE 8192
+#define SMUX_BROADCAST_LCID 0xFF
/* SMUX Protocol Characters */
#define SMUX_MAGIC 0x33FC
@@ -29,6 +30,9 @@
#define SMUX_UT_ECHO_ACK_OK 0xF1
#define SMUX_UT_ECHO_ACK_FAIL 0xF2
+/* Maximum number of packets in retry queue */
+#define SMUX_RX_RETRY_MAX_PKTS 32
+
struct tty_struct;
/* Packet header. */
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
index 242c66e..62e9465 100644
--- a/drivers/tty/smux_test.c
+++ b/drivers/tty/smux_test.c
@@ -75,9 +75,44 @@
} \
do {} while (0)
+/**
+ * In-range unit test assertion for test cases.
+ *
+ * @a lval
+ * @minv Minimum value
+ * @maxv Maximum value
+ *
+ * Assertion fails if @a is not on the exclusive range minv, maxv
+ * ((@a < @minv) or (@a > @maxv)). In the failure case, the macro
+ * logs the function and line number where the error occurred along
+ * with the values of @a and @minv, @maxv.
+ *
+ * Assumes that the following local variables exist:
+ * @buf - buffer to write failure message to
+ * @i - number of bytes written to buffer
+ * @max - maximum size of the buffer
+ * @failed - set to true if test fails
+ */
+#define UT_ASSERT_INT_IN_RANGE(a, minv, maxv) \
+ if (((a) < (minv)) || ((a) > (maxv))) { \
+ i += scnprintf(buf + i, max - i, \
+ "%s:%d Fail: " #a "(%d) < " #minv "(%d) or " \
+ #a "(%d) > " #maxv "(%d)\n", \
+ __func__, __LINE__, \
+ a, minv, a, maxv); \
+ failed = 1; \
+ break; \
+ } \
+ do {} while (0)
+
+
static unsigned char test_array[] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55,
89, 144, 233};
+/* when 1, forces failure of get_rx_buffer_mock function */
+static int get_rx_buffer_mock_fail;
+
+
/* Used for mapping local to remote TIOCM signals */
struct tiocm_test_vector {
uint32_t input;
@@ -93,7 +128,7 @@
{
void *rx_buf;
- rx_buf = kmalloc(size, GFP_ATOMIC);
+ rx_buf = kmalloc(size, GFP_KERNEL);
*pkt_priv = (void *)0x1234;
*buffer = rx_buf;
@@ -118,6 +153,13 @@
struct smux_meta_write meta;
};
+/* Mock object metadata for get_rx_buffer failure event */
+struct mock_get_rx_buff_event {
+ struct list_head list;
+ int size;
+ unsigned long jiffies;
+};
+
/* Mock object for all SMUX callback events */
struct smux_mock_callback {
int cb_count;
@@ -140,6 +182,10 @@
int event_read_failed;
struct list_head read_events;
+ /* read retry data */
+ int get_rx_buff_retry_count;
+ struct list_head get_rx_buff_retry_events;
+
/* write event data */
int event_write_done;
int event_write_failed;
@@ -156,6 +202,7 @@
init_completion(&cb->cb_completion);
spin_lock_init(&cb->lock);
INIT_LIST_HEAD(&cb->read_events);
+ INIT_LIST_HEAD(&cb->get_rx_buff_retry_events);
INIT_LIST_HEAD(&cb->write_events);
}
@@ -191,6 +238,16 @@
kfree(meta);
}
+ cb->get_rx_buff_retry_count = 0;
+ while (!list_empty(&cb->get_rx_buff_retry_events)) {
+ struct mock_get_rx_buff_event *meta;
+ meta = list_first_entry(&cb->get_rx_buff_retry_events,
+ struct mock_get_rx_buff_event,
+ list);
+ list_del(&meta->list);
+ kfree(meta);
+ }
+
cb->event_write_done = 0;
cb->event_write_failed = 0;
while (!list_empty(&cb->write_events)) {
@@ -229,6 +286,8 @@
"\tevent_read_done=%d\n"
"\tevent_read_failed=%d\n"
"\tread_events=%d\n"
+ "\tget_rx_retry=%d\n"
+ "\tget_rx_retry_events=%d\n"
"\tevent_write_done=%d\n"
"\tevent_write_failed=%d\n"
"\twrite_events=%d\n",
@@ -243,6 +302,8 @@
cb->event_read_done,
cb->event_read_failed,
!list_empty(&cb->read_events),
+ cb->get_rx_buff_retry_count,
+ !list_empty(&cb->get_rx_buff_retry_events),
cb->event_write_done,
cb->event_write_failed,
list_empty(&cb->write_events)
@@ -268,83 +329,105 @@
return;
}
- spin_lock_irqsave(&cb_data_ptr->lock, flags);
switch (event) {
case SMUX_CONNECTED:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->event_connected;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_DISCONNECTED:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->event_disconnected;
cb_data_ptr->event_disconnected_ssr =
((struct smux_meta_disconnected *)metadata)->is_ssr;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_READ_DONE:
- ++cb_data_ptr->event_read_done;
read_event_meta = kmalloc(sizeof(struct mock_read_event),
- GFP_ATOMIC);
+ GFP_KERNEL);
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
+ ++cb_data_ptr->event_read_done;
if (read_event_meta) {
read_event_meta->meta =
*(struct smux_meta_read *)metadata;
list_add_tail(&read_event_meta->list,
&cb_data_ptr->read_events);
}
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_READ_FAIL:
- ++cb_data_ptr->event_read_failed;
read_event_meta = kmalloc(sizeof(struct mock_read_event),
- GFP_ATOMIC);
+ GFP_KERNEL);
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
+ ++cb_data_ptr->event_read_failed;
if (read_event_meta) {
- read_event_meta->meta =
+ if (metadata)
+ read_event_meta->meta =
*(struct smux_meta_read *)metadata;
+ else
+ memset(&read_event_meta->meta, 0x0,
+ sizeof(struct smux_meta_read));
list_add_tail(&read_event_meta->list,
&cb_data_ptr->read_events);
}
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_WRITE_DONE:
- ++cb_data_ptr->event_write_done;
write_event_meta = kmalloc(sizeof(struct mock_write_event),
- GFP_ATOMIC);
+ GFP_KERNEL);
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
+ ++cb_data_ptr->event_write_done;
if (write_event_meta) {
write_event_meta->meta =
*(struct smux_meta_write *)metadata;
list_add_tail(&write_event_meta->list,
&cb_data_ptr->write_events);
}
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_WRITE_FAIL:
- ++cb_data_ptr->event_write_failed;
write_event_meta = kmalloc(sizeof(struct mock_write_event),
- GFP_ATOMIC);
+ GFP_KERNEL);
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
+ ++cb_data_ptr->event_write_failed;
if (write_event_meta) {
write_event_meta->meta =
*(struct smux_meta_write *)metadata;
list_add_tail(&write_event_meta->list,
&cb_data_ptr->write_events);
}
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_LOW_WM_HIT:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->event_low_wm;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_HIGH_WM_HIT:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->event_high_wm;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_TIOCM_UPDATE:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->event_tiocm;
cb_data_ptr->tiocm_meta = *(struct smux_meta_tiocm *)metadata;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
default:
pr_err("%s: unknown event %d\n", __func__, event);
};
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->cb_count;
complete(&cb_data_ptr->cb_completion);
spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
@@ -1153,6 +1236,338 @@
return i;
}
+/**
+ * Allocates a new buffer or returns a failure based upon the
+ * global @get_rx_buffer_mock_fail.
+ */
+static int get_rx_buffer_mock(void *priv, void **pkt_priv,
+ void **buffer, int size)
+{
+ void *rx_buf;
+ unsigned long flags;
+ struct smux_mock_callback *cb_ptr;
+
+ cb_ptr = (struct smux_mock_callback *)priv;
+ if (!cb_ptr) {
+ pr_err("%s: no callback data\n", __func__);
+ return -ENXIO;
+ }
+
+ if (get_rx_buffer_mock_fail) {
+ /* force failure and log failure event */
+ struct mock_get_rx_buff_event *meta;
+ meta = kmalloc(sizeof(struct mock_get_rx_buff_event),
+ GFP_KERNEL);
+ if (!meta) {
+ pr_err("%s: unable to allocate metadata\n", __func__);
+ return -ENOMEM;
+ }
+ INIT_LIST_HEAD(&meta->list);
+ meta->size = size;
+ meta->jiffies = jiffies;
+
+ spin_lock_irqsave(&cb_ptr->lock, flags);
+ ++cb_ptr->get_rx_buff_retry_count;
+ list_add_tail(&meta->list, &cb_ptr->get_rx_buff_retry_events);
+ ++cb_ptr->cb_count;
+ complete(&cb_ptr->cb_completion);
+ spin_unlock_irqrestore(&cb_ptr->lock, flags);
+ return -EAGAIN;
+ } else {
+ rx_buf = kmalloc(size, GFP_KERNEL);
+ *pkt_priv = (void *)0x1234;
+ *buffer = rx_buf;
+ return 0;
+ }
+ return 0;
+}
+
+/**
+ * Verify get_rx_buffer callback retry.
+ *
+ * @buf Buffer for status message
+ * @max Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_local_get_rx_buff_retry(char *buf, int max)
+{
+ static struct smux_mock_callback cb_data;
+ static int cb_initialized;
+ int i = 0;
+ int failed = 0;
+ char try_two[] = "try 2";
+ int ret;
+ unsigned long start_j;
+ struct mock_get_rx_buff_event *event;
+ struct mock_read_event *read_event;
+ int try;
+
+ i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+ pr_err("%s", buf);
+
+ if (!cb_initialized)
+ mock_cb_data_init(&cb_data);
+
+ mock_cb_data_reset(&cb_data);
+ smux_byte_loopback = SMUX_TEST_LCID;
+ while (!failed) {
+ /* open port for loopback */
+ ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+ SMUX_CH_OPTION_LOCAL_LOOPBACK,
+ 0);
+ UT_ASSERT_INT(ret, ==, 0);
+
+ ret = msm_smux_open(SMUX_TEST_LCID, &cb_data,
+ smux_mock_cb, get_rx_buffer_mock);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ), >, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+ mock_cb_data_reset(&cb_data);
+
+ /*
+ * Force get_rx_buffer failure for a single RX packet
+ *
+ * The get_rx_buffer calls should follow an exponential
+ * back-off with a maximum timeout of 1024 ms after which we
+ * will get a failure notification.
+ *
+ * Try Post Delay (ms)
+ * 0 -
+ * 1 1
+ * 2 2
+ * 3 4
+ * 4 8
+ * 5 16
+ * 6 32
+ * 7 64
+ * 8 128
+ * 9 256
+ * 10 512
+ * 11 1024
+ * 12 Fail
+ *
+ * All times are limited by the precision of the timer
+ * framework, so ranges are used in the test
+ * verification.
+ */
+ get_rx_buffer_mock_fail = 1;
+ start_j = jiffies;
+ ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+ test_array, sizeof(test_array));
+ UT_ASSERT_INT(ret, ==, 0);
+ ret = msm_smux_write(SMUX_TEST_LCID, (void *)2,
+ try_two, sizeof(try_two));
+ UT_ASSERT_INT(ret, ==, 0);
+
+ /* wait for RX failure event */
+ while (cb_data.event_read_failed == 0) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, 2*HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ if (failed)
+ break;
+
+ /* verify retry attempts */
+ UT_ASSERT_INT(cb_data.get_rx_buff_retry_count, ==, 12);
+ event = list_first_entry(&cb_data.get_rx_buff_retry_events,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 0, 0 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 1, 1 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 2, 2 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 4, 4 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 8, 8 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 16, 16 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 32 - 20, 32 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 64 - 20, 64 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 128 - 20, 128 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 256 - 20, 256 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 512 - 20, 512 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 1024 - 20, 1024 + 20);
+ mock_cb_data_reset(&cb_data);
+
+ /* verify 2nd pending RX packet goes through */
+ get_rx_buffer_mock_fail = 0;
+ INIT_COMPLETION(cb_data.cb_completion);
+ if (cb_data.event_read_done == 0)
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+ UT_ASSERT_INT(list_empty(&cb_data.read_events), ==, 0);
+ read_event = list_first_entry(&cb_data.read_events,
+ struct mock_read_event, list);
+ UT_ASSERT_PTR(read_event->meta.pkt_priv, ==, (void *)0x1234);
+ UT_ASSERT_PTR(read_event->meta.buffer, !=, NULL);
+ UT_ASSERT_INT(0, ==, memcmp(read_event->meta.buffer, try_two,
+ sizeof(try_two)));
+ mock_cb_data_reset(&cb_data);
+
+ /* Test maximum retry queue size */
+ get_rx_buffer_mock_fail = 1;
+ for (try = 0; try < (SMUX_RX_RETRY_MAX_PKTS + 1); ++try) {
+ mock_cb_data_reset(&cb_data);
+ ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+ test_array, sizeof(test_array));
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ }
+
+ /* should have 32 successful rx packets and 1 failed */
+ while (cb_data.event_read_failed == 0) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, 2*HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ if (failed)
+ break;
+
+ get_rx_buffer_mock_fail = 0;
+ while (cb_data.event_read_done < SMUX_RX_RETRY_MAX_PKTS) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, 2*HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ if (failed)
+ break;
+
+ UT_ASSERT_INT(1, ==, cb_data.event_read_failed);
+ UT_ASSERT_INT(SMUX_RX_RETRY_MAX_PKTS, ==,
+ cb_data.event_read_done);
+ mock_cb_data_reset(&cb_data);
+
+ /* close port */
+ ret = msm_smux_close(SMUX_TEST_LCID);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+ UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ break;
+ }
+
+ if (!failed) {
+ i += scnprintf(buf + i, max - i, "\tOK\n");
+ } else {
+ pr_err("%s: Failed\n", __func__);
+ i += scnprintf(buf + i, max - i, "\tFailed\n");
+ i += mock_cb_data_print(&cb_data, buf + i, max - i);
+ msm_smux_close(SMUX_TEST_LCID);
+ }
+ smux_byte_loopback = 0;
+ mock_cb_data_reset(&cb_data);
+ return i;
+}
+
static char debug_buffer[DEBUG_BUFMAX];
static ssize_t debug_read(struct file *file, char __user *buf,
@@ -1214,6 +1629,8 @@
debug_create("ut_local_wm", 0444, dent, smux_ut_local_wm);
debug_create("ut_local_smuxld_receive_buf", 0444, dent,
smux_ut_local_smuxld_receive_buf);
+ debug_create("ut_local_get_rx_buff_retry", 0444, dent,
+ smux_ut_local_get_rx_buff_retry);
return 0;
}
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 6bd0577..5ed16cc 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -690,6 +690,13 @@
skip_phy_resume:
+ if (!(readl_relaxed(USB_USBCMD) & CMD_RUN) &&
+ (readl_relaxed(USB_PORTSC) & PORT_SUSPEND)) {
+ writel_relaxed(readl_relaxed(USB_USBCMD) | CMD_RUN ,
+ USB_USBCMD);
+ dbg_log_event(NULL, "Set RS", readl_relaxed(USB_USBCMD));
+ }
+
usb_hcd_resume_root_hub(hcd);
atomic_set(&mehci->in_lpm, 0);
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index bf8e5f4..6ee3204 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -479,7 +479,7 @@
result = usb_autopm_get_interface(dev->intf);
if (result < 0) {
dev_err(&dev->udev->dev, "%s: resume failure\n", __func__);
- goto error;
+ goto pm_error;
}
txurb = usb_alloc_urb(0, GFP_KERNEL);
@@ -536,7 +536,7 @@
error:
dev->txurb_drp_cnt++;
usb_autopm_put_interface(dev->intf);
-
+pm_error:
return result;
}
EXPORT_SYMBOL(data_bridge_write);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 59f01f6..61fbac0 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -838,10 +838,14 @@
clk_disable_unprepare(motg->core_clk);
/* usb phy no more require TCXO clock, hence vote for TCXO disable */
- ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
- if (ret)
- dev_err(phy->dev, "%s failed to devote for "
- "TCXO D0 buffer%d\n", __func__, ret);
+ if (!host_bus_suspend) {
+ ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
+ if (ret)
+ dev_err(phy->dev, "%s failed to devote for "
+ "TCXO D0 buffer%d\n", __func__, ret);
+ else
+ motg->lpm_flags |= XO_SHUTDOWN;
+ }
if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
!host_bus_suspend && !dcp) {
@@ -886,10 +890,13 @@
wake_lock(&motg->wlock);
/* Vote for TCXO when waking up the phy */
- ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
- if (ret)
- dev_err(phy->dev, "%s failed to vote for "
- "TCXO D0 buffer%d\n", __func__, ret);
+ if (motg->lpm_flags & XO_SHUTDOWN) {
+ ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
+ if (ret)
+ dev_err(phy->dev, "%s failed to vote for "
+ "TCXO D0 buffer%d\n", __func__, ret);
+ motg->lpm_flags &= ~XO_SHUTDOWN;
+ }
clk_prepare_enable(motg->core_clk);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 7fd2d91..ca5d2c6 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -93,7 +93,7 @@
static struct delayed_work mdp_pipe_ctrl_worker;
static boolean mdp_suspended = FALSE;
-static DEFINE_MUTEX(mdp_suspend_mutex);
+DEFINE_MUTEX(mdp_suspend_mutex);
#ifdef CONFIG_FB_MSM_MDP40
struct mdp_dma_data dma2_data;
@@ -1887,7 +1887,7 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
if (mdp_rev >= MDP_REV_41 && mfd->panel.type == MIPI_CMD_PANEL)
- mdp_dsi_cmd_overlay_suspend();
+ mdp_dsi_cmd_overlay_suspend(mfd);
return ret;
}
@@ -1897,7 +1897,6 @@
#ifdef CONFIG_FB_MSM_MDP40
struct msm_fb_data_type *mfd;
- mdp4_overlay_ctrl_db_reset();
mfd = platform_get_drvdata(pdev);
@@ -2575,17 +2574,6 @@
return rc;
}
-unsigned int mdp_check_suspended(void)
-{
- unsigned int ret;
-
- mutex_lock(&mdp_suspend_mutex);
- ret = mdp_suspended;
- mutex_unlock(&mdp_suspend_mutex);
-
- return ret;
-}
-
void mdp_footswitch_ctrl(boolean on)
{
mutex_lock(&mdp_suspend_mutex);
@@ -2652,7 +2640,6 @@
#ifdef CONFIG_FB_MSM_DTV
mdp4_dtv_set_black_screen();
#endif
- mdp4_iommu_detach();
mdp_footswitch_ctrl(FALSE);
}
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index b104b33..511edb6 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -801,7 +801,6 @@
void mdp_histogram_handle_isr(struct mdp_hist_mgmt *mgmt);
void __mdp_histogram_kickoff(struct mdp_hist_mgmt *mgmt);
void __mdp_histogram_reset(struct mdp_hist_mgmt *mgmt);
-unsigned int mdp_check_suspended(void);
void mdp_footswitch_ctrl(boolean on);
#ifdef CONFIG_FB_MSM_MDP303
@@ -825,14 +824,10 @@
#endif
#ifndef CONFIG_FB_MSM_MDP40
-static inline void mdp_dsi_cmd_overlay_suspend(void)
+static inline void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
{
/* empty */
}
-static inline void mdp4_iommu_detach(void)
-{
- /* empty */
-}
#endif
int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index a7161fe..16fede10 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -173,6 +173,7 @@
MDP4_MIXER_STAGE0, /* zorder 0 */
MDP4_MIXER_STAGE1, /* zorder 1 */
MDP4_MIXER_STAGE2, /* zorder 2 */
+ MDP4_MIXER_STAGE3, /* zorder 3 */
MDP4_MIXER_STAGE_MAX
};
@@ -256,6 +257,19 @@
u8 mark_unmap;
};
+struct blend_cfg {
+ u32 op;
+ u32 bg_alpha;
+ u32 fg_alpha;
+ u32 co3_sel;
+ u32 transp_low0;
+ u32 transp_low1;
+ u32 transp_high0;
+ u32 transp_high1;
+ int solidfill;
+ struct mdp4_overlay_pipe *solidfill_pipe;
+};
+
struct mdp4_overlay_pipe {
uint32 pipe_used;
uint32 pipe_type; /* rgb, video/graphic */
@@ -403,6 +417,7 @@
void mdp4_intr_clear_set(ulong clear, ulong set);
void mdp4_dma_p_cfg(void);
unsigned is_mdp4_hw_reset(void);
+void mdp4_overlay_cfg_init(void);
void mdp4_hw_init(void);
void mdp4_isr_read(int);
void mdp4_clear_lcdc(void);
@@ -417,6 +432,7 @@
uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe);
uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe);
uint32 mdp4_overlay_op_mode(struct mdp4_overlay_pipe *pipe);
+void mdp4_lcdc_base_swap(struct mdp4_overlay_pipe *pipe);
void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd);
#ifdef CONFIG_FB_MSM_DTV
void mdp4_overlay_dtv_start(void);
@@ -489,6 +505,7 @@
struct mdp4_overlay_pipe *pipe);
int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
+void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe);
void mdp4_dtv_overlay(struct msm_fb_data_type *mfd);
int mdp4_dtv_on(struct platform_device *pdev);
int mdp4_dtv_off(struct platform_device *pdev);
@@ -506,7 +523,7 @@
int mdp4_overlay_dsi_state_get(void);
void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all);
-void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe);
+void mdp4_mixer_blend_setup(int mixer);
struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage);
void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe);
void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe);
@@ -519,6 +536,7 @@
int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req);
int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req);
int mdp4_overlay_unset(struct fb_info *info, int ndx);
+int mdp4_overlay_unset_mixer(int mixer);
int mdp4_overlay_play_wait(struct fb_info *info,
struct msmfb_overlay_data *req);
int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req);
@@ -533,7 +551,7 @@
void mdp4_overlay0_done_lcdc(struct mdp_dma_data *dma);
void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma);
void mdp4_dma_s_done_mddi(void);
-void mdp4_dma_p_done_mddi(void);
+void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma);
void mdp4_dma_p_done_dsi(struct mdp_dma_data *dma);
void mdp4_dma_p_done_dsi_video(struct mdp_dma_data *dma);
void mdp4_dma_p_done_lcdc(void);
@@ -557,10 +575,32 @@
{
/* empty */
}
+static inline void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd)
+{
+ /* empty */
+}
static inline void mdp4_mddi_overlay_restore(void)
{
/* empty */
}
+static inline void mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd)
+{
+ /*empty*/
+}
+static inline void mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+{
+ /*empty*/
+}
+static inline void mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req)
+{
+ /* empty */
+}
+static inline void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req)
+{
+ /* empty*/
+}
#endif
void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
@@ -590,6 +630,7 @@
struct msmfb_overlay_blt *req);
int mdp4_dsi_video_overlay_blt_offset(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req);
+void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe);
#ifdef CONFIG_FB_MSM_MDP40
static inline void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
@@ -598,6 +639,13 @@
}
#endif
#else
+int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req);
+void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req);
+int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd);
+int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd);
+void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd);
static inline int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd)
{
return -ENODEV;
@@ -630,6 +678,10 @@
{
return -ENODEV;
}
+static inline void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ /* empty */
+}
#endif
void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd,
@@ -640,9 +692,6 @@
void mdp4_lcdc_overlay_blt_stop(struct msm_fb_data_type *mfd);
void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd);
void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd);
-
-int mdp4_mddi_overlay_blt_offset(int *off);
-void mdp4_mddi_overlay_blt(ulong addr);
void mdp4_overlay_panel_mode(int mixer_num, uint32 mode);
void mdp4_overlay_panel_mode_unset(int mixer_num, uint32 mode);
int mdp4_overlay_mixer_play(int mixer_num);
@@ -664,7 +713,7 @@
void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
void mdp4_dsi_cmd_overlay_restore(void);
-void mdp_dsi_cmd_overlay_suspend(void);
+void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd);
#else
static inline void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
{
@@ -688,7 +737,7 @@
/* empty */
}
#ifdef CONFIG_FB_MSM_MDP40
-static inline void mdp_dsi_cmd_overlay_suspend(void)
+static inline void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
{
/* empty */
}
@@ -701,6 +750,7 @@
struct mdp4_overlay_pipe *pipe);
void mdp4_dsi_cmd_overlay_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
+void mdp4_dsi_cmd_base_swap(struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_panel_3d(int mixer_num, uint32 panel_3d);
int mdp4_overlay_3d_sbys(struct fb_info *info, struct msmfb_overlay_3d *req);
@@ -721,7 +771,7 @@
void mdp4_overlay_dsi_video_wait4vsync(struct msm_fb_data_type *mfd);
void mdp4_primary_vsync_dsi_video(void);
uint32_t mdp4_ss_table_value(int8_t param, int8_t index);
-void mdp4_overlay_ctrl_db_reset(void);
+void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe);
int mdp4_overlay_writeback_on(struct platform_device *pdev);
int mdp4_overlay_writeback_off(struct platform_device *pdev);
@@ -759,7 +809,6 @@
int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg);
void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe);
void mdp4_iommu_attach(void);
-void mdp4_iommu_detach(void);
int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req,
struct mdp4_overlay_pipe **ppipe);
void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 6d4e44b..2a15506 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -46,8 +46,12 @@
struct mdp4_overlay_ctrl {
struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX];
struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
+ struct mdp4_overlay_pipe *baselayer[MDP4_MIXER_MAX];
+ struct blend_cfg blend[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
uint32 mixer_cfg[MDP4_MIXER_MAX];
+ uint32 flush[MDP4_MIXER_MAX];
uint32 cs_controller;
+ uint32 hw_version;
uint32 panel_3d;
uint32 panel_mode;
uint32 mixer0_played;
@@ -198,14 +202,6 @@
}
}
-void mdp4_overlay_ctrl_db_reset(void)
-{
- int i;
-
- for (i = MDP4_MIXER0; i < MDP4_MIXER_MAX; i++)
- ctrl->mixer_cfg[i] = 0;
-}
-
int mdp4_overlay_mixer_play(int mixer_num)
{
if (mixer_num == MDP4_MIXER2)
@@ -236,6 +232,20 @@
return ctrl->panel_mode;
}
+void mdp4_overlay_cfg_init(void)
+{
+ if (ctrl->hw_version == 0) {
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ ctrl->hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ }
+
+ if (ctrl->hw_version >= 0x0402030b) {
+ /* MDP_LAYERMIXER_IN_CFG_UPDATE_METHOD */
+ outpdw(MDP_BASE + 0x100fc, 0x01);
+ }
+}
+
void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv)
{
uint32 dmae_cfg_reg;
@@ -847,6 +857,8 @@
case MDP_YCRCB_H1V1:
case MDP_YCBCR_H1V1:
return OVERLAY_TYPE_VIDEO;
+ case MDP_RGB_BORDERFILL:
+ return OVERLAY_TYPE_BF;
default:
mdp4_stat.err_format++;
return -ERANGE;
@@ -1120,6 +1132,9 @@
pipe->element2 = C2_R_Cr; /* R */
}
pipe->bpp = 3; /* 3 bpp */
+ case MDP_RGB_BORDERFILL:
+ pipe->alpha_enable = 0;
+ pipe->alpha = 0;
break;
default:
/* not likely */
@@ -1441,13 +1456,13 @@
return -ENODEV;
cnt = 0;
- ndx = 1; /* ndx 0 if not used */
-
+ ndx = MDP4_MIXER_STAGE_BASE;
for ( ; ndx < MDP4_MIXER_STAGE_MAX; ndx++) {
pipe = ctrl->stage[mixer_num][ndx];
if (pipe == NULL)
continue;
info->z_order = pipe->mixer_stage - MDP4_MIXER_STAGE0;
+ /* z_order == -1, means base layer */
info->ptype = pipe->pipe_type;
info->pnum = pipe->pipe_num;
info->pndx = pipe->pipe_ndx;
@@ -1458,331 +1473,458 @@
return cnt;
}
-static void mdp4_overlay_bg_solidfill_clear(uint32 mixer_num)
-{
- struct mdp4_overlay_pipe *bg_pipe;
- unsigned char *rgb_base;
- uint32 rgb_src_format;
- int pnum;
-
- bg_pipe = mdp4_overlay_stage_pipe(mixer_num,
- MDP4_MIXER_STAGE_BASE);
- if (bg_pipe && bg_pipe->pipe_type == OVERLAY_TYPE_BF) {
- bg_pipe = mdp4_overlay_stage_pipe(mixer_num,
- MDP4_MIXER_STAGE0);
- }
-
- if (bg_pipe && bg_pipe->pipe_type == OVERLAY_TYPE_RGB) {
- rgb_src_format = mdp4_overlay_format(bg_pipe);
- if (!(rgb_src_format & MDP4_FORMAT_SOLID_FILL)) {
- pnum = bg_pipe->pipe_num - OVERLAY_PIPE_RGB1;
- rgb_base = MDP_BASE + MDP4_RGB_BASE;
- rgb_base += MDP4_RGB_OFF * pnum;
- outpdw(rgb_base + 0x50, rgb_src_format);
- outpdw(rgb_base + 0x0058, bg_pipe->op_mode);
- mdp4_overlay_reg_flush(bg_pipe, 0);
- }
- }
-}
-
-void mdp4_mixer_pipe_cleanup(int mixer)
-{
- struct mdp4_overlay_pipe *pipe;
- int j;
-
- for (j = MDP4_MIXER_STAGE_MAX - 1; j > MDP4_MIXER_STAGE_BASE; j--) {
- pipe = ctrl->stage[mixer][j];
- if (pipe == NULL)
- continue;
- pr_debug("%s(): pipe %u\n", __func__, pipe->pipe_ndx);
- mdp4_mixer_stage_down(pipe);
- mdp4_overlay_pipe_free(pipe);
- }
-}
-
static void mdp4_mixer_stage_commit(int mixer)
{
struct mdp4_overlay_pipe *pipe;
- int i, j, off;
- u32 data = 0, stage, flush_bits = 0, pipe_cnt = 0, pull_mode = 0;
- u32 cfg[MDP4_MIXER_MAX];
+ int i, num;
+ u32 data, stage;
+ int off;
+ unsigned long flags;
- if (mixer == MDP4_MIXER0)
- flush_bits |= 0x1;
- else if (mixer == MDP4_MIXER1)
- flush_bits |= 0x2;
+ data = 0;
+ for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+ pipe = ctrl->stage[mixer][i];
+ if (pipe == NULL)
+ continue;
+ pr_debug("%s: mixer=%d ndx=%d stage=%d\n", __func__,
+ mixer, pipe->pipe_ndx, i);
+ stage = pipe->mixer_stage;
+ if (mixer >= MDP4_MIXER1)
+ stage += 8;
+ stage <<= (4 * pipe->pipe_num);
+ data |= stage;
+ }
- for (i = MDP4_MIXER0; i < MDP4_MIXER_MAX; i++) {
- cfg[i] = 0;
- for (j = MDP4_MIXER_STAGE_BASE; j < MDP4_MIXER_STAGE_MAX; j++) {
- pipe = ctrl->stage[i][j];
- if (pipe == NULL)
- break;
- stage = pipe->mixer_stage;
- if (i >= MDP4_MIXER1)
- stage += 8;
- stage <<= (4 * pipe->pipe_num);
- cfg[i] |= stage;
- pipe_cnt++;
+ mdp4_mixer_blend_setup(mixer);
- mdp4_mixer_blend_setup(pipe);
+ off = 0;
+ if (data != ctrl->mixer_cfg[mixer]) {
+ ctrl->mixer_cfg[mixer] = data;
+ if (mixer >= MDP4_MIXER2) {
+ /* MDP_LAYERMIXER2_IN_CFG */
+ off = 0x100f0;
+ } else {
+ /* mixer 0 or 1 */
+ num = mixer + 1;
+ num &= 0x01;
+ data |= ctrl->mixer_cfg[num];
+ off = 0x10100;
}
+ pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
+ mixer, data, ctrl->flush[mixer]);
}
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- if (ctrl->mixer_cfg[mixer] != cfg[mixer]) {
- if ((ctrl->mixer_cfg[MDP4_MIXER0] != cfg[MDP4_MIXER0]) ||
- (ctrl->mixer_cfg[MDP4_MIXER1] != cfg[MDP4_MIXER1])) {
- off = 0x10100;
- if (ctrl->mixer_cfg[MDP4_MIXER0] != cfg[MDP4_MIXER0]) {
- flush_bits |= 0x1;
- ctrl->mixer_cfg[MDP4_MIXER0] = cfg[MDP4_MIXER0];
+ local_irq_save(flags);
+ if (off)
+ outpdw(MDP_BASE + off, data);
- if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
- (ctrl->panel_mode & MDP4_PANEL_LCDC))
- pull_mode = 1;
- }
- if (ctrl->mixer_cfg[MDP4_MIXER1] != cfg[MDP4_MIXER1]) {
- flush_bits |= 0x2;
- ctrl->mixer_cfg[MDP4_MIXER1] = cfg[MDP4_MIXER1];
-
- pull_mode = 1;
- }
-
- data = cfg[MDP4_MIXER0] | cfg[MDP4_MIXER1];
-
- pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
- mixer, data, flush_bits);
-
- outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
- if (pull_mode) {
- outpdw(MDP_BASE + 0x18000, flush_bits);
- /* wait for vsync on both pull mode interfaces */
- msleep(20);
- }
- }
-
- if (ctrl->mixer_cfg[MDP4_MIXER2] != cfg[MDP4_MIXER2]) {
- off = 0x100F0;
- ctrl->mixer_cfg[MDP4_MIXER2] = cfg[MDP4_MIXER2];
- data = cfg[MDP4_MIXER2];
-
- pr_debug("%s: mixer=%d data=%x\n", __func__,
- mixer, data);
-
- outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
- }
- } else {
- if (mixer == MDP4_MIXER0) {
- if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
- (ctrl->panel_mode & MDP4_PANEL_LCDC))
- pull_mode = 1;
- } else if (mixer == MDP4_MIXER1) {
- pull_mode = 1;
- }
-
- if (pull_mode)
- outpdw(MDP_BASE + 0x18000, flush_bits);
+ if (ctrl->flush[mixer]) {
+ outpdw(MDP_BASE + 0x18000, ctrl->flush[mixer]);
+ ctrl->flush[mixer] = 0;
}
+ local_irq_restore(flags);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
- if (data && pipe_cnt == 1)
- mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
}
+
void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
{
- struct mdp4_overlay_pipe *spipe;
- int mixer;
+ struct mdp4_overlay_pipe *pp;
+ int i, mixer;
mixer = pipe->mixer_num;
- spipe = ctrl->stage[mixer][pipe->mixer_stage];
- if ((spipe != NULL) && (spipe->pipe_num != pipe->pipe_num)) {
- mdp4_stat.err_stage++;
- return;
+ for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+ pp = ctrl->stage[mixer][i];
+ if (pp == pipe) {
+ ctrl->stage[mixer][i] = NULL;
+ break;
+ }
}
ctrl->stage[mixer][pipe->mixer_stage] = pipe; /* keep it */
- if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
+ if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) {
+ pr_debug("%s: mixer=%d ndx=%d stage=%d flags=%x\n",
+ __func__, mixer, pipe->pipe_ndx,
+ pipe->mixer_stage, pipe->flags);
mdp4_mixer_stage_commit(mixer);
+ }
}
void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe)
{
- struct mdp4_overlay_pipe *spipe;
+ struct mdp4_overlay_pipe *pp;
+ int i, mixer;
- spipe = ctrl->stage[pipe->mixer_num][pipe->mixer_stage];
- if (spipe == NULL) /* not running */
+ mixer = pipe->mixer_num;
+
+ for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+ pp = ctrl->stage[mixer][i];
+ if (pp == pipe)
+ ctrl->stage[mixer][i] = NULL; /* clear it */
+ }
+
+ if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) {
+ pr_debug("%s: mixer=%d ndx=%d stage=%d flags=%x\n",
+ __func__, pipe->mixer_num, pipe->pipe_ndx,
+ pipe->mixer_stage, pipe->flags);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
+ }
+}
+/*
+ * mixer0: rgb3: border color at register 0x15004, 0x15008
+ * mixer1: vg3: border color at register 0x1D004, 0x1D008
+ * mixer2: xxx: border color at register 0x8D004, 0x8D008
+ */
+void mdp4_overlay_borderfill_stage_up(struct mdp4_overlay_pipe *pipe)
+{
+ struct mdp4_overlay_pipe *bspipe;
+ int ptype, pnum, pndx, mixer;
+ int format, alpha_enable, alpha;
+
+ if (pipe->pipe_type != OVERLAY_TYPE_BF)
return;
- ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL; /* clear it */
+ mixer = pipe->mixer_num;
- mdp4_mixer_stage_commit(pipe->mixer_num);
+ if (ctrl->baselayer[mixer])
+ return;
+
+ bspipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+
+ /* save original base layer */
+ ctrl->baselayer[mixer] = bspipe;
+
+ pipe->alpha = 0; /* make sure bf pipe has alpha 0 */
+ ptype = pipe->pipe_type;
+ pnum = pipe->pipe_num;
+ pndx = pipe->pipe_ndx;
+ format = pipe->src_format;
+ alpha_enable = pipe->alpha_enable;
+ alpha = pipe->alpha;
+ *pipe = *bspipe; /* keep base layer configuration */
+ pipe->pipe_type = ptype;
+ pipe->pipe_num = pnum;
+ pipe->pipe_ndx = pndx;
+ pipe->src_format = format;
+ pipe->alpha_enable = alpha_enable;
+ pipe->alpha = alpha;
+
+ /* free original base layer pipe to be sued as normal pipe */
+ bspipe->pipe_used = 0;
+
+ if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
+ mdp4_dsi_video_base_swap(pipe);
+ else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
+ mdp4_lcdc_base_swap(pipe);
+ else if (ctrl->panel_mode & MDP4_PANEL_DTV)
+ mdp4_dtv_base_swap(pipe);
+
+ mdp4_overlay_reg_flush(bspipe, 1);
+ /* borderfill pipe as base layer */
+ mdp4_mixer_stage_up(pipe);
}
-void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe)
+void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe)
{
- struct mdp4_overlay_pipe *bg_pipe;
- unsigned char *overlay_base, *rgb_base;
- uint32 c0, c1, c2, blend_op, constant_color = 0, rgb_src_format;
- uint32 fg_color3_out, fg_alpha = 0, bg_alpha = 0;
- int off, pnum;
+ struct mdp4_overlay_pipe *bspipe;
+ int ptype, pnum, pndx, mixer;
+ int format, alpha_enable, alpha;
- if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE)
+ if (pipe->pipe_type != OVERLAY_TYPE_BF)
return;
+ mixer = pipe->mixer_num;
+
+ /* retrieve original base layer */
+ bspipe = ctrl->baselayer[mixer];
+ if (bspipe == NULL) {
+ pr_err("%s: no base layer at mixer=%d\n",
+ __func__, mixer);
+ return;
+ }
+
+ ptype = bspipe->pipe_type;
+ pnum = bspipe->pipe_num;
+ pndx = bspipe->pipe_ndx;
+ format = bspipe->src_format;
+ alpha_enable = bspipe->alpha_enable;
+ alpha = bspipe->alpha;
+ *bspipe = *pipe; /* restore base layer configuration */
+ bspipe->pipe_type = ptype;
+ bspipe->pipe_num = pnum;
+ bspipe->pipe_ndx = pndx;
+ bspipe->src_format = format;
+ bspipe->alpha_enable = alpha_enable;
+ bspipe->alpha = alpha;
+
+ bspipe->pipe_used++; /* mark base layer pipe used */
+
+ ctrl->baselayer[mixer] = NULL;
+
+ /* free borderfill pipe */
+ pipe->pipe_used = 0;
+
+ mdp4_dsi_video_base_swap(bspipe);
+
+ /* free borderfill pipe */
+ mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_mixer_stage_down(pipe);
+ mdp4_overlay_pipe_free(pipe);
+
+ /* stage up base layer */
+ mdp4_overlay_reg_flush(bspipe, 1);
+ /* restore original base layer */
+ mdp4_mixer_stage_up(bspipe);
+}
+
+
+static struct mdp4_overlay_pipe *mdp4_background_layer(int mixer,
+ struct mdp4_overlay_pipe *sp)
+{
+ struct mdp4_overlay_pipe *pp;
+ struct mdp4_overlay_pipe *kp;
+ int i;
+
+ kp = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+ for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+ pp = ctrl->stage[mixer][i];
+ if (pp == NULL)
+ continue;
+ if (pp == sp)
+ break;
+
+ if ((pp->dst_x <= sp->dst_x) &&
+ ((pp->dst_x + pp->dst_w) >= (sp->dst_x + sp->dst_w))) {
+ if ((pp->dst_y <= sp->dst_y) &&
+ ((pp->dst_y + pp->dst_h) >=
+ (sp->dst_y + sp->dst_h))) {
+ kp = pp;
+ }
+ }
+ }
+ return kp;
+}
+
+static void mdp4_overlay_bg_solidfill(struct blend_cfg *blend)
+{
+ struct mdp4_overlay_pipe *pipe;
+ char *base;
+ u32 op_mode, format;
+ int pnum, ptype;
+
+ pipe = blend->solidfill_pipe;
+ if (pipe == NULL)
+ return;
+
+ if (pipe->pipe_type == OVERLAY_TYPE_BF)
+ return;
+
+ ptype = mdp4_overlay_format2type(pipe->src_format);
+ if (ptype == OVERLAY_TYPE_RGB) {
+ pnum = pipe->pipe_num - OVERLAY_PIPE_RGB1;
+ base = MDP_BASE + MDP4_RGB_BASE;
+ base += MDP4_RGB_OFF * pnum;
+ } else {
+ pnum = pipe->pipe_num - OVERLAY_PIPE_VG1;
+ base = MDP_BASE + MDP4_VIDEO_BASE;
+ base += MDP4_VIDEO_OFF * pnum;
+ }
+
+ format = inpdw(base + 0x50);
+ if (blend->solidfill) {
+ format |= MDP4_FORMAT_SOLID_FILL;
+ /*
+ * If solid fill is enabled, flip and scale
+ * have to be disabled. otherwise, h/w
+ * underruns.
+ */
+ op_mode = inpdw(base + 0x0058);
+ op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
+ op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
+ outpdw(base + 0x0058, op_mode);
+ outpdw(base + 0x1008, 0); /* black */
+ } else {
+ format &= ~MDP4_FORMAT_SOLID_FILL;
+ blend->solidfill_pipe = NULL;
+ }
+
+ outpdw(base + 0x50, format);
+
+ mdp4_overlay_reg_flush(pipe, 0);
+}
+
+/*
+ * D(i+1) = Ks * S + Kd * D(i)
+ */
+void mdp4_mixer_blend_setup(int mixer)
+{
+ struct mdp4_overlay_pipe *d_pipe;
+ struct mdp4_overlay_pipe *s_pipe;
+ struct blend_cfg *blend;
+ int i, off, ptype;
+ int d_alpha, s_alpha;
+ unsigned char *overlay_base;
+ uint32 c0, c1, c2;
+
+
+ d_pipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+ if (d_pipe == NULL) {
+ pr_err("%s: Error: no bg_pipe at mixer=%d\n", __func__, mixer);
+ return;
+ }
+
+ blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE0];
+ for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
+ blend->solidfill = 0;
+ blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
+ MDP4_BLEND_BG_ALPHA_BG_CONST);
+ s_pipe = ctrl->stage[mixer][i];
+ if (s_pipe == NULL) {
+ blend++;
+ d_pipe = NULL;
+ d_alpha = 0;
+ continue;
+ }
+ d_pipe = mdp4_background_layer(mixer, s_pipe);
+ d_alpha = d_pipe->alpha_enable;
+ s_alpha = s_pipe->alpha_enable;
+ pr_debug("%s: stage=%d: bg: ndx=%d da=%d dalpha=%x "
+ "fg: ndx=%d sa=%d salpha=%x is_fg=%d\n",
+ __func__, i-2, d_pipe->pipe_ndx, d_alpha, d_pipe->alpha,
+ s_pipe->pipe_ndx, s_alpha, s_pipe->alpha, s_pipe->is_fg);
+
+ /* base on fg's alpha */
+ blend->bg_alpha = 0x0ff - s_pipe->alpha;
+ blend->fg_alpha = s_pipe->alpha;
+ blend->co3_sel = 1; /* use fg alpha */
+
+ if (s_pipe->is_fg) {
+ if (s_pipe->alpha == 0xff) {
+ blend->solidfill = 1;
+ blend->solidfill_pipe = d_pipe;
+ }
+ } else if (s_alpha) {
+ blend->op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
+ MDP4_BLEND_BG_INV_ALPHA);
+ } else if (d_alpha) {
+ ptype = mdp4_overlay_format2type(s_pipe->src_format);
+ if (ptype == OVERLAY_TYPE_VIDEO) {
+ blend->op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
+ MDP4_BLEND_FG_ALPHA_BG_PIXEL |
+ MDP4_BLEND_FG_INV_ALPHA);
+ blend->co3_sel = 0; /* use bg alpha */
+ } else {
+ /* s_pipe is rgb without alpha */
+ blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
+ MDP4_BLEND_BG_ALPHA_BG_CONST);
+ blend->bg_alpha = 0;
+ }
+ }
+
+ if (s_pipe->transp != MDP_TRANSP_NOP) {
+ if (s_pipe->is_fg) {
+ transp_color_key(s_pipe->src_format,
+ s_pipe->transp, &c0, &c1, &c2);
+ /* Fg blocked */
+ blend->op |= MDP4_BLEND_FG_TRANSP_EN;
+ /* lower limit */
+ blend->transp_low0 = (c1 << 16 | c0);
+ blend->transp_low1 = c2;
+ /* upper limit */
+ blend->transp_high0 = (c1 << 16 | c0);
+ blend->transp_high1 = c2;
+ } else {
+ transp_color_key(d_pipe->src_format,
+ s_pipe->transp, &c0, &c1, &c2);
+ /* Fg blocked */
+ blend->op |= MDP4_BLEND_BG_TRANSP_EN;
+ blend--; /* one stage back */
+ /* lower limit */
+ blend->transp_low0 = (c1 << 16 | c0);
+ blend->transp_low1 = c2;
+ /* upper limit */
+ blend->transp_high0 = (c1 << 16 | c0);
+ blend->transp_high1 = c2;
+ blend++; /* back to original stage */
+ }
+ }
+ blend++;
+ }
+
/* mixer numer, /dev/fb0, /dev/fb1, /dev/fb2 */
- if (pipe->mixer_num == MDP4_MIXER2)
+ if (mixer == MDP4_MIXER2)
overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;/* 0x88000 */
- else if (pipe->mixer_num == MDP4_MIXER1)
+ else if (mixer == MDP4_MIXER1)
overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
else
overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
- /* stage 0 to stage 2 */
- off = 0x20 * (pipe->mixer_stage - MDP4_MIXER_STAGE0);
-
- bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
- MDP4_MIXER_STAGE_BASE);
- if (bg_pipe == NULL) {
- pr_err("%s: Error: no bg_pipe\n", __func__);
- return;
- }
-
- if (bg_pipe->pipe_type == OVERLAY_TYPE_BF &&
- pipe->mixer_stage > MDP4_MIXER_STAGE0) {
- bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
- MDP4_MIXER_STAGE0);
- }
-
- if (pipe->alpha_enable) {
- /* alpha channel is lost on VG pipe when downscaling */
- if (pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
- (pipe->dst_w < pipe->src_w || pipe->dst_h < pipe->src_h))
- fg_alpha = 0;
- else
- fg_alpha = 1;
- }
-
- if (!fg_alpha && bg_pipe && bg_pipe->alpha_enable) {
- struct mdp4_overlay_pipe *tmp;
- int stage;
-
- bg_alpha = 1;
- /* check all bg layers are opaque to propagate bg alpha */
- stage = bg_pipe->mixer_stage + 1;
- for (; stage < pipe->mixer_stage; stage++) {
- tmp = mdp4_overlay_stage_pipe(pipe->mixer_num, stage);
- if (!tmp || tmp->alpha_enable || tmp->is_fg) {
- bg_alpha = 0;
- break;
- }
- }
- }
-
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE];
+ /* lower limit */
+ outpdw(overlay_base + 0x180, blend->transp_low0);
+ outpdw(overlay_base + 0x184, blend->transp_low1);
+ /* upper limit */
+ outpdw(overlay_base + 0x188, blend->transp_high0);
+ outpdw(overlay_base + 0x18c, blend->transp_high1);
+ blend++; /* stage0 */
+ for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
+ off = 20 * i;
+ off = 0x20 * (i - MDP4_MIXER_STAGE0);
+ if (i == MDP4_MIXER_STAGE3)
+ off -= 4;
- blend_op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
- MDP4_BLEND_BG_ALPHA_BG_CONST);
- outpdw(overlay_base + off + 0x108, pipe->alpha);
- outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha);
- fg_color3_out = 1; /* keep fg alpha by default */
+ if (blend->solidfill_pipe)
+ mdp4_overlay_bg_solidfill(blend);
- if (pipe->is_fg) {
- if (pipe->alpha == 0xff &&
- bg_pipe->pipe_type == OVERLAY_TYPE_RGB) {
- u32 op_mode;
- pnum = bg_pipe->pipe_num - OVERLAY_PIPE_RGB1;
- rgb_base = MDP_BASE + MDP4_RGB_BASE;
- rgb_base += MDP4_RGB_OFF * pnum;
- rgb_src_format = inpdw(rgb_base + 0x50);
- rgb_src_format |= MDP4_FORMAT_SOLID_FILL;
- /*
- * If solid fill is enabled, flip and scale
- * have to be disabled. otherwise, h/w
- * underruns. Also flush the pipe inorder
- * to take solid fill into effect.
- */
- op_mode = inpdw(rgb_base + 0x0058);
- op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
- op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
- outpdw(rgb_base + 0x0058, op_mode);
- outpdw(rgb_base + 0x50, rgb_src_format);
- outpdw(rgb_base + 0x1008, constant_color);
- mdp4_overlay_reg_flush(bg_pipe, 0);
- }
- } else if (fg_alpha) {
- blend_op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
- MDP4_BLEND_BG_INV_ALPHA);
- fg_color3_out = 1; /* keep fg alpha */
- } else if (bg_alpha) {
- blend_op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
- MDP4_BLEND_FG_ALPHA_BG_PIXEL |
- MDP4_BLEND_FG_INV_ALPHA);
- fg_color3_out = 0; /* keep bg alpha */
- }
-
- if (pipe->transp != MDP_TRANSP_NOP) {
- if (pipe->is_fg) {
- transp_color_key(pipe->src_format, pipe->transp,
- &c0, &c1, &c2);
- /* Fg blocked */
- blend_op |= MDP4_BLEND_FG_TRANSP_EN;
- /* lower limit */
- outpdw(overlay_base + off + 0x110,
- (c1 << 16 | c0));/* low */
- outpdw(overlay_base + off + 0x114, c2);/* low */
+ outpdw(overlay_base + off + 0x108, blend->fg_alpha);
+ outpdw(overlay_base + off + 0x10c, blend->bg_alpha);
+ outpdw(overlay_base + off + 0x104, blend->op);
+ outpdw(overlay_base + (off << 5) + 0x1004, blend->co3_sel);
+ outpdw(overlay_base + off + 0x110, blend->transp_low0);/* low */
+ outpdw(overlay_base + off + 0x114, blend->transp_low1);/* low */
/* upper limit */
- outpdw(overlay_base + off + 0x118,
- (c1 << 16 | c0));
- outpdw(overlay_base + off + 0x11c, c2);
- } else if (bg_pipe) {
- transp_color_key(bg_pipe->src_format,
- pipe->transp, &c0, &c1, &c2);
- /* bg blocked */
- blend_op |= MDP4_BLEND_BG_TRANSP_EN;
- /* lower limit */
- outpdw(overlay_base + 0x180,
- (c1 << 16 | c0));/* low */
- outpdw(overlay_base + 0x184, c2);/* low */
- /* upper limit */
- outpdw(overlay_base + 0x188,
- (c1 << 16 | c0));/* high */
- outpdw(overlay_base + 0x18c, c2);/* high */
- }
+ outpdw(overlay_base + off + 0x118, blend->transp_high0);
+ outpdw(overlay_base + off + 0x11c, blend->transp_high1);
+ blend++;
}
-
- outpdw(overlay_base + off + 0x104, blend_op);
- outpdw(overlay_base + (off << 5) + 0x1004, fg_color3_out);
-
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all)
{
- struct mdp4_overlay_pipe *bg_pipe;
- uint32 bits = 0;
+ int mixer;
+ uint32 *reg;
+
+ mixer = pipe->mixer_num;
+ reg = &ctrl->flush[mixer];
+ *reg |= (1 << (2 + pipe->pipe_num));
if (all) {
- if (pipe->mixer_num == MDP4_MIXER1)
- bits |= 0x02;
+ if (mixer == MDP4_MIXER0)
+ *reg |= 0x01;
else
- bits |= 0x01;
+ *reg |= 0x02;
}
+}
- if (pipe->pipe_num <= OVERLAY_PIPE_RGB2)
- bits |= 1 << (2 + pipe->pipe_num);
- if (pipe->is_fg && pipe->alpha == 0xFF) {
- bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
- MDP4_MIXER_STAGE_BASE);
- bits |= 1 << (2 + bg_pipe->pipe_num);
- }
+void mdp4_overlay_flush_piggyback(int m0, int m1)
+{
+ u32 data;
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- outpdw(MDP_BASE + 0x18000, bits); /* MDP_OVERLAY_REG_FLUSH */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ data = ctrl->flush[m0] | ctrl->flush[m1];
+ ctrl->flush[m0] = data;
+}
+
+void mdp4_overlay_reg_flush_reset(struct mdp4_overlay_pipe *pipe)
+{
+ int mixer;
+
+ mixer = pipe->mixer_num;
+ ctrl->flush[mixer] = 0;
}
struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage)
@@ -1810,6 +1952,11 @@
int i;
struct mdp4_overlay_pipe *pipe;
+ if (ptype == OVERLAY_TYPE_BF) {
+ if (!mdp4_overlay_borderfill_supported())
+ return NULL;
+ }
+
for (i = 0; i < OVERLAY_PIPE_MAX; i++) {
pipe = &ctrl->plist[i];
if ((pipe->pipe_used == 0) && ((pipe->pipe_type == ptype) ||
@@ -1951,7 +2098,7 @@
return -ERANGE;
}
- if (req->z_order < 0 || req->z_order > 2) {
+ if (req->z_order < 0 || req->z_order > 3) {
pr_err("%s: z_order=%d out of range!\n", __func__,
req->z_order);
mdp4_stat.err_zorder++;
@@ -2076,12 +2223,12 @@
if (req->id == MSMFB_NEW_REQUEST) { /* new request */
pipe->pipe_used++;
pipe->mixer_num = mixer;
- pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0;
pr_debug("%s: zorder=%d pipe ndx=%d num=%d\n", __func__,
req->z_order, pipe->pipe_ndx, pipe->pipe_num);
}
+ pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0;
pipe->src_width = req->src.width & 0x1fff; /* source img width */
pipe->src_height = req->src.height & 0x1fff; /* source img height */
pipe->src_h = req->src_rect.h & 0x07ff;
@@ -2217,6 +2364,8 @@
mdp4_dsi_video_overlay_blt(mfd, req);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
mdp4_lcdc_overlay_blt(mfd, req);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_overlay_blt(mfd, req);
mutex_unlock(&mfd->dma->ov_mutex);
@@ -2238,6 +2387,8 @@
ret = mdp4_dsi_video_overlay_blt_offset(mfd, req);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
ret = mdp4_lcdc_overlay_blt_offset(mfd, req);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_overlay_blt_offset(mfd, req);
mutex_unlock(&mfd->dma->ov_mutex);
@@ -2331,7 +2482,14 @@
void mdp4_update_perf_level(u32 perf_level)
{
+ static int first = 1;
+
new_perf_level = perf_level;
+
+ if (first) {
+ first = 0;
+ mdp4_set_perf_level();
+ }
}
void mdp4_set_perf_level(void)
@@ -2365,6 +2523,8 @@
mdp4_dsi_video_blt_start(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_overlay_blt_start(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_overlay_blt_start(mfd);
} else {
if (mfd->panel_info.type == LCDC_PANEL ||
mfd->panel_info.type == LVDS_PANEL)
@@ -2373,6 +2533,8 @@
mdp4_dsi_video_blt_stop(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_overlay_blt_stop(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_overlay_blt_stop(mfd);
}
mfd->ov0_blt_state = mfd->use_ov0_blt;
}
@@ -2413,6 +2575,12 @@
use_blt = 1;
}
+ if (mfd->panel_info.type == MDDI_PANEL) {
+ if ((req->src_rect.h/2) >= req->dst_rect.h ||
+ (req->src_rect.w/2) >= req->dst_rect.w)
+ use_blt = 1;
+ }
+
if (mfd->mdp_rev == MDP_REV_41) {
/*
* writeback (blt) mode to provide work around for
@@ -2539,6 +2707,7 @@
mdp4_set_perf_level();
} else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
mdp4_mddi_dma_busy_wait(mfd);
+ mdp4_mddi_blt_dmap_busy_wait(mfd);
mdp4_set_perf_level();
}
} else {
@@ -2553,6 +2722,24 @@
return 0;
}
+int mdp4_overlay_unset_mixer(int mixer)
+{
+ struct mdp4_overlay_pipe *pipe;
+ int i, cnt = 0;
+
+ for (i = MDP4_MIXER_STAGE3; i >= MDP4_MIXER_STAGE_BASE; i--) {
+ pipe = ctrl->stage[mixer][i];
+ if (pipe == NULL)
+ continue;
+ pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+ mdp4_mixer_stage_down(pipe);
+ mdp4_overlay_pipe_free(pipe);
+ cnt++;
+ }
+
+ return cnt;
+}
+
int mdp4_overlay_unset(struct fb_info *info, int ndx)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -2573,6 +2760,12 @@
return -ENODEV;
}
+ if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+ mdp4_overlay_borderfill_stage_down(pipe);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return 0;
+ }
+
if (pipe->mixer_num == MDP4_MIXER2)
ctrl->mixer2_played = 0;
else if (pipe->mixer_num == MDP4_MIXER1)
@@ -2589,21 +2782,17 @@
#else
if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
if (mfd->panel_power_on)
- mdp4_mddi_dma_busy_wait(mfd);
+ mdp4_mddi_blt_dmap_busy_wait(mfd);
}
#endif
}
- if (mfd->mdp_rev >= MDP_REV_41 &&
- mdp4_overlay_is_rgb_type(pipe->src_format) &&
- !mfd->use_ov0_blt && (pipe->mixer_num == MDP4_MIXER0 ||
- hdmi_prim_display)) {
- ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;
- } else {
- if (pipe->is_fg &&
- !mdp4_overlay_is_rgb_type(pipe->src_format)) {
- mdp4_overlay_bg_solidfill_clear(pipe->mixer_num);
- pipe->is_fg = 0;
+ {
+ mdp4_overlay_reg_flush(pipe, 1);
+
+ if (mfd->use_ov0_blt || pipe->mixer_num == MDP4_MIXER1) {
+ /* unstage pipe forcedly */
+ pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
}
mdp4_mixer_stage_down(pipe);
@@ -2764,6 +2953,12 @@
if (mutex_lock_interruptible(&mfd->dma->ov_mutex))
return -EINTR;
+ if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+ mdp4_overlay_borderfill_stage_up(pipe);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return 0;
+ }
+
img = &req->data;
get_img(img, info, pipe, 0, &start, &len, &srcp0_file,
&ps0_need, &srcp0_ihdl);
@@ -2778,6 +2973,10 @@
pipe->srcp0_addr = addr;
pipe->srcp0_ystride = pipe->src_width * pipe->bpp;
+
+ pr_debug("%s: mixer=%d ndx=%x addr=%x flags=%x\n", __func__,
+ pipe->mixer_num, pipe->pipe_ndx, (int)addr, pipe->flags);
+
if ((req->version_key & VERSION_KEY_MASK) == 0xF9E8D700)
overlay_version = (req->version_key & ~VERSION_KEY_MASK);
@@ -2874,6 +3073,7 @@
if (mfd->use_ov1_blt)
mdp4_overlay1_update_blt_mode(mfd);
+
if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
} else {
@@ -2886,11 +3086,7 @@
mdp4_overlay_rgb_setup(pipe); /* rgb pipe */
}
- if ((ctrl->panel_mode & MDP4_PANEL_DTV) ||
- (ctrl->panel_mode & MDP4_PANEL_LCDC) ||
- (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO))
- mdp4_overlay_reg_flush(pipe, 0);
-
+ mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
if (pipe->mixer_num == MDP4_MIXER2) {
@@ -2905,6 +3101,9 @@
ctrl->mixer1_played++;
/* enternal interface */
if (ctrl->panel_mode & MDP4_PANEL_DTV) {
+ if (pipe->flags & MDP_OV_PLAY_NOWAIT)
+ mdp4_overlay_flush_piggyback(MDP4_MIXER0,
+ MDP4_MIXER1);
mdp4_overlay_dtv_start();
mdp4_overlay_dtv_ov_done_push(mfd, pipe);
if (!mfd->use_ov1_blt)
@@ -2933,6 +3132,7 @@
}
#endif
else {
+ mdp4_overlay_reg_flush_reset(pipe);
/* mddi & mipi dsi cmd mode */
if (pipe->flags & MDP_OV_PLAY_NOWAIT) {
mdp4_stat.overlay_play[pipe->mixer_num]++;
@@ -3002,7 +3202,6 @@
},
};
-static int iommu_enabled;
static int mdp_iommu_fault_handler(struct iommu_domain *domain,
struct device *dev, unsigned long iova, int flags)
{
@@ -3012,10 +3211,11 @@
void mdp4_iommu_attach(void)
{
+ static int done;
struct iommu_domain *domain;
int i;
- if (!iommu_enabled) {
+ if (!done) {
for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
int domain_idx;
struct device *ctx = msm_iommu_get_ctx(
@@ -3040,38 +3240,7 @@
continue;
}
}
- pr_debug("Attached MDP IOMMU device\n");
- iommu_enabled = 1;
- }
-}
-
-void mdp4_iommu_detach(void)
-{
- struct iommu_domain *domain;
- int i;
-
- if (!mdp_check_suspended() || mdp4_extn_disp)
- return;
-
- if (iommu_enabled) {
- for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
- int domain_idx;
- struct device *ctx = msm_iommu_get_ctx(
- msm_iommu_ctx_names[i].name);
-
- if (!ctx)
- continue;
-
- domain_idx = msm_iommu_ctx_names[i].domain;
-
- domain = msm_get_iommu_domain(domain_idx);
- if (!domain)
- continue;
-
- iommu_detach_device(domain, ctx);
- }
- pr_debug("Detached MDP IOMMU device\n");
- iommu_enabled = 0;
+ done = 1;
}
}
@@ -3092,7 +3261,7 @@
return err;
}
- mdp4_mixer_blend_setup(pipe);
+ mdp4_mixer_blend_setup(pipe->mixer_num);
*ppipe = pipe;
return 0;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index a5b4b3e..7ba4e75 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -114,6 +114,11 @@
}
}
+void mdp4_dsi_cmd_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ dsi_pipe = pipe;
+}
+
void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf = &mfd->ibuf;
@@ -162,6 +167,14 @@
} else {
pipe = dsi_pipe;
}
+
+ if (pipe->pipe_used == 0 ||
+ pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+ pr_err("%s: NOT baselayer\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
+
/*
* configure dsi stream id
* dma_p = 0, dma_s = 1
@@ -207,6 +220,8 @@
mdp4_overlay_rgb_setup(pipe);
+ mdp4_overlay_reg_flush(pipe, 1);
+
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
@@ -240,6 +255,12 @@
dsi_pipe->src_width_3d = r3d->width;
pipe = dsi_pipe;
+ if (pipe->pipe_used == 0 ||
+ pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+ pr_err("%s: NOT baselayer\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
if (pipe->is_3d)
mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_SIDE_BY_SIDE);
@@ -282,6 +303,8 @@
mdp4_overlay_rgb_setup(pipe);
+ mdp4_overlay_reg_flush(pipe, 1);
+
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
@@ -651,12 +674,22 @@
mdp4_stat.kickoff_ov0++;
}
-void mdp_dsi_cmd_overlay_suspend(void)
+void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
{
/* dis-engage rgb0 from mixer0 */
if (dsi_pipe) {
- mdp4_mixer_stage_down(dsi_pipe);
- mdp4_iommu_unmap(dsi_pipe);
+ if (mfd->ref_cnt == 0) {
+ /* adb stop */
+ if (dsi_pipe->pipe_type == OVERLAY_TYPE_BF)
+ mdp4_overlay_borderfill_stage_down(dsi_pipe);
+
+ /* dsi_pipe == rgb1 */
+ mdp4_overlay_unset_mixer(dsi_pipe->mixer_num);
+ dsi_pipe = NULL;
+ } else {
+ mdp4_mixer_stage_down(dsi_pipe);
+ mdp4_iommu_unmap(dsi_pipe);
+ }
}
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index fb71cc1..05c6fe8 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -69,6 +69,11 @@
static void mdp4_overlay_dsi_video_wait4event(struct msm_fb_data_type *mfd,
int intr_done);
+void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ dsi_pipe = pipe;
+}
+
int mdp4_dsi_video_on(struct platform_device *pdev)
{
int dsi_width;
@@ -118,8 +123,6 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mdp4_overlay_ctrl_db_reset();
-
fbi = mfd->fbi;
var = &fbi->var;
@@ -192,8 +195,9 @@
mdp4_overlay_dmap_xy(pipe); /* dma_p */
mdp4_overlay_dmap_cfg(mfd, 1);
-
mdp4_overlay_rgb_setup(pipe);
+ mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
@@ -291,10 +295,12 @@
int mdp4_dsi_video_off(struct platform_device *pdev)
{
int ret = 0;
+ struct msm_fb_data_type *mfd;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp4_mixer_pipe_cleanup(dsi_pipe->mixer_num);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
dsi_video_enabled = 0;
/* MDP cmd block disable */
@@ -308,8 +314,18 @@
/* dis-engage rgb0 from mixer0 */
if (dsi_pipe) {
- mdp4_mixer_stage_down(dsi_pipe);
- mdp4_iommu_unmap(dsi_pipe);
+ if (mfd->ref_cnt == 0) {
+ /* adb stop */
+ if (dsi_pipe->pipe_type == OVERLAY_TYPE_BF)
+ mdp4_overlay_borderfill_stage_down(dsi_pipe);
+
+ /* dsi_pipe == rgb1 */
+ mdp4_overlay_unset_mixer(dsi_pipe->mixer_num);
+ dsi_pipe = NULL;
+ } else {
+ mdp4_mixer_stage_down(dsi_pipe);
+ mdp4_iommu_unmap(dsi_pipe);
+ }
}
return ret;
@@ -384,7 +400,6 @@
mdp4_overlay_dmap_cfg(mfd, 1);
mdp4_overlay_reg_flush(pipe, 1);
-
mdp4_mixer_stage_up(pipe);
mb();
@@ -632,7 +647,6 @@
spin_unlock_irqrestore(&mdp_spin_lock, flag);
-
/*
* may need mutex here to sync with whom dsiable
* timing generator
@@ -693,6 +707,12 @@
mutex_lock(&mfd->dma->ov_mutex);
pipe = dsi_pipe;
+ if (pipe->pipe_used == 0 ||
+ pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+ pr_err("%s: NOT baselayer\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
if (mfd->display_iova)
pipe->srcp0_addr = mfd->display_iova + buf_offset;
@@ -700,7 +720,7 @@
pipe->srcp0_addr = (uint32)(buf + buf_offset);
mdp4_overlay_rgb_setup(pipe);
- mdp4_overlay_reg_flush(pipe, 0);
+ mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
mdp4_overlay_dsi_video_start();
mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index dd96439..aa1795f 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -56,6 +56,12 @@
static struct mdp4_overlay_pipe *dtv_pipe;
static DECLARE_COMPLETION(dtv_comp);
+void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ if (hdmi_prim_display)
+ dtv_pipe = pipe;
+}
+
static int mdp4_dtv_start(struct msm_fb_data_type *mfd)
{
int dtv_width;
@@ -208,7 +214,6 @@
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp4_mixer_pipe_cleanup(dtv_pipe->mixer_num);
msleep(20);
MDP_OUTP(MDP_BASE + DTV_BASE, 0);
dtv_enabled = 0;
@@ -262,19 +267,24 @@
if (dtv_pipe != NULL) {
mdp4_dtv_stop(mfd);
+ if (hdmi_prim_display && mfd->ref_cnt == 0) {
+ /* adb stop */
+ if (dtv_pipe->pipe_type == OVERLAY_TYPE_BF)
+ mdp4_overlay_borderfill_stage_down(dtv_pipe);
- /* delay to make sure the last frame finishes */
- msleep(20);
-
- mdp4_mixer_stage_down(dtv_pipe);
- mdp4_overlay_pipe_free(dtv_pipe);
- mdp4_iommu_unmap(dtv_pipe);
- dtv_pipe = NULL;
+ /* dtv_pipe == rgb1 */
+ mdp4_overlay_unset_mixer(dtv_pipe->mixer_num);
+ dtv_pipe = NULL;
+ } else {
+ mdp4_mixer_stage_down(dtv_pipe);
+ mdp4_overlay_pipe_free(dtv_pipe);
+ mdp4_iommu_unmap(dtv_pipe);
+ dtv_pipe = NULL;
+ }
}
mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV);
ret = panel_next_off(pdev);
- mdp4_iommu_detach();
mdp_footswitch_ctrl(FALSE);
dev_info(&pdev->dev, "mdp4_overlay_dtv: off");
@@ -610,7 +620,8 @@
*/
temp_src_format = inpdw(rgb_base + 0x0050);
MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
- mdp4_overlay_reg_flush(dtv_pipe, 0);
+ mdp4_overlay_reg_flush(dtv_pipe, 1);
+ mdp4_mixer_stage_up(dtv_pipe);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
@@ -696,11 +707,19 @@
}
mutex_lock(&mfd->dma->ov_mutex);
pipe = dtv_pipe;
+
+ if (hdmi_prim_display && (pipe->pipe_used == 0 ||
+ pipe->mixer_stage != MDP4_MIXER_STAGE_BASE)) {
+ pr_err("%s: NOT baselayer\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
+
if (pipe->pipe_type == OVERLAY_TYPE_RGB) {
pipe->srcp0_addr = (uint32) mfd->ibuf.buf;
mdp4_overlay_rgb_setup(pipe);
}
- mdp4_overlay_reg_flush(pipe, 0);
+ mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
mdp4_overlay_dtv_start();
mdp4_overlay_dtv_ov_done_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index a1fecb6..18d2107 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -46,6 +46,11 @@
static struct mdp4_overlay_pipe *lcdc_pipe;
static struct completion lcdc_comp;
+void mdp4_lcdc_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ lcdc_pipe = pipe;
+}
+
int mdp_lcdc_on(struct platform_device *pdev)
{
int lcdc_width;
@@ -95,8 +100,6 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mdp4_overlay_ctrl_db_reset();
-
fbi = mfd->fbi;
var = &fbi->var;
@@ -155,6 +158,8 @@
mdp4_overlay_dmap_cfg(mfd, 1);
mdp4_overlay_rgb_setup(pipe);
+ mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
@@ -263,7 +268,6 @@
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp4_mixer_pipe_cleanup(lcdc_pipe->mixer_num);
MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
lcdc_enabled = 0;
/* MDP cmd block disable */
@@ -280,8 +284,18 @@
/* dis-engage rgb0 from mixer0 */
if (lcdc_pipe) {
- mdp4_mixer_stage_down(lcdc_pipe);
- mdp4_iommu_unmap(lcdc_pipe);
+ if (mfd->ref_cnt == 0) {
+ /* adb stop */
+ if (lcdc_pipe->pipe_type == OVERLAY_TYPE_BF)
+ mdp4_overlay_borderfill_stage_down(lcdc_pipe);
+
+ /* lcdc_pipe == rgb1 */
+ mdp4_overlay_unset_mixer(lcdc_pipe->mixer_num);
+ lcdc_pipe = NULL;
+ } else {
+ mdp4_mixer_stage_down(lcdc_pipe);
+ mdp4_iommu_unmap(lcdc_pipe);
+ }
}
#ifdef CONFIG_MSM_BUS_SCALING
@@ -494,7 +508,7 @@
}
}
/*
- * make sure the MIPI_DSI_WRITEBACK_SIZE defined at boardfile
+ * make sure the WRITEBACK_SIZE defined at boardfile
* has enough space h * w * 3 * 2
*/
static void mdp4_lcdc_do_blt(struct msm_fb_data_type *mfd, int enable)
@@ -585,6 +599,12 @@
mutex_lock(&mfd->dma->ov_mutex);
pipe = lcdc_pipe;
+ if (pipe->pipe_used == 0 ||
+ pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+ pr_err("%s: NOT baselayer\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
if (mfd->display_iova)
pipe->srcp0_addr = mfd->display_iova + buf_offset;
@@ -592,7 +612,7 @@
pipe->srcp0_addr = (uint32)(buf + buf_offset);
mdp4_overlay_rgb_setup(pipe);
- mdp4_overlay_reg_flush(pipe, 0);
+ mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
mdp4_overlay_lcdc_start();
mdp4_overlay_lcdc_vsync_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index 5aa5965..82864918 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -124,7 +124,6 @@
printk(KERN_INFO "%s: format2type failed\n", __func__);
mddi_pipe = pipe; /* keep it */
- mddi_pipe->blt_end = 1; /* mark as end */
mddi_ld_param = 0;
mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
@@ -163,6 +162,8 @@
(MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
MDP_OUTP(MDP_BASE + 0x00098, 0x01);
+ mdp4_init_writeback_buf(mfd, MDP4_MIXER0);
+ pipe->blt_addr = 0;
} else {
pipe = mddi_pipe;
}
@@ -246,59 +247,82 @@
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
}
-int mdp4_mddi_overlay_blt_offset(int *off)
-{
- if (mdp_hw_revision < MDP4_REVISION_V2_1) { /* need dmas dmap switch */
- if (mddi_pipe->blt_end ||
- (mdp4_overlay_mixer_play(mddi_pipe->mixer_num) == 0)) {
- *off = -1;
- return -EINVAL;
- }
- } else {
- /* no dmas dmap switch */
- if (mddi_pipe->blt_end) {
- *off = -1;
- return -EINVAL;
- }
- }
-
- if (mddi_pipe->blt_cnt & 0x01)
- *off = mddi_pipe->src_height * mddi_pipe->src_width * 3;
- else
- *off = 0;
-
- return 0;
-}
-
-void mdp4_mddi_overlay_blt(ulong addr)
+int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd)
{
unsigned long flag;
- spin_lock_irqsave(&mdp_spin_lock, flag);
- if (addr) {
- mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp_intr_mask |= INTR_DMA_P_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- mddi_pipe->blt_cnt = 0;
- mddi_pipe->blt_end = 0;
- mddi_pipe->blt_addr = addr;
- } else {
- mddi_pipe->blt_end = 1; /* mark as end */
+ pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n",
+ __func__, mddi_pipe->blt_end, (int)mddi_pipe->blt_addr, current->pid);
+
+ mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+
+ if (mfd->ov0_wb_buf->phys_addr == 0) {
+ pr_info("%s: no blt_base assigned\n", __func__);
+ return -EBUSY;
}
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ if (mddi_pipe->blt_addr == 0) {
+ mdp4_mddi_dma_busy_wait(mfd);
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mddi_pipe->blt_end = 0;
+ mddi_pipe->blt_cnt = 0;
+ mddi_pipe->ov_cnt = 0;
+ mddi_pipe->dmap_cnt = 0;
+ mddi_pipe->blt_addr = mfd->ov0_wb_buf->phys_addr;
+ mdp4_stat.blt_mddi++;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ return 0;
+}
+
+ return -EBUSY;
+}
+
+int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+{
+ unsigned long flag;
+
+ pr_debug("%s: blt_end=%d blt_addr=%x\n",
+ __func__, mddi_pipe->blt_end, (int)mddi_pipe->blt_addr);
+
+ if ((mddi_pipe->blt_end == 0) && mddi_pipe->blt_addr) {
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mddi_pipe->blt_end = 1; /* mark as end */
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ return 0;
+ }
+
+ return -EBUSY;
+}
+
+int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req)
+{
+ req->offset = 0;
+ req->width = mddi_pipe->src_width;
+ req->height = mddi_pipe->src_height;
+ req->bpp = mddi_pipe->bpp;
+
+ return sizeof(*req);
+}
+
+void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req)
+{
+ if (req->enable)
+ mdp4_mddi_overlay_blt_start(mfd);
+ else if (req->enable == 0)
+ mdp4_mddi_overlay_blt_stop(mfd);
+
}
void mdp4_blt_xy_update(struct mdp4_overlay_pipe *pipe)
{
- uint32 off, addr;
+ uint32 off, addr, addr2;
int bpp;
char *overlay_base;
-
if (pipe->blt_addr == 0)
return;
@@ -317,29 +341,62 @@
/* dmap */
MDP_OUTP(MDP_BASE + 0x90008, addr);
+ off = 0;
+ if (pipe->ov_cnt & 0x01)
+ off = pipe->src_height * pipe->src_width * bpp;
+ addr2 = pipe->blt_addr + off;
/* overlay 0 */
overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
- outpdw(overlay_base + 0x000c, addr);
- outpdw(overlay_base + 0x001c, addr);
+ outpdw(overlay_base + 0x000c, addr2);
+ outpdw(overlay_base + 0x001c, addr2);
}
/*
* mdp4_dmap_done_mddi: called from isr
*/
-void mdp4_dma_p_done_mddi(void)
+void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma)
{
- if (mddi_pipe->blt_end) {
- mddi_pipe->blt_addr = 0;
- mdp_intr_mask &= ~INTR_DMA_P_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- mdp4_overlayproc_cfg(mddi_pipe);
- mdp4_overlay_dmap_xy(mddi_pipe);
+ int diff;
+
+ mddi_pipe->dmap_cnt++;
+ diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
+ pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
+ __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+
+ if (diff <= 0) {
+ spin_lock(&mdp_spin_lock);
+ dma->dmap_busy = FALSE;
+ complete(&dma->dmap_comp);
+ spin_unlock(&mdp_spin_lock);
+
+ if (mddi_pipe->blt_end) {
+ mddi_pipe->blt_end = 0;
+ mddi_pipe->blt_addr = 0;
+ pr_debug("%s: END, ov_cnt=%d dmap_cnt=%d\n", __func__,
+ mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+ mdp_intr_mask &= ~INTR_DMA_P_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ }
+
+ mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+ mdp_disable_irq_nosync(MDP_DMA2_TERM); /* disable intr */
+ return;
}
- /*
- * single buffer, no need to increase
- * mdd_pipe->dmap_cnt here
- */
+ spin_lock(&mdp_spin_lock);
+ dma->busy = FALSE;
+ spin_unlock(&mdp_spin_lock);
+ complete(&dma->comp);
+ if (busy_wait_cnt)
+ busy_wait_cnt--;
+
+ pr_debug("%s: kickoff dmap\n", __func__);
+
+ mdp4_blt_xy_update(mddi_pipe);
+ /* kick off dmap */
+ outpdw(MDP_BASE + 0x000c, 0x0);
+ mdp4_stat.kickoff_dmap++;
+ mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
}
/*
@@ -347,37 +404,60 @@
*/
void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma)
{
- mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+ int diff;
+ if (mddi_pipe->blt_addr == 0) {
+ mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+ spin_lock(&mdp_spin_lock);
+ dma->busy = FALSE;
+ spin_unlock(&mdp_spin_lock);
+ complete(&dma->comp);
+
+ if (busy_wait_cnt)
+ busy_wait_cnt--;
+ mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+
+ return;
+ }
+
+ /* blt enabled */
+ if (mddi_pipe->blt_end == 0)
+ mddi_pipe->ov_cnt++;
+
+ pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
+ __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+
+ if (mddi_pipe->blt_cnt == 0) {
+ /* first kickoff since blt enabled */
+ mdp_intr_mask |= INTR_DMA_P_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ }
+
+ mddi_pipe->blt_cnt++;
+
+ diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
+ if (diff >= 2) {
+ mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+ return;
+ }
+
+ spin_lock(&mdp_spin_lock);
dma->busy = FALSE;
+ dma->dmap_busy = TRUE;
+ spin_unlock(&mdp_spin_lock);
complete(&dma->comp);
- mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK,
- MDP_BLOCK_POWER_OFF, TRUE);
if (busy_wait_cnt)
busy_wait_cnt--;
- pr_debug("%s: ISR-done\n", __func__);
+ pr_debug("%s: kickoff dmap\n", __func__);
- if (mddi_pipe->blt_addr) {
- if (mddi_pipe->blt_cnt == 0) {
- mdp4_overlayproc_cfg(mddi_pipe);
- mdp4_overlay_dmap_xy(mddi_pipe);
- mddi_pipe->ov_cnt = 0;
- mddi_pipe->dmap_cnt = 0;
- /* BLT start from next frame */
- } else {
- mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON,
- FALSE);
- mdp4_blt_xy_update(mddi_pipe);
- outpdw(MDP_BASE + 0x000c, 0x0); /* start DMAP */
- }
- mddi_pipe->blt_cnt++;
- mddi_pipe->ov_cnt++;
- }
-
-
-
+ mdp4_blt_xy_update(mddi_pipe);
+ mdp_enable_irq(MDP_DMA2_TERM); /* enable intr */
+ /* kick off dmap */
+ outpdw(MDP_BASE + 0x000c, 0x0);
+ mdp4_stat.kickoff_dmap++;
+ mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
}
void mdp4_mddi_overlay_restore(void)
@@ -392,6 +472,9 @@
if (mddi_mfd && mddi_pipe) {
mdp4_mddi_dma_busy_wait(mddi_mfd);
mdp4_overlay_update_lcd(mddi_mfd);
+
+ if (mddi_pipe->blt_addr)
+ mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe);
mddi_mfd->dma_update_flag = 1;
}
@@ -399,9 +482,27 @@
mdp4_mddi_overlay_dmas_restore();
}
+void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd)
+{
+ unsigned long flag;
+ int need_wait = 0;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ if (mfd->dma->dmap_busy == TRUE) {
+ INIT_COMPLETION(mfd->dma->dmap_comp);
+ need_wait++;
+ }
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ if (need_wait) {
+ /* wait until DMA finishes the current job */
+ wait_for_completion(&mfd->dma->dmap_comp);
+ }
+}
+
/*
* mdp4_mddi_cmd_dma_busy_wait: check mddi link activity
- * dsi link is a shared resource and it can only be used
+ * mddi link is a shared resource and it can only be used
* while it is in idle state.
* ov_mutex need to be acquired before call this function.
*/
@@ -432,7 +533,24 @@
void mdp4_mddi_kickoff_video(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
- pr_debug("%s: pid=%d\n", __func__, current->pid);
+ /*
+ * a video kickoff may happen before UI kickoff after
+ * blt enabled. mdp4_overlay_update_lcd() need
+ * to be called before kickoff.
+ * vice versa for blt disabled.
+ */
+ if (mddi_pipe->blt_addr && mddi_pipe->blt_cnt == 0)
+ mdp4_overlay_update_lcd(mfd); /* first time */
+ else if (mddi_pipe->blt_addr == 0 && mddi_pipe->blt_cnt) {
+ mdp4_overlay_update_lcd(mfd); /* last time */
+ mddi_pipe->blt_cnt = 0;
+ }
+
+ pr_debug("%s: blt_addr=%d blt_cnt=%d\n",
+ __func__, (int)mddi_pipe->blt_addr, mddi_pipe->blt_cnt);
+
+ if (mddi_pipe->blt_addr)
+ mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
mdp4_mddi_overlay_kickoff(mfd, pipe);
}
@@ -447,11 +565,16 @@
void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
+ unsigned long flag;
/* change mdp clk while mdp is idle` */
mdp4_set_perf_level();
mdp_enable_irq(MDP_OVERLAY0_TERM);
+ spin_lock_irqsave(&mdp_spin_lock, flag);
mfd->dma->busy = TRUE;
+ if (mddi_pipe->blt_addr)
+ mfd->dma->dmap_busy = TRUE;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
/* start OVERLAY pipe */
mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
mdp4_stat.kickoff_ov0++;
@@ -533,7 +656,10 @@
mdp4_set_perf_level();
mdp_enable_irq(MDP_DMA_S_TERM);
- mfd->dma->busy = TRUE;
+
+ if (mddi_pipe->blt_addr == 0)
+ mfd->dma->busy = TRUE;
+
mfd->ibuf_flushed = TRUE;
/* start dma_s pipe */
mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd);
@@ -561,6 +687,10 @@
if (mfd && mfd->panel_power_on) {
mdp4_mddi_dma_busy_wait(mfd);
+
+ if (mddi_pipe && mddi_pipe->blt_addr)
+ mdp4_mddi_blt_dmap_busy_wait(mfd);
+
mdp4_overlay_update_lcd(mfd);
if (mdp_hw_revision < MDP4_REVISION_V2_1) {
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index b2657cf3..f192b12 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -314,6 +314,8 @@
clk_rate = mdp_get_core_clk();
mdp4_fetch_cfg(clk_rate);
+ mdp4_overlay_cfg_init();
+
/* Mark hardware as initialized. Only revisions > v2.1 have a register
* for tracking core reset status. */
if (mdp_hw_revision > MDP4_REVISION_V2_1)
@@ -378,6 +380,7 @@
outpdw(MDP_INTR_CLEAR, isr);
if (isr & INTR_PRIMARY_INTF_UDERRUN) {
+ pr_debug("%s: UNDERRUN -- primary\n", __func__);
mdp4_stat.intr_underrun_p++;
/* When underun occurs mdp clear the histogram registers
that are set before in hw_init so restore them back so
@@ -395,8 +398,10 @@
}
}
- if (isr & INTR_EXTERNAL_INTF_UDERRUN)
+ if (isr & INTR_EXTERNAL_INTF_UDERRUN) {
+ pr_debug("%s: UNDERRUN -- external\n", __func__);
mdp4_stat.intr_underrun_e++;
+ }
isr &= mask;
@@ -522,7 +527,7 @@
}
#else
else { /* MDDI */
- mdp4_dma_p_done_mddi();
+ mdp4_dma_p_done_mddi(dma);
mdp_pipe_ctrl(MDP_DMA2_BLOCK,
MDP_BLOCK_POWER_OFF, TRUE);
complete(&dma->comp);
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 7defd82..4a0ea4c 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -437,38 +437,38 @@
len = snprintf(bp, dlen, "frame_push:\n");
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "rgb1: %08lu\t\t",
+ len = snprintf(bp, dlen, "rgb1: %08lu\t",
mdp4_stat.pipe[OVERLAY_PIPE_RGB1]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "rgb2: %08lu\n",
+ len = snprintf(bp, dlen, "rgb2: %08lu\n",
mdp4_stat.pipe[OVERLAY_PIPE_RGB2]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "vg1: %08lu\t\t",
+ len = snprintf(bp, dlen, "vg1 : %08lu\t",
mdp4_stat.pipe[OVERLAY_PIPE_VG1]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "vg2: %08lu\n",
+ len = snprintf(bp, dlen, "vg2 : %08lu\n",
mdp4_stat.pipe[OVERLAY_PIPE_VG2]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_mixer: %08lu\t", mdp4_stat.err_mixer);
+ len = snprintf(bp, dlen, "err_mixer : %08lu\t", mdp4_stat.err_mixer);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_size : %08lu\n", mdp4_stat.err_size);
+ len = snprintf(bp, dlen, "err_size : %08lu\n", mdp4_stat.err_size);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_scale: %08lu\t", mdp4_stat.err_scale);
+ len = snprintf(bp, dlen, "err_scale : %08lu\t", mdp4_stat.err_scale);
bp += len;
dlen -= len;
len = snprintf(bp, dlen, "err_format: %08lu\n", mdp4_stat.err_format);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_play: %08lu\t", mdp4_stat.err_play);
+ len = snprintf(bp, dlen, "err_play : %08lu\t", mdp4_stat.err_play);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_stage: %08lu\n", mdp4_stat.err_stage);
+ len = snprintf(bp, dlen, "err_stage : %08lu\n", mdp4_stat.err_stage);
bp += len;
dlen -= len;
len = snprintf(bp, dlen, "err_underflow: %08lu\n\n",
diff --git a/drivers/video/msm/mdp_ppp_v20.c b/drivers/video/msm/mdp_ppp_v20.c
index d271b85..418528e 100644
--- a/drivers/video/msm/mdp_ppp_v20.c
+++ b/drivers/video/msm/mdp_ppp_v20.c
@@ -2403,7 +2403,10 @@
uint32 width,
uint32 height, int bpp, MDPIBUF *iBuf, int layer)
{
- *src0 += (x + y * width) * bpp;
+ if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO && layer == 0)
+ *src0 += (x + y * ALIGN(width, 32)) * bpp;
+ else
+ *src0 += (x + y * width) * bpp;
/* if it's dest/bg buffer, we need to adjust it for rotation */
if (layer != 0)
@@ -2414,9 +2417,14 @@
* MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now
* we need to shift x direction same as y dir for offsite
*/
- *src1 +=
- ((x / h_slice) * h_slice +
- ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
+ if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO
+ && layer == 0)
+ *src1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 :
+ (((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2))))
+ * bpp;
+ else
+ *src1 += ((x / h_slice) * h_slice +
+ ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
/* if it's dest/bg buffer, we need to adjust it for rotation */
if (layer != 0)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index 50c3696..8a33512 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -30,6 +30,9 @@
#define DDL_MAX_FRAME_WIDTH 1920
#define DDL_MAX_FRAME_HEIGHT 1088
+#define DDL_MAX_VC1_FRAME_WIDTH (DDL_MAX_FRAME_WIDTH)
+#define DDL_MAX_VC1_FRAME_HEIGHT (1280)
+
#define MAX_DPB_SIZE_L4PT0_MBS DDL_KILO_BYTE(32)
#define MAX_FRAME_SIZE_L4PT0_MBS DDL_KILO_BYTE(8)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 3487f53..58d1f23 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -312,6 +312,20 @@
return process_further;
}
break;
+ case VCD_CODEC_VC1:
+ case VCD_CODEC_VC1_RCV:
+ if ((seq_hdr_info.img_size_x >
+ DDL_MAX_VC1_FRAME_WIDTH) ||
+ (seq_hdr_info.img_size_y >
+ DDL_MAX_VC1_FRAME_HEIGHT)) {
+ DDL_MSG_ERROR("Unsupported VC1 clip: "
+ "Resolution X=%d and Y=%d",
+ seq_hdr_info.img_size_x,
+ seq_hdr_info.img_size_y);
+ ddl_client_fatal_cb(ddl);
+ return process_further;
+ }
+ break;
default:
break;
}
@@ -1703,6 +1717,13 @@
(void)ddl_get_encoded_frame(output_frame,
encoder->codec.codec, encoder->enc_frame_info.enc_frame
);
+ if (!IS_ERR_OR_NULL(output_frame->buff_ion_handle)) {
+ msm_ion_do_cache_op(ddl_context->video_ion_client,
+ output_frame->buff_ion_handle,
+ (unsigned long *) output_frame->virtual,
+ (unsigned long) output_frame->alloc_len,
+ ION_IOC_INV_CACHES);
+ }
ddl_process_encoder_metadata(ddl);
ddl_vidc_encode_dynamic_property(ddl, false);
ddl->input_frame.frm_trans_end = false;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 878db622..839a9c1 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -207,7 +207,7 @@
#define VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT 0x0
#define VIDC_SM_EXTENDED_PAR_ADDR 0x00cc
#define VIDC_SM_EXTENDED_PAR_WIDTH_BMSK 0xffff0000
-#define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT 0xf
+#define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT 16
#define VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK 0x0000ffff
#define VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT 0x0
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index d90b8ca..5b22b21 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -28,8 +28,8 @@
#define PIL_FW_BASE_ADDR 0x9fe00000
#define PIL_FW_SIZE 0x200000
-static unsigned int vidc_clk_table[3] = {
- 48000000, 133330000, 200000000
+static unsigned int vidc_clk_table[4] = {
+ 48000000, 133330000, 200000000, 228570000,
};
static unsigned int restrk_mmu_subsystem[] = {
MSM_SUBSYSTEM_VIDEO, MSM_SUBSYSTEM_VIDEO_FWARE};
@@ -544,17 +544,27 @@
enc_perf_level += cctxt_itr->reqd_perf_lvl;
cctxt_itr = cctxt_itr->next;
}
+
if (!enc_perf_level)
client_type = 1;
if (perf_level <= RESTRK_1080P_VGA_PERF_LEVEL)
bus_clk_index = 0;
else if (perf_level <= RESTRK_1080P_720P_PERF_LEVEL)
bus_clk_index = 1;
- else
+ else if (perf_level <= RESTRK_1080P_MAX_PERF_LEVEL)
bus_clk_index = 2;
+ else
+ bus_clk_index = 3;
if (dev_ctxt->reqd_perf_lvl + dev_ctxt->curr_perf_lvl == 0)
bus_clk_index = 2;
+ else if (resource_context.vidc_platform_data->disable_turbo
+ && bus_clk_index == 3) {
+ VCDRES_MSG_ERROR("Warning: Turbo mode not supported "
+ " falling back to 1080p bus\n");
+ bus_clk_index = 2;
+ }
+
bus_clk_index = (bus_clk_index << 1) + (client_type + 1);
VCDRES_MSG_LOW("%s(), bus_clk_index = %d", __func__, bus_clk_index);
VCDRES_MSG_LOW("%s(),context.pcl = %x", __func__, resource_context.pcl);
@@ -575,6 +585,13 @@
return false;
}
VCDRES_MSG_LOW("%s(), req_perf_lvl = %d", __func__, req_perf_lvl);
+
+ if (resource_context.vidc_platform_data->disable_turbo
+ && req_perf_lvl > RESTRK_1080P_MAX_PERF_LEVEL) {
+ VCDRES_MSG_ERROR("%s(): Turbo not supported! dev_ctxt(%p)\n",
+ __func__, dev_ctxt);
+ }
+
#ifdef CONFIG_MSM_BUS_SCALING
if (!res_trk_update_bus_perf_level(dev_ctxt, req_perf_lvl) < 0) {
VCDRES_MSG_ERROR("%s(): update buf perf level failed\n",
@@ -592,10 +609,22 @@
} else if (req_perf_lvl <= RESTRK_1080P_720P_PERF_LEVEL) {
vidc_freq = vidc_clk_table[1];
*pn_set_perf_lvl = RESTRK_1080P_720P_PERF_LEVEL;
+ } else if (req_perf_lvl <= RESTRK_1080P_MAX_PERF_LEVEL) {
+ vidc_freq = vidc_clk_table[2];
+ *pn_set_perf_lvl = RESTRK_1080P_MAX_PERF_LEVEL;
} else {
+ vidc_freq = vidc_clk_table[3];
+ *pn_set_perf_lvl = RESTRK_1080P_TURBO_PERF_LEVEL;
+ }
+
+ if (resource_context.vidc_platform_data->disable_turbo &&
+ *pn_set_perf_lvl == RESTRK_1080P_TURBO_PERF_LEVEL) {
+ VCDRES_MSG_ERROR("Warning: Turbo mode not supported "
+ " falling back to 1080p clocks\n");
vidc_freq = vidc_clk_table[2];
*pn_set_perf_lvl = RESTRK_1080P_MAX_PERF_LEVEL;
}
+
resource_context.perf_level = *pn_set_perf_lvl;
VCDRES_MSG_MED("VIDC: vidc_freq = %u, req_perf_lvl = %u\n",
vidc_freq, req_perf_lvl);
@@ -969,6 +998,9 @@
case VCD_PERF_LEVEL2:
res_trk_perf_level = RESTRK_1080P_MAX_PERF_LEVEL;
break;
+ case VCD_PERF_LEVEL_TURBO:
+ res_trk_perf_level = RESTRK_1080P_TURBO_PERF_LEVEL;
+ break;
default:
VCD_MSG_ERROR("Invalid perf level: %d\n", perf_level);
res_trk_perf_level = -EINVAL;
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
index bf8607d..d5e656b 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
@@ -28,6 +28,7 @@
#define RESTRK_1080P_MIN_PERF_LEVEL RESTRK_1080P_VGA_PERF_LEVEL
#define RESTRK_1080P_MAX_PERF_LEVEL RESTRK_1080P_1080P_PERF_LEVEL
+#define RESTRK_1080P_TURBO_PERF_LEVEL (RESTRK_1080P_MAX_PERF_LEVEL + 1)
struct res_trk_context {
struct device *device;
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 1b77b67..67917b9 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -252,6 +252,8 @@
/* Timestamp pass-through from input frame */
venc_msg->venc_msg_info.buf.timestamp =
vcd_frame_data->time_stamp;
+ venc_msg->venc_msg_info.buf.sz =
+ vcd_frame_data->alloc_len;
/* Decoded picture width and height */
venc_msg->venc_msg_info.msgdata_size =
@@ -269,7 +271,7 @@
msm_ion_do_cache_op(client_ctx->user_ion_client,
buff_handle,
(unsigned long *) kernel_vaddr,
- (unsigned long)venc_msg->venc_msg_info.buf.len,
+ (unsigned long)venc_msg->venc_msg_info.buf.sz,
ION_IOC_CLEAN_INV_CACHES);
}
}
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index bbbe0cf2..43e8d5e 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1723,6 +1723,7 @@
struct file *file;
s32 buffer_index = -1;
u32 vcd_status = VCD_ERR_FAIL;
+ struct ion_handle *buff_handle = NULL;
struct vcd_frame_data vcd_frame;
@@ -1738,9 +1739,13 @@
memset((void *)&vcd_frame, 0,
sizeof(struct vcd_frame_data));
+ vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
+ pmem_fd, kernel_vaddr, buffer_index,
+ &buff_handle);
vcd_frame.virtual = (u8 *) kernel_vaddr;
vcd_frame.frm_clnt_data = (u32) output_frame_info->clientdata;
vcd_frame.alloc_len = output_frame_info->sz;
+ vcd_frame.buff_ion_handle = buff_handle;
vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle,
&vcd_frame);
diff --git a/include/linux/mfd/pm8xxx/mpp.h b/include/linux/mfd/pm8xxx/mpp.h
index 802948b1..2a934e5 100644
--- a/include/linux/mfd/pm8xxx/mpp.h
+++ b/include/linux/mfd/pm8xxx/mpp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -168,7 +168,7 @@
#define PM8921_MPP_DIG_LEVEL_VPH 7
/* Digital Input/Output: level [PM8821] */
-#define PM8821_MPP_DIG_LEVEL_1P8 1
+#define PM8821_MPP_DIG_LEVEL_1P8 0
#define PM8821_MPP_DIG_LEVEL_VPH 7
/* Digital Input/Output: level [PM8018] */
diff --git a/include/linux/mfd/pm8xxx/pm8821-irq.h b/include/linux/mfd/pm8xxx/pm8821-irq.h
new file mode 100644
index 0000000..af985e6
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/pm8821-irq.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+/*
+ * Qualcomm PMIC irq 8821 driver header file
+ *
+ */
+
+#ifndef __MFD_PM8821_IRQ_H
+#define __MFD_PM8821_IRQ_H
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/mfd/pm8xxx/irq.h>
+
+#ifdef CONFIG_MFD_PM8821_IRQ
+int pm8821_get_irq_stat(struct pm_irq_chip *chip, int irq);
+struct pm_irq_chip *pm8821_irq_init(struct device *dev,
+ const struct pm8xxx_irq_platform_data *pdata);
+int pm8821_irq_exit(struct pm_irq_chip *chip);
+#else
+static inline int pm8821_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+ return -ENXIO;
+}
+static inline struct pm_irq_chip *pm8821_irq_init(const struct device *dev,
+ const struct pm8xxx_irq_platform_data *pdata)
+{
+ return ERR_PTR(-ENXIO);
+}
+static inline int pm8821_irq_exit(struct pm_irq_chip *chip)
+{
+ return -ENXIO;
+}
+#endif /* CONFIG_MFD_PM8821_IRQ */
+#endif /* __MFD_PM8821_IRQ_H */
diff --git a/include/linux/mfd/pm8xxx/pm8821.h b/include/linux/mfd/pm8xxx/pm8821.h
index 850e8c1..7ed7617 100644
--- a/include/linux/mfd/pm8xxx/pm8821.h
+++ b/include/linux/mfd/pm8xxx/pm8821.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,14 +19,19 @@
#define __MFD_PM8821_H
#include <linux/device.h>
-#include <linux/mfd/pm8xxx/irq.h>
+#include <linux/mfd/pm8xxx/pm8821-irq.h>
#include <linux/mfd/pm8xxx/mpp.h>
-#define PM8821_NR_IRQS (64)
+#define PM8821_NR_IRQS (112)
#define PM8821_NR_MPPS (4)
-#define PM8821_MPP_BLOCK_START (16)
-#define PM8821_IRQ_BLOCK_BIT(block, bit) ((block) * 8 + (bit))
+#define PM8821_MPP_BLOCK_START (4)
+
+/*
+ * Block 0 does not exist in PM8821 IRQ SSBI address space,
+ * IRQ0 is assigned to bit0 of block1
+ */
+#define PM8821_IRQ_BLOCK_BIT(block, bit) ((block-1) * 8 + (bit))
/* MPPs [1,N] */
#define PM8821_MPP_IRQ(base, mpp) ((base) + \
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index a0af4b5..f757fae 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -99,6 +99,7 @@
MDP_YCRCB_H1V1, /* YCrCb interleave */
MDP_YCBCR_H1V1, /* YCbCr interleave */
MDP_IMGTYPE_LIMIT,
+ MDP_RGB_BORDERFILL, /* border fill pipe */
MDP_BGR_565 = MDP_IMGTYPE2_START, /* BGR 565 planer */
MDP_FB_FORMAT, /* framebuffer format */
MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index e2a0392..f8329dd 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -335,6 +335,7 @@
unsigned long lpm_flags;
#define PHY_PWR_COLLAPSED BIT(0)
#define PHY_RETENTIONED BIT(1)
+#define XO_SHUTDOWN BIT(2)
int reset_counter;
unsigned long b_last_se0_sess;
unsigned long tmouts;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 0cd570b..f6f3c1e 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -401,6 +401,7 @@
#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
#define V4L2_PIX_FMT_DIVX_311 v4l2_fourcc('D', 'I', 'V', '3') /* DIVX311 */
#define V4L2_PIX_FMT_DIVX v4l2_fourcc('D', 'I', 'V', 'X') /* DIVX */
+#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* ON2 VP8 stream */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -1643,6 +1644,10 @@
#define V4L2_CID_MPEG_QCOM_BASE (V4L2_CTRL_CLASS_MPEG | 0x2100)
#define V4L2_CID_MPEG_QCOM_SET_PERF_LEVEL (V4L2_CID_MPEG_QCOM_BASE + 0)
+enum v3l2_mpeg_qcom_perf_level {
+ V4L2_CID_MPEG_QCOM_PERF_LEVEL_PERFORMANCE = 0,
+ V4L2_CID_MPEG_QCOM_PERF_LEVEL_TURBO = 1,
+};
#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY (V4L2_CID_MPEG_MFC51_BASE+0)
#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE (V4L2_CID_MPEG_MFC51_BASE+1)
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 03951ce..2a21336 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -5,3 +5,4 @@
header-y += msm_isp.h
header-y += msm_gemini.h
header-y += msm_gestures.h
+header-y += msm_mercury.h
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index cd00800..37d2343 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -99,6 +99,7 @@
VCD_PERF_LEVEL0,
VCD_PERF_LEVEL1,
VCD_PERF_LEVEL2,
+ VCD_PERF_LEVEL_TURBO,
};
#define VCD_METADATA_DATANONE 0x001
diff --git a/include/media/msm_mercury.h b/include/media/msm_mercury.h
new file mode 100644
index 0000000..1d14724
--- /dev/null
+++ b/include/media/msm_mercury.h
@@ -0,0 +1,119 @@
+#ifndef __LINUX_MSM_MERCURY_H
+#define __LINUX_MSM_MERCURY_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define MSM_MERCURY_HW_VERSION_REG 0x0004/* this offset does not exist in HW*/
+
+#define OUTPUT_H2V1 0
+#define OUTPUT_H2V2 1
+#define OUTPUT_BYTE 6
+
+#define MSM_MERCURY_MODE_REALTIME_ENCODE 0
+#define MSM_MERCURY_MODE_OFFLINE_ENCODE 1
+#define MSM_MERCURY_MODE_REALTIME_ROTATION 2
+#define MSM_MERCURY_MODE_OFFLINE_ROTATION 3
+
+#define MSM_MERCURY_EVT_RESET 1
+#define MSM_MERCURY_EVT_FRAMEDONE 2
+#define MSM_MERCURY_EVT_ERR 3
+#define MSM_MERCURY_EVT_UNBLOCK 4
+
+#define MSM_MERCURY_HW_CMD_TYPE_READ 0
+#define MSM_MERCURY_HW_CMD_TYPE_WRITE 1
+#define MSM_MERCURY_HW_CMD_TYPE_WRITE_OR 2
+#define MSM_MERCURY_HW_CMD_TYPE_UWAIT 3
+#define MSM_MERCURY_HW_CMD_TYPE_MWAIT 4
+#define MSM_MERCURY_HW_CMD_TYPE_MDELAY 5
+#define MSM_MERCURY_HW_CMD_TYPE_UDELAY 6
+
+#define MSM_MCR_IOCTL_MAGIC 'g'
+
+#define MSM_MCR_IOCTL_GET_HW_VERSION \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 1, struct msm_mercury_hw_cmd *)
+
+#define MSM_MCR_IOCTL_RESET \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 2, struct msm_mercury_ctrl_cmd *)
+
+#define MSM_MCR_IOCTL_STOP \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 3, struct msm_mercury_hw_cmds *)
+
+#define MSM_MCR_IOCTL_START \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 4, struct msm_mercury_hw_cmds *)
+
+#define MSM_MCR_IOCTL_INPUT_BUF_CFG \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 5, struct msm_mercury_buf *)
+
+#define MSM_MCR_IOCTL_INPUT_GET \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 6, struct msm_mercury_buf *)
+
+#define MSM_MCR_IOCTL_INPUT_GET_UNBLOCK \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 7, int)
+
+#define MSM_MCR_IOCTL_OUTPUT_BUF_CFG \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 8, struct msm_mercury_buf *)
+
+#define MSM_MCR_IOCTL_OUTPUT_GET \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 9, struct msm_mercury_buf *)
+
+#define MSM_MCR_IOCTL_OUTPUT_GET_UNBLOCK \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 10, int)
+
+#define MSM_MCR_IOCTL_EVT_GET \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 11, struct msm_mercury_ctrl_cmd *)
+
+#define MSM_MCR_IOCTL_EVT_GET_UNBLOCK \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 12, int)
+
+#define MSM_MCR_IOCTL_HW_CMD \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 13, struct msm_mercury_hw_cmd *)
+
+#define MSM_MCR_IOCTL_HW_CMDS \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 14, struct msm_mercury_hw_cmds *)
+
+#define MSM_MCR_IOCTL_TEST_DUMP_REGION \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 15, unsigned long)
+
+struct msm_mercury_ctrl_cmd {
+ uint32_t type;
+ uint32_t len;
+ void *value;
+};
+
+struct msm_mercury_buf {
+ uint32_t type;
+ int fd;
+ void *vaddr;
+ uint32_t y_off;
+ uint32_t y_len;
+ uint32_t framedone_len;
+ uint32_t cbcr_off;
+ uint32_t cbcr_len;
+ uint32_t num_of_mcu_rows;
+ uint32_t offset;
+};
+
+struct msm_mercury_hw_cmd {
+
+ uint32_t type:4;
+ /* n microseconds of timeout for WAIT */
+ /* n microseconds of time for DELAY */
+ /* repeat n times for READ/WRITE */
+ /* max is 0xFFF, 4095 */
+ uint32_t n:12;
+ uint32_t offset:16;
+ uint32_t mask;
+ union {
+ /* for single READ/WRITE/WAIT, n = 1 */
+ uint32_t data;
+ uint32_t *pdata;/* for multiple READ/WRITE/WAIT, n > 1 */
+ };
+};
+
+struct msm_mercury_hw_cmds {
+ uint32_t m; /* number of elements in the hw_cmd array */
+ struct msm_mercury_hw_cmd hw_cmd[1];
+};
+
+#endif /* __LINUX_MSM_MERCURY_H */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 96795a3..ec8d73e 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -59,6 +59,9 @@
#define INT_FM_TX 0x3005 /* index = 29 */
#define RT_PROXY_PORT_001_RX 0x2000 /* index = 30 */
#define RT_PROXY_PORT_001_TX 0x2001 /* index = 31 */
+#define SECONDARY_PCM_RX 12 /* index = 32 */
+#define SECONDARY_PCM_TX 13 /* index = 33 */
+
#define AFE_PORT_INVALID 0xFFFF
#define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
diff --git a/include/sound/q6afe.h b/include/sound/q6afe.h
index 8cdcc18..f93af1f 100644
--- a/include/sound/q6afe.h
+++ b/include/sound/q6afe.h
@@ -68,6 +68,8 @@
IDX_INT_FM_TX = 29,
IDX_RT_PROXY_PORT_001_RX = 30,
IDX_RT_PROXY_PORT_001_TX = 31,
+ IDX_SECONDARY_PCM_RX = 32,
+ IDX_SECONDARY_PCM_TX = 33,
AFE_MAX_PORTS
};
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 54a9187..ee90797 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -81,7 +81,8 @@
#define SESSION_MAX 0x08
#define SOFT_PAUSE_PERIOD 30 /* ramp up/down for 30ms */
-#define SOFT_PAUSE_STEP 2000 /* Step value 2ms or 2000us */
+#define SOFT_PAUSE_STEP_LINEAR 0 /* Step value 0ms or 0us */
+#define SOFT_PAUSE_STEP 2000 /* Step value 2000ms or 2000us */
enum {
SOFT_PAUSE_CURVE_LINEAR = 0,
SOFT_PAUSE_CURVE_EXP,
@@ -89,7 +90,8 @@
};
#define SOFT_VOLUME_PERIOD 30 /* ramp up/down for 30ms */
-#define SOFT_VOLUME_STEP 2000 /* Step value 2ms or 2000us */
+#define SOFT_VOLUME_STEP_LINEAR 0 /* Step value 0ms or 0us */
+#define SOFT_VOLUME_STEP 2000 /* Step value 2000ms or 2000us */
enum {
SOFT_VOLUME_CURVE_LINEAR = 0,
SOFT_VOLUME_CURVE_EXP,
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index c5dbdae..94bdd27 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -257,6 +257,23 @@
struct sitar_priv *debug_sitar_priv;
#endif
+static int sitar_get_anc_slot(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ ucontrol->value.integer.value[0] = sitar->anc_slot;
+ return 0;
+}
+
+static int sitar_put_anc_slot(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ sitar->anc_slot = ucontrol->value.integer.value[0];
+ return 0;
+}
static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -536,6 +553,9 @@
SOC_SINGLE("MICBIAS1 CAPLESS Switch", SITAR_A_MICB_1_CTL, 4, 1, 1),
SOC_SINGLE("MICBIAS2 CAPLESS Switch", SITAR_A_MICB_2_CTL, 4, 1, 1),
+ SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, sitar_get_anc_slot,
+ sitar_put_anc_slot),
+
SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
@@ -633,11 +653,11 @@
};
static const char *dec1_mux_text[] = {
- "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANCFB1",
+ "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANC1_FB",
};
static const char *dec2_mux_text[] = {
- "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANCFB2",
+ "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANC2_FB",
};
static const char *dec3_mux_text[] = {
@@ -648,6 +668,15 @@
"ZERO", "DMIC4", "ADC1", "ADC2", "ADC3", "DMIC3", "DMIC2", "DMIC1"
};
+static const char const *anc_mux_text[] = {
+ "ZERO", "ADC1", "ADC2", "ADC3", "RSVD1", "RSVD2", "RSVD3",
+ "MBADC", "RSVD4", "DMIC1", "DMIC2", "DMIC3", "DMIC4"
+};
+
+static const char const *anc1_fb_mux_text[] = {
+ "ZERO", "EAR_HPH_L", "EAR_LINE_1",
+};
+
static const char *iir1_inp1_text[] = {
"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
"ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
@@ -710,6 +739,15 @@
static const struct soc_enum dec4_mux_enum =
SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 3, 8, dec4_mux_text);
+static const struct soc_enum anc1_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 0, 13, anc_mux_text);
+
+static const struct soc_enum anc2_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 4, 13, anc_mux_text);
+
+static const struct soc_enum anc1_fb_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
+
static const struct soc_enum iir1_inp1_mux_enum =
SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir1_inp1_text);
@@ -773,6 +811,15 @@
static const struct snd_kcontrol_new iir1_inp1_mux =
SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+static const struct snd_kcontrol_new anc1_mux =
+ SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
+
+static const struct snd_kcontrol_new anc2_mux =
+ SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
+
+static const struct snd_kcontrol_new anc1_fb_mux =
+ SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
+
static const struct snd_kcontrol_new dac1_switch[] = {
SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
};
@@ -803,27 +850,39 @@
{
struct snd_soc_codec *codec = w->codec;
u16 adc_reg;
+ u8 init_bit_shift;
pr_debug("%s %d\n", __func__, event);
if (w->reg == SITAR_A_TX_1_2_EN)
adc_reg = SITAR_A_TX_1_2_TEST_CTL;
+ else if (w->reg == SITAR_A_TX_3_EN)
+ adc_reg = SITAR_A_TX_3_TEST_CTL;
else {
pr_err("%s: Error, invalid adc register\n", __func__);
return -EINVAL;
}
+ if (w->shift == 3)
+ init_bit_shift = 6;
+ else if (w->shift == 7)
+ init_bit_shift = 7;
+ else {
+ pr_err("%s: Error, invalid init bit postion adc register\n",
+ __func__);
+ return -EINVAL;
+ }
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
sitar_codec_enable_adc_block(codec, 1);
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+ 1 << init_bit_shift);
break;
case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
- 1 << w->shift);
- usleep_range(1000, 1000);
- snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
- usleep_range(1000, 1000);
- snd_soc_update_bits(codec, adc_reg, 0x08, 0x08);
+
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+
break;
case SND_SOC_DAPM_POST_PMD:
sitar_codec_enable_adc_block(codec, 0);
@@ -949,6 +1008,115 @@
return 0;
}
+static int sitar_codec_enable_anc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ const char *filename;
+ const struct firmware *fw;
+ int i;
+ int ret;
+ int num_anc_slots;
+ struct anc_header *anc_head;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ u32 anc_writes_size = 0;
+ int anc_size_remaining;
+ u32 *anc_ptr;
+ u16 reg;
+ u8 mask, val, old_val;
+
+ pr_debug("%s %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ /* Use the same firmware file as that of WCD9310,
+ * since the register sequences are same for
+ * WCD9310 and WCD9304
+ */
+ filename = "wcd9310/wcd9310_anc.bin";
+
+ ret = request_firmware(&fw, filename, codec->dev);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
+ ret);
+ return -ENODEV;
+ }
+
+ if (fw->size < sizeof(struct anc_header)) {
+ dev_err(codec->dev, "Not enough data\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ /* First number is the number of register writes */
+ anc_head = (struct anc_header *)(fw->data);
+ anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
+ anc_size_remaining = fw->size - sizeof(struct anc_header);
+ num_anc_slots = anc_head->num_anc_slots;
+
+ if (sitar->anc_slot >= num_anc_slots) {
+ dev_err(codec->dev, "Invalid ANC slot selected\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_anc_slots; i++) {
+
+ if (anc_size_remaining < SITAR_PACKED_REG_SIZE) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+ anc_writes_size = (u32)(*anc_ptr);
+ anc_size_remaining -= sizeof(u32);
+ anc_ptr += 1;
+
+ if (anc_writes_size * SITAR_PACKED_REG_SIZE
+ > anc_size_remaining) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ if (sitar->anc_slot == i)
+ break;
+
+ anc_size_remaining -= (anc_writes_size *
+ SITAR_PACKED_REG_SIZE);
+ anc_ptr += anc_writes_size;
+ }
+ if (i == num_anc_slots) {
+ dev_err(codec->dev, "Selected ANC slot not present\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < anc_writes_size; i++) {
+ SITAR_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
+ mask, val);
+ old_val = snd_soc_read(codec, reg);
+ snd_soc_write(codec, reg, (old_val & ~mask) |
+ (val & mask));
+ }
+
+ release_firmware(fw);
+
+ /* For Sitar, it is required to enable both Feed-forward
+ * and Feed back clocks to enable ANC
+ */
+ snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x0F);
+
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
+ snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x00);
+ break;
+ }
+ return 0;
+}
+
+
static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
@@ -1708,6 +1876,15 @@
SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
&dec4_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
+ SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
+
+ SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
+ sitar_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
+
SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
@@ -1774,6 +1951,10 @@
{"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
{"LINEOUT1 DAC", NULL, "DAC2 MUX"},
+ {"ANC1 FB MUX", "EAR_HPH_L", "RX2 MIX1"},
+ {"ANC1 FB MUX", "EAR_LINE_1", "RX3 MIX1"},
+ {"ANC", NULL, "ANC1 FB MUX"},
+
/* Headset (RX MIX1 and RX MIX2) */
{"HEADPHONE", NULL, "HPHL"},
@@ -1805,6 +1986,21 @@
{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+ /* ANC */
+ {"ANC", NULL, "ANC1 MUX"},
+ {"ANC", NULL, "ANC2 MUX"},
+ {"ANC1 MUX", "ADC1", "ADC1"},
+ {"ANC1 MUX", "ADC2", "ADC2"},
+ {"ANC1 MUX", "ADC3", "ADC3"},
+ {"ANC2 MUX", "ADC1", "ADC1"},
+ {"ANC2 MUX", "ADC2", "ADC2"},
+ {"ANC2 MUX", "ADC3", "ADC3"},
+
+ {"ANC", NULL, "CDC_CONN"},
+
+ {"RX2 MIX1", NULL, "ANC"},
+ {"RX3 MIX1", NULL, "ANC"},
+
/* SLIMBUS Connections */
/* Slimbus port 5 is non functional in Sitar 1.0 */
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index f48bab9..8c45f8a 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -67,7 +67,8 @@
SLIM_1_TX_1 = 146, /* BT-SCO and USB 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_3_TX_1 = 153, /* HDMI RX */
+ SLIM_3_TX_2 = 154, /* 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 */
@@ -1031,6 +1032,7 @@
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};
+ unsigned int tx_ch[2] = {SLIM_3_TX_1, SLIM_3_TX_2};
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
pr_debug("%s: slim_3_rx_ch %d, sch %d %d\n",
@@ -1046,7 +1048,16 @@
goto end;
}
} else {
- pr_err("%s: SLIMBUS_3_TX not defined for this DAI\n", __func__);
+ pr_debug("%s: MDM RX -> SLIMBUS_3_TX -> APQ HDMI ch: %d, %d\n",
+ __func__, tx_ch[0], tx_ch[1]);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 2, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: Erorr %d setting SLIM_3 TX channel map\n",
+ __func__, ret);
+
+ goto end;
+ }
}
end:
@@ -1243,6 +1254,22 @@
return 0;
}
+static int msm_slim_3_tx_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 = 2;
+
+ return 0;
+}
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1870,6 +1897,18 @@
.ops = &msm_slimbus_3_be_ops,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
},
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_slim_3_tx_be_hw_params_fixup,
+ .ops = &msm_slimbus_3_be_ops,
+ },
};
struct snd_soc_card snd_soc_card_msm = {
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 41a9c48..363635f 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -47,10 +47,15 @@
#define TOP_SPK_AMP_POS 0x4
#define TOP_SPK_AMP_NEG 0x8
-#define GPIO_AUX_PCM_DOUT 63
-#define GPIO_AUX_PCM_DIN 64
-#define GPIO_AUX_PCM_SYNC 65
-#define GPIO_AUX_PCM_CLK 66
+#define GPIO_AUX_PCM_DOUT 23
+#define GPIO_AUX_PCM_DIN 22
+#define GPIO_AUX_PCM_SYNC 21
+#define GPIO_AUX_PCM_CLK 20
+
+#define GPIO_SEC_AUX_PCM_DOUT 28
+#define GPIO_SEC_AUX_PCM_DIN 27
+#define GPIO_SEC_AUX_PCM_SYNC 26
+#define GPIO_SEC_AUX_PCM_CLK 25
#define TABLA_EXT_CLK_RATE 12288000
@@ -144,6 +149,9 @@
#define LPA_IF_REG_BASE (LPA_IF_BASE + 0x00000000)
#define LPASS_SIF_MUX_ADDR (SIF_MUX_REG_BASE + 0x00004000)
#define LPAIF_SPARE_ADDR (LPA_IF_REG_BASE + 0x00000070)
+#define SEC_PCM_PORT_SLC_ADDR 0x00802074
+/* bits 2:0 should be updated with 100 to select SDC2 */
+#define SEC_PCM_PORT_SLC_VALUE 0x4
/* SIF & SPARE MUX Values */
#define MSM_SIF_FUNC_PCM 0
#define MSM_SIF_FUNC_I2S_MIC 1
@@ -168,6 +176,7 @@
static int msm9615_i2s_rx_ch = 1;
static int msm9615_i2s_tx_ch = 1;
static int msm9615_i2s_spk_control;
+
/* SIF mux bit mask & shift */
#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK 0x30000
#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT 0x10
@@ -182,6 +191,8 @@
static u32 spare_shadow;
static u32 sif_shadow;
+static atomic_t msm9615_auxpcm_ref;
+static atomic_t msm9615_sec_auxpcm_ref;
struct msm_i2s_mux_ctl {
const u8 sifconfig;
@@ -240,6 +251,10 @@
static u32 top_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(3);
static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
+
+void *sif_virt_addr;
+void *secpcm_portslc_virt_addr;
+
static int mdm9615_spk_control;
static int mdm9615_ext_bottom_spk_pamp;
static int mdm9615_ext_top_spk_pamp;
@@ -1601,6 +1616,63 @@
return 0;
}
+static int mdm9615_sec_aux_pcm_get_gpios(void)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ ret = gpio_request(GPIO_SEC_AUX_PCM_DOUT, "SEC_AUX PCM DOUT");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM DOUT",
+ __func__, GPIO_SEC_AUX_PCM_DOUT);
+ goto fail_dout;
+ }
+
+ ret = gpio_request(GPIO_SEC_AUX_PCM_DIN, "SEC_AUX PCM DIN");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM DIN",
+ __func__, GPIO_SEC_AUX_PCM_DIN);
+ goto fail_din;
+ }
+
+ ret = gpio_request(GPIO_SEC_AUX_PCM_SYNC, "SEC_AUX PCM SYNC");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM SYNC",
+ __func__, GPIO_SEC_AUX_PCM_SYNC);
+ goto fail_sync;
+ }
+
+ ret = gpio_request(GPIO_SEC_AUX_PCM_CLK, "SEC_AUX PCM CLK");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM CLK",
+ __func__, GPIO_SEC_AUX_PCM_CLK);
+ goto fail_clk;
+ }
+
+ return 0;
+
+fail_clk:
+ gpio_free(GPIO_SEC_AUX_PCM_SYNC);
+fail_sync:
+ gpio_free(GPIO_SEC_AUX_PCM_DIN);
+fail_din:
+ gpio_free(GPIO_SEC_AUX_PCM_DOUT);
+fail_dout:
+
+ return ret;
+}
+
+static int mdm9615_sec_aux_pcm_free_gpios(void)
+{
+ gpio_free(GPIO_SEC_AUX_PCM_DIN);
+ gpio_free(GPIO_SEC_AUX_PCM_DOUT);
+ gpio_free(GPIO_SEC_AUX_PCM_SYNC);
+ gpio_free(GPIO_SEC_AUX_PCM_CLK);
+
+ return 0;
+}
+
static int mdm9615_startup(struct snd_pcm_substream *substream)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -1608,15 +1680,37 @@
return 0;
}
+void msm9615_config_sif_mux(u8 value)
+{
+ u32 sif_shadow = 0x00000;
+
+ sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_SEC_MUX_SEL_BMSK) |
+ (value << LPASS_SIF_MUX_CTL_SEC_MUX_SEL_SHFT);
+ iowrite32(sif_shadow, sif_virt_addr);
+ /* Dont read SIF register. Device crashes. */
+ pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_shadow);
+}
+
+void msm9615_config_port_select(void)
+{
+ pr_debug("%s() port select defualt = 0x%x\n",
+ __func__, ioread32(secpcm_portslc_virt_addr));
+ iowrite32(SEC_PCM_PORT_SLC_VALUE, secpcm_portslc_virt_addr);
+ pr_debug("%s() port select after updating = 0x%x\n",
+ __func__, ioread32(secpcm_portslc_virt_addr));
+}
+
static int mdm9615_auxpcm_startup(struct snd_pcm_substream *substream)
{
int ret = 0;
pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = mdm9615_aux_pcm_get_gpios();
- if (ret < 0) {
- pr_err("%s: Aux PCM GPIO request failed\n", __func__);
- return -EINVAL;
+ if (atomic_inc_return(&msm9615_auxpcm_ref) == 1) {
+ ret = mdm9615_aux_pcm_get_gpios();
+ if (ret < 0) {
+ pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+ return -EINVAL;
+ }
}
return 0;
}
@@ -1625,7 +1719,33 @@
{
pr_debug("%s(): substream = %s\n", __func__, substream->name);
- mdm9615_aux_pcm_free_gpios();
+ if (atomic_dec_return(&msm9615_auxpcm_ref) == 0)
+ mdm9615_aux_pcm_free_gpios();
+}
+
+static int mdm9615_sec_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s\n", __func__, substream->name);
+ if (atomic_inc_return(&msm9615_sec_auxpcm_ref) == 1) {
+ ret = mdm9615_sec_aux_pcm_get_gpios();
+ if (ret < 0) {
+ pr_err("%s: SEC Aux PCM GPIO request failed\n",
+ __func__);
+ return -EINVAL;
+ }
+ msm9615_config_sif_mux(MSM_SIF_FUNC_PCM);
+ msm9615_config_port_select();
+ }
+ return 0;
+}
+
+static void mdm9615_sec_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s(): substream = %s\n", __func__, substream->name);
+ if (atomic_dec_return(&msm9615_sec_auxpcm_ref) == 0)
+ mdm9615_sec_aux_pcm_free_gpios();
}
static void mdm9615_shutdown(struct snd_pcm_substream *substream)
@@ -1645,6 +1765,12 @@
.shutdown = mdm9615_auxpcm_shutdown,
};
+static struct snd_soc_ops mdm9615_sec_auxpcm_be_ops = {
+ .startup = mdm9615_sec_auxpcm_startup,
+ .shutdown = mdm9615_sec_auxpcm_shutdown,
+};
+
+
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link mdm9615_dai_common[] = {
/* FrontEnd DAI Links */
@@ -1823,8 +1949,34 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
+ .ops = &mdm9615_auxpcm_be_ops,
},
+ /* SECONDARY AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_SEC_AUXPCM_RX,
+ .stream_name = "SEC AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6.12",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ .be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
+ .ops = &mdm9615_sec_auxpcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SEC_AUXPCM_TX,
+ .stream_name = "SEC AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6.13",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ .be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
+ .ops = &mdm9615_sec_auxpcm_be_ops,
+ },
};
static struct snd_soc_dai_link mdm9615_dai_i2s_tabla[] = {
@@ -2000,7 +2152,12 @@
snd_soc_card_mdm9615.dai_link = mdm9615_i2s_dai;
snd_soc_card_mdm9615.num_links =
ARRAY_SIZE(mdm9615_i2s_dai);
+ } else{
+ snd_soc_card_mdm9615.dai_link = mdm9615_dai_common;
+ snd_soc_card_mdm9615.num_links =
+ ARRAY_SIZE(mdm9615_dai_common);
}
+
platform_set_drvdata(mdm9615_snd_device, &snd_soc_card_mdm9615);
ret = platform_device_add(mdm9615_snd_device);
if (ret) {
@@ -2014,11 +2171,14 @@
} else
mdm9615_headset_gpios_configured = 1;
+ atomic_set(&msm9615_auxpcm_ref, 0);
+ atomic_set(&msm9615_sec_auxpcm_ref, 0);
msm9x15_i2s_ctl.sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
msm9x15_i2s_ctl.spare_virt_addr = ioremap(LPAIF_SPARE_ADDR, 4);
+ sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
+ secpcm_portslc_virt_addr = ioremap(SEC_PCM_PORT_SLC_ADDR, 4);
return ret;
-
}
module_init(mdm9615_audio_init);
@@ -2033,6 +2193,8 @@
kfree(mbhc_cfg.calibration);
iounmap(msm9x15_i2s_ctl.sif_virt_addr);
iounmap(msm9x15_i2s_ctl.spare_virt_addr);
+ iounmap(sif_virt_addr);
+ iounmap(secpcm_portslc_virt_addr);
}
module_exit(mdm9615_audio_exit);
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index e5bc922..b3e5120 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -48,9 +48,11 @@
};
static struct clk *pcm_clk;
+static struct clk *sec_pcm_clk;
static DEFINE_MUTEX(aux_pcm_mutex);
static int aux_pcm_count;
static struct msm_dai_auxpcm_pdata *auxpcm_plat_data;
+static struct msm_dai_auxpcm_pdata *sec_auxpcm_plat_data;
static int msm_dai_q6_mi2s_format_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -558,6 +560,48 @@
return 0;
}
+static int msm_dai_q6_sec_auxpcm_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata =
+ (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+
+ pr_debug("%s\n", __func__);
+ if (params_channels(params) != 1) {
+ dev_err(dai->dev, "SEC AUX PCM supports only mono stream\n");
+ return -EINVAL;
+ }
+ dai_data->channels = params_channels(params);
+
+ dai_data->rate = params_rate(params);
+ switch (dai_data->rate) {
+ case 8000:
+ dai_data->port_config.pcm.mode = auxpcm_pdata->mode_8k.mode;
+ dai_data->port_config.pcm.sync = auxpcm_pdata->mode_8k.sync;
+ dai_data->port_config.pcm.frame = auxpcm_pdata->mode_8k.frame;
+ dai_data->port_config.pcm.quant = auxpcm_pdata->mode_8k.quant;
+ dai_data->port_config.pcm.slot = auxpcm_pdata->mode_8k.slot;
+ dai_data->port_config.pcm.data = auxpcm_pdata->mode_8k.data;
+ break;
+ case 16000:
+ dai_data->port_config.pcm.mode = auxpcm_pdata->mode_16k.mode;
+ dai_data->port_config.pcm.sync = auxpcm_pdata->mode_16k.sync;
+ dai_data->port_config.pcm.frame = auxpcm_pdata->mode_16k.frame;
+ dai_data->port_config.pcm.quant = auxpcm_pdata->mode_16k.quant;
+ dai_data->port_config.pcm.slot = auxpcm_pdata->mode_16k.slot;
+ dai_data->port_config.pcm.data = auxpcm_pdata->mode_16k.data;
+ break;
+ default:
+ dev_err(dai->dev, "AUX PCM supports only 8kHz and 16kHz sampling rate\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
@@ -606,6 +650,7 @@
case SLIMBUS_1_TX:
case SLIMBUS_2_RX:
case SLIMBUS_2_TX:
+ case SLIMBUS_3_TX:
case SLIMBUS_4_RX:
case SLIMBUS_4_TX:
rc = msm_dai_q6_slim_bus_hw_params(params, dai,
@@ -682,6 +727,52 @@
mutex_unlock(&aux_pcm_mutex);
}
+static void msm_dai_q6_sec_auxpcm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int rc = 0;
+
+ pr_debug("%s\n", __func__);
+ mutex_lock(&aux_pcm_mutex);
+
+ if (aux_pcm_count == 0) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
+ " return\n", __func__, dai->id);
+ mutex_unlock(&aux_pcm_mutex);
+ return;
+ }
+
+ aux_pcm_count--;
+
+ if (aux_pcm_count > 0) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
+ __func__, dai->id, aux_pcm_count);
+ mutex_unlock(&aux_pcm_mutex);
+ return;
+ } else if (aux_pcm_count < 0) {
+ dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+ " aux_pcm_count = %d < 0\n",
+ __func__, dai->id, aux_pcm_count);
+ aux_pcm_count = 0;
+ mutex_unlock(&aux_pcm_mutex);
+ return;
+ }
+
+ pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
+ dai->id, aux_pcm_count);
+
+ clk_disable_unprepare(sec_pcm_clk);
+ rc = afe_close(SECONDARY_PCM_RX); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
+
+ rc = afe_close(SECONDARY_PCM_TX);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUX PCM TX port\n");
+
+ mutex_unlock(&aux_pcm_mutex);
+}
+
static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -768,7 +859,7 @@
if (dai_data->rate == 8000) {
pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
} else if (dai_data->rate == 16000) {
- pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+ pcm_clk_rate = auxpcm_pdata->mode_16k.pcm_clk_rate;
} else {
dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
dai_data->rate);
@@ -789,6 +880,88 @@
return rc;
}
+static int msm_dai_q6_sec_auxpcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ int rc = 0;
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata =
+ (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+ unsigned long pcm_clk_rate;
+
+ pr_info("%s\n", __func__);
+
+ mutex_lock(&aux_pcm_mutex);
+
+ if (aux_pcm_count == 2) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
+ " return.\n", __func__, dai->id);
+ mutex_unlock(&aux_pcm_mutex);
+ return 0;
+ } else if (aux_pcm_count > 2) {
+ dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+ " aux_pcm_count = %d > 2\n",
+ __func__, dai->id, aux_pcm_count);
+ mutex_unlock(&aux_pcm_mutex);
+ return 0;
+ }
+
+ aux_pcm_count++;
+ if (aux_pcm_count == 2) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
+ " increment\n", __func__, dai->id, aux_pcm_count);
+ mutex_unlock(&aux_pcm_mutex);
+ return 0;
+ }
+
+ pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
+ __func__, dai->id, aux_pcm_count);
+
+ rc = afe_q6_interface_prepare();
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to open AFE APR\n");
+
+ /*
+ * For AUX PCM Interface the below sequence of clk
+ * settings and afe_open is a strict requirement.
+ *
+ * Also using afe_open instead of afe_port_start_nowait
+ * to make sure the port is open before deasserting the
+ * clock line. This is required because pcm register is
+ * not written before clock deassert. Hence the hw does
+ * not get updated with new setting if the below clock
+ * assert/deasset and afe_open sequence is not followed.
+ */
+
+ clk_reset(sec_pcm_clk, CLK_RESET_ASSERT);
+
+ afe_open(SECONDARY_PCM_RX, &dai_data->port_config, dai_data->rate);
+
+ afe_open(SECONDARY_PCM_TX, &dai_data->port_config, dai_data->rate);
+ if (dai_data->rate == 8000) {
+ pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+ } else if (dai_data->rate == 16000) {
+ pcm_clk_rate = auxpcm_pdata->mode_16k.pcm_clk_rate;
+ } else {
+ dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
+ dai_data->rate);
+ return -EINVAL;
+ }
+
+ rc = clk_set_rate(sec_pcm_clk, pcm_clk_rate);
+ if (rc < 0) {
+ pr_err("%s: clk_set_rate failed\n", __func__);
+ return rc;
+ }
+
+ clk_prepare_enable(sec_pcm_clk);
+ clk_reset(sec_pcm_clk, CLK_RESET_DEASSERT);
+
+ mutex_unlock(&aux_pcm_mutex);
+
+ return rc;
+}
+
static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -940,6 +1113,55 @@
return rc;
}
+static int msm_dai_q6_dai_sec_auxpcm_probe(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data;
+ int rc = 0;
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata =
+ (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+
+ pr_info("%s\n", __func__);
+
+ mutex_lock(&aux_pcm_mutex);
+
+ if (!sec_auxpcm_plat_data)
+ sec_auxpcm_plat_data = auxpcm_pdata;
+ else if (sec_auxpcm_plat_data != auxpcm_pdata) {
+ dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
+ " same platform data sec_auxpcm_plat_data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * The clk name for AUX PCM operation is passed as platform
+ * data to the cpu driver, since cpu drive is unaware of any
+ * boarc specific configuration.
+ */
+ if (!sec_pcm_clk) {
+
+ sec_pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
+ if (IS_ERR(sec_pcm_clk)) {
+ pr_err("%s: could not get sec_pcm_clk\n", __func__);
+ sec_pcm_clk = NULL;
+ return -ENODEV;
+ }
+ }
+
+ mutex_unlock(&aux_pcm_mutex);
+
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
+
+ if (!dai_data) {
+ dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
+ dai->id);
+ rc = -ENOMEM;
+ } else
+ dev_set_drvdata(dai->dev, dai_data);
+
+ pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
+ return rc;
+}
+
static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
{
struct msm_dai_q6_dai_data *dai_data;
@@ -989,6 +1211,56 @@
return 0;
}
+static int msm_dai_q6_dai_sec_auxpcm_remove(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data;
+ int rc;
+
+ pr_debug("%s\n", __func__);
+ dai_data = dev_get_drvdata(dai->dev);
+
+ mutex_lock(&aux_pcm_mutex);
+
+ if (aux_pcm_count == 0) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
+ " up and return\n", __func__, dai->id);
+ goto done;
+ }
+
+ aux_pcm_count--;
+
+ if (aux_pcm_count > 0) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
+ __func__, dai->id, aux_pcm_count);
+ goto done;
+ } else if (aux_pcm_count < 0) {
+ dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+ " aux_pcm_count = %d < 0\n",
+ __func__, dai->id, aux_pcm_count);
+ goto done;
+ }
+
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
+ "closing afe\n",
+ __func__, dai->id, aux_pcm_count);
+
+ rc = afe_close(SECONDARY_PCM_RX); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
+
+ rc = afe_close(SECONDARY_PCM_TX);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
+
+done:
+ kfree(dai_data);
+ snd_soc_unregister_dai(dai->dev);
+
+ mutex_unlock(&aux_pcm_mutex);
+
+ return 0;
+}
+
static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
{
struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
@@ -1164,6 +1436,7 @@
case SLIMBUS_0_TX:
case SLIMBUS_1_TX:
case SLIMBUS_2_TX:
+ case SLIMBUS_3_TX:
case SLIMBUS_4_TX:
/* channel number to be between 128 and 255. For RX port
* use channel numbers from 138 to 144, for TX port
@@ -1217,6 +1490,13 @@
.shutdown = msm_dai_q6_auxpcm_shutdown,
};
+static struct snd_soc_dai_ops msm_dai_q6_sec_auxpcm_ops = {
+ .prepare = msm_dai_q6_sec_auxpcm_prepare,
+ .trigger = msm_dai_q6_auxpcm_trigger,
+ .hw_params = msm_dai_q6_sec_auxpcm_hw_params,
+ .shutdown = msm_dai_q6_sec_auxpcm_shutdown,
+};
+
static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
@@ -1423,6 +1703,34 @@
.remove = msm_dai_q6_dai_auxpcm_remove,
};
+static struct snd_soc_dai_driver msm_dai_q6_sec_aux_pcm_rx_dai = {
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_sec_auxpcm_ops,
+ .probe = msm_dai_q6_dai_sec_auxpcm_probe,
+ .remove = msm_dai_q6_dai_sec_auxpcm_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_sec_aux_pcm_tx_dai = {
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_sec_auxpcm_ops,
+ .probe = msm_dai_q6_dai_sec_auxpcm_probe,
+ .remove = msm_dai_q6_dai_sec_auxpcm_remove,
+};
+
/* Channel min and max are initialized base on platform data */
static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai = {
.playback = {
@@ -1543,6 +1851,14 @@
&msm_dai_q6_aux_pcm_tx_dai);
break;
+ case SECONDARY_PCM_RX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_sec_aux_pcm_rx_dai);
+ break;
+ case SECONDARY_PCM_TX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_sec_aux_pcm_tx_dai);
+ break;
case SLIMBUS_0_RX:
case SLIMBUS_4_RX:
rc = snd_soc_register_dai(&pdev->dev,
@@ -1550,6 +1866,7 @@
break;
case SLIMBUS_0_TX:
case SLIMBUS_4_TX:
+ case SLIMBUS_3_TX:
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_slimbus_tx_dai);
break;
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index c65a7d2..3cab34f 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -109,8 +109,11 @@
break;
} else
atomic_set(&prtd->pending_buffer, 0);
- if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
- break;
+ if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
+ memset((void *)buf[0].phys +
+ (prtd->out_head * prtd->pcm_count),
+ 0, prtd->pcm_count);
+ }
pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
__func__, prtd->pcm_count);
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 7a269ca7..357a53b 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -172,9 +172,12 @@
{ 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_3_TX, 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},
+ { SECONDARY_PCM_RX, 0, 0, 0, 0, 0},
+ { SECONDARY_PCM_TX, 0, 0, 0, 0, 0},
};
@@ -1167,6 +1170,15 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
SOC_SINGLE_EXT("PRI_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -1180,6 +1192,9 @@
SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -1302,6 +1317,18 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new sec_aux_pcm_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1351,6 +1378,9 @@
SOC_SINGLE_EXT("AUX_PCM_TX_Voice", MSM_BACKEND_DAI_AUXPCM_TX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_volte_mixer_controls[] = {
@@ -1369,6 +1399,9 @@
SOC_SINGLE_EXT("AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_AUXPCM_TX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
@@ -1390,6 +1423,9 @@
SOC_SINGLE_EXT("AUX_PCM_TX_Voip", MSM_BACKEND_DAI_AUXPCM_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
@@ -1408,6 +1444,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_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[] = {
@@ -1465,6 +1504,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_HDMI_RX,
MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_BACKEND_DAI_SLIMBUS_3_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_port_mixer_controls[] = {
@@ -1817,6 +1859,10 @@
SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("AUX_PCM_TX", "AUX PCM Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_AUX_PCM_RX", "SEC AUX PCM Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_AUX_PCM_TX", "SEC AUX PCM Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOICE_STUB_DL", "VOICE_STUB Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VOICE_STUB_UL", "VOICE_STUB Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("STUB_RX", "Stub Playback", 0, 0, 0, 0),
@@ -1825,6 +1871,7 @@
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),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_3_TX", "Slimbus3 Capture", 0, 0, 0, 0),
/* Switch Definitions */
SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
@@ -1848,6 +1895,8 @@
mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_auxpcm_rx_mixer_controls, ARRAY_SIZE(sec_auxpcm_rx_mixer_controls)),
/* incall */
SND_SOC_DAPM_MIXER("Incall_Music Audio Mixer", SND_SOC_NOPM, 0, 0,
incall_music_delivery_mixer_controls,
@@ -1879,6 +1928,10 @@
SND_SOC_NOPM, 0, 0,
aux_pcm_rx_voice_mixer_controls,
ARRAY_SIZE(aux_pcm_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ sec_aux_pcm_rx_voice_mixer_controls,
+ ARRAY_SIZE(sec_aux_pcm_rx_voice_mixer_controls)),
SND_SOC_DAPM_MIXER("HDMI_RX_Voice Mixer",
SND_SOC_NOPM, 0, 0,
hdmi_rx_voice_mixer_controls,
@@ -1990,6 +2043,7 @@
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2023,6 +2077,10 @@
{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX Audio Mixer"},
+
{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
@@ -2053,6 +2111,11 @@
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
+
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
@@ -2065,12 +2128,14 @@
{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
{"Voice_Tx Mixer", "AFE_PCM_TX_Voice", "PCM_TX"},
{"Voice_Tx Mixer", "AUX_PCM_TX_Voice", "AUX_PCM_TX"},
+ {"Voice_Tx Mixer", "SEC_AUX_PCM_TX_Voice", "SEC_AUX_PCM_TX"},
{"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
{"VoLTE_Tx Mixer", "PRI_TX_VoLTE", "PRI_I2S_TX"},
{"VoLTE_Tx Mixer", "SLIM_0_TX_VoLTE", "SLIMBUS_0_TX"},
{"VoLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_VoLTE", "INT_BT_SCO_TX"},
{"VoLTE_Tx Mixer", "AFE_PCM_TX_VoLTE", "PCM_TX"},
{"VoLTE_Tx Mixer", "AUX_PCM_TX_VoLTE", "AUX_PCM_TX"},
+ {"VoLTE_Tx Mixer", "SEC_AUX_PCM_TX_VoLTE", "SEC_AUX_PCM_TX"},
{"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
{"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
@@ -2078,6 +2143,7 @@
{"Voip_Tx Mixer", "INTERNAL_BT_SCO_TX_Voip", "INT_BT_SCO_TX"},
{"Voip_Tx Mixer", "AFE_PCM_TX_Voip", "PCM_TX"},
{"Voip_Tx Mixer", "AUX_PCM_TX_Voip", "AUX_PCM_TX"},
+ {"Voip_Tx Mixer", "SEC_AUX_PCM_TX_Voip", "SEC_AUX_PCM_TX"},
{"VOIP_UL", NULL, "Voip_Tx Mixer"},
{"SLIMBUS_DL_HL", "Switch", "SLIM0_DL_HL"},
@@ -2108,6 +2174,7 @@
{"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 Tx Mixer", "MI2S_TX", "MI2S_TX"},
+ {"Voice Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -2117,6 +2184,7 @@
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
+ {"HDMI_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"},
@@ -2131,6 +2199,7 @@
{"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"HDMI_RX Port Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
{"HDMI", NULL, "HDMI_RX Port Mixer"},
{"SEC_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index ff073ce..3065861 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -26,6 +26,8 @@
#define LPASS_BE_AFE_PCM_TX "RT_PROXY_DAI_002_TX"
#define LPASS_BE_AUXPCM_RX "AUX_PCM_RX"
#define LPASS_BE_AUXPCM_TX "AUX_PCM_TX"
+#define LPASS_BE_SEC_AUXPCM_RX "SEC_AUX_PCM_RX"
+#define LPASS_BE_SEC_AUXPCM_TX "SEC_AUX_PCM_TX"
#define LPASS_BE_VOICE_PLAYBACK_TX "VOICE_PLAYBACK_TX"
#define LPASS_BE_INCALL_RECORD_RX "INCALL_RECORD_TX"
#define LPASS_BE_INCALL_RECORD_TX "INCALL_RECORD_RX"
@@ -39,6 +41,7 @@
#define LPASS_BE_SLIMBUS_1_TX "SLIMBUS_1_TX"
#define LPASS_BE_STUB_1_TX "STUB_1_TX"
#define LPASS_BE_SLIMBUS_3_RX "SLIMBUS_3_RX"
+#define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX"
#define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX"
#define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX"
@@ -90,9 +93,12 @@
MSM_BACKEND_DAI_SLIMBUS_4_RX,
MSM_BACKEND_DAI_SLIMBUS_4_TX,
MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_SLIMBUS_3_TX,
MSM_BACKEND_DAI_EXTPROC_RX,
MSM_BACKEND_DAI_EXTPROC_TX,
MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_BACKEND_DAI_MAX,
};
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 0f91665..20ac6e1 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -311,11 +311,11 @@
{"MIC BIAS2 Internal1", NULL, "Headset Mic"},
/* Microphone path */
- {"AMIC1", NULL, "MIC BIAS2 Internal1"},
- {"MIC BIAS2 Internal1", NULL, "ANCLeft Headset Mic"},
+ {"AMIC1", NULL, "MIC BIAS2 External"},
+ {"MIC BIAS2 External", NULL, "ANCLeft Headset Mic"},
- {"AMIC3", NULL, "MIC BIAS2 Internal1"},
- {"MIC BIAS2 Internal1", NULL, "ANCRight Headset Mic"},
+ {"AMIC3", NULL, "MIC BIAS2 External"},
+ {"MIC BIAS2 External", NULL, "ANCRight Headset Mic"},
{"HEADPHONE", NULL, "LDO_H"},
@@ -514,7 +514,7 @@
#undef S
#define S(X, Y) ((SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar_cal)->X) = (Y))
S(v_no_mic, 30);
- S(v_hs_max, 1550);
+ S(v_hs_max, 1650);
#undef S
#define S(X, Y) ((SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal)->X) = (Y))
S(c[0], 62);
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 51ef359..7b16adb 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -142,6 +142,7 @@
switch (port_id) {
case PRIMARY_I2S_RX:
case PCM_RX:
+ case SECONDARY_PCM_RX:
case SECONDARY_I2S_RX:
case MI2S_RX:
case HDMI_RX:
@@ -160,6 +161,7 @@
case PRIMARY_I2S_TX:
case PCM_TX:
+ case SECONDARY_PCM_TX:
case SECONDARY_I2S_TX:
case MI2S_TX:
case DIGI_MIC_TX:
@@ -167,6 +169,7 @@
case SLIMBUS_0_TX:
case SLIMBUS_1_TX:
case SLIMBUS_2_TX:
+ case SLIMBUS_3_TX:
case INT_FM_TX:
case VOICE_RECORD_RX:
case INT_BT_SCO_TX:
@@ -192,6 +195,8 @@
case PRIMARY_I2S_TX:
case PCM_RX:
case PCM_TX:
+ case SECONDARY_PCM_RX:
+ case SECONDARY_PCM_TX:
case SECONDARY_I2S_RX:
case SECONDARY_I2S_TX:
case MI2S_RX:
@@ -210,6 +215,7 @@
case SLIMBUS_2_RX:
case SLIMBUS_2_TX:
case SLIMBUS_3_RX:
+ case SLIMBUS_3_TX:
case INT_BT_SCO_RX:
case INT_BT_SCO_TX:
case INT_BT_A2DP_RX:
@@ -259,6 +265,8 @@
case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
case PCM_RX: return IDX_PCM_RX;
case PCM_TX: return IDX_PCM_TX;
+ case SECONDARY_PCM_RX: return IDX_SECONDARY_PCM_RX;
+ case SECONDARY_PCM_TX: return IDX_SECONDARY_PCM_TX;
case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
case MI2S_RX: return IDX_MI2S_RX;
@@ -277,6 +285,7 @@
case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
+ case SLIMBUS_3_TX: return IDX_SLIMBUS_3_TX;
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;
@@ -313,6 +322,7 @@
case SLIMBUS_2_RX:
case SLIMBUS_2_TX:
case SLIMBUS_3_RX:
+ case SLIMBUS_3_TX:
case SLIMBUS_4_RX:
case SLIMBUS_4_TX:
ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
@@ -323,6 +333,8 @@
break;
case PCM_RX:
case PCM_TX:
+ case SECONDARY_PCM_RX:
+ case SECONDARY_PCM_TX:
default:
ret_size = SIZEOF_CFG_CMD(afe_port_pcm_cfg);
break;