Merge "msm: mdss: Increase commit count for first kickoff"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 15b94ca..bbc9f08 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -88,6 +88,18 @@
- <consumer_supply_name>-supply = <&phandle_of_regulator>: consumer_supply_name
is the name that's defined in thermal driver.
phandle_of_regulator is defined by reuglator device tree.
+- qcom,default-temp: Default cpu temperature limit for SoC. It is an optional
+ property. Not defining this property requires a full truth
+ table for qcom,efuse temperature map and valid efuse info for
+ qcom,efuse-data otherwise feature will be disabled.
+- qcom,efuse-data: Efuse data for getting device parts info for cpu temperature
+ limit recommendation for SoC. It expects below data in order to
+ read target parts, efuse address, efuse size, row number to be
+ read, starting bit number of the row for identifying device parts
+ and number of bits to read from start bit as bit mask.
+- qcom,efuse-temperature-map: Truth table of efuse value temperature value pair for
+ different parts. if qcom,default temp is defined, then it can
+ specify only pairs which deviate from default temperature.
Optional child nodes
- qti,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request
@@ -147,6 +159,9 @@
qti,pmic-opt-curr-temp-hysteresis = <10>;
qti,pmic-opt-curr-regs = "vdd-dig";
vdd-dig-supply=<&pm8841_s2_floor_corner>
+ qcom,default-temp = <80>;
+ qcom,efuse-data = <0xfc4b8000 0x1000 23 30 0x3>;
+ qcom,efuse-temperature-map = <0x0 80>, <0x1 70>, <0x2 80>, <0x3 80>;
qcom,vdd-dig-rstr{
qcom,vdd-rstr-reg = "vdd-dig";
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index f6b4923..3144045 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -172,6 +172,8 @@
horizontal back porch (HBP) blanking period.
- qcom,mdss-dsi-hsa-power-mode: Boolean to determine DSI lane state during
horizontal sync active (HSA) mode.
+- qcom,mdss-dsi-last-line-interleave Boolean to determine if last line
+ interleave flag needs to be enabled.
- qcom,mdss-dsi-bllp-eof-power-mode: Boolean to determine DSI lane state during
blanking low power period (BLLP) EOF mode.
- qcom,mdss-dsi-bllp-power-mode: Boolean to determine DSI lane state during
@@ -347,6 +349,7 @@
qcom,mdss-dsi-hsa-power-mode;
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-last-line-interleave;
qcom,mdss-dsi-traffic-mode = <0>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-color-order = <0>;
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
index 32f6a24..3ee245e 100644
--- a/Documentation/devicetree/bindings/memory.txt
+++ b/Documentation/devicetree/bindings/memory.txt
@@ -36,6 +36,7 @@
reg = <(baseaddr) (size)>;
(linux,contiguous-region);
(linux,default-contiguous-region);
+ (linux,reserve-region);
(linux,memory-limit);
label = (unique_name);
};
@@ -49,6 +50,9 @@
linux,default-contiguous-region: property indicating that the region
is the default region for all contiguous memory
allocations, Linux specific (optional)
+linux,reserve-region: property indicating that the contiguous memory will
+ not be given back to the system allocator. The memory be
+ always be available for contiguous use.
linux,memory-limit: property specifying an upper bound on the physical address
of the region if the region is placed dynamically. If no limit
is specificed, the region may be placed anywhere in the physical
diff --git a/Documentation/devicetree/bindings/sound/voice-svc.txt b/Documentation/devicetree/bindings/sound/voice-svc.txt
index deca7f5..bb8649f 100644
--- a/Documentation/devicetree/bindings/sound/voice-svc.txt
+++ b/Documentation/devicetree/bindings/sound/voice-svc.txt
@@ -1,4 +1,6 @@
* Voice Service binding
+Provides an interface to access voice services
+exposed by DSP over APR interface.
Required properties:
- compatible : "qcom,msm-voice-svc"
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index 5201827..8eb9b64 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -27,6 +27,15 @@
should be performed during boot up.
- qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value,
using a smaller count for this buffer will reduce the memory usage.
+- qcom,wcnss-pm : <Core rail LDO#, PA rail LDO#, XO settling time,
+ RPM power collapse enabled, standalone power collapse enabled>
+ Power manager related parameter for LDO configuration.
+ 11 - WCN CORE rail LDO number
+ 21 - WCN PA rail LDO number
+ 1200 - WCN XO settling time (usec)
+ 1 - WCN RPM power collapse enabled
+ 1 - WCN standalone power collapse enabled
+
Example:
@@ -51,4 +60,5 @@
qcom,has-48mhz-xo;
qcom,has-pronto-hw;
qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
+ qcom,wcnss-pm = <11 21 1200 1 1>;
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 63a37f5..4eb26a2 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1738,6 +1738,10 @@
compatible = "qti,msm-pcm-loopback";
};
+ qcom,msm-voice-svc {
+ compatible = "qcom,msm-voice-svc";
+ };
+
qcom,msm-dai-q6 {
compatible = "qcom,msm-dai-q6";
qcom,msm-dai-q6-sb-0-rx {
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
index a44bc56..d0bf90a 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. 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
@@ -22,3 +22,29 @@
<217 0x10000>,
<218 0x10000>;
};
+
+&soc {
+ i2c@f9928000 { /* BLSP1 QUP6 */
+ nfc-nci@e {
+ compatible = "qcom,nfc-nci";
+ reg = <0x0e>;
+ qcom,irq-gpio = <&msmgpio 57 0x00>;
+ qcom,dis-gpio = <&msmgpio 13 0x00>;
+ qcom,clk-src = "BBCLK2";
+ interrupt-parent = <&msmgpio>;
+ interrupts = <57 0>;
+ qcom,clk-gpio = <&pm8941_gpios 32 0>;
+ };
+ };
+};
+
+&pm8941_gpios {
+ gpio@df00 {
+ /* NFC clk request */
+ qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index d398f72..bb4c619 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -1593,12 +1593,12 @@
<26 512 0 3680000>, <89 604 0 6224000>,
/* Nominal / Nominal */
<26 512 0 4912000>, <89 604 0 6224000>,
- /* low Turbo / Nominal */
- <26 512 0 6400000>, <89 604 0 6224000>,
+ /* Turbo / Nominal */
+ <26 512 0 7464000>, <89 604 0 6224000>,
+ /* low Nominal / low Turbo */
+ <26 512 0 3680000>, <89 604 0 7398000>,
/* Nominal / low Turbo */
<26 512 0 4912000>, <89 604 0 7398000>,
- /* low Turbo / low Turbo */
- <26 512 0 6400000>, <89 604 0 7398000>,
/* Turbo / low Turbo */
<26 512 0 7464000>, <89 604 0 7398000>,
/* Nominal / Turbo */
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 6b551cd..3721809 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1837,22 +1837,6 @@
Support for receiving handset events like headset detect,
headset switch and clamshell state.
-config MSM_RMT_STORAGE_CLIENT
- depends on (ARCH_MSM && MSM_ONCRPCROUTER)
- default n
- bool "Remote Storage RPC client"
- help
- Provide RPC mechanism for remote processors to access storage
- device on apps processor.
-
-config MSM_RMT_STORAGE_CLIENT_STATS
- depends on (MSM_RMT_STORAGE_CLIENT && DEBUG_FS)
- default n
- bool "Remote storage RPC client performance statistics"
- help
- Collects performance statistics and shows this information
- through a debugfs file rmt_storage_stats.
-
config MSM_DALRPC
bool "DAL RPC support"
default n
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 5f7f0d9..c945b10 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -314,7 +314,6 @@
obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o
obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
-obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o
obj-$(CONFIG_MSM_RPM) += rpm.o rpm_resources.o
obj-$(CONFIG_MSM_LPM_TEST) += test-lpm.o
obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o lpm_levels.o
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
index 661d496..8de3d60 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
@@ -45,6 +45,28 @@
#define USM_STREAM_CMD_CLOSE 0x0001230A
+#define USM_STREAM_CMD_SET_PARAM 0x00012731
+struct usm_stream_cmd_set_param {
+ struct apr_hdr hdr;
+ u32 buf_addr_lsw;
+ u32 buf_addr_msw;
+ u32 mem_map_handle;
+ u32 buf_size;
+ u32 module_id;
+ u32 param_id;
+} __packed;
+
+#define USM_STREAM_CMD_GET_PARAM 0x00012732
+struct usm_stream_cmd_get_param {
+ struct apr_hdr hdr;
+ u32 buf_addr_lsw;
+ u32 buf_addr_msw;
+ u32 mem_map_handle;
+ u32 buf_size;
+ u32 module_id;
+ u32 param_id;
+} __packed;
+
/* Encoder configuration definitions */
#define USM_STREAM_CMD_SET_ENC_PARAM 0x0001230B
/* Decoder configuration definitions */
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index faf50d2..9944353 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -39,6 +39,15 @@
#define US_GET_VERSION _IOWR(USF_IOCTL_MAGIC, 9, \
struct us_version_info_type)
+#define US_SET_TX_STREAM_PARAM _IOW(USF_IOCTL_MAGIC, 10, \
+ struct us_stream_param_type)
+#define US_GET_TX_STREAM_PARAM _IOWR(USF_IOCTL_MAGIC, 11, \
+ struct us_stream_param_type)
+#define US_SET_RX_STREAM_PARAM _IOW(USF_IOCTL_MAGIC, 12, \
+ struct us_stream_param_type)
+#define US_GET_RX_STREAM_PARAM _IOWR(USF_IOCTL_MAGIC, 13, \
+ struct us_stream_param_type)
+
/* Special timeout values */
#define USF_NO_WAIT_TIMEOUT 0x00000000
/* Infinitive */
@@ -130,6 +139,8 @@
uint16_t params_data_size;
/* Pointer to the parameters */
uint8_t *params_data;
+/* Max size of buffer for get and set parameter */
+ uint32_t max_get_set_param_buf_size;
};
struct us_input_info_type {
@@ -273,4 +284,15 @@
char *pbuf;
};
+struct us_stream_param_type {
+/* Id of module */
+ uint32_t module_id;
+/* Id of parameter */
+ uint32_t param_id;
+/* Size of memory of the parameter buffer */
+ uint32_t buf_size;
+/* Pointer to the memory of the parameter buffer */
+ uint8_t __user *pbuf;
+};
+
#endif /* __USF_H__ */
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
index caeb79d..d95c356 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -232,7 +232,12 @@
kfree(audio);
return -ENOMEM;
}
-
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
@@ -261,11 +266,6 @@
rc = -EACCES;
goto fail;
}
- rc = audio_aio_open(audio, file);
- if (rc < 0) {
- pr_err("audio_aio_open rc=%d\n", rc);
- goto fail;
- }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_aac_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
index fc023c1..5d57293 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -91,7 +91,12 @@
kfree(audio);
return -ENOMEM;
}
-
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
@@ -119,11 +124,6 @@
rc = -EACCES;
goto fail;
}
- rc = audio_aio_open(audio, file);
- if (rc < 0) {
- pr_err("audio_aio_open rc=%d\n", rc);
- goto fail;
- }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_amrnb_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
index 256da4d..d2728b7 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -93,6 +93,12 @@
kfree(audio);
return -ENOMEM;
}
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -121,11 +127,6 @@
rc = -EACCES;
goto fail;
}
- rc = audio_aio_open(audio, file);
- if (rc < 0) {
- pr_err("audio_aio_open rc=%d\n", rc);
- goto fail;
- }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_amrwb_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
index 544bf9c..8169914 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -170,6 +170,12 @@
kfree(audio);
return -ENOMEM;
}
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -198,11 +204,6 @@
rc = -EACCES;
goto fail;
}
- rc = audio_aio_open(audio, file);
- if (rc < 0) {
- pr_err("audio_aio_open rc=%d\n", rc);
- goto fail;
- }
config_debug_fs(audio);
pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
index 3498e69..2de2178 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -99,6 +99,12 @@
kfree(audio);
return -ENOMEM;
}
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -127,11 +133,6 @@
rc = -EACCES;
goto fail;
}
- rc = audio_aio_open(audio, file);
- if (rc < 0) {
- pr_err("audio_aio_open rc=%d\n", rc);
- goto fail;
- }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_evrc_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
index d2f0270..9132486 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -98,6 +98,12 @@
kfree(audio);
return -ENOMEM;
}
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -127,11 +133,6 @@
rc = -EACCES;
goto fail;
}
- rc = audio_aio_open(audio, file);
- if (rc < 0) {
- pr_err("audio_aio_open rc=%d\n", rc);
- goto fail;
- }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_mp3_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index 0a8ce8e..ecea6d0 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -252,6 +252,12 @@
kfree(audio);
return -ENOMEM;
}
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -281,11 +287,6 @@
rc = -EACCES;
goto fail;
}
- rc = audio_aio_open(audio, file);
- if (rc < 0) {
- pr_err("audio_aio_open rc=%d\n", rc);
- goto fail;
- }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
index 4993226..acfcb65 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -104,6 +104,12 @@
kfree(audio);
return -ENOMEM;
}
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -132,11 +138,6 @@
rc = -EACCES;
goto fail;
}
- rc = audio_aio_open(audio, file);
- if (rc < 0) {
- pr_err("audio_aio_open rc=%d\n", rc);
- goto fail;
- }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_qcelp_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wma.c b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
index 5e3de86..5a64a69 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -138,6 +138,12 @@
kfree(audio);
return -ENOMEM;
}
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
@@ -166,11 +172,6 @@
rc = -EACCES;
goto fail;
}
- rc = audio_aio_open(audio, file);
- if (rc < 0) {
- pr_err("audio_aio_open rc=%d\n", rc);
- goto fail;
- }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_wma_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
index ce49cac..7d0edf0 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -198,6 +198,12 @@
return -ENOMEM;
}
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
/* open in T/NT mode */
if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
@@ -226,11 +232,6 @@
rc = -EACCES;
goto fail;
}
- rc = audio_aio_open(audio, file);
- if (rc < 0) {
- pr_err("audio_aio_open rc=%d\n", rc);
- goto fail;
- }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_wmapro_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index 7ab4ec3..58a6431 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -65,6 +65,14 @@
spinlock_t dsp_lock;
/* extended parameters, related to q6 variants */
void *ext;
+ /* physical address of parameter buffer */
+ dma_addr_t param_phys;
+ /* buffer which stores the parameter data */
+ u8 *param_buf;
+ /* size of parameter buffer */
+ uint32_t param_buf_size;
+ /* parameter buffer memory handle */
+ void *param_buf_mem_handle;
};
struct us_client {
@@ -88,6 +96,8 @@
int q6usm_cmd(struct us_client *usc, int cmd);
int q6usm_us_client_buf_alloc(unsigned int dir, struct us_client *usc,
unsigned int bufsz, unsigned int bufcnt);
+int q6usm_us_param_buf_alloc(unsigned int dir, struct us_client *usc,
+ unsigned int bufsz);
int q6usm_enc_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg);
int q6usm_dec_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg);
int q6usm_read(struct us_client *usc, uint32_t read_ind);
@@ -104,5 +114,9 @@
int q6usm_set_us_detection(struct us_client *usc,
struct usm_session_cmd_detect_info *detect_info,
uint16_t detect_info_size);
+int q6usm_set_us_stream_param(int dir, struct us_client *usc,
+ uint32_t module_id, uint32_t param_id, uint32_t buf_size);
+int q6usm_get_us_stream_param(int dir, struct us_client *usc,
+ uint32_t module_id, uint32_t param_id, uint32_t buf_size);
#endif /* __Q6_USM_H__ */
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 192aaf9..1c42020 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -27,8 +27,8 @@
#include "usfcdev.h"
/* The driver version*/
-#define DRV_VERSION "1.6.1"
-#define USF_VERSION_ID 0x0161
+#define DRV_VERSION "1.7.1"
+#define USF_VERSION_ID 0x0171
/* Standard timeout in the asynchronous ops */
#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
@@ -36,6 +36,8 @@
/* Undefined USF device */
#define USF_UNDEF_DEV_ID 0xffff
+/* TX memory mapping flag */
+#define USF_VM_READ 1
/* RX memory mapping flag */
#define USF_VM_WRITE 2
@@ -973,6 +975,13 @@
return rc;
}
+ rc = q6usm_us_param_buf_alloc(OUT, usf_xx->usc,
+ config_tx.us_xx_info.max_get_set_param_buf_size);
+ if (rc) {
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ return rc;
+ }
+
rc = q6usm_enc_cfg_blk(usf_xx->usc,
&usf_xx->encdec_cfg);
if (!rc &&
@@ -1027,6 +1036,13 @@
return rc;
}
+ rc = q6usm_us_param_buf_alloc(IN, usf_xx->usc,
+ config_rx.us_xx_info.max_get_set_param_buf_size);
+ if (rc) {
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ return rc;
+ }
+
rc = q6usm_dec_cfg_blk(usf_xx->usc,
&usf_xx->encdec_cfg);
if (rc)
@@ -1270,6 +1286,120 @@
return rc;
} /* usf_get_version */
+static int usf_set_stream_param(struct usf_xx_type *usf_xx,
+ unsigned long arg, int dir)
+{
+ struct us_stream_param_type set_stream_param;
+ struct us_client *usc = usf_xx->usc;
+ struct us_port_data *port = &usc->port[dir];
+ int rc = 0;
+
+ if (port->param_buf == NULL) {
+ pr_err("%s: parameter buffer is null\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ rc = copy_from_user(&set_stream_param,
+ (struct us_stream_param_type __user *) arg,
+ sizeof(set_stream_param));
+
+ if (rc) {
+ pr_err("%s: copy set_stream_param from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ if (set_stream_param.buf_size > port->param_buf_size) {
+ pr_err("%s: buf_size (%d) > maximum buf size (%d)\n",
+ __func__, set_stream_param.buf_size,
+ port->param_buf_size);
+ return -EINVAL;
+ }
+
+ if (set_stream_param.buf_size == 0) {
+ pr_err("%s: buf_size is 0\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = copy_from_user(port->param_buf,
+ (uint8_t __user *) set_stream_param.pbuf,
+ set_stream_param.buf_size);
+ if (rc) {
+ pr_err("%s: copy param buf from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ rc = q6usm_set_us_stream_param(dir, usc, set_stream_param.module_id,
+ set_stream_param.param_id,
+ set_stream_param.buf_size);
+ if (rc) {
+ pr_err("%s: q6usm_set_us_stream_param failed; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ return rc;
+} /* usf_set_stream_param */
+
+static int usf_get_stream_param(struct usf_xx_type *usf_xx,
+ unsigned long arg, int dir)
+{
+ struct us_stream_param_type get_stream_param;
+ struct us_client *usc = usf_xx->usc;
+ struct us_port_data *port = &usc->port[dir];
+ int rc = 0;
+
+ if (port->param_buf == NULL) {
+ pr_err("%s: parameter buffer is null\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ rc = copy_from_user(&get_stream_param,
+ (struct us_stream_param_type __user *) arg,
+ sizeof(get_stream_param));
+
+ if (rc) {
+ pr_err("%s: copy get_stream_param from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ if (get_stream_param.buf_size > port->param_buf_size) {
+ pr_err("%s: buf_size (%d) > maximum buf size (%d)\n",
+ __func__, get_stream_param.buf_size,
+ port->param_buf_size);
+ return -EINVAL;
+ }
+
+ if (get_stream_param.buf_size == 0) {
+ pr_err("%s: buf_size is 0\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = q6usm_get_us_stream_param(dir, usc, get_stream_param.module_id,
+ get_stream_param.param_id,
+ get_stream_param.buf_size);
+ if (rc) {
+ pr_err("%s: q6usm_get_us_stream_param failed; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ rc = copy_to_user((uint8_t __user *) get_stream_param.pbuf,
+ port->param_buf,
+ get_stream_param.buf_size);
+ if (rc) {
+ pr_err("%s: copy param buf to user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ return rc;
+} /* usf_get_stream_param */
+
static long usf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int rc = 0;
@@ -1402,6 +1532,26 @@
break;
} /* US_GET_VERSION */
+ case US_SET_TX_STREAM_PARAM: {
+ rc = usf_set_stream_param(&usf->usf_tx, arg, OUT);
+ break;
+ } /* US_SET_TX_STREAM_PARAM */
+
+ case US_GET_TX_STREAM_PARAM: {
+ rc = usf_get_stream_param(&usf->usf_tx, arg, OUT);
+ break;
+ } /* US_GET_TX_STREAM_PARAM */
+
+ case US_SET_RX_STREAM_PARAM: {
+ rc = usf_set_stream_param(&usf->usf_rx, arg, IN);
+ break;
+ } /* US_SET_RX_STREAM_PARAM */
+
+ case US_GET_RX_STREAM_PARAM: {
+ rc = usf_get_stream_param(&usf->usf_rx, arg, IN);
+ break;
+ } /* US_GET_RX_STREAM_PARAM */
+
default:
pr_err("%s: unsupported IOCTL command [%d]\n",
__func__,
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index af3c1f5..1a1d587 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -53,7 +53,7 @@
static struct usm_mmap this_mmap;
-static void q6usm_add_mmaphdr(struct us_client *usc, struct apr_hdr *hdr,
+static void q6usm_add_mmaphdr(struct apr_hdr *hdr,
uint32_t pkt_size, bool cmd_flg, u32 token)
{
hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
@@ -68,20 +68,20 @@
return;
}
-static int q6usm_memory_map(struct us_client *usc, uint32_t buf_add, int dir,
- uint32_t bufsz, uint32_t bufcnt)
+static int q6usm_memory_map(uint32_t buf_add, int dir, uint32_t bufsz,
+ uint32_t bufcnt, uint32_t session, uint32_t *mem_handle)
{
struct usm_cmd_memory_map_region mem_region_map;
int rc = 0;
- if ((usc == NULL) || (usc->apr == NULL) || (this_mmap.apr == NULL)) {
+ if (this_mmap.apr == NULL) {
pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
- q6usm_add_mmaphdr(usc, &mem_region_map.hdr,
+ q6usm_add_mmaphdr(&mem_region_map.hdr,
sizeof(struct usm_cmd_memory_map_region), true,
- ((usc->session << 8) | dir));
+ ((session << 8) | dir));
mem_region_map.hdr.opcode = USM_CMD_SHARED_MEM_MAP_REGION;
mem_region_map.mempool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
@@ -108,32 +108,29 @@
rc = -ETIME;
pr_err("%s: timeout. waited for memory_map\n", __func__);
} else {
- struct us_port_data *port = &usc->port[dir];
-
- *((uint32_t *)(port->ext)) = this_mmap.mem_handle;
+ *mem_handle = this_mmap.mem_handle;
rc = 0;
}
fail_cmd:
return rc;
}
-int q6usm_memory_unmap(struct us_client *usc, uint32_t buf_add, int dir)
+int q6usm_memory_unmap(uint32_t buf_add, int dir, uint32_t session,
+ uint32_t mem_handle)
{
struct usm_cmd_memory_unmap_region mem_unmap;
- struct us_port_data *port = &usc->port[dir];
int rc = 0;
- if ((usc == NULL) || (usc->apr == NULL) || (this_mmap.apr == NULL)) {
+ if (this_mmap.apr == NULL) {
pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
- port = &usc->port[dir];
- q6usm_add_mmaphdr(usc, &mem_unmap.hdr,
+ q6usm_add_mmaphdr(&mem_unmap.hdr,
sizeof(struct usm_cmd_memory_unmap_region), true,
- ((usc->session << 8) | dir));
+ ((session << 8) | dir));
mem_unmap.hdr.opcode = USM_CMD_SHARED_MEM_UNMAP_REGION;
- mem_unmap.mem_map_handle = *((uint32_t *)(port->ext));
+ mem_unmap.mem_map_handle = mem_handle;
rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_unmap);
if (rc < 0) {
@@ -209,7 +206,8 @@
return 0;
}
- rc = q6usm_memory_unmap(usc, port->phys, dir);
+ rc = q6usm_memory_unmap(port->phys, dir, usc->session,
+ *((uint32_t *)port->ext));
pr_debug("%s: data[%p]phys[%p][%p]\n", __func__,
(void *)port->data, (void *)port->phys, (void *)&port->phys);
/* 4K boundary is required by the API with QDSP6 */
@@ -224,6 +222,45 @@
return rc;
}
+int q6usm_us_param_buf_free(unsigned int dir,
+ struct us_client *usc)
+{
+ struct us_port_data *port;
+ int rc = 0;
+ uint32_t size = 0;
+
+ if ((usc == NULL) ||
+ ((dir != IN) && (dir != OUT)))
+ return -EINVAL;
+
+ mutex_lock(&usc->cmd_lock);
+ port = &usc->port[dir];
+ if (port == NULL) {
+ mutex_unlock(&usc->cmd_lock);
+ return -EINVAL;
+ }
+
+ if (port->param_buf == NULL) {
+ mutex_unlock(&usc->cmd_lock);
+ return 0;
+ }
+
+ rc = q6usm_memory_unmap(port->param_phys, dir, usc->session,
+ *((uint32_t *)port->param_buf_mem_handle));
+ pr_debug("%s: data[%p]phys[%p][%p]\n", __func__,
+ (void *)port->param_buf, (void *)port->param_phys,
+ (void *)&port->param_phys);
+ /* 4K boundary is required by the API with QDSP6 */
+ size = (port->param_buf_size + MEM_4K_OFFSET) & MEM_4K_MASK;
+ dma_free_coherent(NULL, size, port->param_buf, port->param_phys);
+ port->param_buf = NULL;
+ port->param_phys = 0;
+ port->param_buf_size = 0;
+
+ mutex_unlock(&usc->cmd_lock);
+ return rc;
+}
+
void q6usm_us_client_free(struct us_client *usc)
{
int loopcnt = 0;
@@ -240,6 +277,7 @@
continue;
pr_debug("%s: loopcnt = %d\n", __func__, loopcnt);
q6usm_us_client_buf_free(loopcnt, usc);
+ q6usm_us_param_buf_free(loopcnt, usc);
}
q6usm_session_free(usc);
apr_deregister(usc->apr);
@@ -279,7 +317,7 @@
pr_err("%s: us_client allocation failed\n", __func__);
return NULL;
}
- p_mem_handle = kzalloc(sizeof(uint32_t) * 2, GFP_KERNEL);
+ p_mem_handle = kzalloc(sizeof(uint32_t) * 4, GFP_KERNEL);
if (p_mem_handle == NULL) {
pr_err("%s: p_mem_handle allocation failed\n", __func__);
kfree(usc);
@@ -320,6 +358,7 @@
mutex_init(&usc->port[lcnt].lock);
spin_lock_init(&usc->port[lcnt].dsp_lock);
usc->port[lcnt].ext = (void *)p_mem_handle++;
+ usc->port[lcnt].param_buf_mem_handle = (void *)p_mem_handle++;
pr_err("%s: usc->port[%d].ext=%p;\n",
__func__, lcnt, usc->port[lcnt].ext);
}
@@ -372,11 +411,71 @@
(void *)&port->phys);
size = (size + MEM_4K_OFFSET) & MEM_4K_MASK;
- rc = q6usm_memory_map(usc, port->phys, dir, size, 1);
+ rc = q6usm_memory_map(port->phys, dir, size, 1, usc->session,
+ (uint32_t *)port->ext);
if (rc < 0) {
pr_err("%s: CMD Memory_map failed\n", __func__);
mutex_unlock(&usc->cmd_lock);
q6usm_us_client_buf_free(dir, usc);
+ q6usm_us_param_buf_free(dir, usc);
+ } else {
+ mutex_unlock(&usc->cmd_lock);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int q6usm_us_param_buf_alloc(unsigned int dir,
+ struct us_client *usc,
+ unsigned int bufsz)
+{
+ int rc = 0;
+ struct us_port_data *port = NULL;
+ unsigned int size = 0;
+
+ if ((usc == NULL) ||
+ ((dir != IN) && (dir != OUT)) ||
+ (usc->session <= 0 || usc->session > SESSION_MAX)) {
+ pr_err("%s: wrong parameters: direction=%d, bufsz=%d\n",
+ __func__, dir, bufsz);
+ return -EINVAL;
+ }
+
+ mutex_lock(&usc->cmd_lock);
+
+ port = &usc->port[dir];
+
+ if (bufsz == 0) {
+ pr_debug("%s: bufsz=0, get/set param commands are forbidden\n",
+ __func__);
+ port->param_buf = NULL;
+ mutex_unlock(&usc->cmd_lock);
+ return rc;
+ }
+
+ port->param_buf = dma_alloc_coherent(NULL, bufsz,
+ &(port->param_phys), GFP_KERNEL);
+ if (port->param_buf == NULL) {
+ pr_err("%s: Parameter buffer allocation failed\n", __func__);
+ mutex_unlock(&usc->cmd_lock);
+ return -ENOMEM;
+ }
+
+ port->param_buf_size = bufsz;
+ pr_debug("%s: param_buf[%p]; param_phys[%p]; [%p]\n", __func__,
+ (void *)port->param_buf,
+ (void *)port->param_phys,
+ (void *)&port->param_phys);
+
+ size = (bufsz + MEM_4K_OFFSET) & MEM_4K_MASK;
+ rc = q6usm_memory_map(port->param_phys, (IN | OUT), size, 1,
+ usc->session, (uint32_t *)port->param_buf_mem_handle);
+ if (rc < 0) {
+ pr_err("%s: CMD Memory_map failed\n", __func__);
+ mutex_unlock(&usc->cmd_lock);
+ q6usm_us_client_buf_free(dir, usc);
+ q6usm_us_param_buf_free(dir, usc);
} else {
mutex_unlock(&usc->cmd_lock);
rc = 0;
@@ -471,6 +570,8 @@
case USM_STREAM_CMD_SET_ENC_PARAM:
case USM_DATA_CMD_MEDIA_FORMAT_UPDATE:
case USM_SESSION_CMD_SIGNAL_DETECT_MODE:
+ case USM_STREAM_CMD_SET_PARAM:
+ case USM_STREAM_CMD_GET_PARAM:
if (atomic_read(&usc->cmd_state)) {
atomic_set(&usc->cmd_state, 0);
wake_up(&usc->cmd_wait);
@@ -1230,6 +1331,98 @@
return rc;
}
+int q6usm_set_us_stream_param(int dir, struct us_client *usc,
+ uint32_t module_id, uint32_t param_id, uint32_t buf_size)
+{
+ int rc = 0;
+ struct usm_stream_cmd_set_param cmd_set_param;
+ struct us_port_data *port = NULL;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ port = &usc->port[dir];
+
+ q6usm_add_hdr(usc, &cmd_set_param.hdr,
+ (sizeof(cmd_set_param) - APR_HDR_SIZE), true);
+
+ cmd_set_param.hdr.opcode = USM_STREAM_CMD_SET_PARAM;
+ cmd_set_param.buf_size = buf_size;
+ cmd_set_param.buf_addr_msw = upper_32_bits(port->param_phys);
+ cmd_set_param.buf_addr_lsw = lower_32_bits(port->param_phys);
+ cmd_set_param.mem_map_handle =
+ *((uint32_t *)(port->param_buf_mem_handle));
+ cmd_set_param.module_id = module_id;
+ cmd_set_param.param_id = param_id;
+ cmd_set_param.hdr.token = 0;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &cmd_set_param);
+
+ if (rc < 0) {
+ pr_err("%s:write op[0x%x];rc[%d]\n",
+ __func__, cmd_set_param.hdr.opcode, rc);
+ }
+
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: CMD_SET_PARAM: timeout=%d\n",
+ __func__, Q6USM_TIMEOUT_JIFFIES);
+ } else
+ rc = 0;
+
+ return rc;
+}
+
+int q6usm_get_us_stream_param(int dir, struct us_client *usc,
+ uint32_t module_id, uint32_t param_id, uint32_t buf_size)
+{
+ int rc = 0;
+ struct usm_stream_cmd_get_param cmd_get_param;
+ struct us_port_data *port = NULL;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ port = &usc->port[dir];
+
+ q6usm_add_hdr(usc, &cmd_get_param.hdr,
+ (sizeof(cmd_get_param) - APR_HDR_SIZE), true);
+
+ cmd_get_param.hdr.opcode = USM_STREAM_CMD_GET_PARAM;
+ cmd_get_param.buf_size = buf_size;
+ cmd_get_param.buf_addr_msw = upper_32_bits(port->param_phys);
+ cmd_get_param.buf_addr_lsw = lower_32_bits(port->param_phys);
+ cmd_get_param.mem_map_handle =
+ *((uint32_t *)(port->param_buf_mem_handle));
+ cmd_get_param.module_id = module_id;
+ cmd_get_param.param_id = param_id;
+ cmd_get_param.hdr.token = 0;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &cmd_get_param);
+
+ if (rc < 0) {
+ pr_err("%s:write op[0x%x];rc[%d]\n",
+ __func__, cmd_get_param.hdr.opcode, rc);
+ }
+
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: CMD_GET_PARAM: timeout=%d\n",
+ __func__, Q6USM_TIMEOUT_JIFFIES);
+ } else
+ rc = 0;
+
+ return rc;
+}
+
static int __init q6usm_init(void)
{
pr_debug("%s\n", __func__);
diff --git a/arch/arm/mach-msm/rmt_storage_client.c b/arch/arm/mach-msm/rmt_storage_client.c
deleted file mode 100644
index 550624c..0000000
--- a/arch/arm/mach-msm/rmt_storage_client.c
+++ /dev/null
@@ -1,1839 +0,0 @@
-/* Copyright (c) 2009-2013, Linux Foundation. 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/miscdevice.h>
-#include <linux/wait.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include <linux/sched.h>
-#include <linux/wakelock.h>
-#include <linux/rmt_storage_client.h>
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/reboot.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <mach/msm_rpcrouter.h>
-#ifdef CONFIG_MSM_SDIO_SMEM
-#include <mach/sdio_smem.h>
-#endif
-#include <mach/msm_smem.h>
-
-enum {
- RMT_STORAGE_EVNT_OPEN = 0,
- RMT_STORAGE_EVNT_CLOSE,
- RMT_STORAGE_EVNT_WRITE_BLOCK,
- RMT_STORAGE_EVNT_GET_DEV_ERROR,
- RMT_STORAGE_EVNT_WRITE_IOVEC,
- RMT_STORAGE_EVNT_SEND_USER_DATA,
- RMT_STORAGE_EVNT_READ_IOVEC,
- RMT_STORAGE_EVNT_ALLOC_RMT_BUF,
-} rmt_storage_event;
-
-struct shared_ramfs_entry {
- uint32_t client_id; /* Client id to uniquely identify a client */
- uint32_t base_addr; /* Base address of shared RAMFS memory */
- uint32_t size; /* Size of the shared RAMFS memory */
- uint32_t client_sts; /* This will be initialized to 1 when
- remote storage RPC client is ready
- to process requests */
-};
-struct shared_ramfs_table {
- uint32_t magic_id; /* Identify RAMFS details in SMEM */
- uint32_t version; /* Version of shared_ramfs_table */
- uint32_t entries; /* Total number of valid entries */
- /* List all entries */
- struct shared_ramfs_entry ramfs_entry[MAX_RAMFS_TBL_ENTRIES];
-};
-
-struct rmt_storage_client_info {
- unsigned long cids;
- struct list_head shrd_mem_list; /* List of shared memory entries */
- int open_excl;
- atomic_t total_events;
- wait_queue_head_t event_q;
- struct list_head event_list;
- struct list_head client_list; /* List of remote storage clients */
- /* Lock to protect lists */
- spinlock_t lock;
- /* Wakelock to be acquired when processing requests from modem */
- struct wake_lock wlock;
- atomic_t wcount;
- struct workqueue_struct *workq;
-};
-
-struct rmt_storage_kevent {
- struct list_head list;
- struct rmt_storage_event event;
-};
-
-/* Remote storage server on modem */
-struct rmt_storage_srv {
- uint32_t prog;
- int sync_token;
- struct platform_driver plat_drv;
- struct msm_rpc_client *rpc_client;
- struct delayed_work restart_work;
-};
-
-/* Remote storage client on modem */
-struct rmt_storage_client {
- uint32_t handle;
- uint32_t sid; /* Storage ID */
- char path[MAX_PATH_NAME];
- struct rmt_storage_srv *srv;
- struct list_head list;
-};
-
-struct rmt_shrd_mem {
- struct list_head list;
- struct rmt_shrd_mem_param param;
- struct shared_ramfs_entry *smem_info;
- struct rmt_storage_srv *srv;
-};
-
-static struct rmt_storage_srv *rmt_storage_get_srv(uint32_t prog);
-static uint32_t rmt_storage_get_sid(const char *path);
-#ifdef CONFIG_MSM_SDIO_SMEM
-static void rmt_storage_sdio_smem_work(struct work_struct *work);
-#endif
-
-static struct rmt_storage_client_info *rmc;
-struct rmt_storage_srv *rmt_srv;
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-DECLARE_DELAYED_WORK(sdio_smem_work, rmt_storage_sdio_smem_work);
-#endif
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-#define MDM_LOCAL_BUF_SZ 0xC0000
-static struct sdio_smem_client *sdio_smem;
-#endif
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-struct rmt_storage_op_stats {
- unsigned long count;
- ktime_t start;
- ktime_t min;
- ktime_t max;
- ktime_t total;
-};
-struct rmt_storage_stats {
- char path[MAX_PATH_NAME];
- struct rmt_storage_op_stats rd_stats;
- struct rmt_storage_op_stats wr_stats;
-};
-static struct rmt_storage_stats client_stats[MAX_NUM_CLIENTS];
-static struct dentry *stats_dentry;
-#endif
-
-#define MSM_RMT_STORAGE_APIPROG 0x300000A7
-#define MDM_RMT_STORAGE_APIPROG 0x300100A7
-
-#define RMT_STORAGE_OP_FINISH_PROC 2
-#define RMT_STORAGE_REGISTER_OPEN_PROC 3
-#define RMT_STORAGE_REGISTER_WRITE_IOVEC_PROC 4
-#define RMT_STORAGE_REGISTER_CB_PROC 5
-#define RMT_STORAGE_UN_REGISTER_CB_PROC 6
-#define RMT_STORAGE_FORCE_SYNC_PROC 7
-#define RMT_STORAGE_GET_SYNC_STATUS_PROC 8
-#define RMT_STORAGE_REGISTER_READ_IOVEC_PROC 9
-#define RMT_STORAGE_REGISTER_ALLOC_RMT_BUF_PROC 10
-
-#define RMT_STORAGE_OPEN_CB_TYPE_PROC 1
-#define RMT_STORAGE_WRITE_IOVEC_CB_TYPE_PROC 2
-#define RMT_STORAGE_EVENT_CB_TYPE_PROC 3
-#define RMT_STORAGE_READ_IOVEC_CB_TYPE_PROC 4
-#define RMT_STORAGE_ALLOC_RMT_BUF_CB_TYPE_PROC 5
-
-#define RAMFS_INFO_MAGICNUMBER 0x654D4D43
-#define RAMFS_INFO_VERSION 0x00000001
-#define RAMFS_DEFAULT 0xFFFFFFFF
-
-/* MSM EFS*/
-#define RAMFS_MODEMSTORAGE_ID 0x4D454653
-#define RAMFS_SHARED_EFS_RAM_BASE 0x46100000
-#define RAMFS_SHARED_EFS_RAM_SIZE (3 * 1024 * 1024)
-
-/* MDM EFS*/
-#define RAMFS_MDM_STORAGE_ID 0x4D4583A1
-/* SSD */
-#define RAMFS_SSD_STORAGE_ID 0x00535344
-#define RAMFS_SHARED_SSD_RAM_BASE 0x42E00000
-#define RAMFS_SHARED_SSD_RAM_SIZE 0x2000
-
-static struct rmt_storage_client *rmt_storage_get_client(uint32_t handle)
-{
- struct rmt_storage_client *rs_client;
- list_for_each_entry(rs_client, &rmc->client_list, list)
- if (rs_client->handle == handle)
- return rs_client;
- return NULL;
-}
-
-static struct rmt_storage_client *
-rmt_storage_get_client_by_path(const char *path)
-{
- struct rmt_storage_client *rs_client;
- list_for_each_entry(rs_client, &rmc->client_list, list)
- if (!strncmp(path, rs_client->path, MAX_PATH_NAME))
- return rs_client;
- return NULL;
-}
-
-static struct rmt_shrd_mem_param *rmt_storage_get_shrd_mem(uint32_t sid)
-{
- struct rmt_shrd_mem *shrd_mem;
- struct rmt_shrd_mem_param *shrd_mem_param = NULL;
-
- spin_lock(&rmc->lock);
- list_for_each_entry(shrd_mem, &rmc->shrd_mem_list, list)
- if (shrd_mem->param.sid == sid)
- shrd_mem_param = &shrd_mem->param;
- spin_unlock(&rmc->lock);
-
- return shrd_mem_param;
-}
-
-static int rmt_storage_add_shrd_mem(uint32_t sid, uint32_t start,
- uint32_t size, void *base,
- struct shared_ramfs_entry *smem_info,
- struct rmt_storage_srv *srv)
-{
- struct rmt_shrd_mem *shrd_mem;
-
- shrd_mem = kzalloc(sizeof(struct rmt_shrd_mem), GFP_KERNEL);
- if (!shrd_mem)
- return -ENOMEM;
- shrd_mem->param.sid = sid;
- shrd_mem->param.start = start;
- shrd_mem->param.size = size;
- shrd_mem->param.base = base;
- shrd_mem->smem_info = smem_info;
- shrd_mem->srv = srv;
-
- spin_lock(&rmc->lock);
- list_add(&shrd_mem->list, &rmc->shrd_mem_list);
- spin_unlock(&rmc->lock);
- return 0;
-}
-
-static struct msm_rpc_client *rmt_storage_get_rpc_client(uint32_t handle)
-{
- struct rmt_storage_client *rs_client;
-
- rs_client = rmt_storage_get_client(handle);
- if (!rs_client)
- return NULL;
- return rs_client->srv->rpc_client;
-}
-
-static int rmt_storage_validate_iovec(uint32_t handle,
- struct rmt_storage_iovec_desc *xfer)
-{
- struct rmt_storage_client *rs_client;
- struct rmt_shrd_mem_param *shrd_mem;
-
- rs_client = rmt_storage_get_client(handle);
- if (!rs_client)
- return -EINVAL;
- shrd_mem = rmt_storage_get_shrd_mem(rs_client->sid);
- if (!shrd_mem)
- return -EINVAL;
-
- if ((xfer->data_phy_addr < shrd_mem->start) ||
- ((xfer->data_phy_addr + RAMFS_BLOCK_SIZE * xfer->num_sector) >
- (shrd_mem->start + shrd_mem->size)))
- return -EINVAL;
- return 0;
-}
-
-static int rmt_storage_send_sts_arg(struct msm_rpc_client *client,
- struct msm_rpc_xdr *xdr, void *data)
-{
- struct rmt_storage_send_sts *args = data;
-
- xdr_send_uint32(xdr, &args->handle);
- xdr_send_uint32(xdr, &args->err_code);
- xdr_send_uint32(xdr, &args->data);
- return 0;
-}
-
-static void put_event(struct rmt_storage_client_info *rmc,
- struct rmt_storage_kevent *kevent)
-{
- spin_lock(&rmc->lock);
- list_add_tail(&kevent->list, &rmc->event_list);
- spin_unlock(&rmc->lock);
-}
-
-static struct rmt_storage_kevent *get_event(struct rmt_storage_client_info *rmc)
-{
- struct rmt_storage_kevent *kevent = NULL;
-
- spin_lock(&rmc->lock);
- if (!list_empty(&rmc->event_list)) {
- kevent = list_first_entry(&rmc->event_list,
- struct rmt_storage_kevent, list);
- list_del(&kevent->list);
- }
- spin_unlock(&rmc->lock);
- return kevent;
-}
-
-static int rmt_storage_event_open_cb(struct rmt_storage_event *event_args,
- struct msm_rpc_xdr *xdr)
-{
- uint32_t cid, len, event_type;
- char *path;
- int ret;
- struct rmt_storage_srv *srv;
- struct rmt_storage_client *rs_client = NULL;
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
- struct rmt_storage_stats *stats;
-#endif
-
- srv = rmt_storage_get_srv(event_args->usr_data);
- if (!srv)
- return -EINVAL;
-
- xdr_recv_uint32(xdr, &event_type);
- if (event_type != RMT_STORAGE_EVNT_OPEN)
- return -1;
-
- pr_info("%s: open callback received\n", __func__);
-
- ret = xdr_recv_bytes(xdr, (void **)&path, &len);
- if (ret || !path) {
- pr_err("%s: Invalid path\n", __func__);
- if (!ret)
- ret = -1;
- goto free_rs_client;
- }
-
- rs_client = rmt_storage_get_client_by_path(path);
- if (rs_client) {
- pr_debug("%s: Handle %d found for %s\n",
- __func__, rs_client->handle, path);
- event_args->id = RMT_STORAGE_NOOP;
- cid = rs_client->handle;
- goto end_open_cb;
- }
-
- rs_client = kzalloc(sizeof(struct rmt_storage_client), GFP_KERNEL);
- if (!rs_client) {
- pr_err("%s: Error allocating rmt storage client\n", __func__);
- ret = -ENOMEM;
- goto free_path;
- }
-
- memcpy(event_args->path, path, len);
- rs_client->sid = rmt_storage_get_sid(event_args->path);
- if (!rs_client->sid) {
- pr_err("%s: No storage id found for %s\n", __func__,
- event_args->path);
- ret = -EINVAL;
- goto free_path;
- }
- strncpy(rs_client->path, event_args->path, MAX_PATH_NAME);
-
- cid = find_first_zero_bit(&rmc->cids, sizeof(rmc->cids) * 8);
- if (cid > MAX_NUM_CLIENTS) {
- pr_err("%s: Max clients are reached\n", __func__);
- cid = 0;
- return cid;
- }
- __set_bit(cid, &rmc->cids);
- pr_info("open partition %s handle=%d\n", event_args->path, cid);
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
- stats = &client_stats[cid - 1];
- memcpy(stats->path, event_args->path, len);
- memset(stats->rd_stats, 0, sizeof(struct rmt_storage_op_stats));
- memset(stats->wr_stats, 0, sizeof(struct rmt_storage_op_stats));
- stats->rd_stats.min.tv64 = KTIME_MAX;
- stats->wr_stats.min.tv64 = KTIME_MAX;
-#endif
- event_args->id = RMT_STORAGE_OPEN;
- event_args->sid = rs_client->sid;
- event_args->handle = cid;
-
- rs_client->handle = event_args->handle;
- rs_client->srv = srv;
- INIT_LIST_HEAD(&rs_client->list);
- spin_lock(&rmc->lock);
- list_add_tail(&rs_client->list, &rmc->client_list);
- spin_unlock(&rmc->lock);
-
-end_open_cb:
- kfree(path);
- return cid;
-
-free_path:
- kfree(path);
-free_rs_client:
- kfree(rs_client);
- return ret;
-}
-
-struct rmt_storage_close_args {
- uint32_t handle;
-};
-
-struct rmt_storage_rw_block_args {
- uint32_t handle;
- uint32_t data_phy_addr;
- uint32_t sector_addr;
- uint32_t num_sector;
-};
-
-struct rmt_storage_get_err_args {
- uint32_t handle;
-};
-
-struct rmt_storage_user_data_args {
- uint32_t handle;
- uint32_t data;
-};
-
-struct rmt_storage_event_params {
- uint32_t type;
- union {
- struct rmt_storage_close_args close;
- struct rmt_storage_rw_block_args block;
- struct rmt_storage_get_err_args get_err;
- struct rmt_storage_user_data_args user_data;
- } params;
-};
-
-static int rmt_storage_parse_params(struct msm_rpc_xdr *xdr,
- struct rmt_storage_event_params *event)
-{
- xdr_recv_uint32(xdr, &event->type);
-
- switch (event->type) {
- case RMT_STORAGE_EVNT_CLOSE: {
- struct rmt_storage_close_args *args;
- args = &event->params.close;
-
- xdr_recv_uint32(xdr, &args->handle);
- break;
- }
-
- case RMT_STORAGE_EVNT_WRITE_BLOCK: {
- struct rmt_storage_rw_block_args *args;
- args = &event->params.block;
-
- xdr_recv_uint32(xdr, &args->handle);
- xdr_recv_uint32(xdr, &args->data_phy_addr);
- xdr_recv_uint32(xdr, &args->sector_addr);
- xdr_recv_uint32(xdr, &args->num_sector);
- break;
- }
-
- case RMT_STORAGE_EVNT_GET_DEV_ERROR: {
- struct rmt_storage_get_err_args *args;
- args = &event->params.get_err;
-
- xdr_recv_uint32(xdr, &args->handle);
- break;
- }
-
- case RMT_STORAGE_EVNT_SEND_USER_DATA: {
- struct rmt_storage_user_data_args *args;
- args = &event->params.user_data;
-
- xdr_recv_uint32(xdr, &args->handle);
- xdr_recv_uint32(xdr, &args->data);
- break;
- }
-
- default:
- pr_err("%s: unknown event %d\n", __func__, event->type);
- return -1;
- }
- return 0;
-}
-
-static int rmt_storage_event_close_cb(struct rmt_storage_event *event_args,
- struct msm_rpc_xdr *xdr)
-{
- struct rmt_storage_event_params *event;
- struct rmt_storage_close_args *close;
- struct rmt_storage_client *rs_client;
- uint32_t event_type;
- int ret;
-
- xdr_recv_uint32(xdr, &event_type);
- if (event_type != RMT_STORAGE_EVNT_CLOSE)
- return -1;
-
- pr_debug("%s: close callback received\n", __func__);
- ret = xdr_recv_pointer(xdr, (void **)&event,
- sizeof(struct rmt_storage_event_params),
- rmt_storage_parse_params);
-
- if (ret || !event)
- return -1;
-
- close = &event->params.close;
- event_args->handle = close->handle;
- event_args->id = RMT_STORAGE_CLOSE;
- __clear_bit(event_args->handle, &rmc->cids);
- rs_client = rmt_storage_get_client(event_args->handle);
- if (rs_client) {
- list_del(&rs_client->list);
- kfree(rs_client);
- }
- kfree(event);
- return RMT_STORAGE_NO_ERROR;
-}
-
-static int rmt_storage_event_write_block_cb(
- struct rmt_storage_event *event_args,
- struct msm_rpc_xdr *xdr)
-{
- struct rmt_storage_event_params *event;
- struct rmt_storage_rw_block_args *write_block;
- struct rmt_storage_iovec_desc *xfer;
- uint32_t event_type;
- int ret;
-
- xdr_recv_uint32(xdr, &event_type);
- if (event_type != RMT_STORAGE_EVNT_WRITE_BLOCK)
- return -1;
-
- pr_debug("%s: write block callback received\n", __func__);
- ret = xdr_recv_pointer(xdr, (void **)&event,
- sizeof(struct rmt_storage_event_params),
- rmt_storage_parse_params);
-
- if (ret || !event)
- return -1;
-
- write_block = &event->params.block;
- event_args->handle = write_block->handle;
- xfer = &event_args->xfer_desc[0];
- xfer->sector_addr = write_block->sector_addr;
- xfer->data_phy_addr = write_block->data_phy_addr;
- xfer->num_sector = write_block->num_sector;
-
- ret = rmt_storage_validate_iovec(event_args->handle, xfer);
- if (ret)
- return -1;
- event_args->xfer_cnt = 1;
- event_args->id = RMT_STORAGE_WRITE;
-
- if (atomic_inc_return(&rmc->wcount) == 1)
- wake_lock(&rmc->wlock);
-
- pr_debug("sec_addr = %u, data_addr = %x, num_sec = %d\n\n",
- xfer->sector_addr, xfer->data_phy_addr,
- xfer->num_sector);
-
- kfree(event);
- return RMT_STORAGE_NO_ERROR;
-}
-
-static int rmt_storage_event_get_err_cb(struct rmt_storage_event *event_args,
- struct msm_rpc_xdr *xdr)
-{
- struct rmt_storage_event_params *event;
- struct rmt_storage_get_err_args *get_err;
- uint32_t event_type;
- int ret;
-
- xdr_recv_uint32(xdr, &event_type);
- if (event_type != RMT_STORAGE_EVNT_GET_DEV_ERROR)
- return -1;
-
- pr_debug("%s: get err callback received\n", __func__);
- ret = xdr_recv_pointer(xdr, (void **)&event,
- sizeof(struct rmt_storage_event_params),
- rmt_storage_parse_params);
-
- if (ret || !event)
- return -1;
-
- get_err = &event->params.get_err;
- event_args->handle = get_err->handle;
- kfree(event);
- /* Not implemented */
- return -1;
-
-}
-
-static int rmt_storage_event_user_data_cb(struct rmt_storage_event *event_args,
- struct msm_rpc_xdr *xdr)
-{
- struct rmt_storage_event_params *event;
- struct rmt_storage_user_data_args *user_data;
- uint32_t event_type;
- int ret;
-
- xdr_recv_uint32(xdr, &event_type);
- if (event_type != RMT_STORAGE_EVNT_SEND_USER_DATA)
- return -1;
-
- pr_info("%s: send user data callback received\n", __func__);
- ret = xdr_recv_pointer(xdr, (void **)&event,
- sizeof(struct rmt_storage_event_params),
- rmt_storage_parse_params);
-
- if (ret || !event)
- return -1;
-
- user_data = &event->params.user_data;
- event_args->handle = user_data->handle;
- event_args->usr_data = user_data->data;
- event_args->id = RMT_STORAGE_SEND_USER_DATA;
-
- kfree(event);
- return RMT_STORAGE_NO_ERROR;
-}
-
-static int rmt_storage_event_write_iovec_cb(
- struct rmt_storage_event *event_args,
- struct msm_rpc_xdr *xdr)
-{
- struct rmt_storage_iovec_desc *xfer;
- uint32_t i, ent, event_type;
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
- struct rmt_storage_stats *stats;
-#endif
-
- xdr_recv_uint32(xdr, &event_type);
- if (event_type != RMT_STORAGE_EVNT_WRITE_IOVEC)
- return -EINVAL;
-
- pr_info("%s: write iovec callback received\n", __func__);
- xdr_recv_uint32(xdr, &event_args->handle);
- xdr_recv_uint32(xdr, &ent);
- pr_debug("handle = %d\n", event_args->handle);
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
- stats = &client_stats[event_args->handle - 1];
- stats->wr_stats.start = ktime_get();
-#endif
- for (i = 0; i < ent; i++) {
- xfer = &event_args->xfer_desc[i];
- xdr_recv_uint32(xdr, &xfer->sector_addr);
- xdr_recv_uint32(xdr, &xfer->data_phy_addr);
- xdr_recv_uint32(xdr, &xfer->num_sector);
-
- if (rmt_storage_validate_iovec(event_args->handle, xfer))
- return -EINVAL;
-
- pr_debug("sec_addr = %u, data_addr = %x, num_sec = %d\n",
- xfer->sector_addr, xfer->data_phy_addr,
- xfer->num_sector);
- }
- xdr_recv_uint32(xdr, &event_args->xfer_cnt);
- event_args->id = RMT_STORAGE_WRITE;
- if (atomic_inc_return(&rmc->wcount) == 1)
- wake_lock(&rmc->wlock);
-
- pr_debug("iovec transfer count = %d\n\n", event_args->xfer_cnt);
- return RMT_STORAGE_NO_ERROR;
-}
-
-static int rmt_storage_event_read_iovec_cb(
- struct rmt_storage_event *event_args,
- struct msm_rpc_xdr *xdr)
-{
- struct rmt_storage_iovec_desc *xfer;
- uint32_t i, ent, event_type;
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
- struct rmt_storage_stats *stats;
-#endif
-
- xdr_recv_uint32(xdr, &event_type);
- if (event_type != RMT_STORAGE_EVNT_READ_IOVEC)
- return -EINVAL;
-
- pr_info("%s: read iovec callback received\n", __func__);
- xdr_recv_uint32(xdr, &event_args->handle);
- xdr_recv_uint32(xdr, &ent);
- pr_debug("handle = %d\n", event_args->handle);
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
- stats = &client_stats[event_args->handle - 1];
- stats->rd_stats.start = ktime_get();
-#endif
- for (i = 0; i < ent; i++) {
- xfer = &event_args->xfer_desc[i];
- xdr_recv_uint32(xdr, &xfer->sector_addr);
- xdr_recv_uint32(xdr, &xfer->data_phy_addr);
- xdr_recv_uint32(xdr, &xfer->num_sector);
-
- if (rmt_storage_validate_iovec(event_args->handle, xfer))
- return -EINVAL;
-
- pr_debug("sec_addr = %u, data_addr = %x, num_sec = %d\n",
- xfer->sector_addr, xfer->data_phy_addr,
- xfer->num_sector);
- }
- xdr_recv_uint32(xdr, &event_args->xfer_cnt);
- event_args->id = RMT_STORAGE_READ;
- if (atomic_inc_return(&rmc->wcount) == 1)
- wake_lock(&rmc->wlock);
-
- pr_debug("iovec transfer count = %d\n\n", event_args->xfer_cnt);
- return RMT_STORAGE_NO_ERROR;
-}
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int sdio_smem_cb(int event)
-{
- pr_debug("%s: Received event %d\n", __func__, event);
-
- switch (event) {
- case SDIO_SMEM_EVENT_READ_DONE:
- pr_debug("Read done\n");
- break;
- case SDIO_SMEM_EVENT_READ_ERR:
- pr_err("Read overflow\n");
- return -EIO;
- default:
- pr_err("Unhandled event\n");
- }
- return 0;
-}
-
-static int rmt_storage_sdio_smem_probe(struct platform_device *pdev)
-{
- int ret = 0;
- struct rmt_shrd_mem_param *shrd_mem;
-
- sdio_smem = container_of(pdev, struct sdio_smem_client, plat_dev);
-
- /* SDIO SMEM is supported only for MDM */
- shrd_mem = rmt_storage_get_shrd_mem(RAMFS_MDM_STORAGE_ID);
- if (!shrd_mem) {
- pr_err("%s: No shared mem entry for sid=0x%08x\n",
- __func__, (uint32_t)RAMFS_MDM_STORAGE_ID);
- return -ENOMEM;
- }
- sdio_smem->buf = __va(shrd_mem->start);
- sdio_smem->size = shrd_mem->size;
- sdio_smem->cb_func = sdio_smem_cb;
- ret = sdio_smem_register_client();
- if (ret)
- pr_info("%s: Error (%d) registering sdio_smem client\n",
- __func__, ret);
- return ret;
-}
-
-static int rmt_storage_sdio_smem_remove(struct platform_device *pdev)
-{
- sdio_smem_unregister_client();
- queue_delayed_work(rmc->workq, &sdio_smem_work, 0);
- return 0;
-}
-
-static int sdio_smem_drv_registered;
-static struct platform_driver sdio_smem_drv = {
- .probe = rmt_storage_sdio_smem_probe,
- .remove = rmt_storage_sdio_smem_remove,
- .driver = {
- .name = "SDIO_SMEM_CLIENT",
- .owner = THIS_MODULE,
- },
-};
-
-static void rmt_storage_sdio_smem_work(struct work_struct *work)
-{
- platform_driver_unregister(&sdio_smem_drv);
- sdio_smem_drv_registered = 0;
-}
-#endif
-
-static int rmt_storage_event_alloc_rmt_buf_cb(
- struct rmt_storage_event *event_args,
- struct msm_rpc_xdr *xdr)
-{
- struct rmt_storage_client *rs_client;
- struct rmt_shrd_mem_param *shrd_mem;
- uint32_t event_type, handle, size;
-#ifdef CONFIG_MSM_SDIO_SMEM
- int ret;
-#endif
- xdr_recv_uint32(xdr, &event_type);
- if (event_type != RMT_STORAGE_EVNT_ALLOC_RMT_BUF)
- return -EINVAL;
-
- pr_info("%s: Alloc rmt buf callback received\n", __func__);
- xdr_recv_uint32(xdr, &handle);
- xdr_recv_uint32(xdr, &size);
-
- pr_debug("%s: handle=0x%x size=0x%x\n", __func__, handle, size);
-
- rs_client = rmt_storage_get_client(handle);
- if (!rs_client) {
- pr_err("%s: Unable to find client for handle=%d\n",
- __func__, handle);
- return -EINVAL;
- }
-
- rs_client->sid = rmt_storage_get_sid(rs_client->path);
- if (!rs_client->sid) {
- pr_err("%s: No storage id found for %s\n",
- __func__, rs_client->path);
- return -EINVAL;
- }
-
- shrd_mem = rmt_storage_get_shrd_mem(rs_client->sid);
- if (!shrd_mem) {
- pr_err("%s: No shared memory entry found\n",
- __func__);
- return -ENOMEM;
- }
- if (shrd_mem->size < size) {
- pr_err("%s: Size mismatch for handle=%d\n",
- __func__, rs_client->handle);
- return -EINVAL;
- }
- pr_debug("%s: %d bytes at phys=0x%x for handle=%d found\n",
- __func__, size, shrd_mem->start, rs_client->handle);
-
-#ifdef CONFIG_MSM_SDIO_SMEM
- if (rs_client->srv->prog == MDM_RMT_STORAGE_APIPROG) {
- if (!sdio_smem_drv_registered) {
- ret = platform_driver_register(&sdio_smem_drv);
- if (!ret)
- sdio_smem_drv_registered = 1;
- else
- pr_err("%s: Cant register sdio smem client\n",
- __func__);
- }
- }
-#endif
- event_args->id = RMT_STORAGE_NOOP;
- return (int)shrd_mem->start;
-}
-
-static int handle_rmt_storage_call(struct msm_rpc_client *client,
- struct rpc_request_hdr *req,
- struct msm_rpc_xdr *xdr)
-{
- int rc;
- uint32_t result = RMT_STORAGE_NO_ERROR;
- uint32_t rpc_status = RPC_ACCEPTSTAT_SUCCESS;
- struct rmt_storage_event *event_args;
- struct rmt_storage_kevent *kevent;
-
- kevent = kzalloc(sizeof(struct rmt_storage_kevent), GFP_KERNEL);
- if (!kevent) {
- rpc_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
- goto out;
- }
- event_args = &kevent->event;
-
- switch (req->procedure) {
- case RMT_STORAGE_OPEN_CB_TYPE_PROC:
- /* client created in cb needs a ref. to its server */
- event_args->usr_data = client->prog;
- /* fall through */
-
- case RMT_STORAGE_WRITE_IOVEC_CB_TYPE_PROC:
- /* fall through */
-
- case RMT_STORAGE_READ_IOVEC_CB_TYPE_PROC:
- /* fall through */
-
- case RMT_STORAGE_ALLOC_RMT_BUF_CB_TYPE_PROC:
- /* fall through */
-
- case RMT_STORAGE_EVENT_CB_TYPE_PROC: {
- uint32_t cb_id;
- int (*cb_func)(struct rmt_storage_event *event_args,
- struct msm_rpc_xdr *xdr);
-
- xdr_recv_uint32(xdr, &cb_id);
- cb_func = msm_rpc_get_cb_func(client, cb_id);
-
- if (!cb_func) {
- rpc_status = RPC_ACCEPTSTAT_GARBAGE_ARGS;
- kfree(kevent);
- goto out;
- }
-
- rc = cb_func(event_args, xdr);
- if (IS_ERR_VALUE(rc)) {
- pr_err("%s: Invalid parameters received\n", __func__);
- if (req->procedure == RMT_STORAGE_OPEN_CB_TYPE_PROC)
- result = 0; /* bad handle to signify err */
- else
- result = RMT_STORAGE_ERROR_PARAM;
- kfree(kevent);
- goto out;
- }
- result = (uint32_t) rc;
- break;
- }
-
- default:
- kfree(kevent);
- pr_err("%s: unknown procedure %d\n", __func__, req->procedure);
- rpc_status = RPC_ACCEPTSTAT_PROC_UNAVAIL;
- goto out;
- }
-
- if (kevent->event.id != RMT_STORAGE_NOOP) {
- put_event(rmc, kevent);
- atomic_inc(&rmc->total_events);
- wake_up(&rmc->event_q);
- } else
- kfree(kevent);
-
-out:
- pr_debug("%s: Sending result=0x%x\n", __func__, result);
- xdr_start_accepted_reply(xdr, rpc_status);
- xdr_send_uint32(xdr, &result);
- rc = xdr_send_msg(xdr);
- if (rc)
- pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
-
- return rc;
-}
-
-static int rmt_storage_open(struct inode *ip, struct file *fp)
-{
- int ret = 0;
-
- spin_lock(&rmc->lock);
- if (!rmc->open_excl)
- rmc->open_excl = 1;
- else
- ret = -EBUSY;
- spin_unlock(&rmc->lock);
-
- return ret;
-}
-
-static int rmt_storage_release(struct inode *ip, struct file *fp)
-{
- spin_lock(&rmc->lock);
- rmc->open_excl = 0;
- spin_unlock(&rmc->lock);
-
- return 0;
-}
-
-static long rmt_storage_ioctl(struct file *fp, unsigned int cmd,
- unsigned long arg)
-{
- int ret = 0;
- struct rmt_storage_kevent *kevent;
- struct rmt_storage_send_sts status;
- static struct msm_rpc_client *rpc_client;
- struct rmt_shrd_mem_param usr_shrd_mem, *shrd_mem;
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
- struct rmt_storage_stats *stats;
- struct rmt_storage_op_stats *op_stats;
- ktime_t curr_stat;
-#endif
-
- switch (cmd) {
-
- case RMT_STORAGE_SHRD_MEM_PARAM:
- pr_debug("%s: get shared memory parameters ioctl\n", __func__);
- if (copy_from_user(&usr_shrd_mem, (void __user *)arg,
- sizeof(struct rmt_shrd_mem_param))) {
- pr_err("%s: copy from user failed\n\n", __func__);
- ret = -EFAULT;
- break;
- }
-
- shrd_mem = rmt_storage_get_shrd_mem(usr_shrd_mem.sid);
- if (!shrd_mem) {
- pr_err("%s: invalid sid (0x%x)\n", __func__,
- usr_shrd_mem.sid);
- ret = -EFAULT;
- break;
- }
-
- if (copy_to_user((void __user *)arg, shrd_mem,
- sizeof(struct rmt_shrd_mem_param))) {
- pr_err("%s: copy to user failed\n\n", __func__);
- ret = -EFAULT;
- }
- break;
-
- case RMT_STORAGE_WAIT_FOR_REQ:
- pr_debug("%s: wait for request ioctl\n", __func__);
- if (atomic_read(&rmc->total_events) == 0) {
- ret = wait_event_interruptible(rmc->event_q,
- atomic_read(&rmc->total_events) != 0);
- }
- if (ret < 0)
- break;
- atomic_dec(&rmc->total_events);
-
- kevent = get_event(rmc);
- WARN_ON(kevent == NULL);
- if (copy_to_user((void __user *)arg, &kevent->event,
- sizeof(struct rmt_storage_event))) {
- pr_err("%s: copy to user failed\n\n", __func__);
- ret = -EFAULT;
- }
- kfree(kevent);
- break;
-
- case RMT_STORAGE_SEND_STATUS:
- pr_info("%s: send status ioctl\n", __func__);
- if (copy_from_user(&status, (void __user *)arg,
- sizeof(struct rmt_storage_send_sts))) {
- pr_err("%s: copy from user failed\n\n", __func__);
- ret = -EFAULT;
- if (atomic_dec_return(&rmc->wcount) == 0)
- wake_unlock(&rmc->wlock);
- break;
- }
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
- stats = &client_stats[status.handle - 1];
- if (status.xfer_dir == RMT_STORAGE_WRITE)
- op_stats = &stats->wr_stats;
- else
- op_stats = &stats->rd_stats;
- curr_stat = ktime_sub(ktime_get(), op_stats->start);
- op_stats->total = ktime_add(op_stats->total, curr_stat);
- op_stats->count++;
- if (curr_stat.tv64 < stats->min.tv64)
- op_stats->min = curr_stat;
- if (curr_stat.tv64 > stats->max.tv64)
- op_stats->max = curr_stat;
-#endif
- pr_debug("%s: \thandle=%d err_code=%d data=0x%x\n", __func__,
- status.handle, status.err_code, status.data);
- rpc_client = rmt_storage_get_rpc_client(status.handle);
- if (rpc_client)
- ret = msm_rpc_client_req2(rpc_client,
- RMT_STORAGE_OP_FINISH_PROC,
- rmt_storage_send_sts_arg,
- &status, NULL, NULL, -1);
- else
- ret = -EINVAL;
- if (ret < 0)
- pr_err("%s: send status failed with ret val = %d\n",
- __func__, ret);
- if (atomic_dec_return(&rmc->wcount) == 0)
- wake_unlock(&rmc->wlock);
- break;
-
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-struct rmt_storage_sync_recv_arg {
- int data;
-};
-
-static int rmt_storage_receive_sync_arg(struct msm_rpc_client *client,
- struct msm_rpc_xdr *xdr, void *data)
-{
- struct rmt_storage_sync_recv_arg *args = data;
- struct rmt_storage_srv *srv;
-
- srv = rmt_storage_get_srv(client->prog);
- if (!srv)
- return -EINVAL;
- xdr_recv_int32(xdr, &args->data);
- srv->sync_token = args->data;
- return 0;
-}
-
-static int rmt_storage_force_sync(struct msm_rpc_client *client)
-{
- struct rmt_storage_sync_recv_arg args;
- int rc;
- rc = msm_rpc_client_req2(client,
- RMT_STORAGE_FORCE_SYNC_PROC, NULL, NULL,
- rmt_storage_receive_sync_arg, &args, -1);
- if (rc) {
- pr_err("%s: force sync RPC req failed: %d\n", __func__, rc);
- return rc;
- }
- return 0;
-}
-
-struct rmt_storage_sync_sts_arg {
- int token;
-};
-
-static int rmt_storage_send_sync_sts_arg(struct msm_rpc_client *client,
- struct msm_rpc_xdr *xdr, void *data)
-{
- struct rmt_storage_sync_sts_arg *req = data;
-
- xdr_send_int32(xdr, &req->token);
- return 0;
-}
-
-static int rmt_storage_receive_sync_sts_arg(struct msm_rpc_client *client,
- struct msm_rpc_xdr *xdr, void *data)
-{
- struct rmt_storage_sync_recv_arg *args = data;
-
- xdr_recv_int32(xdr, &args->data);
- return 0;
-}
-
-static int rmt_storage_get_sync_status(struct msm_rpc_client *client)
-{
- struct rmt_storage_sync_recv_arg recv_args;
- struct rmt_storage_sync_sts_arg send_args;
- struct rmt_storage_srv *srv;
- int rc;
-
- srv = rmt_storage_get_srv(client->prog);
- if (!srv)
- return -EINVAL;
-
- if (srv->sync_token < 0)
- return -EINVAL;
-
- send_args.token = srv->sync_token;
- rc = msm_rpc_client_req2(client,
- RMT_STORAGE_GET_SYNC_STATUS_PROC,
- rmt_storage_send_sync_sts_arg, &send_args,
- rmt_storage_receive_sync_sts_arg, &recv_args, -1);
- if (rc) {
- pr_err("%s: sync status RPC req failed: %d\n", __func__, rc);
- return rc;
- }
- return recv_args.data;
-}
-
-static int rmt_storage_mmap(struct file *file, struct vm_area_struct *vma)
-{
- unsigned long vsize = vma->vm_end - vma->vm_start;
- int ret = -EINVAL;
-
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vsize, vma->vm_page_prot);
- if (ret < 0)
- pr_err("%s: failed with return val %d\n", __func__, ret);
- return ret;
-}
-
-struct rmt_storage_reg_cb_args {
- uint32_t event;
- uint32_t cb_id;
-};
-
-static int rmt_storage_arg_cb(struct msm_rpc_client *client,
- struct msm_rpc_xdr *xdr, void *data)
-{
- struct rmt_storage_reg_cb_args *args = data;
-
- xdr_send_uint32(xdr, &args->event);
- xdr_send_uint32(xdr, &args->cb_id);
- return 0;
-}
-
-static int rmt_storage_reg_cb(struct msm_rpc_client *client,
- uint32_t proc, uint32_t event, void *callback)
-{
- struct rmt_storage_reg_cb_args args;
- int rc, cb_id;
- int retries = 10;
-
- cb_id = msm_rpc_add_cb_func(client, callback);
- if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
- return cb_id;
-
- args.event = event;
- args.cb_id = cb_id;
-
- while (retries) {
- rc = msm_rpc_client_req2(client, proc, rmt_storage_arg_cb,
- &args, NULL, NULL, -1);
- if (rc != -ETIMEDOUT)
- break;
- retries--;
- udelay(1000);
- }
- if (rc)
- pr_err("%s: Failed to register callback for event %d\n",
- __func__, event);
- return rc;
-}
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-static int rmt_storage_stats_open(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static ssize_t rmt_storage_stats_read(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- uint32_t tot_clients;
- char buf[512];
- int max, j, i = 0;
- struct rmt_storage_stats *stats;
-
- max = sizeof(buf) - 1;
- tot_clients = find_first_zero_bit(&rmc->cids, sizeof(rmc->cids)) - 1;
-
- for (j = 0; j < tot_clients; j++) {
- stats = &client_stats[j];
- i += scnprintf(buf + i, max - i, "stats for partition %s:\n",
- stats->path);
- i += scnprintf(buf + i, max - i, "Min read time: %lld us\n",
- ktime_to_us(stats->rd_stats.min));
- i += scnprintf(buf + i, max - i, "Max read time: %lld us\n",
- ktime_to_us(stats->rd_stats.max));
- i += scnprintf(buf + i, max - i, "Total read time: %lld us\n",
- ktime_to_us(stats->rd_stats.total));
- i += scnprintf(buf + i, max - i, "Total read requests: %ld\n",
- stats->rd_stats.count);
- if (stats->count)
- i += scnprintf(buf + i, max - i,
- "Avg read time: %lld us\n",
- div_s64(ktime_to_us(stats->total),
- stats->rd_stats.count));
-
- i += scnprintf(buf + i, max - i, "Min write time: %lld us\n",
- ktime_to_us(stats->wr_stats.min));
- i += scnprintf(buf + i, max - i, "Max write time: %lld us\n",
- ktime_to_us(stats->wr_stats.max));
- i += scnprintf(buf + i, max - i, "Total write time: %lld us\n",
- ktime_to_us(stats->wr_stats.total));
- i += scnprintf(buf + i, max - i, "Total read requests: %ld\n",
- stats->wr_stats.count);
- if (stats->count)
- i += scnprintf(buf + i, max - i,
- "Avg write time: %lld us\n",
- div_s64(ktime_to_us(stats->total),
- stats->wr_stats.count));
- }
- return simple_read_from_buffer(ubuf, count, ppos, buf, i);
-}
-
-static const struct file_operations debug_ops = {
- .owner = THIS_MODULE,
- .open = rmt_storage_stats_open,
- .read = rmt_storage_stats_read,
-};
-#endif
-
-const struct file_operations rmt_storage_fops = {
- .owner = THIS_MODULE,
- .open = rmt_storage_open,
- .unlocked_ioctl = rmt_storage_ioctl,
- .mmap = rmt_storage_mmap,
- .release = rmt_storage_release,
-};
-
-static struct miscdevice rmt_storage_device = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "rmt_storage",
- .fops = &rmt_storage_fops,
-};
-
-static int rmt_storage_get_ramfs(struct rmt_storage_srv *srv)
-{
- struct shared_ramfs_table *ramfs_table;
- struct shared_ramfs_entry *ramfs_entry;
- int index, ret;
-
- if (srv->prog != MSM_RMT_STORAGE_APIPROG)
- return 0;
-
- ramfs_table = smem_alloc(SMEM_SEFS_INFO,
- sizeof(struct shared_ramfs_table));
-
- if (!ramfs_table) {
- pr_err("%s: No RAMFS table in SMEM\n", __func__);
- return -ENOENT;
- }
-
- if ((ramfs_table->magic_id != (u32) RAMFS_INFO_MAGICNUMBER) ||
- (ramfs_table->version != (u32) RAMFS_INFO_VERSION)) {
- pr_err("%s: Magic / Version mismatch:, "
- "magic_id=%#x, format_version=%#x\n", __func__,
- ramfs_table->magic_id, ramfs_table->version);
- return -ENOENT;
- }
-
- for (index = 0; index < ramfs_table->entries; index++) {
- ramfs_entry = &ramfs_table->ramfs_entry[index];
- if (!ramfs_entry->client_id ||
- ramfs_entry->client_id == (u32) RAMFS_DEFAULT)
- break;
-
- pr_info("%s: RAMFS entry: addr = 0x%08x, size = 0x%08x\n",
- __func__, ramfs_entry->base_addr, ramfs_entry->size);
-
- ret = rmt_storage_add_shrd_mem(ramfs_entry->client_id,
- ramfs_entry->base_addr,
- ramfs_entry->size,
- NULL,
- ramfs_entry,
- srv);
- if (ret) {
- pr_err("%s: Error (%d) adding shared mem\n",
- __func__, ret);
- return ret;
- }
- }
- return 0;
-}
-
-static ssize_t
-show_force_sync(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct platform_device *pdev;
- struct rpcsvr_platform_device *rpc_pdev;
- struct rmt_storage_srv *srv;
-
- pdev = container_of(dev, struct platform_device, dev);
- rpc_pdev = container_of(pdev, struct rpcsvr_platform_device, base);
- srv = rmt_storage_get_srv(rpc_pdev->prog);
- if (!srv) {
- pr_err("%s: Unable to find prog=0x%x\n", __func__,
- rpc_pdev->prog);
- return -EINVAL;
- }
-
- return rmt_storage_force_sync(srv->rpc_client);
-}
-
-/* Returns -EINVAL for invalid sync token and an error value for any failure
- * in RPC call. Upon success, it returns a sync status of 1 (sync done)
- * or 0 (sync still pending).
- */
-static ssize_t
-show_sync_sts(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct platform_device *pdev;
- struct rpcsvr_platform_device *rpc_pdev;
- struct rmt_storage_srv *srv;
-
- pdev = container_of(dev, struct platform_device, dev);
- rpc_pdev = container_of(pdev, struct rpcsvr_platform_device, base);
- srv = rmt_storage_get_srv(rpc_pdev->prog);
- if (!srv) {
- pr_err("%s: Unable to find prog=0x%x\n", __func__,
- rpc_pdev->prog);
- return -EINVAL;
- }
- return snprintf(buf, PAGE_SIZE, "%d\n",
- rmt_storage_get_sync_status(srv->rpc_client));
-}
-
-/*
- * Initiate the remote storage force sync and wait until
- * sync status is done or maximum 4 seconds in the reboot notifier.
- * Usually RMT storage sync is not taking more than 2 seconds
- * for encryption and sync.
- */
-#define MAX_GET_SYNC_STATUS_TRIES 200
-#define RMT_SLEEP_INTERVAL_MS 20
-static int rmt_storage_reboot_call(
- struct notifier_block *this, unsigned long code, void *cmd)
-{
- int ret, count = 0;
-
- /*
- * In recovery mode RMT daemon is not available,
- * so return from reboot notifier without initiating
- * force sync.
- */
- spin_lock(&rmc->lock);
- if (!rmc->open_excl) {
- spin_unlock(&rmc->lock);
- msm_rpc_unregister_client(rmt_srv->rpc_client);
- return NOTIFY_DONE;
- }
-
- spin_unlock(&rmc->lock);
- switch (code) {
- case SYS_RESTART:
- case SYS_HALT:
- case SYS_POWER_OFF:
- pr_info("%s: Sending force-sync RPC request\n", __func__);
- ret = rmt_storage_force_sync(rmt_srv->rpc_client);
- if (ret)
- break;
-
- do {
- count++;
- msleep(RMT_SLEEP_INTERVAL_MS);
- ret = rmt_storage_get_sync_status(rmt_srv->rpc_client);
- } while (ret != 1 && count < MAX_GET_SYNC_STATUS_TRIES);
-
- if (ret == 1)
- pr_info("%s: Final-sync successful\n", __func__);
- else
- pr_err("%s: Final-sync failed\n", __func__);
-
- /*
- * Check if any ongoing efs_sync triggered just before force
- * sync is pending. If so, wait for 4sec for completing efs_sync
- * before unregistring client.
- */
- count = 0;
- while (count < MAX_GET_SYNC_STATUS_TRIES) {
- if (atomic_read(&rmc->wcount) == 0) {
- break;
- } else {
- count++;
- msleep(RMT_SLEEP_INTERVAL_MS);
- }
- }
- if (atomic_read(&rmc->wcount))
- pr_err("%s: Efs_sync still incomplete\n", __func__);
-
- pr_info("%s: Un-register RMT storage client\n", __func__);
- msm_rpc_unregister_client(rmt_srv->rpc_client);
- break;
-
- default:
- break;
- }
- return NOTIFY_DONE;
-}
-
-/*
- * For the RMT storage sync, RPC channels are required. If we do not
- * give max priority to RMT storage reboot notifier, RPC channels may get
- * closed before RMT storage sync completed if RPC reboot notifier gets
- * executed before this remotefs reboot notifier. Hence give the maximum
- * priority to this reboot notifier.
- */
-static struct notifier_block rmt_storage_reboot_notifier = {
- .notifier_call = rmt_storage_reboot_call,
- .priority = INT_MAX,
-};
-
-static int rmt_storage_init_ramfs(struct rmt_storage_srv *srv)
-{
- struct shared_ramfs_table *ramfs_table;
-
- if (srv->prog != MSM_RMT_STORAGE_APIPROG)
- return 0;
-
- ramfs_table = smem_alloc(SMEM_SEFS_INFO,
- sizeof(struct shared_ramfs_table));
-
- if (!ramfs_table) {
- pr_err("%s: No RAMFS table in SMEM\n", __func__);
- return -ENOENT;
- }
-
- if (ramfs_table->magic_id == RAMFS_INFO_MAGICNUMBER) {
- pr_debug("RAMFS table already filled... skipping %s", \
- __func__);
- return 0;
- }
-
- ramfs_table->ramfs_entry[0].client_id = RAMFS_MODEMSTORAGE_ID;
- ramfs_table->ramfs_entry[0].base_addr = RAMFS_SHARED_EFS_RAM_BASE;
- ramfs_table->ramfs_entry[0].size = RAMFS_SHARED_EFS_RAM_SIZE;
- ramfs_table->ramfs_entry[0].client_sts = RAMFS_DEFAULT;
-
- ramfs_table->ramfs_entry[1].client_id = RAMFS_SSD_STORAGE_ID;
- ramfs_table->ramfs_entry[1].base_addr = RAMFS_SHARED_SSD_RAM_BASE;
- ramfs_table->ramfs_entry[1].size = RAMFS_SHARED_SSD_RAM_SIZE;
- ramfs_table->ramfs_entry[1].client_sts = RAMFS_DEFAULT;
-
- ramfs_table->entries = 2;
- ramfs_table->version = RAMFS_INFO_VERSION;
- ramfs_table->magic_id = RAMFS_INFO_MAGICNUMBER;
-
- return 0;
-}
-
-static void rmt_storage_set_client_status(struct rmt_storage_srv *srv,
- int enable)
-{
- struct rmt_shrd_mem *shrd_mem;
-
- spin_lock(&rmc->lock);
- list_for_each_entry(shrd_mem, &rmc->shrd_mem_list, list)
- if (shrd_mem->srv->prog == srv->prog)
- if (shrd_mem->smem_info)
- shrd_mem->smem_info->client_sts = !!enable;
- spin_unlock(&rmc->lock);
-}
-
-static DEVICE_ATTR(force_sync, S_IRUGO | S_IWUSR, show_force_sync, NULL);
-static DEVICE_ATTR(sync_sts, S_IRUGO | S_IWUSR, show_sync_sts, NULL);
-static struct attribute *dev_attrs[] = {
- &dev_attr_force_sync.attr,
- &dev_attr_sync_sts.attr,
- NULL,
-};
-static struct attribute_group dev_attr_grp = {
- .attrs = dev_attrs,
-};
-
-static void handle_restart_teardown(struct msm_rpc_client *client)
-{
- struct rmt_storage_srv *srv;
-
- srv = rmt_storage_get_srv(client->prog);
- if (!srv)
- return;
- pr_debug("%s: Modem restart for 0x%08x\n", __func__, srv->prog);
- cancel_delayed_work_sync(&srv->restart_work);
-}
-
-#define RESTART_WORK_DELAY_MS 1000
-
-static void handle_restart_setup(struct msm_rpc_client *client)
-{
- struct rmt_storage_srv *srv;
-
- srv = rmt_storage_get_srv(client->prog);
- if (!srv)
- return;
- pr_debug("%s: Scheduling restart for 0x%08x\n", __func__, srv->prog);
- queue_delayed_work(rmc->workq, &srv->restart_work,
- msecs_to_jiffies(RESTART_WORK_DELAY_MS));
-}
-
-static int rmt_storage_reg_callbacks(struct msm_rpc_client *client)
-{
- int ret;
-
- ret = rmt_storage_reg_cb(client,
- RMT_STORAGE_REGISTER_OPEN_PROC,
- RMT_STORAGE_EVNT_OPEN,
- rmt_storage_event_open_cb);
- if (ret)
- return ret;
- ret = rmt_storage_reg_cb(client,
- RMT_STORAGE_REGISTER_CB_PROC,
- RMT_STORAGE_EVNT_CLOSE,
- rmt_storage_event_close_cb);
- if (ret)
- return ret;
- ret = rmt_storage_reg_cb(client,
- RMT_STORAGE_REGISTER_CB_PROC,
- RMT_STORAGE_EVNT_WRITE_BLOCK,
- rmt_storage_event_write_block_cb);
- if (ret)
- return ret;
- ret = rmt_storage_reg_cb(client,
- RMT_STORAGE_REGISTER_CB_PROC,
- RMT_STORAGE_EVNT_GET_DEV_ERROR,
- rmt_storage_event_get_err_cb);
- if (ret)
- return ret;
- ret = rmt_storage_reg_cb(client,
- RMT_STORAGE_REGISTER_WRITE_IOVEC_PROC,
- RMT_STORAGE_EVNT_WRITE_IOVEC,
- rmt_storage_event_write_iovec_cb);
- if (ret)
- return ret;
- ret = rmt_storage_reg_cb(client,
- RMT_STORAGE_REGISTER_READ_IOVEC_PROC,
- RMT_STORAGE_EVNT_READ_IOVEC,
- rmt_storage_event_read_iovec_cb);
- if (ret)
- return ret;
- ret = rmt_storage_reg_cb(client,
- RMT_STORAGE_REGISTER_CB_PROC,
- RMT_STORAGE_EVNT_SEND_USER_DATA,
- rmt_storage_event_user_data_cb);
- if (ret)
- return ret;
- ret = rmt_storage_reg_cb(client,
- RMT_STORAGE_REGISTER_ALLOC_RMT_BUF_PROC,
- RMT_STORAGE_EVNT_ALLOC_RMT_BUF,
- rmt_storage_event_alloc_rmt_buf_cb);
- if (ret)
- pr_info("%s: Unable (%d) registering aloc_rmt_buf\n",
- __func__, ret);
-
- pr_debug("%s: Callbacks (re)registered for 0x%08x\n\n", __func__,
- client->prog);
- return 0;
-}
-
-static void rmt_storage_restart_work(struct work_struct *work)
-{
- struct rmt_storage_srv *srv;
- int ret;
-
- srv = container_of((struct delayed_work *)work,
- struct rmt_storage_srv, restart_work);
- if (!rmt_storage_get_srv(srv->prog)) {
- pr_err("%s: Invalid server\n", __func__);
- return;
- }
-
- ret = rmt_storage_reg_callbacks(srv->rpc_client);
- if (!ret)
- return;
-
- pr_err("%s: Error (%d) re-registering callbacks for0x%08x\n",
- __func__, ret, srv->prog);
-
- if (!msm_rpc_client_in_reset(srv->rpc_client))
- queue_delayed_work(rmc->workq, &srv->restart_work,
- msecs_to_jiffies(RESTART_WORK_DELAY_MS));
-}
-
-static int rmt_storage_probe(struct platform_device *pdev)
-{
- struct rpcsvr_platform_device *dev;
- int ret;
-
- dev = container_of(pdev, struct rpcsvr_platform_device, base);
- rmt_srv = rmt_storage_get_srv(dev->prog);
-
- if (!rmt_srv) {
- pr_err("%s: Invalid prog = %#x\n", __func__, dev->prog);
- return -ENXIO;
- }
-
- rmt_storage_init_ramfs(rmt_srv);
- rmt_storage_get_ramfs(rmt_srv);
-
- INIT_DELAYED_WORK(&rmt_srv->restart_work, rmt_storage_restart_work);
-
- /* Client Registration */
- rmt_srv->rpc_client = msm_rpc_register_client2("rmt_storage",
- dev->prog, dev->vers, 1,
- handle_rmt_storage_call);
- if (IS_ERR(rmt_srv->rpc_client)) {
- pr_err("%s: Unable to register client (prog %.8x vers %.8x)\n",
- __func__, dev->prog, dev->vers);
- ret = PTR_ERR(rmt_srv->rpc_client);
- return ret;
- }
-
- ret = msm_rpc_register_reset_callbacks(rmt_srv->rpc_client,
- handle_restart_teardown,
- handle_restart_setup);
- if (ret)
- goto unregister_client;
-
- pr_info("%s: Remote storage RPC client (0x%x)initialized\n",
- __func__, dev->prog);
-
- /* register server callbacks */
- ret = rmt_storage_reg_callbacks(rmt_srv->rpc_client);
- if (ret)
- goto unregister_client;
-
- /* For targets that poll SMEM, set status to ready */
- rmt_storage_set_client_status(rmt_srv, 1);
-
- ret = register_reboot_notifier(&rmt_storage_reboot_notifier);
- if (ret) {
- pr_err("%s: Failed to register reboot notifier", __func__);
- goto unregister_client;
- }
-
- ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
- if (ret)
- pr_err("%s: Failed to create sysfs node: %d\n", __func__, ret);
-
- return 0;
-
-unregister_client:
- msm_rpc_unregister_client(rmt_srv->rpc_client);
- return ret;
-}
-
-static void rmt_storage_client_shutdown(struct platform_device *pdev)
-{
- struct rpcsvr_platform_device *dev;
- struct rmt_storage_srv *srv;
-
- dev = container_of(pdev, struct rpcsvr_platform_device, base);
- srv = rmt_storage_get_srv(dev->prog);
- rmt_storage_set_client_status(srv, 0);
-}
-
-static void rmt_storage_destroy_rmc(void)
-{
- wake_lock_destroy(&rmc->wlock);
-}
-
-static void __init rmt_storage_init_client_info(void)
-{
- /* Initialization */
- init_waitqueue_head(&rmc->event_q);
- spin_lock_init(&rmc->lock);
- atomic_set(&rmc->total_events, 0);
- INIT_LIST_HEAD(&rmc->event_list);
- INIT_LIST_HEAD(&rmc->client_list);
- INIT_LIST_HEAD(&rmc->shrd_mem_list);
- /* The client expects a non-zero return value for
- * its open requests. Hence reserve 0 bit. */
- __set_bit(0, &rmc->cids);
- atomic_set(&rmc->wcount, 0);
- wake_lock_init(&rmc->wlock, WAKE_LOCK_SUSPEND, "rmt_storage");
-}
-
-static struct rmt_storage_srv msm_srv = {
- .prog = MSM_RMT_STORAGE_APIPROG,
- .plat_drv = {
- .probe = rmt_storage_probe,
- .shutdown = rmt_storage_client_shutdown,
- .driver = {
- .name = "rs300000a7",
- .owner = THIS_MODULE,
- },
- },
-};
-
-static struct rmt_storage_srv mdm_srv = {
- .prog = MDM_RMT_STORAGE_APIPROG,
- .plat_drv = {
- .probe = rmt_storage_probe,
- .shutdown = rmt_storage_client_shutdown,
- .driver = {
- .name = "rs300100a7",
- .owner = THIS_MODULE,
- },
- },
-};
-
-static struct rmt_storage_srv *rmt_storage_get_srv(uint32_t prog)
-{
- if (prog == MSM_RMT_STORAGE_APIPROG)
- return &msm_srv;
- if (prog == MDM_RMT_STORAGE_APIPROG)
- return &mdm_srv;
- return NULL;
-}
-
-
-static uint32_t rmt_storage_get_sid(const char *path)
-{
- if (!strncmp(path, "/boot/modem_fs1", MAX_PATH_NAME))
- return RAMFS_MODEMSTORAGE_ID;
- if (!strncmp(path, "/boot/modem_fs2", MAX_PATH_NAME))
- return RAMFS_MODEMSTORAGE_ID;
- if (!strncmp(path, "/boot/modem_fsg", MAX_PATH_NAME))
- return RAMFS_MODEMSTORAGE_ID;
- if (!strncmp(path, "/q6_fs1_parti_id_0x59", MAX_PATH_NAME))
- return RAMFS_MDM_STORAGE_ID;
- if (!strncmp(path, "/q6_fs2_parti_id_0x5A", MAX_PATH_NAME))
- return RAMFS_MDM_STORAGE_ID;
- if (!strncmp(path, "/q6_fsg_parti_id_0x5B", MAX_PATH_NAME))
- return RAMFS_MDM_STORAGE_ID;
- if (!strncmp(path, "ssd", MAX_PATH_NAME))
- return RAMFS_SSD_STORAGE_ID;
- return 0;
-}
-
-static int __init rmt_storage_init(void)
-{
-#ifdef CONFIG_MSM_SDIO_SMEM
- void *mdm_local_buf;
-#endif
- int ret = 0;
-
- rmc = kzalloc(sizeof(struct rmt_storage_client_info), GFP_KERNEL);
- if (!rmc) {
- pr_err("%s: Unable to allocate memory\n", __func__);
- return -ENOMEM;
- }
- rmt_storage_init_client_info();
-
- ret = platform_driver_register(&msm_srv.plat_drv);
- if (ret) {
- pr_err("%s: Unable to register MSM RPC driver\n", __func__);
- goto rmc_free;
- }
-
- ret = platform_driver_register(&mdm_srv.plat_drv);
- if (ret) {
- pr_err("%s: Unable to register MDM RPC driver\n", __func__);
- goto unreg_msm_rpc;
- }
-
- ret = misc_register(&rmt_storage_device);
- if (ret) {
- pr_err("%s: Unable to register misc device %d\n", __func__,
- MISC_DYNAMIC_MINOR);
- goto unreg_mdm_rpc;
- }
-
-#ifdef CONFIG_MSM_SDIO_SMEM
- mdm_local_buf = kzalloc(MDM_LOCAL_BUF_SZ, GFP_KERNEL);
- if (!mdm_local_buf) {
- pr_err("%s: Unable to allocate shadow mem\n", __func__);
- ret = -ENOMEM;
- goto unreg_misc;
- }
-
- ret = rmt_storage_add_shrd_mem(RAMFS_MDM_STORAGE_ID,
- __pa(mdm_local_buf),
- MDM_LOCAL_BUF_SZ,
- NULL, NULL, &mdm_srv);
- if (ret) {
- pr_err("%s: Unable to add shadow mem entry\n", __func__);
- goto free_mdm_local_buf;
- }
-
- pr_debug("%s: Shadow memory at %p (phys=%lx), %d bytes\n", __func__,
- mdm_local_buf, __pa(mdm_local_buf), MDM_LOCAL_BUF_SZ);
-#endif
-
- rmc->workq = create_singlethread_workqueue("rmt_storage");
- if (!rmc->workq)
- return -ENOMEM;
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
- stats_dentry = debugfs_create_file("rmt_storage_stats", 0444, 0,
- NULL, &debug_ops);
- if (!stats_dentry)
- pr_err("%s: Failed to create stats debugfs file\n", __func__);
-#endif
- return 0;
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-free_mdm_local_buf:
- kfree(mdm_local_buf);
-unreg_misc:
- misc_deregister(&rmt_storage_device);
-#endif
-unreg_mdm_rpc:
- platform_driver_unregister(&mdm_srv.plat_drv);
-unreg_msm_rpc:
- platform_driver_unregister(&msm_srv.plat_drv);
-rmc_free:
- rmt_storage_destroy_rmc();
- kfree(rmc);
- return ret;
-}
-
-module_init(rmt_storage_init);
-MODULE_DESCRIPTION("Remote Storage RPC Client");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 935bb9a..7ad6401 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -280,7 +280,8 @@
static void *__alloc_from_contiguous(struct device *dev, size_t size,
pgprot_t prot, struct page **ret_page,
- bool no_kernel_mapping, const void *caller);
+ const void *caller,
+ struct dma_attrs *attrs);
struct dma_pool {
size_t size;
@@ -321,7 +322,7 @@
if (IS_ENABLED(CONFIG_CMA))
ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page,
- false, atomic_pool_init);
+ atomic_pool_init, NULL);
else
ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot,
&page, NULL);
@@ -508,19 +509,22 @@
#define NO_KERNEL_MAPPING_DUMMY 0x2222
static void *__alloc_from_contiguous(struct device *dev, size_t size,
pgprot_t prot, struct page **ret_page,
- bool no_kernel_mapping,
- const void *caller)
+ const void *caller,
+ struct dma_attrs *attrs)
{
unsigned long order = get_order(size);
size_t count = size >> PAGE_SHIFT;
struct page *page;
void *ptr;
+ bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING,
+ attrs);
page = dma_alloc_from_contiguous(dev, count, order);
if (!page)
return NULL;
- __dma_clear_buffer(page, size);
+ if (!dma_get_attr(DMA_ATTR_SKIP_ZEROING, attrs))
+ __dma_clear_buffer(page, size);
if (!PageHighMem(page)) {
__dma_remap(page, size, prot, no_kernel_mapping);
@@ -601,7 +605,7 @@
static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
gfp_t gfp, pgprot_t prot, const void *caller,
- bool no_kernel_mapping)
+ struct dma_attrs *attrs)
{
u64 mask = get_coherent_dma_mask(dev);
struct page *page;
@@ -642,7 +646,7 @@
addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller);
else
addr = __alloc_from_contiguous(dev, size, prot, &page,
- no_kernel_mapping, caller);
+ caller, attrs);
if (addr)
*handle = pfn_to_dma(dev, page_to_pfn(page));
@@ -659,14 +663,12 @@
{
pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
void *memory;
- bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING,
- attrs);
if (dma_alloc_from_coherent(dev, size, handle, &memory))
return memory;
return __dma_alloc(dev, size, handle, gfp, prot,
- __builtin_return_address(0), no_kernel_mapping);
+ __builtin_return_address(0), attrs);
}
/*
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 2adcbbc..4745406 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -47,6 +47,7 @@
unsigned long base_pfn;
unsigned long count;
unsigned long *bitmap;
+ bool in_system;
struct mutex lock;
};
@@ -60,6 +61,7 @@
unsigned long size;
struct cma *cma;
const char *name;
+ bool to_system;
} cma_areas[MAX_CMA_AREAS];
static unsigned cma_area_count;
@@ -170,7 +172,7 @@
}
static __init struct cma *cma_create_area(unsigned long base_pfn,
- unsigned long count)
+ unsigned long count, bool system)
{
int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
struct cma *cma;
@@ -184,14 +186,17 @@
cma->base_pfn = base_pfn;
cma->count = count;
+ cma->in_system = system;
cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
if (!cma->bitmap)
goto no_mem;
- ret = cma_activate_area(base_pfn, count);
- if (ret)
- goto error;
+ if (cma->in_system) {
+ ret = cma_activate_area(base_pfn, count);
+ if (ret)
+ goto error;
+ }
mutex_init(&cma->lock);
pr_debug("%s: returned %p\n", __func__, (void *)cma);
@@ -214,6 +219,7 @@
unsigned long len;
__be32 *prop;
char *name;
+ bool in_system;
phys_addr_t limit = MEMBLOCK_ALLOC_ANYWHERE;
if (!of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
@@ -227,6 +233,8 @@
size = be32_to_cpu(prop[1]);
name = of_get_flat_dt_prop(node, "label", NULL);
+ in_system =
+ of_get_flat_dt_prop(node, "linux,reserve-region", NULL) ? 0 : 1;
prop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
if (prop)
@@ -234,7 +242,8 @@
pr_info("Found %s, memory base %lx, size %ld MiB, limit %pa\n", uname,
(unsigned long)base, (unsigned long)size / SZ_1M, &limit);
- dma_contiguous_reserve_area(size, &base, limit, name);
+ dma_contiguous_reserve_area(size, &base, limit, name,
+ in_system);
return 0;
}
@@ -275,8 +284,8 @@
pr_debug("%s: reserving %ld MiB for global area\n", __func__,
(unsigned long)sel_size / SZ_1M);
- if (dma_contiguous_reserve_area(sel_size, &base, limit, NULL)
- == 0)
+ if (dma_contiguous_reserve_area(sel_size, &base, limit, NULL,
+ true) == 0)
dma_contiguous_def_base = base;
}
#ifdef CONFIG_OF
@@ -299,7 +308,8 @@
* devices.
*/
int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base,
- phys_addr_t limit, const char *name)
+ phys_addr_t limit, const char *name,
+ bool to_system)
{
phys_addr_t base = *res_base;
phys_addr_t alignment;
@@ -352,6 +362,7 @@
cma_areas[cma_area_count].base = base;
cma_areas[cma_area_count].size = size;
cma_areas[cma_area_count].name = name;
+ cma_areas[cma_area_count].to_system = to_system;
cma_area_count++;
*res_base = base;
@@ -434,8 +445,9 @@
for (i = 0; i < cma_area_count; i++) {
phys_addr_t base = PFN_DOWN(cma_areas[i].base);
unsigned int count = cma_areas[i].size >> PAGE_SHIFT;
+ bool system = cma_areas[i].to_system;
- cma = cma_create_area(base, count);
+ cma = cma_create_area(base, count, system);
if (!IS_ERR(cma))
cma_areas[i].cma = cma;
}
@@ -485,7 +497,7 @@
unsigned long mask, pfn, pageno, start = 0;
struct cma *cma = dev_get_cma_area(dev);
struct page *page = NULL;
- int ret;
+ int ret = 0;
int tries = 0;
if (!cma || !cma->count)
@@ -521,7 +533,8 @@
pfn = cma->base_pfn + pageno;
mutex_lock(&cma_mutex);
- ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
+ if (cma->in_system)
+ ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
mutex_unlock(&cma_mutex);
if (ret == 0) {
page = pfn_to_page(pfn);
@@ -573,7 +586,8 @@
VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
- free_contig_range(pfn, count);
+ if (cma->in_system)
+ free_contig_range(pfn, count);
clear_cma_bitmap(cma, pfn, count);
return true;
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 0c7c9e0..936541f 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -640,7 +640,6 @@
char *hdr;
char *bufp;
uint32_t read_data;
- int i;
memwidth = BMVAL(tmc_readl(drvdata, CORESIGHT_DEVID), 8, 10);
if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
@@ -654,16 +653,22 @@
bufp = drvdata->buf;
while (1) {
- for (i = 0; i < memwords; i++) {
- read_data = tmc_readl_no_log(drvdata, TMC_RRD);
- if (read_data == 0xFFFFFFFF)
- goto out;
- memcpy(bufp, &read_data, BYTES_PER_WORD);
- bufp += BYTES_PER_WORD;
+ read_data = tmc_readl_no_log(drvdata, TMC_RRD);
+ if (read_data == 0xFFFFFFFF)
+ goto out;
+ if ((bufp - drvdata->buf) >= drvdata->size) {
+ dev_err(drvdata->dev, "ETF-ETB end marker missing\n");
+ goto out;
}
+ memcpy(bufp, &read_data, BYTES_PER_WORD);
+ bufp += BYTES_PER_WORD;
}
out:
+ if ((bufp - drvdata->buf) % (memwords * BYTES_PER_WORD))
+ dev_dbg(drvdata->dev, "ETF-ETB data is not %lx bytes aligned\n",
+ (unsigned long) memwords * BYTES_PER_WORD);
+
if (drvdata->aborting) {
hdr = drvdata->buf - PAGE_SIZE;
*(uint32_t *)(hdr + TMC_ETFETB_DUMP_MAGIC_OFF) =
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index da68d05..048dc56 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -136,6 +136,7 @@
}
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
+ dma_set_attr(DMA_ATTR_SKIP_ZEROING, &attrs);
cpu_addr = dma_alloc_attrs(sheap->dev, len, &handle, GFP_KERNEL,
&attrs);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index f230033..12fa799 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -627,7 +627,8 @@
}
static inline void refcount_group(struct adreno_perfcount_group *group,
- unsigned int reg, unsigned int flags, unsigned int *lo)
+ unsigned int reg, unsigned int flags,
+ unsigned int *lo, unsigned int *hi)
{
if (flags & PERFCOUNTER_FLAG_KERNEL)
group->regs[reg].kernelcount++;
@@ -636,6 +637,9 @@
if (lo)
*lo = group->regs[reg].offset;
+
+ if (hi)
+ *hi = group->regs[reg].offset_hi;
}
/**
@@ -643,7 +647,8 @@
* @adreno_dev: Adreno device to configure
* @groupid: Desired performance counter group
* @countable: Countable desired to be in a counter
- * @offset: Return offset of the countable
+ * @offset: Return offset of the LO counter assigned
+ * @offset_hi: Return offset of the HI counter assigned
* @flags: Used to setup kernel perf counters
*
* Try to place a countable in an available counter. If the countable is
@@ -653,7 +658,7 @@
int adreno_perfcounter_get(struct adreno_device *adreno_dev,
unsigned int groupid, unsigned int countable, unsigned int *offset,
- unsigned int flags)
+ unsigned int *offset_hi, unsigned int flags)
{
struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
struct adreno_perfcount_group *group;
@@ -663,6 +668,8 @@
/* always clear return variables */
if (offset)
*offset = 0;
+ if (offset_hi)
+ *offset_hi = 0;
if (NULL == counters)
return -EINVAL;
@@ -684,7 +691,8 @@
/* If it is already reserved, just increase the refcounts */
if ((group->regs[countable].kernelcount != 0) ||
(group->regs[countable].usercount != 0)) {
- refcount_group(group, countable, flags, offset);
+ refcount_group(group, countable, flags,
+ offset, offset_hi);
return 0;
}
@@ -700,7 +708,8 @@
for (i = 0; i < group->reg_count; i++) {
if (group->regs[i].countable == countable) {
- refcount_group(group, i, flags, offset);
+ refcount_group(group, i, flags,
+ offset, offset_hi);
return 0;
} else if (group->regs[i].countable ==
KGSL_PERFCOUNTER_NOT_USED) {
@@ -733,6 +742,8 @@
if (offset)
*offset = group->regs[empty].offset;
+ if (offset_hi)
+ *offset_hi = group->regs[empty].offset_hi;
return ret;
}
@@ -3352,7 +3363,8 @@
if (result)
break;
result = adreno_perfcounter_get(adreno_dev, get->groupid,
- get->countable, &get->offset, PERFCOUNTER_FLAG_NONE);
+ get->countable, &get->offset, &get->offset_hi,
+ PERFCOUNTER_FLAG_NONE);
kgsl_active_count_put(device);
break;
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 3d9206b..c690801 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -240,6 +240,7 @@
unsigned int kernelcount;
unsigned int usercount;
unsigned int offset;
+ unsigned int offset_hi;
int load_bit;
unsigned int select;
uint64_t value;
@@ -530,7 +531,7 @@
int adreno_perfcounter_get(struct adreno_device *adreno_dev,
unsigned int groupid, unsigned int countable, unsigned int *offset,
- unsigned int flags);
+ unsigned int *offset_hi, unsigned int flags);
int adreno_perfcounter_put(struct adreno_device *adreno_dev,
unsigned int groupid, unsigned int countable, unsigned int flags);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 2025d73..b0851a2 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -3814,141 +3814,158 @@
static struct adreno_perfcount_register a3xx_perfcounters_cp[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_CP_0_LO,
- 0, A3XX_CP_PERFCOUNTER_SELECT },
+ A3XX_RBBM_PERFCTR_CP_0_HI, 0, A3XX_CP_PERFCOUNTER_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_rbbm[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RBBM_0_LO,
- 1, A3XX_RBBM_PERFCOUNTER0_SELECT },
+ A3XX_RBBM_PERFCTR_RBBM_0_HI, 1, A3XX_RBBM_PERFCOUNTER0_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RBBM_1_LO,
- 2, A3XX_RBBM_PERFCOUNTER1_SELECT },
+ A3XX_RBBM_PERFCTR_RBBM_1_HI, 2, A3XX_RBBM_PERFCOUNTER1_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_pc[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_0_LO,
- 3, A3XX_PC_PERFCOUNTER0_SELECT },
+ A3XX_RBBM_PERFCTR_PC_0_HI, 3, A3XX_PC_PERFCOUNTER0_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_1_LO,
- 4, A3XX_PC_PERFCOUNTER1_SELECT },
+ A3XX_RBBM_PERFCTR_PC_1_HI, 4, A3XX_PC_PERFCOUNTER1_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_2_LO,
- 5, A3XX_PC_PERFCOUNTER2_SELECT },
+ A3XX_RBBM_PERFCTR_PC_2_HI, 5, A3XX_PC_PERFCOUNTER2_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_3_LO,
- 6, A3XX_PC_PERFCOUNTER3_SELECT },
+ A3XX_RBBM_PERFCTR_PC_3_HI, 6, A3XX_PC_PERFCOUNTER3_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_vfd[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VFD_0_LO,
- 7, A3XX_VFD_PERFCOUNTER0_SELECT },
+ A3XX_RBBM_PERFCTR_VFD_0_HI, 7, A3XX_VFD_PERFCOUNTER0_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VFD_1_LO,
- 8, A3XX_VFD_PERFCOUNTER1_SELECT },
+ A3XX_RBBM_PERFCTR_VFD_1_HI, 8, A3XX_VFD_PERFCOUNTER1_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_hlsq[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_0_LO,
- 9, A3XX_HLSQ_PERFCOUNTER0_SELECT },
+ A3XX_RBBM_PERFCTR_HLSQ_0_HI, 9,
+ A3XX_HLSQ_PERFCOUNTER0_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_1_LO,
- 10, A3XX_HLSQ_PERFCOUNTER1_SELECT },
+ A3XX_RBBM_PERFCTR_HLSQ_1_HI, 10,
+ A3XX_HLSQ_PERFCOUNTER1_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_2_LO,
- 11, A3XX_HLSQ_PERFCOUNTER2_SELECT },
+ A3XX_RBBM_PERFCTR_HLSQ_2_HI, 11,
+ A3XX_HLSQ_PERFCOUNTER2_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_3_LO,
- 12, A3XX_HLSQ_PERFCOUNTER3_SELECT },
+ A3XX_RBBM_PERFCTR_HLSQ_3_HI, 12,
+ A3XX_HLSQ_PERFCOUNTER3_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_4_LO,
- 13, A3XX_HLSQ_PERFCOUNTER4_SELECT },
+ A3XX_RBBM_PERFCTR_HLSQ_4_HI, 13,
+ A3XX_HLSQ_PERFCOUNTER4_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_5_LO,
- 14, A3XX_HLSQ_PERFCOUNTER5_SELECT },
+ A3XX_RBBM_PERFCTR_HLSQ_5_HI, 14,
+ A3XX_HLSQ_PERFCOUNTER5_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_vpc[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VPC_0_LO,
- 15, A3XX_VPC_PERFCOUNTER0_SELECT },
+ A3XX_RBBM_PERFCTR_VPC_0_HI, 15, A3XX_VPC_PERFCOUNTER0_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VPC_1_LO,
- 16, A3XX_VPC_PERFCOUNTER1_SELECT },
+ A3XX_RBBM_PERFCTR_VPC_1_HI, 16, A3XX_VPC_PERFCOUNTER1_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_tse[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TSE_0_LO,
- 17, A3XX_GRAS_PERFCOUNTER0_SELECT },
+ A3XX_RBBM_PERFCTR_TSE_0_HI, 17, A3XX_GRAS_PERFCOUNTER0_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TSE_1_LO,
- 18, A3XX_GRAS_PERFCOUNTER1_SELECT },
+ A3XX_RBBM_PERFCTR_TSE_1_HI, 18, A3XX_GRAS_PERFCOUNTER1_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_ras[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RAS_0_LO,
- 19, A3XX_GRAS_PERFCOUNTER2_SELECT },
+ A3XX_RBBM_PERFCTR_RAS_0_HI, 19, A3XX_GRAS_PERFCOUNTER2_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RAS_1_LO,
- 20, A3XX_GRAS_PERFCOUNTER3_SELECT },
+ A3XX_RBBM_PERFCTR_RAS_1_HI, 20, A3XX_GRAS_PERFCOUNTER3_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_uche[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_0_LO,
- 21, A3XX_UCHE_PERFCOUNTER0_SELECT },
+ A3XX_RBBM_PERFCTR_UCHE_0_HI, 21,
+ A3XX_UCHE_PERFCOUNTER0_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_1_LO,
- 22, A3XX_UCHE_PERFCOUNTER1_SELECT },
+ A3XX_RBBM_PERFCTR_UCHE_1_HI, 22,
+ A3XX_UCHE_PERFCOUNTER1_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_2_LO,
- 23, A3XX_UCHE_PERFCOUNTER2_SELECT },
+ A3XX_RBBM_PERFCTR_UCHE_2_HI, 23,
+ A3XX_UCHE_PERFCOUNTER2_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_3_LO,
- 24, A3XX_UCHE_PERFCOUNTER3_SELECT },
+ A3XX_RBBM_PERFCTR_UCHE_3_HI, 24,
+ A3XX_UCHE_PERFCOUNTER3_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_4_LO,
- 25, A3XX_UCHE_PERFCOUNTER4_SELECT },
+ A3XX_RBBM_PERFCTR_UCHE_4_HI, 25,
+ A3XX_UCHE_PERFCOUNTER4_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_5_LO,
- 26, A3XX_UCHE_PERFCOUNTER5_SELECT },
+ A3XX_RBBM_PERFCTR_UCHE_5_HI, 26,
+ A3XX_UCHE_PERFCOUNTER5_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_tp[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_0_LO,
- 27, A3XX_TP_PERFCOUNTER0_SELECT },
+ A3XX_RBBM_PERFCTR_TP_0_HI, 27, A3XX_TP_PERFCOUNTER0_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_1_LO,
- 28, A3XX_TP_PERFCOUNTER1_SELECT },
+ A3XX_RBBM_PERFCTR_TP_1_HI, 28, A3XX_TP_PERFCOUNTER1_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_2_LO,
- 29, A3XX_TP_PERFCOUNTER2_SELECT },
+ A3XX_RBBM_PERFCTR_TP_2_HI, 29, A3XX_TP_PERFCOUNTER2_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_3_LO,
- 30, A3XX_TP_PERFCOUNTER3_SELECT },
+ A3XX_RBBM_PERFCTR_TP_3_HI, 30, A3XX_TP_PERFCOUNTER3_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_4_LO,
- 31, A3XX_TP_PERFCOUNTER4_SELECT },
+ A3XX_RBBM_PERFCTR_TP_4_HI, 31, A3XX_TP_PERFCOUNTER4_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_5_LO,
- 32, A3XX_TP_PERFCOUNTER5_SELECT },
+ A3XX_RBBM_PERFCTR_TP_5_HI, 32, A3XX_TP_PERFCOUNTER5_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_sp[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_0_LO,
- 33, A3XX_SP_PERFCOUNTER0_SELECT },
+ A3XX_RBBM_PERFCTR_SP_0_HI, 33, A3XX_SP_PERFCOUNTER0_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_1_LO,
- 34, A3XX_SP_PERFCOUNTER1_SELECT },
+ A3XX_RBBM_PERFCTR_SP_1_HI, 34, A3XX_SP_PERFCOUNTER1_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_2_LO,
- 35, A3XX_SP_PERFCOUNTER2_SELECT },
+ A3XX_RBBM_PERFCTR_SP_2_HI, 35, A3XX_SP_PERFCOUNTER2_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_3_LO,
- 36, A3XX_SP_PERFCOUNTER3_SELECT },
+ A3XX_RBBM_PERFCTR_SP_3_HI, 36, A3XX_SP_PERFCOUNTER3_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_4_LO,
- 37, A3XX_SP_PERFCOUNTER4_SELECT },
+ A3XX_RBBM_PERFCTR_SP_4_HI, 37, A3XX_SP_PERFCOUNTER4_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_5_LO,
- 38, A3XX_SP_PERFCOUNTER5_SELECT },
+ A3XX_RBBM_PERFCTR_SP_5_HI, 38, A3XX_SP_PERFCOUNTER5_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_6_LO,
- 39, A3XX_SP_PERFCOUNTER6_SELECT },
+ A3XX_RBBM_PERFCTR_SP_6_HI, 39, A3XX_SP_PERFCOUNTER6_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_7_LO,
- 40, A3XX_SP_PERFCOUNTER7_SELECT },
+ A3XX_RBBM_PERFCTR_SP_7_HI, 40, A3XX_SP_PERFCOUNTER7_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_rb[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RB_0_LO,
- 41, A3XX_RB_PERFCOUNTER0_SELECT },
+ A3XX_RBBM_PERFCTR_RB_0_HI, 41, A3XX_RB_PERFCOUNTER0_SELECT },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RB_1_LO,
- 42, A3XX_RB_PERFCOUNTER1_SELECT },
+ A3XX_RBBM_PERFCTR_RB_1_HI, 42, A3XX_RB_PERFCOUNTER1_SELECT },
};
static struct adreno_perfcount_register a3xx_perfcounters_pwr[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PWR_0_LO,
- -1, 0 },
+ A3XX_RBBM_PERFCTR_PWR_0_HI, -1, 0 },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PWR_1_LO,
- -1, 0 },
+ A3XX_RBBM_PERFCTR_PWR_1_HI, -1, 0 },
};
static struct adreno_perfcount_register a3xx_perfcounters_vbif[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT0_LO, -1, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT1_LO, -1, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT0_LO,
+ A3XX_VBIF_PERF_CNT0_HI, -1, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT1_LO,
+ A3XX_VBIF_PERF_CNT1_HI, -1, 0 },
};
static struct adreno_perfcount_register a3xx_perfcounters_vbif_pwr[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT0_LO, -1, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT1_LO, -1, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT2_LO, -1, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT0_LO,
+ A3XX_VBIF_PERF_PWR_CNT0_HI, -1, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT1_LO,
+ A3XX_VBIF_PERF_PWR_CNT1_HI, -1, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT2_LO,
+ A3XX_VBIF_PERF_PWR_CNT2_HI, -1, 0 },
};
static struct adreno_perfcount_group a3xx_perfcounter_groups[] = {
@@ -3983,14 +4000,11 @@
int ret = 0;
if (*lo == 0) {
- *hi = 0;
ret = adreno_perfcounter_get(adreno_dev, group, countable,
- lo, PERFCOUNTER_FLAG_KERNEL);
+ lo, hi, PERFCOUNTER_FLAG_KERNEL);
- if (ret == 0)
- *hi = *lo + 1;
- else {
+ if (ret) {
struct kgsl_device *device = &adreno_dev->dev;
KGSL_DRV_ERR(device,
@@ -4106,18 +4120,18 @@
/* Reserve and start countable 1 in the PWR perfcounter group */
ret = adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
- NULL, PERFCOUNTER_FLAG_KERNEL);
+ NULL, NULL, PERFCOUNTER_FLAG_KERNEL);
if (device->pwrctrl.bus_control) {
/* VBIF waiting for RAM */
ret |= adreno_perfcounter_get(adreno_dev,
KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0,
- NULL, PERFCOUNTER_FLAG_KERNEL);
+ NULL, NULL, PERFCOUNTER_FLAG_KERNEL);
/* VBIF DDR cycles */
ret |= adreno_perfcounter_get(adreno_dev,
KGSL_PERFCOUNTER_GROUP_VBIF,
VBIF_AXI_TOTAL_BEATS,
- &adreno_dev->ram_cycles_lo,
+ &adreno_dev->ram_cycles_lo, NULL,
PERFCOUNTER_FLAG_KERNEL);
}
diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c
index 38e0af8..45075a5 100644
--- a/drivers/gpu/msm/adreno_profile.c
+++ b/drivers/gpu/msm/adreno_profile.c
@@ -146,7 +146,7 @@
entry->offset, data_offset);
IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset,
gpuaddr + data_offset, data_offset);
- IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset + 1,
+ IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset_hi,
gpuaddr + data_offset, data_offset);
/* skip over post_ib counter data */
@@ -185,7 +185,7 @@
IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset,
gpuaddr + data_offset, data_offset);
- IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset + 1,
+ IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset_hi,
gpuaddr + data_offset, data_offset);
}
@@ -281,7 +281,7 @@
static bool _add_to_assignments_list(struct adreno_profile *profile,
const char *str, unsigned int groupid, unsigned int countable,
- unsigned int offset)
+ unsigned int offset, unsigned int offset_hi)
{
struct adreno_profile_assigns_list *entry;
@@ -295,6 +295,7 @@
entry->countable = countable;
entry->groupid = groupid;
entry->offset = offset;
+ entry->offset_hi = offset_hi;
strlcpy(entry->name, str, sizeof(entry->name));
@@ -576,7 +577,7 @@
unsigned int groupid, unsigned int countable)
{
struct adreno_profile *profile = &adreno_dev->profile;
- unsigned int offset;
+ unsigned int offset, offset_hi;
const char *name = NULL;
name = adreno_perfcounter_get_name(adreno_dev, groupid);
@@ -588,13 +589,13 @@
return;
/* add to perf counter allocation, if fail skip it */
- if (adreno_perfcounter_get(adreno_dev, groupid,
- countable, &offset, PERFCOUNTER_FLAG_NONE))
+ if (adreno_perfcounter_get(adreno_dev, groupid, countable,
+ &offset, &offset_hi, PERFCOUNTER_FLAG_NONE))
return;
/* add to assignments list, put counter back if error */
if (!_add_to_assignments_list(profile, name, groupid,
- countable, offset))
+ countable, offset, offset_hi))
adreno_perfcounter_put(adreno_dev, groupid,
countable, PERFCOUNTER_FLAG_KERNEL);
}
diff --git a/drivers/gpu/msm/adreno_profile.h b/drivers/gpu/msm/adreno_profile.h
index 7e1ccb2..dfd22d8 100644
--- a/drivers/gpu/msm/adreno_profile.h
+++ b/drivers/gpu/msm/adreno_profile.h
@@ -27,7 +27,8 @@
char name[25];
unsigned int groupid;
unsigned int countable;
- unsigned int offset; /* LO offset, HI offset is +1 */
+ unsigned int offset; /* LO offset */
+ unsigned int offset_hi; /* HI offset */
};
struct adreno_profile {
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index a96ab2b..5d78879 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -64,14 +64,8 @@
struct sg_table *table;
};
-static void kgsl_put_process_private(struct kgsl_device *device,
- struct kgsl_process_private *private);
-
static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry);
-static void
-kgsl_put_process_private(struct kgsl_device *device,
- struct kgsl_process_private *private);
/**
* kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
* device: KGSL device
@@ -352,8 +346,8 @@
{
int ret;
struct kgsl_process_private *process = dev_priv->process_priv;
-
- ret = kref_get_unless_zero(&process->refcount);
+
+ ret = kgsl_process_private_get(process);
if (!ret)
return -EBADF;
@@ -392,7 +386,7 @@
return ret;
err_put_proc_priv:
- kgsl_put_process_private(dev_priv->device, process);
+ kgsl_process_private_put(process);
return ret;
}
@@ -415,7 +409,7 @@
entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
spin_unlock(&entry->priv->mem_lock);
- kgsl_put_process_private(entry->dev_priv->device, entry->priv);
+ kgsl_process_private_put(entry->priv);
entry->priv = NULL;
}
@@ -473,7 +467,7 @@
* the context is destroyed. This will also prevent the pagetable
* from being destroyed
*/
- if (!kref_get_unless_zero(&dev_priv->process_priv->refcount))
+ if (!kgsl_process_private_get(dev_priv->process_priv))
goto fail_free_id;
context->device = dev_priv->device;
context->dev_priv = dev_priv;
@@ -568,8 +562,7 @@
}
write_unlock(&device->context_lock);
kgsl_sync_timeline_destroy(context);
- kgsl_put_process_private(device,
- context->proc_priv);
+ kgsl_process_private_put(context->proc_priv);
device->ftbl->drawctxt_destroy(context);
}
@@ -811,9 +804,8 @@
return;
}
-static void
-kgsl_put_process_private(struct kgsl_device *device,
- struct kgsl_process_private *private)
+void
+kgsl_process_private_put(struct kgsl_process_private *private)
{
mutex_lock(&kgsl_driver.process_mutex);
@@ -828,13 +820,32 @@
}
/**
- * find_process_private() - Helper function to search for process private
- * @cur_dev_priv: Pointer to device private structure which contains pointers
- * to device and process_private structs.
+ * kgsl_process_private_find() - Find the process associated with the specified
+ * name
+ * @name: pid_t of the process to search for
+ * Return the process struct for the given ID.
+ */
+struct kgsl_process_private *kgsl_process_private_find(pid_t pid)
+{
+ struct kgsl_process_private *p, *private = NULL;
+
+ mutex_lock(&kgsl_driver.process_mutex);
+ list_for_each_entry(p, &kgsl_driver.process_list, list) {
+ if (p->pid == pid) {
+ if (kgsl_process_private_get(p))
+ private = p;
+ break;
+ }
+ }
+ mutex_unlock(&kgsl_driver.process_mutex);
+ return private;
+}
+
+/**
+ * kgsl_process_private_new() - Helper function to search for process private
* Returns: Pointer to the found/newly created private struct
*/
-static struct kgsl_process_private *
-kgsl_find_process_private(struct kgsl_device_private *cur_dev_priv)
+static struct kgsl_process_private *kgsl_process_private_new(void)
{
struct kgsl_process_private *private;
@@ -842,18 +853,16 @@
mutex_lock(&kgsl_driver.process_mutex);
list_for_each_entry(private, &kgsl_driver.process_list, list) {
if (private->pid == task_tgid_nr(current)) {
- kref_get(&private->refcount);
+ if (!kgsl_process_private_get(private))
+ private = NULL;
goto done;
}
}
/* no existing process private found for this dev_priv, create one */
private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
- if (private == NULL) {
- KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n",
- sizeof(struct kgsl_process_private));
+ if (private == NULL)
goto done;
- }
kref_init(&private->refcount);
@@ -875,11 +884,11 @@
* NULL if pagetable creation for this process private obj failed.
*/
static struct kgsl_process_private *
-kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
+kgsl_get_process_private(struct kgsl_device *device)
{
struct kgsl_process_private *private;
- private = kgsl_find_process_private(cur_dev_priv);
+ private = kgsl_process_private_new();
if (!private)
return NULL;
@@ -894,15 +903,15 @@
if ((!private->pagetable) && kgsl_mmu_enabled()) {
unsigned long pt_name;
- struct kgsl_mmu *mmu = &cur_dev_priv->device->mmu;
pt_name = task_tgid_nr(current);
- private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
+ private->pagetable =
+ kgsl_mmu_getpagetable(&device->mmu, pt_name);
if (private->pagetable == NULL)
goto error;
}
- if (kgsl_process_init_sysfs(cur_dev_priv->device, private))
+ if (kgsl_process_init_sysfs(device, private))
goto error;
if (kgsl_process_init_debugfs(private))
goto error;
@@ -915,7 +924,7 @@
error:
mutex_unlock(&private->process_private_mutex);
- kgsl_put_process_private(cur_dev_priv->device, private);
+ kgsl_process_private_put(private);
return NULL;
}
@@ -1009,7 +1018,7 @@
kfree(dev_priv);
- kgsl_put_process_private(device, private);
+ kgsl_process_private_put(private);
pm_runtime_put(device->parentdev);
return result;
@@ -1099,7 +1108,7 @@
* after the first start so that the global pagetable mappings
* are set up before we create the per-process pagetable.
*/
- dev_priv->process_priv = kgsl_get_process_private(dev_priv);
+ dev_priv->process_priv = kgsl_get_process_private(device);
if (dev_priv->process_priv == NULL) {
result = -ENOMEM;
goto err_stop;
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index c1b3139..5645628 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -247,7 +247,7 @@
static void print_mem_entry(struct seq_file *s, struct kgsl_mem_entry *entry)
{
- char flags[6];
+ char flags[7];
char usage[16];
struct kgsl_memdesc *m = &entry->memdesc;
@@ -256,11 +256,12 @@
flags[2] = get_alignflag(m);
flags[3] = get_cacheflag(m);
flags[4] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-';
- flags[5] = '\0';
+ flags[5] = (m->useraddr) ? 'Y' : 'N';
+ flags[6] = '\0';
kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
- seq_printf(s, "%pK %pK %8zd %5d %5s %10s %16s %5d\n",
+ seq_printf(s, "%pK %pK %8zd %5d %6s %10s %16s %5d\n",
(unsigned long *) m->gpuaddr,
(unsigned long *) m->useraddr,
m->size, entry->id, flags,
@@ -274,7 +275,7 @@
struct kgsl_process_private *private = s->private;
int next = 0;
- seq_printf(s, "%8s %8s %8s %5s %5s %10s %16s %5s\n",
+ seq_printf(s, "%8s %8s %8s %5s %6s %10s %16s %5s\n",
"gpuaddr", "useraddr", "size", "id", "flags", "type",
"usage", "sglen");
@@ -303,14 +304,38 @@
static int process_mem_open(struct inode *inode, struct file *file)
{
- return single_open(file, process_mem_print, inode->i_private);
+ int ret;
+ pid_t pid = (pid_t) (unsigned long) inode->i_private;
+ struct kgsl_process_private *private = NULL;
+
+ private = kgsl_process_private_find(pid);
+
+ if (!private)
+ return -ENODEV;
+
+ ret = single_open(file, process_mem_print, private);
+ if (ret)
+ kgsl_process_private_put(private);
+
+ return ret;
+}
+
+static int process_mem_release(struct inode *inode, struct file *file)
+{
+ struct kgsl_process_private *private =
+ ((struct seq_file *)file->private_data)->private;
+
+ if (private)
+ kgsl_process_private_put(private);
+
+ return single_release(inode, file);
}
static const struct file_operations process_mem_fops = {
.open = process_mem_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = single_release,
+ .release = process_mem_release,
};
@@ -349,8 +374,8 @@
* So if debugfs is disabled in kernel, return as
* success.
*/
- dentry = debugfs_create_file("mem", 0444, private->debug_root, private,
- &process_mem_fops);
+ dentry = debugfs_create_file("mem", 0444, private->debug_root,
+ (void *) ((unsigned long) private->pid), &process_mem_fops);
if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 47801a4..1e6fbc9 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -697,6 +697,27 @@
void kgsl_cmdbatch_destroy_object(struct kref *kref);
/**
+* kgsl_process_private_get() - increment the refcount on a kgsl_process_private
+* struct
+* @process: Pointer to the KGSL process_private
+*
+* Returns 0 if the structure is invalid and a reference count could not be
+* obtained, nonzero otherwise.
+*/
+static inline int kgsl_process_private_get(struct kgsl_process_private *process)
+{
+ int ret = 0;
+ if (process != NULL)
+ ret = kref_get_unless_zero(&process->refcount);
+ return ret;
+}
+
+void kgsl_process_private_put(struct kgsl_process_private *private);
+
+
+struct kgsl_process_private *kgsl_process_private_find(pid_t pid);
+
+/**
* kgsl_cmdbatch_put() - Decrement the refcount for a command batch object
* @cmdbatch: Pointer to the command batch object
*/
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 0c22694..915f5e7 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -81,8 +81,6 @@
To compile this driver as a module, choose M here: the
module will be called hbtp_input.
-endif
-
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
@@ -724,3 +722,5 @@
To compile this driver as a module, choose M here: the
module will be called CM36283.
+
+endif
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index f9855c0..4e73c5a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -675,7 +675,7 @@
struct msm_isp_bufq *bufq = NULL;
CDBG("%s: E\n", __func__);
- if (!buf_request->num_buf) {
+ if (!buf_request->num_buf || buf_request->num_buf > VIDEO_MAX_FRAME) {
pr_err("Invalid buffer request\n");
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 805ff0a..69c5190 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -396,6 +396,7 @@
atomic_t stats_comp_mask;
uint16_t stream_handle_cnt;
atomic_t stats_update;
+ uint32_t stats_mask;
};
struct msm_vfe_tasklet_queue_cmd {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 81e9c74..e817680 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -350,6 +350,8 @@
msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x2C);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x34);
+ msm_camera_io_w(vfe_dev->stats_data.stats_mask,
+ vfe_dev->vfe_base + 0x44);
}
static void msm_vfe40_process_reset_irq(struct vfe_device *vfe_dev,
@@ -1272,6 +1274,7 @@
else
comp_mask &= ~stats_mask;
msm_camera_io_w(comp_mask << 16, vfe_dev->vfe_base + 0x44);
+ vfe_dev->stats_data.stats_mask = (comp_mask << 16);
}
static void msm_vfe40_stats_cfg_wm_irq_mask(
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index f44f026..b1521df 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -130,7 +130,10 @@
mutex_lock(&bandwidth_mgr_mutex);
if (!isp_bandwidth_mgr.use_count ||
!isp_bandwidth_mgr.bus_client) {
- pr_err("%s: bandwidth manager inactive\n", __func__);
+ pr_err("%s:error bandwidth manager inactive use_cnt:%d bus_clnt:%d\n",
+ __func__, isp_bandwidth_mgr.use_count,
+ isp_bandwidth_mgr.bus_client);
+ mutex_unlock(&bandwidth_mgr_mutex);
return -EINVAL;
}
@@ -166,8 +169,11 @@
return;
}
- if (!isp_bandwidth_mgr.bus_client)
+ if (!isp_bandwidth_mgr.bus_client) {
+ pr_err("%s:%d error: bus client invalid\n", __func__, __LINE__);
+ mutex_unlock(&bandwidth_mgr_mutex);
return;
+ }
msm_bus_scale_client_update_request(
isp_bandwidth_mgr.bus_client, 0);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index a53ac38..d3a848a 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -37,6 +37,7 @@
#include <media/msmb_camera.h>
#include <media/msmb_generic_buf_mgr.h>
#include <media/msmb_pproc.h>
+#include <mach/clk-provider.h>
#include "msm_cpp.h"
#include "msm_isp_util.h"
#include "msm_camera_io_util.h"
@@ -49,6 +50,7 @@
#define CONFIG_MSM_CPP_DBG 0
#define CPP_CMD_TIMEOUT_MS 300
+#define MSM_CPP_CORE_CLK_IDX 4
#define MSM_MICRO_IFACE_CLK_IDX 7
#define MSM_CPP_NOMINAL_CLOCK 266670000
@@ -98,6 +100,8 @@
qcmd; \
})
+#define MSM_CPP_MAX_TIMEOUT_TRIAL 3
+
static void msm_queue_init(struct msm_device_queue *queue, const char *name)
{
CPP_DBG("E\n");
@@ -135,6 +139,23 @@
{"cpp_bus_clk", -1},
{"micro_iface_clk", -1},
};
+
+#define msm_cpp_empty_list(queue, member) { \
+ unsigned long flags; \
+ struct msm_queue_cmd *qcmd = NULL; \
+ if (queue) { \
+ spin_lock_irqsave(&queue->lock, flags); \
+ while (!list_empty(&queue->list)) { \
+ queue->len--; \
+ qcmd = list_first_entry(&queue->list, \
+ struct msm_queue_cmd, member); \
+ list_del_init(&qcmd->member); \
+ kfree(qcmd); \
+ } \
+ spin_unlock_irqrestore(&queue->lock, flags); \
+ } \
+}
+
static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev);
static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin);
static void cpp_timer_callback(unsigned long data);
@@ -147,6 +168,14 @@
writel_relaxed((data), cpp_base + MSM_CPP_MICRO_FIFO_RX_DATA);
}
+static void msm_cpp_clear_timer(struct cpp_device *cpp_dev)
+{
+ atomic_set(&cpp_timer.used, 0);
+ del_timer(&cpp_timer.cpp_timer);
+ cpp_timer.data.processed_frame = NULL;
+ cpp_dev->timeout_trial_cnt = 0;
+}
+
static uint32_t msm_cpp_read(void __iomem *cpp_base)
{
uint32_t tmp, retry = 0;
@@ -572,7 +601,6 @@
uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
struct cpp_device *cpp_dev = (struct cpp_device *) data;
struct msm_cpp_tasklet_queue_cmd *queue_cmd;
- struct msm_cpp_timer_t *timer = NULL;
while (atomic_read(&cpp_dev->irq_cnt)) {
spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
@@ -601,19 +629,13 @@
CPP_DBG("Frame done!!\n");
/* delete CPP timer */
CPP_DBG("delete timer.\n");
- timer = &cpp_timer;
- atomic_set(&timer->used, 0);
- del_timer(&timer->cpp_timer);
- timer->data.processed_frame = NULL;
+ msm_cpp_clear_timer(cpp_dev);
msm_cpp_notify_frame_done(cpp_dev);
} else if (msg_id ==
MSM_CPP_MSG_ID_FRAME_NACK) {
pr_err("NACK error from hw!!\n");
CPP_DBG("delete timer.\n");
- timer = &cpp_timer;
- atomic_set(&timer->used, 0);
- del_timer(&timer->cpp_timer);
- timer->data.processed_frame = NULL;
+ msm_cpp_clear_timer(cpp_dev);
msm_cpp_notify_frame_done(cpp_dev);
}
i += cmd_len + 2;
@@ -622,6 +644,27 @@
}
}
+static void cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info)
+{
+ uint32_t count;
+ signed long freq_tbl_entry = 0;
+
+ if ((clk == NULL) || (hw_info == NULL) || (clk->ops == NULL) ||
+ (clk->ops->list_rate == NULL)) {
+ pr_err("Bad parameter\n");
+ return;
+ }
+
+ for (count = 0; count < MAX_FREQ_TBL; count++) {
+ freq_tbl_entry = clk->ops->list_rate(clk, count);
+ if (freq_tbl_entry >= 0)
+ hw_info->freq_tbl[count] = freq_tbl_entry;
+ else
+ break;
+ }
+
+ hw_info->freq_tbl_count = count;
+}
static int cpp_init_hardware(struct cpp_device *cpp_dev)
{
int rc = 0;
@@ -630,7 +673,6 @@
pr_err("%s: Bandwidth registration Failed!\n", __func__);
goto bus_scale_register_failed;
}
- msm_isp_update_bandwidth(ISP_CPP, 981345600, 1066680000);
if (cpp_dev->fs_cpp == NULL) {
cpp_dev->fs_cpp =
@@ -735,11 +777,15 @@
pr_debug("CPP HW Version: 0x%x\n", cpp_dev->hw_info.cpp_hw_version);
cpp_dev->hw_info.cpp_hw_caps =
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4);
+ cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX],
+ &cpp_dev->hw_info);
pr_debug("CPP HW Caps: 0x%x\n", cpp_dev->hw_info.cpp_hw_caps);
msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
cpp_dev->taskletq_idx = 0;
atomic_set(&cpp_dev->irq_cnt, 0);
msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE);
+ pr_debug("stream_cnt:%d\n", cpp_dev->stream_cnt);
+ cpp_dev->stream_cnt = 0;
if (cpp_dev->is_firmware_loaded == 1) {
disable_irq(cpp_dev->irq->start);
cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
@@ -763,7 +809,6 @@
regulator_disable(cpp_dev->fs_cpp);
regulator_put(cpp_dev->fs_cpp);
fs_failed:
- msm_isp_update_bandwidth(ISP_CPP, 0, 0);
msm_isp_deinit_bandwidth_mgr(ISP_CPP);
bus_scale_register_failed:
return rc;
@@ -790,7 +835,11 @@
regulator_disable(cpp_dev->fs_cpp);
regulator_put(cpp_dev->fs_cpp);
cpp_dev->fs_cpp = NULL;
- msm_isp_update_bandwidth(ISP_CPP, 0, 0);
+ if (cpp_dev->stream_cnt > 0) {
+ pr_debug("error: stream count active\n");
+ msm_isp_update_bandwidth(ISP_CPP, 0, 0);
+ }
+ cpp_dev->stream_cnt = 0;
msm_isp_deinit_bandwidth_mgr(ISP_CPP);
}
@@ -919,9 +968,19 @@
{
uint32_t i;
struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+ struct msm_device_queue *processing_q = NULL;
+ struct msm_device_queue *eventData_q = NULL;
+
+ if (!cpp_dev) {
+ pr_err("failed: cpp_dev %p\n", cpp_dev);
+ return -EINVAL;
+ }
mutex_lock(&cpp_dev->mutex);
+ processing_q = &cpp_dev->processing_q;
+ eventData_q = &cpp_dev->eventData_q;
+
if (cpp_dev->cpp_open_cnt == 0) {
mutex_unlock(&cpp_dev->mutex);
return 0;
@@ -973,9 +1032,12 @@
pr_debug("DEBUG_R1: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
+ msm_cpp_clear_timer(cpp_dev);
cpp_deinit_mem(cpp_dev);
iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
cpp_release_hardware(cpp_dev);
+ msm_cpp_empty_list(processing_q, list_frame);
+ msm_cpp_empty_list(eventData_q, list_eventdata);
cpp_dev->state = CPP_STATE_OFF;
}
@@ -1005,7 +1067,7 @@
struct v4l2_event v4l2_evt;
struct msm_queue_cmd *frame_qcmd = NULL;
struct msm_queue_cmd *event_qcmd = NULL;
- struct msm_cpp_frame_info_t *processed_frame;
+ struct msm_cpp_frame_info_t *processed_frame = NULL;
struct msm_device_queue *queue = &cpp_dev->processing_q;
struct msm_buf_mngr_info buff_mgr_info;
int rc = 0;
@@ -1097,8 +1159,9 @@
pr_err("cpp_timer_callback called. (jiffies=%lu)\n",
jiffies);
- if (!work) {
- pr_err("Invalid work:%p\n", work);
+ if (!work || cpp_timer.data.cpp_dev->state != CPP_STATE_ACTIVE) {
+ pr_err("Invalid work:%p or state:%d\n", work,
+ cpp_timer.data.cpp_dev->state);
return;
}
if (!atomic_read(&cpp_timer.used)) {
@@ -1122,6 +1185,14 @@
return;
}
+ if (cpp_timer.data.cpp_dev->timeout_trial_cnt >=
+ MSM_CPP_MAX_TIMEOUT_TRIAL) {
+ pr_info("Max trial reached\n");
+ msm_cpp_notify_frame_done(cpp_timer.data.cpp_dev);
+ cpp_timer.data.cpp_dev->timeout_trial_cnt = 0;
+ return;
+ }
+
this_frame = cpp_timer.data.processed_frame;
pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
CPP_CMD_TIMEOUT_MS, jiffies);
@@ -1138,6 +1209,7 @@
for (i = 0; i < this_frame->msg_len; i++)
msm_cpp_write(this_frame->cpp_cmd_msg[i],
cpp_timer.data.cpp_dev->base);
+ cpp_timer.data.cpp_dev->timeout_trial_cnt++;
return;
}
@@ -1394,6 +1466,26 @@
return rc;
}
+void msm_cpp_clean_queue(struct cpp_device *cpp_dev)
+{
+ struct msm_queue_cmd *frame_qcmd = NULL;
+ struct msm_cpp_frame_info_t *processed_frame = NULL;
+ struct msm_device_queue *queue = NULL;
+
+ while (cpp_dev->processing_q.len) {
+ pr_info("queue len:%d\n", cpp_dev->processing_q.len);
+ queue = &cpp_dev->processing_q;
+ frame_qcmd = msm_dequeue(queue, list_frame);
+ if (frame_qcmd) {
+ processed_frame = frame_qcmd->command;
+ kfree(frame_qcmd);
+ if (processed_frame)
+ kfree(processed_frame->cpp_cmd_msg);
+ kfree(processed_frame);
+ }
+ }
+}
+
long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
@@ -1551,6 +1643,23 @@
kfree(k_stream_buff_info.buffer_info);
kfree(u_stream_buff_info);
+ if (cpp_dev->stream_cnt == 0) {
+ rc = msm_isp_update_bandwidth(ISP_CPP, 981345600,
+ 1066680000);
+ if (rc < 0) {
+ pr_err("Bandwidth Set Failed!\n");
+ msm_isp_update_bandwidth(ISP_CPP, 0, 0);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+ cpp_dev->state = CPP_STATE_ACTIVE;
+ msm_cpp_clear_timer(cpp_dev);
+ msm_cpp_clean_queue(cpp_dev);
+ }
+ if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) {
+ cpp_dev->stream_cnt++;
+ pr_debug("stream_cnt:%d\n", cpp_dev->stream_cnt);
+ }
break;
}
case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: {
@@ -1558,7 +1667,7 @@
struct msm_cpp_buff_queue_info_t *buff_queue_info;
if ((ioctl_ptr->len == 0) ||
- (ioctl_ptr->len > sizeof(uint32_t)))
+ (ioctl_ptr->len > sizeof(uint32_t)))
return -EINVAL;
rc = (copy_from_user(&identity,
@@ -1583,6 +1692,21 @@
rc = msm_cpp_free_buff_queue_entry(cpp_dev,
buff_queue_info->session_id,
buff_queue_info->stream_id);
+ if (cpp_dev->stream_cnt > 0) {
+ cpp_dev->stream_cnt--;
+ pr_debug("stream_cnt:%d\n", cpp_dev->stream_cnt);
+ if (cpp_dev->stream_cnt == 0) {
+ rc = msm_isp_update_bandwidth(ISP_CPP, 0, 0);
+ if (rc < 0)
+ pr_err("Bandwidth Reset Failed!\n");
+ cpp_dev->state = CPP_STATE_IDLE;
+ msm_cpp_clear_timer(cpp_dev);
+ msm_cpp_clean_queue(cpp_dev);
+ }
+ } else {
+ pr_err("error: stream count underflow %d\n",
+ cpp_dev->stream_cnt);
+ }
break;
}
case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: {
@@ -1610,7 +1734,9 @@
break;
}
case VIDIOC_MSM_CPP_SET_CLOCK: {
- long clock_rate = 0;
+ struct msm_cpp_clock_settings_t clock_settings;
+ unsigned long clock_rate = 0;
+ CPP_DBG("VIDIOC_MSM_CPP_SET_CLOCK\n");
if (ioctl_ptr->len == 0) {
pr_err("ioctl_ptr->len is 0\n");
mutex_unlock(&cpp_dev->mutex);
@@ -1623,13 +1749,13 @@
return -EINVAL;
}
- if (ioctl_ptr->len > sizeof(clock_rate)) {
+ if (ioctl_ptr->len != sizeof(struct msm_cpp_clock_settings_t)) {
pr_err("Not valid ioctl_ptr->len\n");
mutex_unlock(&cpp_dev->mutex);
return -EINVAL;
}
- rc = (copy_from_user(&clock_rate,
+ rc = (copy_from_user(&clock_settings,
(void __user *)ioctl_ptr->ioctl_ptr,
ioctl_ptr->len) ? -EFAULT : 0);
if (rc) {
@@ -1638,27 +1764,37 @@
return -EINVAL;
}
- if (clock_rate > 0) {
- clock_rate =
- clk_round_rate(cpp_dev->cpp_clk[4], clock_rate);
- CPP_DBG("clk:%ld\n", clock_rate);
- clk_set_rate(cpp_dev->cpp_clk[4], clock_rate);
- rc = msm_isp_update_bandwidth(ISP_CPP, clock_rate * 4,
- clock_rate * 6);
+ if (clock_settings.clock_rate > 0) {
+ rc = msm_isp_update_bandwidth(ISP_CPP,
+ clock_settings.avg,
+ clock_settings.inst);
if (rc < 0) {
pr_err("Bandwidth Set Failed!\n");
msm_isp_update_bandwidth(ISP_CPP, 0, 0);
mutex_unlock(&cpp_dev->mutex);
return -EINVAL;
}
+ clock_rate = clk_round_rate(
+ cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX],
+ clock_settings.clock_rate);
+ if (clock_rate != clock_settings.clock_rate)
+ pr_err("clock rate differ from settings\n");
+ clk_set_rate(cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX],
+ clock_rate);
}
-
break;
}
case MSM_SD_SHUTDOWN: {
mutex_unlock(&cpp_dev->mutex);
+ pr_info("shutdown cpp node. open cnt:%d\n",
+ cpp_dev->cpp_open_cnt);
+
+ if (atomic_read(&cpp_timer.used))
+ pr_info("Timer state not cleared\n");
+
while (cpp_dev->cpp_open_cnt != 0)
cpp_close_node(sd, NULL);
+ mutex_lock(&cpp_dev->mutex);
rc = 0;
break;
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index cf22e6c..bd73ab2 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -161,6 +161,13 @@
struct cpp_device *cpp_dev;
};
+struct msm_cpp_clock_settings_t {
+ long clock_rate;
+ uint64_t avg;
+ uint64_t inst;
+};
+
+
struct cpp_device {
struct platform_device *pdev;
struct msm_sd_subdev msm_sd;
@@ -182,6 +189,8 @@
char *fw_name_bin;
struct workqueue_struct *timer_wq;
struct msm_cpp_work_t *work;
+ uint8_t stream_cnt;
+ uint8_t timeout_trial_cnt;
int domain_num;
struct iommu_domain *domain;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index 8e7dc2c..50f37db 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -304,6 +304,21 @@
if (dest_step_pos == a_ctrl->curr_step_pos)
return rc;
+ if ((sign_dir > MSM_ACTUATOR_MOVE_SIGNED_NEAR) ||
+ (sign_dir < MSM_ACTUATOR_MOVE_SIGNED_FAR)) {
+ pr_err("Invalid sign_dir = %d\n", sign_dir);
+ return -EFAULT;
+ }
+ if ((dir > MOVE_FAR) || (dir < MOVE_NEAR)) {
+ pr_err("Invalid direction = %d\n", dir);
+ return -EFAULT;
+ }
+ if (dest_step_pos > a_ctrl->total_steps) {
+ pr_err("Step pos greater than total steps = %d\n",
+ dest_step_pos);
+ return -EFAULT;
+ }
+ curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];
a_ctrl->i2c_tbl_index = 0;
CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n",
a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos);
@@ -374,6 +389,12 @@
kfree(a_ctrl->step_position_table);
a_ctrl->step_position_table = NULL;
+ if (set_info->af_tuning_params.total_steps
+ > MAX_ACTUATOR_AF_TOTAL_STEPS) {
+ pr_err("Max actuator totalsteps exceeded = %d\n",
+ set_info->af_tuning_params.total_steps);
+ return -EFAULT;
+ }
/* Fill step position table */
a_ctrl->step_position_table =
kmalloc(sizeof(uint16_t) *
@@ -502,12 +523,19 @@
pr_err("Actuator function table not found\n");
return rc;
}
-
- a_ctrl->region_size = set_info->af_tuning_params.region_size;
- if (a_ctrl->region_size > MAX_ACTUATOR_REGION) {
+ if (set_info->af_tuning_params.total_steps
+ > MAX_ACTUATOR_AF_TOTAL_STEPS) {
+ pr_err("Max actuator totalsteps exceeded = %d\n",
+ set_info->af_tuning_params.total_steps);
+ return -EFAULT;
+ }
+ if (set_info->af_tuning_params.region_size
+ > MAX_ACTUATOR_REGION) {
pr_err("MAX_ACTUATOR_REGION is exceeded.\n");
return -EFAULT;
}
+
+ a_ctrl->region_size = set_info->af_tuning_params.region_size;
a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step;
a_ctrl->total_steps = set_info->af_tuning_params.total_steps;
@@ -557,7 +585,9 @@
return -EFAULT;
}
- if (set_info->actuator_params.init_setting_size) {
+ if (set_info->actuator_params.init_setting_size &&
+ set_info->actuator_params.init_setting_size
+ <= MAX_ACTUATOR_REG_TBL_SIZE) {
if (a_ctrl->func_tbl->actuator_init_focus) {
init_settings = kmalloc(sizeof(struct reg_settings_t) *
(set_info->actuator_params.init_setting_size),
@@ -896,6 +926,7 @@
&pdev->id);
CDBG("cell-index %d, rc %d\n", pdev->id, rc);
if (rc < 0) {
+ kfree(msm_actuator_t);
pr_err("failed rc %d\n", rc);
return rc;
}
@@ -904,6 +935,7 @@
&msm_actuator_t->cci_master);
CDBG("qcom,cci-master %d, rc %d\n", msm_actuator_t->cci_master, rc);
if (rc < 0) {
+ kfree(msm_actuator_t);
pr_err("failed rc %d\n", rc);
return rc;
}
@@ -920,6 +952,7 @@
msm_actuator_t->i2c_client.cci_client = kzalloc(sizeof(
struct msm_camera_cci_client), GFP_KERNEL);
if (!msm_actuator_t->i2c_client.cci_client) {
+ kfree(msm_actuator_t);
pr_err("failed no memory\n");
return -ENOMEM;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index d9d65a7..bcd13b8 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -157,7 +157,7 @@
.name = "IDR Period",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1,
- .maximum = 10*MAX_FRAME_RATE,
+ .maximum = INT_MAX,
.default_value = DEFAULT_FRAME_RATE,
.step = 1,
.menu_skip_mask = 0,
@@ -168,7 +168,7 @@
.name = "Intra Period",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1,
- .maximum = 10*MAX_FRAME_RATE,
+ .maximum = INT_MAX,
.default_value = DEFAULT_FRAME_RATE,
.step = 1,
.menu_skip_mask = 0,
@@ -1289,7 +1289,7 @@
default:
goto unknown_value;
}
- /* H263 */
+ /* H263 */
case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
switch (value) {
case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
@@ -1382,6 +1382,17 @@
default:
goto unknown_value;
}
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
+ return HAL_H264_DB_MODE_DISABLE;
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
+ return HAL_H264_DB_MODE_ALL_BOUNDARY;
+ case L_MODE:
+ return HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
+ default:
+ goto unknown_value;
+ }
}
unknown_value:
@@ -1990,23 +2001,58 @@
break;
}
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
- property_id =
- HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
- h264_db_control.mode = ctrl->val;
+ {
+ struct v4l2_ctrl *alpha, *beta;
+
+ alpha = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA);
+ beta = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA);
+
+ property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ h264_db_control.slice_alpha_offset = alpha->val;
+ h264_db_control.slice_beta_offset = beta->val;
+ h264_db_control.mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ ctrl->val);
pdata = &h264_db_control;
break;
+ }
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
- property_id =
- HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ {
+ struct v4l2_ctrl *mode, *beta;
+
+ mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE);
+ beta = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA);
+
+ property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
h264_db_control.slice_alpha_offset = ctrl->val;
+ h264_db_control.slice_beta_offset = beta->val;
+ h264_db_control.mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ mode->val);
pdata = &h264_db_control;
break;
+ }
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
- property_id =
- HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ {
+ struct v4l2_ctrl *mode, *alpha;
+
+ mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE);
+ alpha = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA);
+ property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ h264_db_control.slice_alpha_offset = alpha->val;
h264_db_control.slice_beta_offset = ctrl->val;
+ h264_db_control.mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ mode->val);
pdata = &h264_db_control;
break;
+ }
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
property_id =
HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 5a18265..475683c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -255,8 +255,8 @@
inst->session_type == MSM_VIDC_ENCODER ? "Encoder" : "Decoder");
write_str(&dbg_buf, "===============================\n");
write_str(&dbg_buf, "core: 0x%p\n", inst->core);
- write_str(&dbg_buf, "height: %d\n", inst->prop.height);
- write_str(&dbg_buf, "width: %d\n", inst->prop.width);
+ write_str(&dbg_buf, "height: %d\n", inst->prop.height[CAPTURE_PORT]);
+ write_str(&dbg_buf, "width: %d\n", inst->prop.width[CAPTURE_PORT]);
write_str(&dbg_buf, "fps: %d\n", inst->prop.fps);
write_str(&dbg_buf, "state: %d\n", inst->state);
write_str(&dbg_buf, "-----------Formats-------------\n");
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 05264b4..d06ec85 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -203,6 +203,7 @@
#define WCNSS_VBATT_LEVEL_IND (WCNSS_CTRL_MSG_START + 8)
#define WCNSS_BUILD_VER_REQ (WCNSS_CTRL_MSG_START + 9)
#define WCNSS_BUILD_VER_RSP (WCNSS_CTRL_MSG_START + 10)
+#define WCNSS_PM_CONFIG_REQ (WCNSS_CTRL_MSG_START + 11)
/* max 20mhz channel count */
#define WCNSS_MAX_CH_NUM 45
@@ -377,6 +378,7 @@
struct delayed_work wcnss_work;
struct delayed_work vbatt_work;
struct work_struct wcnssctrl_version_work;
+ struct work_struct wcnss_pm_config_work;
struct work_struct wcnssctrl_nvbin_dnld_work;
struct work_struct wcnssctrl_rx_work;
struct wake_lock wcnss_wake_lock;
@@ -945,6 +947,7 @@
pr_debug("wcnss: opening WCNSS SMD channel :%s",
WCNSS_CTRL_CHANNEL);
schedule_work(&penv->wcnssctrl_version_work);
+ schedule_work(&penv->wcnss_pm_config_work);
break;
@@ -1800,6 +1803,52 @@
return;
}
+static void wcnss_send_pm_config(struct work_struct *worker)
+{
+ struct smd_msg_hdr *hdr;
+ unsigned char *msg = NULL;
+ int rc, prop_len;
+ u32 *payload;
+
+ if (!of_find_property(penv->pdev->dev.of_node,
+ "qcom,wcnss-pm", &prop_len))
+ return;
+
+ msg = kmalloc((sizeof(struct smd_msg_hdr) + prop_len), GFP_KERNEL);
+
+ if (NULL == msg) {
+ pr_err("wcnss: %s: failed to allocate memory\n", __func__);
+ return;
+ }
+
+ payload = (u32 *)(msg + sizeof(struct smd_msg_hdr));
+
+ prop_len /= sizeof(int);
+
+ rc = of_property_read_u32_array(penv->pdev->dev.of_node,
+ "qcom,wcnss-pm", payload, prop_len);
+ if (rc < 0) {
+ pr_err("wcnss: property read failed\n");
+ kfree(msg);
+ return;
+ }
+
+ pr_debug("%s:size=%d: <%d, %d, %d, %d, %d>\n", __func__,
+ prop_len, *payload, *(payload+1), *(payload+2),
+ *(payload+3), *(payload+4));
+
+ hdr = (struct smd_msg_hdr *)msg;
+ hdr->msg_type = WCNSS_PM_CONFIG_REQ;
+ hdr->msg_len = sizeof(struct smd_msg_hdr) + prop_len;
+
+ rc = wcnss_smd_tx(msg, hdr->msg_len);
+ if (rc < 0)
+ pr_err("wcnss: smd tx failed\n");
+
+ kfree(msg);
+ return;
+}
+
static DECLARE_RWSEM(wcnss_pm_sem);
static void wcnss_nvbin_dnld(void)
@@ -2234,6 +2283,7 @@
}
INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler);
INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req);
+ INIT_WORK(&penv->wcnss_pm_config_work, wcnss_send_pm_config);
INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_main);
wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 7b623e4..81b683d 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -30,6 +30,7 @@
#include <linux/of.h>
#include <linux/sysfs.h>
#include <linux/types.h>
+#include <linux/io.h>
#include <linux/android_alarm.h>
#include <linux/thermal.h>
#include <mach/rpm-regulator.h>
@@ -41,6 +42,8 @@
#define MAX_RAILS 5
#define MAX_THRESHOLD 2
#define MONITOR_ALL_TSENS -1
+#define BYTES_PER_FUSE_ROW 8
+#define MAX_EFUSE_VALUE 16
static struct msm_thermal_data msm_thermal_info;
static struct delayed_work check_temp_work;
@@ -89,6 +92,10 @@
static DEFINE_MUTEX(psm_mutex);
static DEFINE_MUTEX(ocr_mutex);
static uint32_t min_freq_limit;
+static uint32_t default_cpu_temp_limit;
+static bool default_temp_limit_enabled;
+static bool default_temp_limit_probed;
+static bool default_temp_limit_nodes_called;
enum thermal_threshold {
HOTPLUG_THRESHOLD_HIGH,
@@ -175,6 +182,15 @@
uint32_t enabled;
};
+enum efuse_data {
+ EFUSE_ADDRESS = 0,
+ EFUSE_SIZE,
+ EFUSE_ROW,
+ EFUSE_START_BIT,
+ EFUSE_BIT_MASK,
+ EFUSE_DATA_MAX,
+};
+
/* For SMPS only*/
enum PMIC_SW_MODE {
PMIC_AUTO_MODE = RPM_REGULATOR_MODE_AUTO,
@@ -394,6 +410,12 @@
return fail_cnt ? (-EFAULT) : ret;
}
+static ssize_t default_cpu_temp_limit_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", default_cpu_temp_limit);
+}
+
static int vdd_rstr_en_show(
struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
@@ -2239,6 +2261,38 @@
return ret;
}
+static struct kobj_attribute default_cpu_temp_limit_attr =
+ __ATTR_RO(default_cpu_temp_limit);
+
+static int msm_thermal_add_default_temp_limit_nodes(void)
+{
+ struct kobject *module_kobj = NULL;
+ int ret = 0;
+
+ if (!default_temp_limit_probed) {
+ default_temp_limit_nodes_called = true;
+ return ret;
+ }
+ if (!default_temp_limit_enabled)
+ return ret;
+
+ module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+ if (!module_kobj) {
+ pr_err("cannot find kobject\n");
+ return -ENOENT;
+ }
+
+ sysfs_attr_init(&default_cpu_temp_limit_attr.attr);
+ ret = sysfs_create_file(module_kobj, &default_cpu_temp_limit_attr.attr);
+ if (ret) {
+ pr_err(
+ "cannot create default_cpu_temp_limit attribute. err:%d\n",
+ ret);
+ return ret;
+ }
+ return ret;
+}
+
static int msm_thermal_add_vdd_rstr_nodes(void)
{
struct kobject *module_kobj = NULL;
@@ -2572,6 +2626,169 @@
return ret;
}
+static int get_efuse_temp_map(struct device_node *node,
+ int *efuse_values,
+ int *efuse_temp)
+{
+ uint32_t i, j, efuse_arr_cnt = 0;
+ int ret = 0, efuse_map_cnt = 0;
+ uint32_t data[2 * MAX_EFUSE_VALUE];
+
+ char *key = "qcom,efuse-temperature-map";
+ if (!of_get_property(node, key, &efuse_map_cnt)
+ || efuse_map_cnt <= 0) {
+ pr_debug("Property %s not defined.\n", key);
+ return -ENODEV;
+ }
+
+ if (efuse_map_cnt % (sizeof(__be32) * 2)) {
+ pr_err("Invalid number(%d) of entry for %s\n",
+ efuse_map_cnt, key);
+ return -EINVAL;
+ }
+
+ efuse_arr_cnt = efuse_map_cnt / sizeof(__be32);
+
+ ret = of_property_read_u32_array(node, key, data, efuse_arr_cnt);
+ if (ret)
+ return -EINVAL;
+
+ efuse_map_cnt /= (sizeof(__be32) * 2);
+
+ j = 0;
+ for (i = 0; i < efuse_map_cnt; i++) {
+ efuse_values[i] = data[j++];
+ efuse_temp[i] = data[j++];
+ }
+
+ return efuse_map_cnt;
+}
+
+static int probe_thermal_efuse_read(struct device_node *node,
+ struct msm_thermal_data *data,
+ struct platform_device *pdev)
+{
+ u64 efuse_bits;
+ int ret = 0;
+ int i = 0;
+ int efuse_map_cnt = 0;
+ int efuse_data_cnt = 0;
+ char *key = NULL;
+ void __iomem *efuse_base = NULL;
+ uint32_t efuse_data[EFUSE_DATA_MAX] = {0};
+ uint32_t efuse_values[MAX_EFUSE_VALUE] = {0};
+ uint32_t efuse_temp[MAX_EFUSE_VALUE] = {0};
+ uint32_t default_temp = 0;
+ uint8_t thermal_efuse_data = 0;
+
+ if (default_temp_limit_probed)
+ goto read_efuse_exit;
+
+ key = "qcom,default-temp";
+ if (of_property_read_u32(node, key, &default_temp))
+ default_temp = 0;
+
+ default_cpu_temp_limit = default_temp;
+
+ key = "qcom,efuse-data";
+ if (!of_get_property(node, key, &efuse_data_cnt) ||
+ efuse_data_cnt <= 0) {
+ ret = -ENODEV;
+ goto read_efuse_fail;
+ }
+ efuse_data_cnt /= sizeof(__be32);
+
+ if (efuse_data_cnt != EFUSE_DATA_MAX) {
+ pr_err("Invalid number of efuse data. data cnt %d\n",
+ efuse_data_cnt);
+ ret = -EINVAL;
+ goto read_efuse_fail;
+ }
+
+ ret = of_property_read_u32_array(node, key, efuse_data,
+ efuse_data_cnt);
+ if (ret)
+ goto read_efuse_fail;
+
+ if (efuse_data[EFUSE_ADDRESS] == 0 ||
+ efuse_data[EFUSE_SIZE] == 0 ||
+ efuse_data[EFUSE_BIT_MASK] == 0) {
+ pr_err("Invalid efuse data: address:%x len:%d bitmask%x\n",
+ efuse_data[EFUSE_ADDRESS], efuse_data[EFUSE_SIZE],
+ efuse_data[EFUSE_BIT_MASK]);
+ ret = -EINVAL;
+ goto read_efuse_fail;
+ }
+
+ efuse_map_cnt = get_efuse_temp_map(node, efuse_values,
+ efuse_temp);
+ if (efuse_map_cnt <= 0 ||
+ efuse_map_cnt > (efuse_data[EFUSE_BIT_MASK] + 1)) {
+ pr_err("Invalid efuse-temperature-map. cnt%d\n",
+ efuse_map_cnt);
+ ret = -EINVAL;
+ goto read_efuse_fail;
+ }
+
+ efuse_base = ioremap(efuse_data[EFUSE_ADDRESS], efuse_data[EFUSE_SIZE]);
+ if (!efuse_base) {
+ pr_err("Unable to map efuse_addr:%x with size%d\n",
+ efuse_data[EFUSE_ADDRESS],
+ efuse_data[EFUSE_SIZE]);
+ ret = -EINVAL;
+ goto read_efuse_fail;
+ }
+
+ efuse_bits = readll_relaxed(efuse_base
+ + efuse_data[EFUSE_ROW] * BYTES_PER_FUSE_ROW);
+
+ thermal_efuse_data = (efuse_bits >> efuse_data[EFUSE_START_BIT]) &
+ efuse_data[EFUSE_BIT_MASK];
+
+ /* Get cpu limit temp from efuse truth table */
+ for (; i < efuse_map_cnt; i++) {
+ if (efuse_values[i] == thermal_efuse_data) {
+ default_cpu_temp_limit = efuse_temp[i];
+ break;
+ }
+ }
+ if (i >= efuse_map_cnt) {
+ if (!default_temp) {
+ pr_err("No matching efuse value. value:%d\n",
+ thermal_efuse_data);
+ ret = -EINVAL;
+ goto read_efuse_fail;
+ }
+ }
+
+ pr_debug(
+ "Efuse address:0x%x [row:%d] = 0x%llx @%d:mask:0x%x = 0x%x temp:%d\n",
+ efuse_data[EFUSE_ADDRESS], efuse_data[EFUSE_ROW], efuse_bits,
+ efuse_data[EFUSE_START_BIT], efuse_data[EFUSE_BIT_MASK],
+ thermal_efuse_data, default_cpu_temp_limit);
+
+ default_temp_limit_enabled = true;
+
+read_efuse_fail:
+ if (efuse_base)
+ iounmap(efuse_base);
+ default_temp_limit_probed = true;
+ if (ret) {
+ if (!default_temp) {
+ dev_info(&pdev->dev,
+ "%s:Failed reading node=%s, key=%s. KTM continues\n",
+ __func__, node->full_name, key);
+ } else {
+ default_temp_limit_enabled = true;
+ pr_debug("Default cpu temp limit is %d\n",
+ default_cpu_temp_limit);
+ ret = 0;
+ }
+ }
+read_efuse_exit:
+ return ret;
+}
+
static int probe_ocr(struct device_node *node, struct msm_thermal_data *data,
struct platform_device *pdev)
{
@@ -2884,6 +3101,7 @@
ret = probe_ocr(node, &data, pdev);
if (ret == -EPROBE_DEFER)
goto fail;
+ probe_thermal_efuse_read(node, &data, pdev);
/*
* In case sysfs add nodes get called before probe function.
@@ -2901,6 +3119,10 @@
msm_thermal_add_ocr_nodes();
ocr_nodes_called = false;
}
+ if (default_temp_limit_nodes_called) {
+ msm_thermal_add_default_temp_limit_nodes();
+ default_temp_limit_nodes_called = false;
+ }
msm_thermal_ioctl_init();
ret = msm_thermal_init(&data);
msm_thermal_probed = true;
@@ -2958,6 +3180,7 @@
msm_thermal_add_psm_nodes();
msm_thermal_add_vdd_rstr_nodes();
msm_thermal_add_ocr_nodes();
+ msm_thermal_add_default_temp_limit_nodes();
alarm_init(&thermal_rtc, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
thermal_rtc_callback);
INIT_WORK(&timer_work, timer_work_fn);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 6a92684..30a678b 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -841,9 +841,6 @@
/* ESS flushes only at end?!? */
hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */
- /* clear setup token semaphores */
- hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */
-
/* clear complete status */
hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c4e5962..ea724d6 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2438,6 +2438,11 @@
* Notify the charger type to power supply
* owner as soon as we determine the charger.
*/
+ if (motg->chg_type == USB_DCP_CHARGER &&
+ motg->ext_chg_opened) {
+ init_completion(&motg->ext_chg_wait);
+ motg->ext_chg_active = DEFAULT;
+ }
msm_otg_notify_chg_type(motg);
msm_chg_block_off(motg);
msm_chg_enable_aca_det(motg);
@@ -2541,7 +2546,7 @@
* detection is completed.
*/
- if (motg->ext_chg_active) {
+ if (motg->ext_chg_active == ACTIVE) {
do_wait:
pr_debug("before msm_otg ext chg wait\n");
@@ -2550,7 +2555,7 @@
msecs_to_jiffies(3000));
if (!t)
pr_err("msm_otg ext chg wait timeout\n");
- else if (motg->ext_chg_active)
+ else if (motg->ext_chg_active == ACTIVE)
goto do_wait;
else
pr_debug("msm_otg ext chg wait done\n");
@@ -2627,11 +2632,6 @@
case USB_DCP_CHARGER:
/* Enable VDP_SRC */
ulpi_write(otg->phy, 0x2, 0x85);
- if (motg->ext_chg_opened) {
- init_completion(
- &motg->ext_chg_wait);
- motg->ext_chg_active = true;
- }
/* fall through */
case USB_PROPRIETARY_CHARGER:
msm_otg_notify_charger(motg,
@@ -2701,6 +2701,8 @@
motg->chg_type = USB_INVALID_CHARGER;
msm_otg_notify_charger(motg, 0);
if (dcp) {
+ if (motg->ext_chg_active == DEFAULT)
+ motg->ext_chg_active = INACTIVE;
msm_otg_wait_for_ext_chg_done(motg);
/* Turn off VDP_SRC */
ulpi_write(otg->phy, 0x2, 0x86);
@@ -4054,7 +4056,7 @@
pr_debug("%s: LPM block request %d\n", __func__, val);
if (val) { /* block LPM */
if (motg->chg_type == USB_DCP_CHARGER) {
- motg->ext_chg_active = true;
+ motg->ext_chg_active = ACTIVE;
/*
* If device is already suspended, resume it.
* The PM usage counter is incremented in
@@ -4067,12 +4069,12 @@
else
pm_runtime_get_sync(motg->phy.dev);
} else {
- motg->ext_chg_active = false;
+ motg->ext_chg_active = INACTIVE;
complete(&motg->ext_chg_wait);
ret = -ENODEV;
}
} else {
- motg->ext_chg_active = false;
+ motg->ext_chg_active = INACTIVE;
complete(&motg->ext_chg_wait);
/*
* If usb cable is disconnected and then userspace
@@ -4910,7 +4912,7 @@
if (phy->state == OTG_STATE_UNDEFINED)
return -EAGAIN;
- if (motg->ext_chg_active) {
+ if (motg->ext_chg_active == DEFAULT) {
dev_dbg(dev, "Deferring LPM\n");
/*
* Charger detection may happen in user space.
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index afa0b7c..462f1d8 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -863,24 +863,6 @@
if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0))
return 0;
- if (req->flags & MDP_ROT_90) {
- if (((req->dst_rect.h == 1) && ((req->src_rect.w != 1) ||
- (req->dst_rect.w == req->src_rect.h))) ||
- ((req->dst_rect.w == 1) && ((req->src_rect.h != 1) ||
- (req->dst_rect.h == req->src_rect.w)))) {
- pr_err("mdp_ppp: error scaling when size is 1!\n");
- return -EINVAL;
- }
- } else {
- if (((req->dst_rect.w == 1) && ((req->src_rect.w != 1) ||
- (req->dst_rect.h == req->src_rect.h))) ||
- ((req->dst_rect.h == 1) && ((req->src_rect.h != 1) ||
- (req->dst_rect.w == req->src_rect.w)))) {
- pr_err("mdp_ppp: error scaling when size is 1!\n");
- return -EINVAL;
- }
- }
-
/* MDP width split workaround */
remainder = (req->dst_rect.w) % 16;
ret = ppp_get_bpp(req->dst.format, mfd->fb_imgType);
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index dd8eec5..e724d68 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -1455,6 +1455,8 @@
pinfo->new_fps = pinfo->mipi.frame_rate;
}
+ pinfo->panel_max_fps = mdss_panel_get_framerate(pinfo);
+ pinfo->panel_max_vtotal = mdss_panel_get_vtotal(pinfo);
ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
"qcom,platform-enable-gpio", 0);
@@ -1518,6 +1520,8 @@
if (!gpio_is_valid(ctrl_pdata->mode_gpio))
pr_info("%s:%d, mode gpio not specified\n",
__func__, __LINE__);
+ } else {
+ ctrl_pdata->mode_gpio = -EINVAL;
}
if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) {
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 962599d..f79391a 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -233,6 +233,7 @@
#define DSI_EV_PLL_UNLOCKED 0x0001
#define DSI_EV_MDP_FIFO_UNDERFLOW 0x0002
+#define DSI_EV_DSI_FIFO_EMPTY 0x0003
#define DSI_EV_MDP_BUSY_RELEASE 0x80000000
struct mdss_dsi_ctrl_pdata {
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 95e7c6e..46ca84f 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -252,6 +252,8 @@
if (pinfo->mode == DSI_VIDEO_MODE) {
data = 0;
+ if (pinfo->last_line_interleave_en)
+ data |= BIT(31);
if (pinfo->pulse_mode_hsa_he)
data |= BIT(28);
if (pinfo->hfp_power_stop)
@@ -1380,6 +1382,9 @@
}
}
+ if (todo & DSI_EV_DSI_FIFO_EMPTY)
+ mdss_dsi_sw_reset_restore(ctrl);
+
if (todo & DSI_EV_MDP_BUSY_RELEASE) {
spin_lock_irqsave(&ctrl->mdp_lock, flag);
ctrl->mdp_busy = false;
@@ -1452,7 +1457,7 @@
status = MIPI_INP(base + 0x000c);/* DSI_FIFO_STATUS */
- /* fifo underflow, overflow */
+ /* fifo underflow, overflow and empty*/
if (status & 0xcccc4489) {
MIPI_OUTP(base + 0x000c, status);
pr_err("%s: status=%x\n", __func__, status);
@@ -1460,6 +1465,8 @@
dsi_send_events(ctrl, DSI_EV_MDP_FIFO_UNDERFLOW);
MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1",
"edp", "hdmi", "panic");
+ if (status & 0x11110000) /* DLN_FIFO_EMPTY */
+ dsi_send_events(ctrl, DSI_EV_DSI_FIFO_EMPTY);
}
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index f58e2a1..7575fe3 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -923,6 +923,8 @@
"qcom,mdss-dsi-hsa-power-mode");
pinfo->mipi.hbp_power_stop = of_property_read_bool(np,
"qcom,mdss-dsi-hbp-power-mode");
+ pinfo->mipi.last_line_interleave_en = of_property_read_bool(np,
+ "qcom,mdss-dsi-last-line-interleave");
pinfo->mipi.bllp_power_stop = of_property_read_bool(np,
"qcom,mdss-dsi-bllp-power-mode");
pinfo->mipi.eof_bllp_power_stop = of_property_read_bool(
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 4395d1b..c14f936 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -815,17 +815,17 @@
{
struct mdss_panel_data *pdata;
+ mutex_lock(&mfd->bl_lock);
if (mfd->unset_bl_level && !mfd->bl_updated) {
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->set_backlight)) {
- mutex_lock(&mfd->bl_lock);
mfd->bl_level = mfd->unset_bl_level;
pdata->set_backlight(pdata, mfd->bl_level);
mfd->bl_level_old = mfd->unset_bl_level;
- mutex_unlock(&mfd->bl_lock);
mfd->bl_updated = 1;
}
}
+ mutex_unlock(&mfd->bl_lock);
}
static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
@@ -880,7 +880,9 @@
mfd->op_enable = false;
curr_pwr_state = mfd->panel_power_on;
mfd->panel_power_on = false;
+ mutex_lock(&mfd->bl_lock);
mfd->bl_updated = 0;
+ mutex_unlock(&mfd->bl_lock);
ret = mfd->mdp.off_fnc(mfd);
if (ret)
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 97d4dc9..037a183 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -56,6 +56,9 @@
#include "mdss_panel.h"
#include "mdss_debug.h"
+#define CREATE_TRACE_POINTS
+#include "mdss_mdp_trace.h"
+
struct mdss_data_type *mdss_res;
static int mdss_fb_mem_get_iommu_domain(void)
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 6ca3c0d..0c10d8c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -440,6 +440,7 @@
struct mdss_data_type *mdata;
struct mutex ov_lock;
+ struct mutex dfps_lock;
struct mdss_mdp_ctl *ctl;
struct mdss_mdp_wb *wb;
struct list_head overlay_list;
@@ -689,7 +690,7 @@
int mdss_mdp_data_check(struct mdss_mdp_data *data,
struct mdss_mdp_plane_sizes *ps);
int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
- struct mdss_mdp_plane_sizes *ps, u32 bwc_mode);
+ struct mdss_mdp_plane_sizes *ps, u32 bwc_mode, bool rotation);
int mdss_mdp_get_rau_strides(u32 w, u32 h, struct mdss_mdp_format_params *fmt,
struct mdss_mdp_plane_sizes *ps);
void mdss_mdp_data_calc_offset(struct mdss_mdp_data *data, u16 x, u16 y,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 65d28a0..307d247 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -23,6 +23,7 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_debug.h"
+#include "mdss_mdp_trace.h"
static void mdss_mdp_xlog_mixer_reg(struct mdss_mdp_ctl *ctl);
static inline u64 fudge_factor(u64 val, u32 numer, u32 denom)
@@ -338,8 +339,13 @@
struct mdss_panel_info *pinfo;
pinfo = &mixer->ctl->panel_data->panel_info;
- fps = mdss_panel_get_framerate(pinfo);
- v_total = mdss_panel_get_vtotal(pinfo);
+ if (pinfo->type == MIPI_VIDEO_PANEL) {
+ fps = pinfo->panel_max_fps;
+ v_total = pinfo->panel_max_vtotal;
+ } else {
+ fps = mdss_panel_get_framerate(pinfo);
+ v_total = mdss_panel_get_vtotal(pinfo);
+ }
xres = pinfo->xres;
is_fbc = pinfo->fbc.enabled;
} else {
@@ -459,8 +465,13 @@
if (!mixer->rotator_mode) {
if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
pinfo = &mixer->ctl->panel_data->panel_info;
- fps = mdss_panel_get_framerate(pinfo);
- v_total = mdss_panel_get_vtotal(pinfo);
+ if (pinfo->type == MIPI_VIDEO_PANEL) {
+ fps = pinfo->panel_max_fps;
+ v_total = pinfo->panel_max_vtotal;
+ } else {
+ fps = mdss_panel_get_framerate(pinfo);
+ v_total = mdss_panel_get_vtotal(pinfo);
+ }
if (pinfo->type == WRITEBACK_PANEL)
pinfo = NULL;
@@ -833,6 +844,7 @@
bus_ib_quota = bw_sum_of_intfs;
bus_ab_quota = apply_fudge_factor(bw_sum_of_intfs,
&mdss_res->ab_factor);
+ trace_mdp_perf_update_bus(bus_ab_quota, bus_ib_quota);
mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
pr_debug("ab=%llu ib=%llu\n", bus_ab_quota, bus_ib_quota);
}
@@ -874,6 +886,7 @@
/*Release the bandwidth only if there are no transactions pending*/
if (!transaction_status) {
+ trace_mdp_cmd_release_bw(ctl->num);
ctl->cur_perf.bw_ctl = 0;
ctl->new_perf.bw_ctl = 0;
pr_debug("Release BW ctl=%d\n", ctl->num);
@@ -1966,6 +1979,7 @@
if (!mixer)
return -ENODEV;
+ trace_mdp_mixer_update(mixer->num);
pr_debug("setup mixer=%d\n", mixer->num);
outsize = (mixer->roi.h << 16) | mixer->roi.w;
@@ -2071,6 +2085,8 @@
mixercfg |= stage << (3 * pipe->num);
+ trace_mdp_sspp_change(pipe);
+
pr_debug("stg=%d op=%x fg_alpha=%x bg_alpha=%x\n", stage,
blend_op, fg_alpha, bg_alpha);
mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
@@ -2486,6 +2502,8 @@
if (ctl->wait_fnc)
ret = ctl->wait_fnc(ctl, NULL);
+ trace_mdp_commit(ctl);
+
mdss_mdp_ctl_perf_update(ctl, 0);
mutex_unlock(&ctl->lock);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index c11b438..ea41159 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -519,7 +519,7 @@
#define MDSS_MDP_REG_INTF_FRAME_COUNT 0x0AC
#define MDSS_MDP_REG_INTF_LINE_COUNT 0x0B0
#define MDSS_MDP_PANEL_FORMAT_RGB888 0x213F
-#define MDSS_MDP_PANEL_FORMAT_RGB666 0x212A
+#define MDSS_MDP_PANEL_FORMAT_RGB666 0x21AA
enum mdss_mdp_pingpong_index {
MDSS_MDP_PINGPONG0,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 293b192..991eb06 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -16,6 +16,7 @@
#include "mdss_mdp.h"
#include "mdss_panel.h"
#include "mdss_debug.h"
+#include "mdss_mdp_trace.h"
#define VSYNC_EXPIRE_TICK 4
@@ -354,6 +355,7 @@
} else
pr_err("%s: should not have pingpong interrupt!\n", __func__);
+ trace_mdp_cmd_pingpong_done(ctl, ctx->pp_num, ctx->koff_cnt);
pr_debug("%s: ctl_num=%d intf_num=%d ctx=%d kcnt=%d\n", __func__,
ctl->num, ctl->intf_num, ctx->pp_num, ctx->koff_cnt);
@@ -531,6 +533,8 @@
rc = wait_for_completion_timeout(
&ctx->pp_comp, KOFF_TIMEOUT);
+ trace_mdp_cmd_wait_pingpong(ctl->num, ctx->koff_cnt);
+
if (rc <= 0) {
WARN(1, "cmd kickoff timed out (%d) ctl=%d\n",
rc, ctl->num);
@@ -596,6 +600,7 @@
spin_lock_irqsave(&ctx->clk_lock, flags);
ctx->koff_cnt++;
spin_unlock_irqrestore(&ctx->clk_lock, flags);
+ trace_mdp_cmd_kickoff(ctl->num, ctx->koff_cnt);
mdss_mdp_cmd_clk_on(ctx);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index b07aab4..eff708c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -22,6 +22,7 @@
#include "mdss_mdp.h"
#include "mdss_panel.h"
#include "mdss_debug.h"
+#include "mdss_mdp_trace.h"
/* wait for at least 2 vsyncs for lowest refresh rate (24hz) */
#define VSYNC_TIMEOUT_US 100000
@@ -493,6 +494,7 @@
ctl->underrun_cnt++;
MDSS_XLOG(ctl->num, ctl->underrun_cnt);
MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1", "edp", "hdmi", "panic");
+ trace_mdp_video_underrun_done(ctl->num, ctl->underrun_cnt);
pr_debug("display underrun detected for ctl=%d count=%d\n", ctl->num,
ctl->underrun_cnt);
@@ -632,9 +634,19 @@
usecs_to_jiffies(VSYNC_TIMEOUT_US));
WARN(rc <= 0, "timeout (%d) vsync interrupt on ctl=%d\n",
rc, ctl->num);
- rc = 0;
- video_vsync_irq_disable(ctl);
+ video_vsync_irq_disable(ctl);
+ /* Do not configure fps on vsync timeout */
+ if (rc <= 0)
+ return rc;
+
+ if (mdss_mdp_video_line_count(ctl) >=
+ pdata->panel_info.yres/2) {
+ pr_err("Too few lines left line_cnt = %d y_res/2 = %d\n",
+ mdss_mdp_video_line_count(ctl),
+ pdata->panel_info.yres/2);
+ return -EPERM;
+ }
rc = mdss_mdp_video_vfp_fps_update(ctl, new_fps);
if (rc < 0) {
pr_err("%s: Error during DFPS\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 27a7707..02e7b75 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. 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
@@ -131,13 +131,17 @@
struct mdss_mdp_format_params *fmt;
u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
u32 opmode = ctx->opmode;
+ bool rotation = false;
struct mdss_data_type *mdata;
pr_debug("wb_num=%d format=%d\n", ctx->wb_num, format);
+ if (ctx->rot90)
+ rotation = true;
+
mdss_mdp_get_plane_sizes(format, ctx->width, ctx->height,
&ctx->dst_planes,
- ctx->opmode & MDSS_MDP_OP_BWC_EN);
+ ctx->opmode & MDSS_MDP_OP_BWC_EN, rotation);
fmt = mdss_mdp_get_format_params(format);
if (!fmt) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 2ec7dc5..53eccc6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1047,6 +1047,7 @@
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
int ret = 0;
int sd_in_pipe = 0;
+ bool need_cleanup = false;
if (ctl->shared_lock) {
mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_BEGIN);
@@ -1091,6 +1092,7 @@
list_for_each_entry(pipe, &mdp5_data->pipes_cleanup, cleanup_list) {
mdss_mdp_pipe_queue_data(pipe, NULL);
mdss_mdp_mixer_pipe_unstage(pipe);
+ need_cleanup = true;
}
ret = __overlay_queue_pipes(mfd);
@@ -1100,8 +1102,10 @@
else
ret = mdss_mdp_display_commit(mdp5_data->ctl, NULL);
- atomic_set(&mfd->kickoff_pending, 0);
- wake_up_all(&mfd->kickoff_wait_q);
+ if (!need_cleanup) {
+ atomic_set(&mfd->kickoff_pending, 0);
+ wake_up_all(&mfd->kickoff_wait_q);
+ }
mutex_unlock(&mfd->lock);
if (IS_ERR_VALUE(ret))
@@ -1128,7 +1132,10 @@
mdss_mdp_overlay_cleanup(mfd);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_FLUSHED);
-
+ if (need_cleanup) {
+ atomic_set(&mfd->kickoff_pending, 0);
+ wake_up_all(&mfd->kickoff_wait_q);
+ }
mutex_unlock(&mdp5_data->ov_lock);
if (ctl->shared_lock)
mutex_unlock(ctl->shared_lock);
@@ -1244,8 +1251,8 @@
}
}
- if (cnt == 0 && !list_empty(&mdp5_data->pipes_cleanup)) {
- pr_debug("overlay release on fb%d called without commit!",
+ if (!mfd->ref_cnt && !list_empty(&mdp5_data->pipes_cleanup)) {
+ pr_debug("fb%d:: free pipes present in cleanup list",
mfd->index);
cnt++;
}
@@ -1711,10 +1718,12 @@
return -ENODEV;
}
+ mutex_lock(&mdp5_data->dfps_lock);
ret = snprintf(buf, PAGE_SIZE, "%d\n",
pdata->panel_info.mipi.frame_rate);
pr_debug("%s: '%d'\n", __func__,
pdata->panel_info.mipi.frame_rate);
+ mutex_unlock(&mdp5_data->dfps_lock);
return ret;
} /* dynamic_fps_sysfs_rda_dfps */
@@ -1749,6 +1758,7 @@
return count;
}
+ mutex_lock(&mdp5_data->dfps_lock);
if (dfps < 30) {
pr_err("Unsupported FPS. Configuring to min_fps = 30\n");
dfps = 30;
@@ -1765,9 +1775,11 @@
} else {
pr_err("Failed to configure '%d' FPS. rc = %d\n",
dfps, rc);
+ mutex_unlock(&mdp5_data->dfps_lock);
return rc;
}
pdata->panel_info.new_fps = dfps;
+ mutex_unlock(&mdp5_data->dfps_lock);
return count;
} /* dynamic_fps_sysfs_wta_dfps */
@@ -3000,6 +3012,7 @@
INIT_LIST_HEAD(&mdp5_data->pipes_cleanup);
INIT_LIST_HEAD(&mdp5_data->rot_proc_list);
mutex_init(&mdp5_data->ov_lock);
+ mutex_init(&mdp5_data->dfps_lock);
mdp5_data->hw_refresh = true;
mdp5_data->overlay_play_enable = true;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index c522857..32b8cbf 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -270,7 +270,7 @@
}
}
rc = mdss_mdp_get_plane_sizes(format, width, pipe->src.h,
- &ps, 0);
+ &ps, 0, 0);
if (rc)
return rc;
@@ -883,6 +883,7 @@
u32 decimation;
struct mdss_mdp_img_rect sci, dst, src;
int ret = 0;
+ bool rotation = false;
pr_debug("pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n",
pipe->num, pipe->img_width, pipe->img_height,
@@ -891,8 +892,12 @@
width = pipe->img_width;
height = pipe->img_height;
+
+ if (pipe->flags & MDP_SOURCE_ROTATED_90)
+ rotation = true;
+
mdss_mdp_get_plane_sizes(pipe->src_fmt->format, width, height,
- &pipe->src_planes, pipe->bwc_mode);
+ &pipe->src_planes, pipe->bwc_mode, rotation);
if (data != NULL) {
ret = mdss_mdp_data_check(data, &pipe->src_planes);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 0c6eb2a..42e7ed2 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -1612,6 +1612,7 @@
u32 disp_num;
int i;
bool valid_mixers = true;
+ bool valid_ad_panel = true;
if ((!ctl->mfd) || (!mdss_pp_res))
return -EINVAL;
@@ -1632,7 +1633,13 @@
if (mixer_id[i] >= mdata->nad_cfgs)
valid_mixers = false;
}
- if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw)) {
+ valid_ad_panel = (ctl->mfd->panel_info->type != DTV_PANEL) &&
+ (((mdata->mdp_rev < MDSS_MDP_HW_REV_103) &&
+ (ctl->mfd->panel_info->type == WRITEBACK_PANEL)) ||
+ (ctl->mfd->panel_info->type != WRITEBACK_PANEL));
+
+ if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw) &&
+ valid_ad_panel) {
ret = mdss_mdp_ad_setup(ctl->mfd);
if (ret < 0)
pr_warn("ad_setup(disp%d) returns %d", disp_num, ret);
diff --git a/drivers/video/msm/mdss/mdss_mdp_splash_logo.c b/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
index 77f6554..838f58f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
+++ b/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
@@ -504,8 +504,8 @@
}
unlock_fb_info(mfd->fbi);
- mfd->bl_updated = true;
mutex_lock(&mfd->bl_lock);
+ mfd->bl_updated = true;
mdss_fb_set_backlight(mfd, mfd->panel_info->bl_max >> 1);
mutex_unlock(&mfd->bl_lock);
diff --git a/drivers/video/msm/mdss/mdss_mdp_trace.h b/drivers/video/msm/mdss/mdss_mdp_trace.h
new file mode 100644
index 0000000..0e0c1e7
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_trace.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. 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.
+ *
+ */
+#if !defined(TRACE_MDSS_MDP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define TRACE_MDSS_MDP_H
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mdss
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE mdss_mdp_trace
+
+#include <linux/tracepoint.h>
+#include "mdss_mdp.h"
+
+DECLARE_EVENT_CLASS(mdp_sspp_template,
+ TP_PROTO(struct mdss_mdp_pipe *pipe),
+ TP_ARGS(pipe),
+ TP_STRUCT__entry(
+ __field(u32, num)
+ __field(u32, play_cnt)
+ __field(u32, mixer)
+ __field(u32, stage)
+ __field(u32, flags)
+ __field(u32, format)
+ __field(u16, img_w)
+ __field(u16, img_h)
+ __field(u16, src_x)
+ __field(u16, src_y)
+ __field(u16, src_w)
+ __field(u16, src_h)
+ __field(u16, dst_x)
+ __field(u16, dst_y)
+ __field(u16, dst_w)
+ __field(u16, dst_h)
+ ),
+ TP_fast_assign(
+ __entry->num = pipe->num;
+ __entry->play_cnt = pipe->play_cnt;
+ __entry->mixer = pipe->mixer->num;
+ __entry->stage = pipe->mixer_stage;
+ __entry->flags = pipe->flags;
+ __entry->format = pipe->src_fmt ?
+ pipe->src_fmt->format : -1;
+ __entry->img_w = pipe->img_width;
+ __entry->img_h = pipe->img_height;
+ __entry->src_x = pipe->src.x;
+ __entry->src_y = pipe->src.y;
+ __entry->src_w = pipe->src.w;
+ __entry->src_h = pipe->src.h;
+ __entry->dst_x = pipe->dst.x;
+ __entry->dst_y = pipe->dst.y;
+ __entry->dst_w = pipe->dst.w;
+ __entry->dst_h = pipe->dst.h;
+ ),
+
+ TP_printk("num=%d mixer=%d play_cnt=%d flags=0x%x stage=%d format=%d img=%dx%d src=[%d,%d,%d,%d] dst=[%d,%d,%d,%d]",
+ __entry->num, __entry->mixer, __entry->play_cnt,
+ __entry->flags, __entry->stage,
+ __entry->format, __entry->img_w, __entry->img_h,
+ __entry->src_x, __entry->src_y,
+ __entry->src_w, __entry->src_h,
+ __entry->dst_x, __entry->dst_y,
+ __entry->dst_w, __entry->dst_h)
+);
+
+DEFINE_EVENT(mdp_sspp_template, mdp_sspp_set,
+ TP_PROTO(struct mdss_mdp_pipe *pipe),
+ TP_ARGS(pipe)
+);
+
+DEFINE_EVENT(mdp_sspp_template, mdp_sspp_change,
+ TP_PROTO(struct mdss_mdp_pipe *pipe),
+ TP_ARGS(pipe)
+);
+
+TRACE_EVENT(mdp_mixer_update,
+ TP_PROTO(u32 mixer_num),
+ TP_ARGS(mixer_num),
+ TP_STRUCT__entry(
+ __field(u32, mixer_num)
+ ),
+ TP_fast_assign(
+ __entry->mixer_num = mixer_num;
+ ),
+ TP_printk("mixer=%d",
+ __entry->mixer_num)
+);
+
+TRACE_EVENT(mdp_commit,
+ TP_PROTO(struct mdss_mdp_ctl *ctl),
+ TP_ARGS(ctl),
+ TP_STRUCT__entry(
+ __field(u32, num)
+ __field(u32, play_cnt)
+ __field(u32, clk_rate)
+ __field(u64, bandwidth)
+ ),
+ TP_fast_assign(
+ __entry->num = ctl->num;
+ __entry->play_cnt = ctl->play_cnt;
+ __entry->clk_rate = ctl->new_perf.mdp_clk_rate;
+ __entry->bandwidth = ctl->new_perf.bw_ctl;
+ ),
+ TP_printk("num=%d play_cnt=%d bandwidth=%llu clk_rate=%u",
+ __entry->num,
+ __entry->play_cnt,
+ __entry->bandwidth,
+ __entry->clk_rate)
+);
+
+TRACE_EVENT(mdp_video_underrun_done,
+ TP_PROTO(u32 ctl_num, u32 underrun_cnt),
+ TP_ARGS(ctl_num, underrun_cnt),
+ TP_STRUCT__entry(
+ __field(u32, ctl_num)
+ __field(u32, underrun_cnt)
+ ),
+ TP_fast_assign(
+ __entry->ctl_num = ctl_num;
+ __entry->underrun_cnt = underrun_cnt;
+ ),
+ TP_printk("ctl=%d count=%d",
+ __entry->ctl_num, __entry->underrun_cnt)
+);
+
+TRACE_EVENT(mdp_perf_update_bus,
+ TP_PROTO(unsigned long long ab_quota, unsigned long long ib_quota),
+ TP_ARGS(ab_quota, ib_quota),
+ TP_STRUCT__entry(
+ __field(u64, ab_quota)
+ __field(u64, ib_quota)
+ ),
+ TP_fast_assign(
+ __entry->ab_quota = ab_quota;
+ __entry->ib_quota = ib_quota;
+ ),
+ TP_printk("ab=%llu ib=%llu",
+ __entry->ab_quota,
+ __entry->ib_quota)
+);
+
+TRACE_EVENT(mdp_cmd_pingpong_done,
+ TP_PROTO(struct mdss_mdp_ctl *ctl, u32 pp_num, int koff_cnt),
+ TP_ARGS(ctl, pp_num, koff_cnt),
+ TP_STRUCT__entry(
+ __field(u32, ctl_num)
+ __field(u32, intf_num)
+ __field(u32, pp_num)
+ __field(int, koff_cnt)
+ ),
+ TP_fast_assign(
+ __entry->ctl_num = ctl->num;
+ __entry->intf_num = ctl->intf_num;
+ __entry->pp_num = pp_num;
+ __entry->koff_cnt = koff_cnt;
+ ),
+ TP_printk("ctl num:%d intf_num:%d ctx:%d kickoff:%d",
+ __entry->ctl_num, __entry->intf_num, __entry->pp_num,
+ __entry->koff_cnt)
+);
+
+TRACE_EVENT(mdp_cmd_release_bw,
+ TP_PROTO(u32 ctl_num),
+ TP_ARGS(ctl_num),
+ TP_STRUCT__entry(
+ __field(u32, ctl_num)
+ ),
+ TP_fast_assign(
+ __entry->ctl_num = ctl_num;
+ ),
+ TP_printk("ctl num:%d", __entry->ctl_num)
+);
+
+TRACE_EVENT(mdp_cmd_kickoff,
+ TP_PROTO(u32 ctl_num, int kickoff_cnt),
+ TP_ARGS(ctl_num, kickoff_cnt),
+ TP_STRUCT__entry(
+ __field(u32, ctl_num)
+ __field(int, kickoff_cnt)
+ ),
+ TP_fast_assign(
+ __entry->ctl_num = ctl_num;
+ __entry->kickoff_cnt = kickoff_cnt;
+ ),
+ TP_printk("kickoff ctl=%d cnt=%d",
+ __entry->ctl_num,
+ __entry->kickoff_cnt)
+);
+
+TRACE_EVENT(mdp_cmd_wait_pingpong,
+ TP_PROTO(u32 ctl_num, int kickoff_cnt),
+ TP_ARGS(ctl_num, kickoff_cnt),
+ TP_STRUCT__entry(
+ __field(u32, ctl_num)
+ __field(int, kickoff_cnt)
+ ),
+ TP_fast_assign(
+ __entry->ctl_num = ctl_num;
+ __entry->kickoff_cnt = kickoff_cnt;
+ ),
+ TP_printk("pingpong ctl=%d cnt=%d",
+ __entry->ctl_num,
+ __entry->kickoff_cnt)
+);
+
+#endif /* if !defined(TRACE_MDSS_MDP_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 69506d4..9336582 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -320,7 +320,7 @@
}
int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
- struct mdss_mdp_plane_sizes *ps, u32 bwc_mode)
+ struct mdss_mdp_plane_sizes *ps, u32 bwc_mode, bool rotation)
{
struct mdss_mdp_format_params *fmt;
int i, rc;
@@ -374,9 +374,19 @@
u8 hmap[] = { 1, 2, 1, 2 };
u8 vmap[] = { 1, 1, 2, 2 };
u8 horiz, vert, stride_align, height_align;
+ u32 chroma_samp;
- horiz = hmap[fmt->chroma_sample];
- vert = vmap[fmt->chroma_sample];
+ chroma_samp = fmt->chroma_sample;
+
+ if (rotation) {
+ if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
+ chroma_samp = MDSS_MDP_CHROMA_H1V2;
+ else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
+ chroma_samp = MDSS_MDP_CHROMA_H2V1;
+ }
+
+ horiz = hmap[chroma_samp];
+ vert = vmap[chroma_samp];
switch (format) {
case MDP_Y_CR_CB_GH2V2:
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index c5ac72e..52c3e71 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -208,6 +208,7 @@
char hbp_power_stop;
char hsa_power_stop;
char eof_bllp_power_stop;
+ char last_line_interleave_en;
char bllp_power_stop;
char traffic_mode;
char frame_rate;
@@ -320,7 +321,8 @@
bool ulps_feature_enabled;
char dfps_update;
int new_fps;
-
+ int panel_max_fps;
+ int panel_max_vtotal;
u32 cont_splash_enabled;
u32 partial_update_enabled;
struct ion_handle *splash_ihdl;
diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h
index 18513e3..74f6714 100644
--- a/include/linux/dma-attrs.h
+++ b/include/linux/dma-attrs.h
@@ -17,6 +17,7 @@
DMA_ATTR_NON_CONSISTENT,
DMA_ATTR_NO_KERNEL_MAPPING,
DMA_ATTR_STRONGLY_ORDERED,
+ DMA_ATTR_SKIP_ZEROING,
DMA_ATTR_MAX,
};
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 78e57cd..9975eef 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -73,7 +73,8 @@
void dma_contiguous_reserve(phys_addr_t addr_limit);
int dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base,
- phys_addr_t limit, const char *name);
+ phys_addr_t limit, const char *name,
+ bool in_system);
int dma_contiguous_add_device(struct device *dev, phys_addr_t base);
@@ -94,7 +95,19 @@
phys_addr_t base, phys_addr_t limit)
{
int ret;
- ret = dma_contiguous_reserve_area(size, &base, limit, NULL);
+ ret = dma_contiguous_reserve_area(size, &base, limit, NULL, true);
+ if (ret == 0)
+ ret = dma_contiguous_add_device(dev, base);
+ return ret;
+}
+
+static inline int dma_declare_contiguous_reserved(struct device *dev,
+ phys_addr_t size,
+ phys_addr_t base,
+ phys_addr_t limit)
+{
+ int ret;
+ ret = dma_contiguous_reserve_area(size, &base, limit, NULL, false);
if (ret == 0)
ret = dma_contiguous_add_device(dev, base);
return ret;
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 17986b5..bc80bda 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -692,7 +692,8 @@
* struct kgsl_perfcounter_get - argument to IOCTL_KGSL_PERFCOUNTER_GET
* @groupid: Performance counter group ID
* @countable: Countable to select within the group
- * @offset: Return offset of the reserved counter
+ * @offset: Return offset of the reserved LO counter
+ * @offset_hi: Return offset of the reserved HI counter
*
* Get an available performance counter from a specified groupid. The offset
* of the performance counter will be returned after successfully assigning
@@ -707,8 +708,9 @@
unsigned int groupid;
unsigned int countable;
unsigned int offset;
+ unsigned int offset_hi;
/* private: reserved for future use */
- unsigned int __pad[2]; /* For future binary compatibility */
+ unsigned int __pad; /* For future binary compatibility */
};
#define IOCTL_KGSL_PERFCOUNTER_GET \
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 4ecacc7..44fe134 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -191,6 +191,20 @@
};
/**
+ * Maintain state for hvdcp external charger status
+ * DEFAULT This is used when DCP is detected
+ * ACTIVE This is used when ioctl is called to block LPM
+ * INACTIVE This is used when ioctl is called to unblock LPM
+ */
+
+enum usb_ext_chg_status {
+ DEFAULT = 1,
+ ACTIVE,
+ INACTIVE,
+};
+
+
+/**
* struct msm_otg_platform_data - platform device data
* for msm_otg driver.
* @phy_init_seq: PHY configuration sequence. val, reg pairs
@@ -463,7 +477,7 @@
struct class *ext_chg_class;
struct device *ext_chg_device;
bool ext_chg_opened;
- bool ext_chg_active;
+ enum usb_ext_chg_status ext_chg_active;
struct completion ext_chg_wait;
int ui_enabled;
bool pm_done;
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 46cec76..b1b54cb 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -40,10 +40,14 @@
#define MAX_ACTUATOR_REGION 5
#define MAX_ACTUATOR_INIT_SET 12
#define MAX_ACTUATOR_REG_TBL_SIZE 8
+#define MAX_ACTUATOR_AF_TOTAL_STEPS 1024
#define MOVE_NEAR 0
#define MOVE_FAR 1
+#define MSM_ACTUATOR_MOVE_SIGNED_FAR -1
+#define MSM_ACTUATOR_MOVE_SIGNED_NEAR 1
+
#define MAX_EEPROM_NAME 32
#define MAX_AF_ITERATIONS 3
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index df9f9e7..59dcca9 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -15,6 +15,7 @@
#define MSM_CPP_MAX_NUM_PLANES 3
#define MSM_CPP_MAX_FRAME_LENGTH 1024
#define MSM_CPP_MAX_FW_NAME_LEN 32
+#define MAX_FREQ_TBL 10
enum msm_cpp_frame_type {
MSM_CPP_OFFLINE_FRAME,
@@ -126,6 +127,8 @@
struct cpp_hw_info {
uint32_t cpp_hw_version;
uint32_t cpp_hw_caps;
+ unsigned long freq_tbl[MAX_FREQ_TBL];
+ uint32_t freq_tbl_count;
};
struct msm_vpe_frame_strip_info {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index bc4888d..76e2afe 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1971,7 +1971,8 @@
restart:
read_lock_bh(&table->tb6_lock);
for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
- if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
+ if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
+ (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);
ip6_del_rt(rt);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c3adef8..cf82dbd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6780,9 +6780,11 @@
data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
}
-
- return rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
+ rdev->cur_cmd_info = info;
+ err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
data, len);
+ rdev->cur_cmd_info = NULL;
+ return err;
}
return -EOPNOTSUPP;
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index a5e0bb3..bbe1ac7 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -2834,7 +2834,7 @@
rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
DAPM_MICBIAS_EXTERNAL_STANDALONE);
else {
- if (msm8x10_wcd->micb_en_count > 0) {
+ if (msm8x10_wcd->micb_en_count > 1) {
msm8x10_wcd->micb_en_count--;
pr_debug("%s micb_en_count : %d", __func__,
msm8x10_wcd->micb_en_count);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 8a71891..9bd1652 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -1649,9 +1649,9 @@
}
}
- if (type == PLUG_TYPE_HEADSET && dvddio) {
- if ((dvddio->_vdces > hs_max) ||
- (dvddio->_vdces > minv + WCD9XXX_THRESHOLD_MIC_THRESHOLD)) {
+ if (type == PLUG_TYPE_HEADSET) {
+ if (dvddio && ((dvddio->_vdces > hs_max) ||
+ (dvddio->_vdces > minv + WCD9XXX_THRESHOLD_MIC_THRESHOLD))) {
pr_debug("%s: Headset with threshold on MIC detected\n",
__func__);
if (mbhc->mbhc_cfg->micbias_enable_flags &
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 8aa1e35..23ed60a 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2413,6 +2413,21 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
},
+ {
+ .name = "VoWLAN",
+ .stream_name = "VoWLAN",
+ .cpu_dai_name = "VoWLAN",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOWLAN,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index aa4d88d..fce1940 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -177,8 +177,31 @@
pr_debug("%s: call q6asm_set_lrgain\n", __func__);
rc = q6asm_set_lrgain(prtd->audio_client,
volume_l, volume_r);
+ if (rc < 0) {
+ pr_err("%s: set lrgain command failed rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ /*
+ * set master gain to unity so that only lr gain
+ * is effective
+ */
+ rc = q6asm_set_volume(prtd->audio_client,
+ COMPRESSED_LR_VOL_MAX_STEPS);
} else {
pr_debug("%s: call q6asm_set_volume\n", __func__);
+ /*
+ * set left and right channel gain to unity so that
+ * only master gain is effective
+ */
+ rc = q6asm_set_lrgain(prtd->audio_client,
+ COMPRESSED_LR_VOL_MAX_STEPS,
+ COMPRESSED_LR_VOL_MAX_STEPS);
+ if (rc < 0) {
+ pr_err("%s: set lrgain command failed rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
rc = q6asm_set_volume(prtd->audio_client, volume_l);
}
if (rc < 0) {
@@ -574,10 +597,6 @@
prtd->session_id,
SNDRV_PCM_STREAM_PLAYBACK);
- ret = msm_compr_set_volume(cstream, 0, 0);
- if (ret < 0)
- pr_err("%s : Set Volume failed : %d", __func__, ret);
-
ret = q6asm_set_softvolume(ac, &softvol);
if (ret < 0)
pr_err("%s: Send SoftVolume Param failed ret=%d\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 08448fe..b49ce46 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -31,6 +31,7 @@
#include <linux/msm_audio_ion.h>
#include <linux/of_device.h>
+#include <sound/tlv.h>
#include <sound/pcm_params.h>
#include "msm-pcm-q6-v2.h"
@@ -38,6 +39,10 @@
static struct audio_locks the_locks;
+#define PCM_MASTER_VOL_MAX_STEPS 0x2000
+static const DECLARE_TLV_DB_LINEAR(msm_pcm_vol_gain, 0,
+ PCM_MASTER_VOL_MAX_STEPS);
+
struct snd_msm {
struct snd_card *card;
struct snd_pcm *pcm;
@@ -819,6 +824,94 @@
.mmap = msm_pcm_mmap,
};
+static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
+{
+ int rc = 0;
+
+ if (prtd && prtd->audio_client) {
+ pr_debug("%s: channels %d volume 0x%x\n", __func__,
+ prtd->channel_mode, volume);
+ rc = q6asm_set_volume(prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc=%d\n",
+ __func__, rc);
+ }
+ }
+ return rc;
+}
+
+static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s\n", __func__);
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ ucontrol->value.integer.value[0] = prtd->volume;
+ return 0;
+}
+
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+ int volume = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: volume : 0x%x\n", __func__, volume);
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd) {
+ rc = msm_pcm_set_volume(prtd, volume);
+ prtd->volume = volume;
+ }
+ return rc;
+}
+
+static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+ struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+
+ dev_dbg(rtd->dev, "%s, Volume control add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1, rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0) {
+ pr_err("%s volume control failed ret %d\n", __func__, ret);
+ return ret;
+ }
+ kctl = volume_info->kctl;
+ kctl->put = msm_pcm_volume_ctl_put;
+ kctl->get = msm_pcm_volume_ctl_get;
+ kctl->tlv.p = msm_pcm_vol_gain;
+ return 0;
+}
+
static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -905,6 +998,10 @@
__func__, kctl->id.name);
kctl->put = msm_pcm_chmap_ctl_put;
kctl->get = msm_pcm_chmap_ctl_get;
+ ret = msm_pcm_add_volume_control(rtd);
+ if (ret)
+ pr_err("%s: Could not add pcm Volume Control %d\n",
+ __func__, ret);
return ret;
}