Merge "msm: pil-vidc: Migrate to devm_clk_get()" into msm-3.4
diff --git a/Documentation/devicetree/bindings/pil/pil-venus.txt b/Documentation/devicetree/bindings/pil/pil-venus.txt
new file mode 100644
index 0000000..93cba32
--- /dev/null
+++ b/Documentation/devicetree/bindings/pil/pil-venus.txt
@@ -0,0 +1,28 @@
+* Qualcomm Venus Video Subsystem Peripheral Image Loader
+
+pil-venus is a peripheral image loading (PIL) driver. It is used for loading
+venus firmware images for video codec into memory and preparing the subsystem's
+processor to execute code. It is also used for shutting down the processor when
+it's not needed.
+
+Required properties:
+- compatible: "pil-venus"
+- reg: offset and length of the register set for the device. The first pair
+ corresponds to VENUS_WRAPPER, the second pair corresponds to VENUS_VBIF.
+- vdd-supply: regulator to supply venus.
+- qcom,firmware-name: Base name of the firmware image. Ex. "venus"
+- qcom,firmware-min-paddr: The lowest addr boundary for firmware image in DDR
+- qcom,firmware-max-paddr: The highest addr boundary for firmware image in DDR
+
+Example:
+ qcom,venus@fdce0000 {
+ compatible = "qcom,pil-venus";
+ reg = <0xfdce0000 0x4000>,
+ <0xfdc80208 0x8>;
+ vdd-supply = <&gdsc_venus>;
+
+ qcom,firmware-name = "venus";
+ qcom,firmware-min-paddr = <0xF500000>;
+ qcom,firmware-max-paddr = <0xFA00000>;
+
+ };
diff --git a/arch/arm/boot/dts/msm8974-iommu.dtsi b/arch/arm/boot/dts/msm8974-iommu.dtsi
old mode 100644
new mode 100755
index 697136a..e1a0a9b
--- a/arch/arm/boot/dts/msm8974-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-iommu.dtsi
@@ -88,4 +88,27 @@
qcom,iommu-ctx-name = "venus_fw";
};
};
+
+ kgsl: qcom,iommu@fdb10000 {
+ compatible = "qcom,msm-smmu-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0xfdb10000 0x10000>;
+ vdd-supply = <&gdsc_oxili_cx>;
+ qcom,iommu-smt-size = <32>;
+
+ qcom,iommu-ctx@fdb18000 {
+ reg = <0xfdb18000 0x1000>;
+ interrupts = <0 240 0>;
+ qcom,iommu-ctx-sids = <0>;
+ qcom,iommu-ctx-name = "gfx3d_user";
+ };
+ qcom,iommu-ctx@fdb19000 {
+ reg = <0xfdb19000 0x1000>;
+ interrupts = <0 241 0>;
+ qcom,iommu-ctx-sids = <1>;
+ qcom,iommu-ctx-name = "gfx3d_priv";
+ };
+ };
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 584bd11..8f8deac 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -471,4 +471,15 @@
compatible = "qcom,tz-log";
reg = <0xfe805720 0x1000>;
};
+
+ qcom,venus@fdce0000 {
+ compatible = "qcom,pil-venus";
+ reg = <0xfdce0000 0x4000>,
+ <0xfdc80208 0x8>;
+ vdd-supply = <&gdsc_venus>;
+
+ qcom,firmware-name = "venus";
+ qcom,firmware-min-paddr = <0xF500000>;
+ qcom,firmware-max-paddr = <0xFA00000>;
+ };
};
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index dd9418f..3cd06a2 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -53,6 +53,7 @@
CONFIG_MSM_RPC_VIBRATOR=y
CONFIG_PM8XXX_RPC_VIBRATOR=y
CONFIG_MSM_SPM_V2=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
CONFIG_ARM_THUMBEE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -250,6 +251,8 @@
CONFIG_MSM_ACTUATOR=y
CONFIG_OV7692=y
CONFIG_RADIO_TAVARUA=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_FB=y
CONFIG_FB_MSM=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index b332e6b..058349a 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -53,6 +53,7 @@
CONFIG_MSM_RPC_VIBRATOR=y
CONFIG_PM8XXX_RPC_VIBRATOR=y
CONFIG_MSM_SPM_V2=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
CONFIG_ARM_THUMBEE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -251,6 +252,8 @@
CONFIG_MSM_ACTUATOR=y
CONFIG_OV7692=y
CONFIG_RADIO_TAVARUA=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_FB=y
CONFIG_FB_MSM=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index ea4c0f6..173dcca 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -416,6 +416,8 @@
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_SSBI=y
+CONFIG_MSM_IOMMU=y
+# CONFIG_IOMMU_PGTABLES_L2 is not set
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 20557e5..f329c81 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -288,6 +288,8 @@
# CONFIG_I2C_MSM is not set
CONFIG_I2C_QUP=y
CONFIG_I2C_SSBI=y
+CONFIG_MSM_IOMMU=y
+# CONFIG_IOMMU_PGTABLES_L2 is not set
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 905cb00..07bd8e6 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -47,6 +47,7 @@
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_MSM_PIL_MBA=y
CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_PIL_VENUS=y
CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_OCMEM=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index b4cfe4b..c9bc610 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -229,8 +229,8 @@
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_GADGET=y
-CONFIG_USB_CI13XXX_MSM=m
-CONFIG_USB_CI13XXX_MSM_HSIC=m
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_CI13XXX_MSM_HSIC=y
CONFIG_USB_G_ANDROID=y
CONFIG_RMNET_SMD_CTL_CHANNEL="DATA36_CNTL"
CONFIG_RMNET_SMD_DATA_CHANNEL="DATA36"
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index d786ab7..2acf3ce 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1906,6 +1906,13 @@
help
Support for authenticating the video core image.
+config MSM_PIL_VENUS
+ tristate "VENUS (Video) Boot Support"
+ depends on MSM_PIL
+ help
+ Support for booting and shutting down the VENUS processor (Video).
+ Venus is the Video subsystem processor used for video codecs.
+
config MSM_PIL_GSS
tristate "GSS (Coretx A5) Boot Support"
depends on MSM_PIL
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 7dfec38..702667b 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -79,6 +79,7 @@
obj-$(CONFIG_MSM_PIL_DSPS) += pil-dsps.o
obj-$(CONFIG_MSM_PIL_GSS) += pil-gss.o
obj-$(CONFIG_MSM_PIL_PRONTO) += pil-pronto.o
+obj-$(CONFIG_MSM_PIL_VENUS) += pil-venus.o
obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
@@ -300,6 +301,7 @@
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-rfkill.o msm_vibrator.o
CFLAGS_msm_vibrator.o += -Idrivers/staging/android
+CFLAGS_board-9615.o += -Idrivers/usb/gadget
obj-$(CONFIG_ARCH_FSM9XXX) += board-fsm9xxx.o
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 9809bdf..c9d3817 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -1615,7 +1615,7 @@
acpu_freq_tbl = acpu_freq_tbl_8627;
l2_freq_tbl = l2_freq_tbl_8627;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8627);
- } else if (cpu_is_msm8930()) {
+ } else if (cpu_is_msm8930() || cpu_is_msm8930aa()) {
enum pvs pvs_id = get_pvs();
scalable = scalable_8930;
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 5edddb5..177e1fd 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -255,6 +255,7 @@
#else
.mem_hid = MEMTYPE_EBI1,
#endif
+ .mdp_iommu_split_domain = 1,
};
void __init apq8064_mdp_writeback(struct memtype_reserve* reserve_table)
@@ -313,7 +314,16 @@
.dev.platform_data = &hdmi_msm_data,
};
+static char wfd_check_mdp_iommu_split_domain(void)
+{
+ return mdp_pdata.mdp_iommu_split_domain;
+}
+
#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static struct msm_wfd_platform_data wfd_pdata = {
+ .wfd_check_mdp_iommu_split = wfd_check_mdp_iommu_split_domain,
+};
+
static struct platform_device wfd_panel_device = {
.name = "wfd_panel",
.id = 0,
@@ -323,6 +333,7 @@
static struct platform_device wfd_device = {
.name = "msm_wfd",
.id = -1,
+ .dev.platform_data = &wfd_pdata,
};
#endif
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 7175123f..f727852 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -256,7 +256,7 @@
VREG_CONSUMERS(EXT_3P3V) = {
REGULATOR_SUPPLY("ext_3p3v", NULL),
REGULATOR_SUPPLY("vdd_io", "spi0.2"),
- REGULATOR_SUPPLY("mhl_ext_3p3v", "msm_otg"),
+ REGULATOR_SUPPLY("mhl_usb_hs_switch", "msm_otg"),
REGULATOR_SUPPLY("lvds_vccs_3p3v", "lvds.0"),
REGULATOR_SUPPLY("dsi1_vccs_3p3v", "mipi_dsi.1"),
REGULATOR_SUPPLY("hdmi_mux_vdd", "hdmi_msm.0"),
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index a574139..f884631 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2970,6 +2970,7 @@
{
apq8064_common_init();
ethernet_init();
+ msm_rotator_set_split_iommu_domain();
platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices));
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
}
@@ -2982,10 +2983,12 @@
if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
machine_is_mpq8064_dtv()) {
enable_avc_i2c_bus();
+ msm_rotator_set_split_iommu_domain();
platform_add_devices(mpq_devices, ARRAY_SIZE(mpq_devices));
mpq8064_pcie_init();
} else {
ethernet_init();
+ msm_rotator_set_split_iommu_domain();
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
spi_register_board_info(spi_board_info,
ARRAY_SIZE(spi_board_info));
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 8a837d6..739dc85 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -429,6 +429,7 @@
#else
.mem_hid = MEMTYPE_EBI1,
#endif
+ .mdp_iommu_split_domain = 0,
};
void __init msm8930_mdp_writeback(struct memtype_reserve* reserve_table)
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index e6a13b1..5abb9f8 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -98,10 +98,7 @@
};
/* Initial pm8038 MPP configurations */
-static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {
- /* External 5V regulator enable; shared by HDMI and USB_OTG switches. */
- PM8XXX_MPP_INIT(3, D_INPUT, PM8038_MPP_DIG_LEVEL_VPH, DIN_TO_INT),
-};
+static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {};
void __init msm8930_pm8038_gpio_mpp_init(void)
{
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index c1017a9..20e9d2b 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -595,6 +595,7 @@
.mem_hid = MEMTYPE_EBI1,
#endif
.cont_splash_enabled = 0x01,
+ .mdp_iommu_split_domain = 0,
};
void __init msm8960_mdp_writeback(struct memtype_reserve* reserve_table)
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 7181990..a312e2b 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -52,6 +52,7 @@
#include "pm.h"
#include "pm-boot.h"
#include <mach/gpiomux.h>
+#include "ci13xxx_udc.h"
#ifdef CONFIG_ION_MSM
#define MSM_ION_AUDIO_SIZE 0xAF000
@@ -762,10 +763,21 @@
.core_clk_always_on_workaround = true,
};
-static struct msm_hsic_peripheral_platform_data msm_hsic_peripheral_pdata = {
+
+static struct ci13xxx_platform_data msm_peripheral_pdata = {
+ .usb_core_id = 0,
+};
+
+static struct msm_hsic_peripheral_platform_data
+ msm_hsic_peripheral_pdata_private = {
.core_clk_always_on_workaround = true,
};
+static struct ci13xxx_platform_data msm_hsic_peripheral_pdata = {
+ .usb_core_id = 1,
+ .prv_data = &msm_hsic_peripheral_pdata_private,
+};
+
#define PID_MAGIC_ID 0x71432909
#define SERIAL_NUM_MAGIC_ID 0x61945374
#define SERIAL_NUMBER_LENGTH 127
@@ -864,6 +876,7 @@
&msm_device_hsic_host,
&msm_device_usb_bam,
&msm_android_usb_device,
+ &msm_android_usb_hsic_device,
&msm9615_device_uart_gsbi4,
&msm9615_device_ext_2p95v_vreg,
&msm9615_device_ssbi_pmic1,
@@ -959,6 +972,8 @@
{
struct android_usb_platform_data *android_pdata =
msm_android_usb_device.dev.platform_data;
+ struct android_usb_platform_data *android_hsic_pdata =
+ msm_android_usb_hsic_device.dev.platform_data;
msm9615_device_init();
msm9615_init_gpiomux();
@@ -976,6 +991,8 @@
msm_device_otg.dev.platform_data = &msm_otg_pdata;
msm_otg_pdata.phy_init_seq = shelby_phy_init_seq;
+ msm_device_gadget_peripheral.dev.platform_data =
+ &msm_peripheral_pdata;
msm_device_hsic_peripheral.dev.platform_data =
&msm_hsic_peripheral_pdata;
msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
@@ -988,8 +1005,12 @@
msm9615_init_mmc();
slim_register_board_info(msm_slim_devices,
ARRAY_SIZE(msm_slim_devices));
+
android_pdata->update_pid_and_serial_num =
usb_diag_update_pid_and_serial_num;
+ android_hsic_pdata->update_pid_and_serial_num =
+ usb_diag_update_pid_and_serial_num;
+
msm_pm_boot_pdata.p_addr = allocate_contiguous_ebi_nomap(SZ_8, SZ_64K);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
msm_tsens_early_init(&msm_tsens_pdata);
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 3ab5ba0..57684f9 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -292,6 +292,14 @@
.gpio_conf = &gpio_conf_ov8825,
};
+static struct msm_actuator_info msm_act_main_cam_3_info = {
+ .board_info = &msm_act_main_cam_i2c_info,
+ .cam_name = MSM_ACTUATOR_MAIN_CAM_3,
+ .bus_id = MSM_GSBI0_QUP_I2C_BUS_ID,
+ .vcm_pwd = GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN,
+ .vcm_enable = 0,
+};
+
static struct msm_camera_sensor_info msm_camera_sensor_ov8825_data = {
.sensor_name = "ov8825",
.sensor_reset_enable = 1,
@@ -303,6 +311,8 @@
.sensor_platform_info = &sensor_board_info_ov8825,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
+ .actuator_info = &msm_act_main_cam_3_info,
};
#ifdef CONFIG_MT9E013
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 7fd07af..1b21c23 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -9788,6 +9788,7 @@
#else
.mem_hid = MEMTYPE_EBI1,
#endif
+ .mdp_iommu_split_domain = 0,
};
static void __init reserve_mdp_memory(void)
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index fc91232..f99e5de8 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5141,7 +5141,8 @@
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "qup_i2c.5"),
CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, ""),
CLK_LOOKUP("iface_clk", gsbi7_p_clk.c, "msm_serial_hsl.0"),
- CLK_LOOKUP("iface_clk", tsif_p_clk.c, ""),
+ CLK_LOOKUP("ref_clk", tsif_ref_clk.c, "msm_tspp.0"),
+ CLK_LOOKUP("iface_clk", tsif_p_clk.c, "msm_tspp.0"),
CLK_LOOKUP("iface_clk", usb_fs1_p_clk.c, ""),
CLK_LOOKUP("iface_clk", usb_hs1_p_clk.c, "msm_otg"),
CLK_LOOKUP("iface_clk", usb_hs3_p_clk.c, "msm_ehci_host.0"),
@@ -5450,7 +5451,6 @@
CLK_LOOKUP("core_clk", sdc4_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("core_clk", sdc5_clk.c, "msm_sdcc.5"),
CLK_LOOKUP("slimbus_xo_src_clk", slimbus_xo_src_clk.c, NULL),
- CLK_LOOKUP("ref_clk", tsif_ref_clk.c, ""),
CLK_LOOKUP("core_clk", tssc_clk.c, ""),
CLK_LOOKUP("alt_core_clk", usb_hs1_xcvr_clk.c, "msm_otg"),
CLK_LOOKUP("phy_clk", usb_phy0_clk.c, "msm_otg"),
@@ -5483,6 +5483,8 @@
CLK_LOOKUP("iface_clk", gsbi11_p_clk.c, ""),
CLK_LOOKUP("iface_clk", gsbi12_p_clk.c, "qup_i2c.12"),
CLK_LOOKUP("iface_clk", tsif_p_clk.c, ""),
+ CLK_LOOKUP("ref_clk", tsif_ref_clk.c, "msm_tspp.0"),
+ CLK_LOOKUP("iface_clk", tsif_p_clk.c, "msm_tspp.0"),
CLK_LOOKUP("iface_clk", usb_fs1_p_clk.c, ""),
CLK_LOOKUP("iface_clk", usb_fs2_p_clk.c, ""),
CLK_LOOKUP("iface_clk", usb_hs1_p_clk.c, "msm_otg"),
@@ -6115,7 +6117,7 @@
if (cpu_is_apq8064())
rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
- if (cpu_is_msm8930() || cpu_is_msm8627())
+ if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627())
rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
if (cpu_is_msm8627())
rmwreg(0x000003C7, SAXI_EN_REG, 0x00003FFF);
@@ -6151,7 +6153,8 @@
rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
}
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8627())
+ if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+ cpu_is_msm8627())
rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
if (cpu_is_msm8960()) {
@@ -6243,7 +6246,7 @@
* Program PLL15 to 900MHz with ref clk = 27MHz and
* only enable PLL main output.
*/
- if (cpu_is_msm8930() || cpu_is_msm8627()) {
+ if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
pll15_config.m = 0x1;
pll15_config.n = 0x3;
@@ -6257,7 +6260,7 @@
{
if (cpu_is_apq8064()) {
vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8064;
- } else if (cpu_is_msm8930() || cpu_is_msm8627()) {
+ } else if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
vdd_dig.set_vdd = set_vdd_dig_8930;
vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8930;
}
@@ -6287,7 +6290,7 @@
* Change the freq tables and voltage requirements for
* clocks which differ between 8960 and 8930.
*/
- if (cpu_is_msm8930() || cpu_is_msm8627()) {
+ if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930,
@@ -6332,7 +6335,8 @@
clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
}
clk_set_rate(&usb_fs1_src_clk.c, 60000000);
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8627())
+ if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+ cpu_is_msm8627())
clk_set_rate(&usb_fs2_src_clk.c, 60000000);
clk_set_rate(&usb_hsic_xcvr_fs_clk.c, 60000000);
clk_set_rate(&usb_hsic_hsic_src_clk.c, 480000000);
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 2660d5e..6c9a566 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -3775,6 +3775,18 @@
},
};
+static struct branch_clk oxilicx_axi_clk = {
+ .cbcr_reg = OXILICX_AXI_CBCR,
+ .parent = &axi_clk_src.c,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "oxilicx_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(oxilicx_axi_clk.c),
+ },
+};
+
static struct branch_clk oxili_gfx3d_clk = {
.cbcr_reg = OXILI_GFX3D_CBCR,
.has_sibling = 1,
@@ -3783,6 +3795,7 @@
.dbg_name = "oxili_gfx3d_clk",
.ops = &clk_ops_branch,
CLK_INIT(oxili_gfx3d_clk.c),
+ .depends = &oxilicx_axi_clk.c,
},
};
@@ -3797,18 +3810,6 @@
},
};
-static struct branch_clk oxilicx_axi_clk = {
- .cbcr_reg = OXILICX_AXI_CBCR,
- .parent = &axi_clk_src.c,
- .has_sibling = 1,
- .base = &virt_bases[MMSS_BASE],
- .c = {
- .dbg_name = "oxilicx_axi_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(oxilicx_axi_clk.c),
- },
-};
-
static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
F_LPASS(28800000, lpapll0, 1, 15, 256),
F_END
@@ -4744,12 +4745,19 @@
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "mdp.0"),
- CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, ""),
- CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, ""),
- CLK_LOOKUP("bus_clk", oxilicx_axi_clk.c, ""),
+ CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fdb00000.qcom,kgsl-3d0"),
+ CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb00000.qcom,kgsl-3d0"),
+ CLK_LOOKUP("core_clk", oxilicx_axi_clk.c, "fdb10000.qcom,iommu"),
+ CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb10000.qcom,iommu"),
CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdc84000.qcom,iommu"),
CLK_LOOKUP("core_clk", venus0_axi_clk.c, "fdc84000.qcom,iommu"),
CLK_LOOKUP("bus_clk", venus0_axi_clk.c, ""),
+ CLK_LOOKUP("src_clk", vcodec0_clk_src.c, "fdce0000.qcom,venus"),
+ CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fdce0000.qcom,venus"),
+ CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdce0000.qcom,venus"),
+ CLK_LOOKUP("bus_clk", venus0_axi_clk.c, "fdce0000.qcom,venus"),
+ CLK_LOOKUP("mem_clk", venus0_ocmemnoc_clk.c, "fdce0000.qcom,venus"),
+
/* LPASS clocks */
CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 614785e..069d738 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2596,15 +2596,15 @@
.name = "jpegd_dst",
.domain = CAMERA_DOMAIN,
},
- /* Rotator */
+ /* Rotator src*/
{
.name = "rot_src",
- .domain = ROTATOR_DOMAIN,
+ .domain = ROTATOR_SRC_DOMAIN,
},
- /* Rotator */
+ /* Rotator dst */
{
.name = "rot_dst",
- .domain = ROTATOR_DOMAIN,
+ .domain = ROTATOR_DST_DOMAIN,
},
/* Video */
{
@@ -2660,18 +2660,36 @@
},
};
-static struct mem_pool apq8064_display_pools[] = {
+static struct mem_pool apq8064_display_read_pools[] = {
[GEN_POOL] =
- /* One address space for display */
+ /* One address space for display reads */
{
.paddr = SZ_128K,
.size = SZ_2G - SZ_128K,
},
};
-static struct mem_pool apq8064_rotator_pools[] = {
+static struct mem_pool apq8064_display_write_pools[] = {
[GEN_POOL] =
- /* One address space for rotator */
+ /* One address space for display writes */
+ {
+ .paddr = SZ_128K,
+ .size = SZ_2G - SZ_128K,
+ },
+};
+
+static struct mem_pool apq8064_rotator_src_pools[] = {
+ [GEN_POOL] =
+ /* One address space for rotator src */
+ {
+ .paddr = SZ_128K,
+ .size = SZ_2G - SZ_128K,
+ },
+};
+
+static struct mem_pool apq8064_rotator_dst_pools[] = {
+ [GEN_POOL] =
+ /* One address space for rotator dst */
{
.paddr = SZ_128K,
.size = SZ_2G - SZ_128K,
@@ -2687,13 +2705,21 @@
.iova_pools = apq8064_camera_pools,
.npools = ARRAY_SIZE(apq8064_camera_pools),
},
- [DISPLAY_DOMAIN] = {
- .iova_pools = apq8064_display_pools,
- .npools = ARRAY_SIZE(apq8064_display_pools),
+ [DISPLAY_READ_DOMAIN] = {
+ .iova_pools = apq8064_display_read_pools,
+ .npools = ARRAY_SIZE(apq8064_display_read_pools),
},
- [ROTATOR_DOMAIN] = {
- .iova_pools = apq8064_rotator_pools,
- .npools = ARRAY_SIZE(apq8064_rotator_pools),
+ [DISPLAY_WRITE_DOMAIN] = {
+ .iova_pools = apq8064_display_write_pools,
+ .npools = ARRAY_SIZE(apq8064_display_write_pools),
+ },
+ [ROTATOR_SRC_DOMAIN] = {
+ .iova_pools = apq8064_rotator_src_pools,
+ .npools = ARRAY_SIZE(apq8064_rotator_src_pools),
+ },
+ [ROTATOR_DST_DOMAIN] = {
+ .iova_pools = apq8064_rotator_dst_pools,
+ .npools = ARRAY_SIZE(apq8064_rotator_dst_pools),
},
};
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 3212364..a36e7d7 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -767,12 +767,12 @@
/* Rotator */
{
.name = "rot_src",
- .domain = ROTATOR_DOMAIN,
+ .domain = ROTATOR_SRC_DOMAIN,
},
/* Rotator */
{
.name = "rot_dst",
- .domain = ROTATOR_DOMAIN,
+ .domain = ROTATOR_SRC_DOMAIN,
},
/* Video */
{
@@ -828,18 +828,18 @@
},
};
-static struct mem_pool msm8930_display_pools[] = {
+static struct mem_pool msm8930_display_read_pools[] = {
[GEN_POOL] =
- /* One address space for display */
+ /* One address space for display reads */
{
.paddr = SZ_128K,
.size = SZ_2G - SZ_128K,
},
};
-static struct mem_pool msm8930_rotator_pools[] = {
+static struct mem_pool msm8930_rotator_src_pools[] = {
[GEN_POOL] =
- /* One address space for rotator */
+ /* One address space for rotator src */
{
.paddr = SZ_128K,
.size = SZ_2G - SZ_128K,
@@ -855,13 +855,13 @@
.iova_pools = msm8930_camera_pools,
.npools = ARRAY_SIZE(msm8930_camera_pools),
},
- [DISPLAY_DOMAIN] = {
- .iova_pools = msm8930_display_pools,
- .npools = ARRAY_SIZE(msm8930_display_pools),
+ [DISPLAY_READ_DOMAIN] = {
+ .iova_pools = msm8930_display_read_pools,
+ .npools = ARRAY_SIZE(msm8930_display_read_pools),
},
- [ROTATOR_DOMAIN] = {
- .iova_pools = msm8930_rotator_pools,
- .npools = ARRAY_SIZE(msm8930_rotator_pools),
+ [ROTATOR_SRC_DOMAIN] = {
+ .iova_pools = msm8930_rotator_src_pools,
+ .npools = ARRAY_SIZE(msm8930_rotator_src_pools),
},
};
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 369e826..7d93fe7 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2291,6 +2291,11 @@
.platform_data = &rotator_pdata,
},
};
+
+void __init msm_rotator_set_split_iommu_domain(void)
+{
+ rotator_pdata.rot_iommu_split_domain = 1;
+}
#endif
#define MIPI_DSI_HW_BASE 0x04700000
@@ -3643,12 +3648,12 @@
/* Rotator */
{
.name = "rot_src",
- .domain = ROTATOR_DOMAIN,
+ .domain = ROTATOR_SRC_DOMAIN,
},
/* Rotator */
{
.name = "rot_dst",
- .domain = ROTATOR_DOMAIN,
+ .domain = ROTATOR_SRC_DOMAIN,
},
/* Video */
{
@@ -3704,18 +3709,18 @@
},
};
-static struct mem_pool msm8960_display_pools[] = {
+static struct mem_pool msm8960_display_read_pools[] = {
[GEN_POOL] =
- /* One address space for display */
+ /* One address space for display reads */
{
.paddr = SZ_128K,
.size = SZ_2G - SZ_128K,
},
};
-static struct mem_pool msm8960_rotator_pools[] = {
+static struct mem_pool msm8960_rotator_src_pools[] = {
[GEN_POOL] =
- /* One address space for rotator */
+ /* One address space for rotator src */
{
.paddr = SZ_128K,
.size = SZ_2G - SZ_128K,
@@ -3731,13 +3736,13 @@
.iova_pools = msm8960_camera_pools,
.npools = ARRAY_SIZE(msm8960_camera_pools),
},
- [DISPLAY_DOMAIN] = {
- .iova_pools = msm8960_display_pools,
- .npools = ARRAY_SIZE(msm8960_display_pools),
+ [DISPLAY_READ_DOMAIN] = {
+ .iova_pools = msm8960_display_read_pools,
+ .npools = ARRAY_SIZE(msm8960_display_read_pools),
},
- [ROTATOR_DOMAIN] = {
- .iova_pools = msm8960_rotator_pools,
- .npools = ARRAY_SIZE(msm8960_rotator_pools),
+ [ROTATOR_SRC_DOMAIN] = {
+ .iova_pools = msm8960_rotator_src_pools,
+ .npools = ARRAY_SIZE(msm8960_rotator_src_pools),
},
};
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 06d8653..9c2b26a 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1348,7 +1348,9 @@
return 0;
}
-struct android_usb_platform_data msm_android_usb_pdata;
+struct android_usb_platform_data msm_android_usb_pdata = {
+ .usb_core_id = 0,
+};
struct platform_device msm_android_usb_device = {
.name = "android_usb",
@@ -1358,6 +1360,19 @@
},
};
+struct android_usb_platform_data msm_android_usb_hsic_pdata = {
+ .usb_core_id = 1,
+};
+
+struct platform_device msm_android_usb_hsic_device = {
+ .name = "android_usb_hsic",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_android_usb_hsic_pdata,
+ },
+};
+
+
void __init msm9615_device_init(void)
{
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
@@ -1365,6 +1380,8 @@
BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
msm_android_usb_pdata.swfi_latency =
msm_rpmrs_levels[0].latency_us;
+ msm_android_usb_hsic_pdata.swfi_latency =
+ msm_rpmrs_levels[0].latency_us;
}
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 43c5f88..2ced412 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1561,7 +1561,7 @@
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &rotator_bus_scale_pdata,
#endif
-
+ .rot_iommu_split_domain = 0,
};
struct platform_device msm_rotator_device = {
@@ -3014,12 +3014,12 @@
/* Rotator */
{
.name = "rot_src",
- .domain = ROTATOR_DOMAIN,
+ .domain = ROTATOR_SRC_DOMAIN,
},
/* Rotator */
{
.name = "rot_dst",
- .domain = ROTATOR_DOMAIN,
+ .domain = ROTATOR_SRC_DOMAIN,
},
/* Video */
{
@@ -3102,11 +3102,11 @@
.iova_pools = msm8660_camera_pools,
.npools = ARRAY_SIZE(msm8660_camera_pools),
},
- [DISPLAY_DOMAIN] = {
+ [DISPLAY_READ_DOMAIN] = {
.iova_pools = msm8660_display_pools,
.npools = ARRAY_SIZE(msm8660_display_pools),
},
- [ROTATOR_DOMAIN] = {
+ [ROTATOR_SRC_DOMAIN] = {
.iova_pools = msm8660_rotator_pools,
.npools = ARRAY_SIZE(msm8660_rotator_pools),
},
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index e9911cf..045dfb9 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -27,6 +27,7 @@
void __init msm9615_init_irq(void);
void __init msm_rotator_update_bus_vectors(unsigned int xres,
unsigned int yres);
+void __init msm_rotator_set_split_iommu_domain(void);
extern struct platform_device asoc_msm_pcm;
extern struct platform_device asoc_msm_dai0;
@@ -113,6 +114,7 @@
extern struct platform_device msm_device_otg;
extern struct platform_device msm_android_usb_device;
+extern struct platform_device msm_android_usb_hsic_device;
extern struct platform_device msm_device_hsic_peripheral;
extern struct platform_device msm8960_device_otg;
extern struct platform_device msm8960_device_gadget_peripheral;
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index 4e488d7..e5dca00 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -74,7 +74,6 @@
};
static void msm_dmov_clock_work(struct work_struct *);
-static int msm_dmov_clk_toggle(int, int);
#ifdef CONFIG_ARCH_MSM8X60
@@ -232,40 +231,40 @@
#define PRINT_FLOW(format, args...) \
MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
-static int msm_dmov_clk_toggle(int adm, int on)
+static int msm_dmov_clk_on(int adm)
{
- int ret = 0;
+ int ret;
- if (on) {
- ret = clk_enable(dmov_conf[adm].clk);
- if (ret)
- goto err;
- if (dmov_conf[adm].pclk) {
- ret = clk_enable(dmov_conf[adm].pclk);
- if (ret) {
- clk_disable(dmov_conf[adm].clk);
- goto err;
- }
+ ret = clk_prepare_enable(dmov_conf[adm].clk);
+ if (ret)
+ return ret;
+ if (dmov_conf[adm].pclk) {
+ ret = clk_prepare_enable(dmov_conf[adm].pclk);
+ if (ret) {
+ clk_disable_unprepare(dmov_conf[adm].clk);
+ return ret;
}
- if (dmov_conf[adm].ebiclk) {
- ret = clk_enable(dmov_conf[adm].ebiclk);
- if (ret) {
- if (dmov_conf[adm].pclk)
- clk_disable(dmov_conf[adm].pclk);
- clk_disable(dmov_conf[adm].clk);
- }
- }
- } else {
- clk_disable(dmov_conf[adm].clk);
- if (dmov_conf[adm].pclk)
- clk_disable(dmov_conf[adm].pclk);
- if (dmov_conf[adm].ebiclk)
- clk_disable(dmov_conf[adm].ebiclk);
}
-err:
+ if (dmov_conf[adm].ebiclk) {
+ ret = clk_prepare_enable(dmov_conf[adm].ebiclk);
+ if (ret) {
+ if (dmov_conf[adm].pclk)
+ clk_disable_unprepare(dmov_conf[adm].pclk);
+ clk_disable_unprepare(dmov_conf[adm].clk);
+ }
+ }
return ret;
}
+static void msm_dmov_clk_off(int adm)
+{
+ if (dmov_conf[adm].ebiclk)
+ clk_disable_unprepare(dmov_conf[adm].ebiclk);
+ if (dmov_conf[adm].pclk)
+ clk_disable_unprepare(dmov_conf[adm].pclk);
+ clk_disable_unprepare(dmov_conf[adm].clk);
+}
+
static void msm_dmov_clock_work(struct work_struct *work)
{
struct msm_dmov_conf *conf =
@@ -274,7 +273,7 @@
mutex_lock(&conf->lock);
if (conf->clk_ctl == CLK_TO_BE_DIS) {
BUG_ON(conf->channel_active);
- msm_dmov_clk_toggle(adm, 0);
+ msm_dmov_clk_off(adm);
conf->clk_ctl = CLK_DIS;
}
mutex_unlock(&conf->lock);
@@ -321,7 +320,7 @@
mutex_lock(&dmov_conf[adm].lock);
if (dmov_conf[adm].clk_ctl == CLK_DIS) {
- status = msm_dmov_clk_toggle(adm, 1);
+ status = msm_dmov_clk_on(adm);
if (status != 0)
goto error;
}
@@ -588,7 +587,7 @@
mutex_lock(&dmov_conf[adm].lock);
if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
BUG_ON(dmov_conf[adm].channel_active);
- msm_dmov_clk_toggle(adm, 0);
+ msm_dmov_clk_off(adm);
dmov_conf[adm].clk_ctl = CLK_DIS;
}
mutex_unlock(&dmov_conf[adm].lock);
@@ -726,7 +725,7 @@
PRINT_ERROR("Requesting ADM%d clocks failed\n", adm);
goto out_irq;
}
- ret = msm_dmov_clk_toggle(adm, 1);
+ ret = msm_dmov_clk_on(adm);
if (ret) {
PRINT_ERROR("Enabling ADM%d clocks failed\n", adm);
goto out_irq;
@@ -743,7 +742,7 @@
DMOV_REG(DMOV_RSLT_CONF(i), adm));
}
wmb();
- msm_dmov_clk_toggle(adm, 0);
+ msm_dmov_clk_off(adm);
return ret;
out_irq:
free_irq(dmov_conf[adm].irq, NULL);
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 1aa3814..198cd38 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -401,6 +401,7 @@
u32 ov1_wb_size; /* overlay1 writeback size */
u32 mem_hid;
char cont_splash_enabled;
+ char mdp_iommu_split_domain;
};
@@ -466,6 +467,10 @@
int *gpio;
};
+struct msm_wfd_platform_data {
+ char (*wfd_check_mdp_iommu_split)(void);
+};
+
#define PANEL_NAME_MAX_LEN 50
struct msm_fb_platform_data {
int (*detect_client)(const char *name);
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index 1d32003..a0bcd2b 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -162,17 +162,24 @@
TLMM_HDRV_SDC3_CLK,
TLMM_HDRV_SDC3_CMD,
TLMM_HDRV_SDC3_DATA,
+ TLMM_HDRV_SDC2_CLK,
+ TLMM_HDRV_SDC2_CMD,
+ TLMM_HDRV_SDC2_DATA,
TLMM_HDRV_SDC1_CLK,
TLMM_HDRV_SDC1_CMD,
TLMM_HDRV_SDC1_DATA,
};
enum msm_tlmm_pull_tgt {
- TLMM_PULL_SDC4_CMD = 0,
+ TLMM_PULL_SDC4_CLK = 0,
+ TLMM_PULL_SDC4_CMD,
TLMM_PULL_SDC4_DATA,
TLMM_PULL_SDC3_CLK,
TLMM_PULL_SDC3_CMD,
TLMM_PULL_SDC3_DATA,
+ TLMM_PULL_SDC2_CLK,
+ TLMM_PULL_SDC2_CMD,
+ TLMM_PULL_SDC2_DATA,
TLMM_PULL_SDC1_CLK,
TLMM_PULL_SDC1_CMD,
TLMM_PULL_SDC1_DATA,
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index 1a3a022..1d538f2 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -18,8 +18,10 @@
enum {
VIDEO_DOMAIN,
CAMERA_DOMAIN,
- DISPLAY_DOMAIN,
- ROTATOR_DOMAIN,
+ DISPLAY_READ_DOMAIN,
+ DISPLAY_WRITE_DOMAIN,
+ ROTATOR_SRC_DOMAIN,
+ ROTATOR_DST_DOMAIN,
MAX_DOMAINS
};
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 6b4ce2a..15aebcd 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -73,6 +73,7 @@
MSM_CPU_7X25AB,
MSM_CPU_8064,
MSM_CPU_8930,
+ MSM_CPU_8930AA,
MSM_CPU_7X27AA,
MSM_CPU_9615,
MSM_CPU_8974,
@@ -262,6 +263,15 @@
#endif
}
+static inline int cpu_is_msm8930aa(void)
+{
+#ifdef CONFIG_ARCH_MSM8930
+ return read_msm_cpu_type() == MSM_CPU_8930AA;
+#else
+ return 0;
+#endif
+}
+
static inline int cpu_is_msm8627(void)
{
/* 8930 and 8627 will share the same CONFIG_ARCH type unless otherwise needed */
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index e92b5c5..42f0438 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -400,6 +400,9 @@
struct iommu_domains_pdata *p = pdev->dev.platform_data;
int i, j;
+ if (!msm_use_iommu())
+ return -ENODEV;
+
if (!p)
return -ENODEV;
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 1132be2..fd7b7b5 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -281,8 +281,8 @@
{
int ret;
- if (!cpu_is_msm8960() && !cpu_is_msm8930() && !cpu_is_msm9615() &&
- !cpu_is_msm8627())
+ if (!cpu_is_msm8960() && !cpu_is_msm8930() && !cpu_is_msm8930aa() &&
+ !cpu_is_msm9615() && !cpu_is_msm8627())
return -ENODEV;
ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index fb01427..9825ce5 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -234,8 +234,8 @@
struct msm_xo *xo = xo_voter->xo;
int is_d0 = xo == &msm_xo_sources[MSM_XO_TCXO_D0];
int needs_workaround = cpu_is_msm8960() || cpu_is_apq8064() ||
- cpu_is_msm8930() || cpu_is_msm9615() ||
- cpu_is_msm8627();
+ cpu_is_msm8930() || cpu_is_msm8930aa() ||
+ cpu_is_msm9615() || cpu_is_msm8627();
if (xo_voter->mode == mode)
return 0;
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
new file mode 100644
index 0000000..6a0aeaa
--- /dev/null
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -0,0 +1,464 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/page.h>
+#include <asm/sizes.h>
+
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+/* VENUS WRAPPER registers */
+#define VENUS_WRAPPER_CLOCK_CONFIG 0x4
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR 0x1018
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR 0x101C
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR 0x1020
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR 0x1024
+#define VENUS_WRAPPER_CPU_CLOCK_CONFIG 0x2000
+#define VENUS_WRAPPER_SW_RESET 0x3000
+
+/* VENUS VBIF registers */
+#define VENUS_VBIF_AXI_HALT_CTRL0 0x0
+#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ BIT(0)
+
+#define VENUS_VBIF_AXI_HALT_CTRL1 0x4
+#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0)
+#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US 500000
+
+/* PIL proxy vote timeout */
+#define VENUS_PROXY_TIMEOUT 10000
+
+/* Poll interval in uS */
+#define POLL_INTERVAL_US 50
+
+static const char * const clk_names[] = {
+ "core_clk",
+ "iface_clk",
+ "bus_clk",
+ "mem_clk",
+};
+
+struct venus_data {
+ void __iomem *venus_wrapper_base;
+ void __iomem *venus_vbif_base;
+ struct pil_device *pil;
+ struct regulator *gdsc;
+ phys_addr_t start_addr;
+ struct clk *clks[ARRAY_SIZE(clk_names)];
+ struct device *iommu_fw_ctx;
+ struct iommu_domain *iommu_fw_domain;
+ int venus_domain_num;
+ bool is_booted;
+ u32 fw_sz;
+ u32 fw_min_paddr;
+ u32 fw_max_paddr;
+};
+
+static int venus_register_domain(u32 fw_max_sz)
+{
+ struct msm_iova_partition venus_fw_partition = {
+ .start = 0,
+ .size = fw_max_sz,
+ };
+ struct msm_iova_layout venus_fw_layout = {
+ .partitions = &venus_fw_partition,
+ .npartitions = 1,
+ .client_name = "pil_venus",
+ .domain_flags = 0,
+ };
+
+ return msm_register_domain(&venus_fw_layout);
+}
+
+/* Get venus clocks and set rates for rate-settable clocks */
+static int venus_clock_setup(struct device *dev)
+{
+ struct venus_data *drv = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(drv->clks); i++) {
+ drv->clks[i] = devm_clk_get(dev, clk_names[i]);
+ if (IS_ERR(drv->clks[i])) {
+ dev_err(dev, "failed to get %s\n",
+ clk_names[i]);
+ return PTR_ERR(drv->clks[i]);
+ }
+ /* Make sure rate-settable clocks' rates are set */
+ if (clk_get_rate(drv->clks[i]) == 0)
+ clk_set_rate(drv->clks[i],
+ clk_round_rate(drv->clks[i], 0));
+ }
+
+ return 0;
+}
+
+static int venus_clock_prepare_enable(struct device *dev)
+{
+ struct venus_data *drv = dev_get_drvdata(dev);
+ int rc, i;
+
+ for (i = 0; i < ARRAY_SIZE(drv->clks); i++) {
+ rc = clk_prepare_enable(drv->clks[i]);
+ if (rc) {
+ dev_err(dev, "failed to enable %s\n",
+ clk_names[i]);
+ for (i--; i >= 0; i--)
+ clk_disable_unprepare(drv->clks[i]);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static void venus_clock_disable_unprepare(struct device *dev)
+{
+ struct venus_data *drv = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(drv->clks); i++)
+ clk_disable_unprepare(drv->clks[i]);
+}
+
+static int pil_venus_make_proxy_vote(struct pil_desc *pil)
+{
+ struct venus_data *drv = dev_get_drvdata(pil->dev);
+ int rc;
+
+ /*
+ * Clocks need to be proxy voted to be able to pass control
+ * of clocks from PIL driver to the Venus driver. But GDSC
+ * needs to be turned on before clocks can be turned on. So
+ * enable the GDSC here.
+ */
+ rc = regulator_enable(drv->gdsc);
+ if (rc) {
+ dev_err(pil->dev, "GDSC enable failed\n");
+ return rc;
+ }
+
+ rc = venus_clock_prepare_enable(pil->dev);
+ if (rc)
+ regulator_disable(drv->gdsc);
+
+ return rc;
+}
+
+static void pil_venus_remove_proxy_vote(struct pil_desc *pil)
+{
+ struct venus_data *drv = dev_get_drvdata(pil->dev);
+
+ venus_clock_disable_unprepare(pil->dev);
+
+ /* Disable GDSC */
+ regulator_disable(drv->gdsc);
+}
+
+static int pil_venus_init_image(struct pil_desc *pil, const u8 *metadata,
+ size_t size)
+{
+ const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+ struct venus_data *drv = dev_get_drvdata(pil->dev);
+
+ drv->start_addr = ehdr->e_entry;
+
+ if (drv->start_addr < drv->fw_min_paddr ||
+ drv->start_addr >= drv->fw_max_paddr) {
+ dev_err(pil->dev, "fw start addr is not within valid range\n");
+ return -EINVAL;
+ }
+
+ drv->fw_sz = drv->fw_max_paddr - drv->start_addr;
+
+ return 0;
+}
+
+static int pil_venus_reset(struct pil_desc *pil)
+{
+ int rc;
+ struct venus_data *drv = dev_get_drvdata(pil->dev);
+ void __iomem *wrapper_base = drv->venus_wrapper_base;
+ phys_addr_t pa = drv->start_addr;
+ unsigned long iova;
+
+ /*
+ * GDSC needs to remain on till Venus is shutdown. So, enable
+ * the GDSC here again to make sure it remains on beyond the
+ * expiry of the proxy vote timer.
+ */
+ rc = regulator_enable(drv->gdsc);
+ if (rc) {
+ dev_err(pil->dev, "GDSC enable failed\n");
+ return rc;
+ }
+
+ /* Program CPA start and end address */
+ writel_relaxed(0, wrapper_base +
+ VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR);
+ writel_relaxed(drv->fw_sz, wrapper_base +
+ VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR);
+
+ /* Program FW start and end address */
+ writel_relaxed(0, wrapper_base +
+ VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR);
+ writel_relaxed(drv->fw_sz, wrapper_base +
+ VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR);
+
+ rc = iommu_attach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
+ if (rc) {
+ dev_err(pil->dev, "venus fw iommu attach failed\n");
+ goto err_iommu_attach;
+ }
+
+ /* Enable all Venus internal clocks */
+ writel_relaxed(0, wrapper_base + VENUS_WRAPPER_CLOCK_CONFIG);
+ writel_relaxed(0, wrapper_base + VENUS_WRAPPER_CPU_CLOCK_CONFIG);
+
+ /* Make sure clocks are enabled */
+ mb();
+
+ /*
+ * Need to wait 10 cycles of internal clocks before bringing ARM9
+ * out of reset.
+ */
+ udelay(1);
+
+ /* Map virtual addr space 0 - fw_sz to firmware physical addr space */
+ rc = msm_iommu_map_contig_buffer(pa, drv->venus_domain_num, 0,
+ drv->fw_sz, SZ_4K, 0, &iova);
+
+ if (rc || (iova != 0)) {
+ dev_err(pil->dev, "Failed to setup IOMMU\n");
+ goto err_iommu_map;
+ }
+
+ /* Bring Arm9 out of reset */
+ writel_relaxed(0, wrapper_base + VENUS_WRAPPER_SW_RESET);
+
+ drv->is_booted = 1;
+
+ return 0;
+
+err_iommu_map:
+ iommu_detach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
+
+err_iommu_attach:
+ regulator_disable(drv->gdsc);
+
+ return rc;
+}
+
+static int pil_venus_shutdown(struct pil_desc *pil)
+{
+ struct venus_data *drv = dev_get_drvdata(pil->dev);
+ void __iomem *vbif_base = drv->venus_vbif_base;
+ void __iomem *wrapper_base = drv->venus_wrapper_base;
+ u32 reg;
+ int rc;
+
+ if (!drv->is_booted)
+ return 0;
+
+ venus_clock_prepare_enable(pil->dev);
+
+ /* Halt AXI and AXI OCMEM VBIF Access */
+ reg = readl_relaxed(vbif_base + VENUS_VBIF_AXI_HALT_CTRL0);
+ reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+ writel_relaxed(reg, vbif_base + VENUS_VBIF_AXI_HALT_CTRL0);
+
+ /* Request for AXI bus port halt */
+ rc = readl_poll_timeout(vbif_base + VENUS_VBIF_AXI_HALT_CTRL1,
+ reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+ POLL_INTERVAL_US,
+ VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+ if (rc)
+ dev_err(pil->dev, "Port halt timeout\n");
+
+ /* Assert the reset to ARM9 */
+ reg = readl_relaxed(wrapper_base + VENUS_WRAPPER_SW_RESET);
+ reg |= BIT(4);
+ writel_relaxed(reg, wrapper_base + VENUS_WRAPPER_SW_RESET);
+
+ /* Make sure reset is asserted before the mapping is removed */
+ mb();
+
+ msm_iommu_unmap_contig_buffer(0, drv->venus_domain_num,
+ 0, drv->fw_sz);
+
+ iommu_detach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
+
+ venus_clock_disable_unprepare(pil->dev);
+
+ regulator_disable(drv->gdsc);
+
+ drv->is_booted = 0;
+
+ return 0;
+}
+
+static struct pil_reset_ops pil_venus_ops = {
+ .init_image = pil_venus_init_image,
+ .auth_and_reset = pil_venus_reset,
+ .shutdown = pil_venus_shutdown,
+ .proxy_vote = pil_venus_make_proxy_vote,
+ .proxy_unvote = pil_venus_remove_proxy_vote,
+};
+
+static int __devinit pil_venus_probe(struct platform_device *pdev)
+{
+ struct venus_data *drv;
+ struct resource *res;
+ struct pil_desc *desc;
+ int rc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+
+ drv->venus_wrapper_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->venus_wrapper_base)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return -EINVAL;
+
+ drv->venus_vbif_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->venus_vbif_base)
+ return -ENOMEM;
+
+ drv->gdsc = devm_regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(drv->gdsc)) {
+ dev_err(&pdev->dev, "Failed to get Venus GDSC\n");
+ return -ENODEV;
+ }
+
+ rc = venus_clock_setup(&pdev->dev);
+ if (rc)
+ return rc;
+
+ drv->iommu_fw_ctx = msm_iommu_get_ctx("venus_fw");
+ if (!drv->iommu_fw_ctx) {
+ dev_err(&pdev->dev, "No iommu fw context found\n");
+ return -ENODEV;
+ }
+
+ /* Get fw address boundaries */
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,firmware-max-paddr",
+ &drv->fw_max_paddr);
+ if (rc) {
+ dev_err(&pdev->dev, "Failed to get fw max paddr\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,firmware-min-paddr",
+ &drv->fw_min_paddr);
+ if (rc) {
+ dev_err(&pdev->dev, "Failed to get fw min paddr\n");
+ return rc;
+ }
+
+ if (drv->fw_max_paddr <= drv->fw_min_paddr) {
+ dev_err(&pdev->dev, "Invalid fw max paddr or min paddr\n");
+ return -EINVAL;
+ }
+
+ drv->venus_domain_num =
+ venus_register_domain(drv->fw_max_paddr - drv->fw_min_paddr);
+ if (drv->venus_domain_num < 0) {
+ dev_err(&pdev->dev, "Venus fw iommu domain register failed\n");
+ return -ENODEV;
+ }
+
+ drv->iommu_fw_domain = msm_get_iommu_domain(drv->venus_domain_num);
+ if (!drv->iommu_fw_domain) {
+ dev_err(&pdev->dev, "No iommu fw domain found\n");
+ return -ENODEV;
+ }
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+ &desc->name);
+ if (rc)
+ return rc;
+
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ desc->proxy_timeout = VENUS_PROXY_TIMEOUT;
+
+ /* TODO: need to add secure boot when the support is available */
+ desc->ops = &pil_venus_ops;
+ dev_info(&pdev->dev, "using non-secure boot\n");
+
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+
+ return 0;
+}
+
+static int __devexit pil_venus_remove(struct platform_device *pdev)
+{
+ struct venus_data *drv = platform_get_drvdata(pdev);
+ msm_pil_unregister(drv->pil);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id msm_pil_venus_match[] = {
+ {.compatible = "qcom,pil-venus"},
+ {}
+};
+#endif
+
+static struct platform_driver pil_venus_driver = {
+ .probe = pil_venus_probe,
+ .remove = __devexit_p(pil_venus_remove),
+ .driver = {
+ .name = "pil_venus",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(msm_pil_venus_match),
+ },
+};
+
+module_platform_driver(pil_venus_driver);
+
+MODULE_DESCRIPTION("Support for booting VENUS processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 428b998..48a236f 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -142,8 +142,8 @@
if (machine_is_msm8974_sim())
return krait_release_secondary_sim(0xf9088000, cpu);
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064() ||
- cpu_is_msm8627())
+ if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+ cpu_is_apq8064() || cpu_is_msm8627())
return krait_release_secondary(0x02088000, cpu);
WARN(1, "unknown CPU case in release_secondary\n");
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index b485058..eee7e37 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -1262,7 +1262,7 @@
clk_set_rate(mod->clk, adsp_info.module[i].clk_rate);
mod->verify_cmd = adsp_info.module[i].verify_cmd;
mod->patch_event = adsp_info.module[i].patch_event;
- INIT_HLIST_HEAD(&mod->pmem_regions);
+ INIT_HLIST_HEAD(&mod->ion_regions);
mod->pdev.name = adsp_info.module[i].pdev_name;
mod->pdev.id = -1;
adsp_info.id_to_module[i] = mod;
diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h
index 0f16111..06e2f22 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.h
+++ b/arch/arm/mach-msm/qdsp5/adsp.h
@@ -20,12 +20,16 @@
#include <linux/types.h>
#include <linux/msm_adsp.h>
+#include <linux/ion.h>
#include <mach/msm_rpcrouter.h>
#include <mach/msm_adsp.h>
int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr,
unsigned long len);
-int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
+int adsp_ion_do_cache_op(struct msm_adsp_module *module, void *addr,
+ void *paddr, unsigned long len,
+ unsigned long offset, int cmd);
+int adsp_ion_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
unsigned long *kvaddr, unsigned long len,
struct file **filp, unsigned long *offset);
int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr);
@@ -276,8 +280,8 @@
struct clk *clk;
int open_count;
- struct mutex pmem_regions_lock;
- struct hlist_head pmem_regions;
+ struct mutex ion_regions_lock;
+ struct hlist_head ion_regions;
int (*verify_cmd) (struct msm_adsp_module*, unsigned int, void *,
size_t);
int (*patch_event) (struct msm_adsp_module*, struct adsp_event *);
diff --git a/arch/arm/mach-msm/qdsp5/adsp_driver.c b/arch/arm/mach-msm/qdsp5/adsp_driver.c
index 6860d84..9d261ae 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_driver.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_driver.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/qdsp5/adsp_driver.c
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2012 Code Aurora Forum. All rights reserved.
* Author: Iliyan Malchev <ibm@android.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -23,25 +23,27 @@
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/module.h>
-
#include "adsp.h"
-
#include <linux/msm_adsp.h>
#include <linux/android_pmem.h>
#include <mach/debug_mm.h>
-struct adsp_pmem_info {
+struct adsp_ion_info {
int fd;
void *vaddr;
};
-struct adsp_pmem_region {
+struct adsp_ion_region {
struct hlist_node list;
void *vaddr;
unsigned long paddr;
unsigned long kvaddr;
unsigned long len;
+ unsigned long ion_flag;
struct file *file;
+ struct ion_handle *handle;
+ struct ion_client *client;
+ int fd;
};
struct adsp_device {
@@ -90,14 +92,14 @@
res; \
})
-static int adsp_pmem_check(struct msm_adsp_module *module,
+static int adsp_ion_check(struct msm_adsp_module *module,
void *vaddr, unsigned long len)
{
- struct adsp_pmem_region *region_elt;
+ struct adsp_ion_region *region_elt;
struct hlist_node *node;
- struct adsp_pmem_region t = { .vaddr = vaddr, .len = len };
+ struct adsp_ion_region t = { .vaddr = vaddr, .len = len };
- hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+ hlist_for_each_entry(region_elt, node, &module->ion_regions, list) {
if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
OVERLAPS(region_elt, &t)) {
MM_ERR("module %s:"
@@ -116,58 +118,109 @@
return 0;
}
-static int adsp_pmem_add(struct msm_adsp_module *module,
- struct adsp_pmem_info *info)
+static int get_ion_region_info(int fd, struct adsp_ion_region *region)
{
- unsigned long paddr, kvaddr, len;
- struct file *file;
- struct adsp_pmem_region *region;
+ unsigned long ionflag;
+ void *temp_ptr;
int rc = -EINVAL;
- mutex_lock(&module->pmem_regions_lock);
- region = kmalloc(sizeof(*region), GFP_KERNEL);
+ region->client = msm_ion_client_create(UINT_MAX, "Video_Client");
+ if (IS_ERR_OR_NULL(region->client)) {
+ pr_err("Unable to create ION client\n");
+ goto client_error;
+ }
+ region->handle = ion_import_dma_buf(region->client, fd);
+ if (IS_ERR_OR_NULL(region->handle)) {
+ pr_err("%s: could not get handle of the given fd\n", __func__);
+ goto import_error;
+ }
+ rc = ion_handle_get_flags(region->client, region->handle, &ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n", __func__);
+ goto flag_error;
+ }
+ temp_ptr = ion_map_kernel(region->client, region->handle, ionflag);
+ if (IS_ERR_OR_NULL(temp_ptr)) {
+ pr_err("%s: could not get virtual address\n", __func__);
+ goto map_error;
+ }
+ region->kvaddr = (unsigned long) temp_ptr;
+ region->ion_flag = (unsigned long) ionflag;
+
+ rc = ion_phys(region->client, region->handle, ®ion->paddr,
+ (size_t *)(®ion->len));
+ if (rc) {
+ pr_err("%s: could not get physical address\n", __func__);
+ goto ion_error;
+ }
+ return rc;
+ion_error:
+ ion_unmap_kernel(region->client, region->handle);
+map_error:
+ ion_free(region->client, region->handle);
+flag_error:
+import_error:
+ ion_client_destroy(region->client);
+client_error:
+ return -EINVAL;
+}
+
+static void free_ion_region(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ ion_unmap_kernel(client, handle);
+ ion_free(client, handle);
+ ion_client_destroy(client);
+}
+
+static int adsp_ion_add(struct msm_adsp_module *module,
+ struct adsp_ion_info *info)
+{
+ struct adsp_ion_region *region;
+ int rc = -EINVAL;
+ mutex_lock(&module->ion_regions_lock);
+ region = kmalloc(sizeof(struct adsp_ion_region), GFP_KERNEL);
if (!region) {
rc = -ENOMEM;
goto end;
}
INIT_HLIST_NODE(®ion->list);
- if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+ if (get_ion_region_info(info->fd, region)) {
kfree(region);
goto end;
}
- rc = adsp_pmem_check(module, info->vaddr, len);
+ rc = adsp_ion_check(module, info->vaddr, region->len);
if (rc < 0) {
- put_pmem_file(file);
+ free_ion_region(region->client, region->handle);
kfree(region);
goto end;
}
-
region->vaddr = info->vaddr;
- region->paddr = paddr;
- region->kvaddr = kvaddr;
- region->len = len;
- region->file = file;
-
- hlist_add_head(®ion->list, &module->pmem_regions);
+ region->fd = info->fd;
+ region->file = NULL;
+ MM_INFO("adsp_ion_add: module %s: fd %d, vaddr Ox%x, len %d\n",
+ module->name, region->fd, (unsigned int)region->vaddr,
+ (int)region->len);
+ hlist_add_head(®ion->list, &module->ion_regions);
end:
- mutex_unlock(&module->pmem_regions_lock);
+ mutex_unlock(&module->ion_regions_lock);
return rc;
}
-static int adsp_pmem_lookup_vaddr(struct msm_adsp_module *module, void **addr,
- unsigned long len, struct adsp_pmem_region **region)
+static int adsp_ion_lookup_vaddr(struct msm_adsp_module *module, void **addr,
+ unsigned long len, struct adsp_ion_region **region)
{
struct hlist_node *node;
void *vaddr = *addr;
- struct adsp_pmem_region *region_elt;
+ struct adsp_ion_region *region_elt;
int match_count = 0;
*region = NULL;
/* returns physical address or zero */
- hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+ hlist_for_each_entry(region_elt, node, &module->ion_regions, list) {
if (vaddr >= region_elt->vaddr &&
vaddr < region_elt->vaddr + region_elt->len &&
vaddr + len <= region_elt->vaddr + region_elt->len) {
@@ -186,7 +239,7 @@
"multiple hits for vaddr %p, len %ld\n",
module->name, vaddr, len);
hlist_for_each_entry(region_elt, node,
- &module->pmem_regions, list) {
+ &module->ion_regions, list) {
if (vaddr >= region_elt->vaddr &&
vaddr < region_elt->vaddr + region_elt->len &&
vaddr + len <= region_elt->vaddr + region_elt->len)
@@ -200,16 +253,37 @@
return *region ? 0 : -1;
}
-int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
+int adsp_ion_do_cache_op(struct msm_adsp_module *module,
+ void *addr, void *paddr, unsigned long len,
+ unsigned long offset, int cmd)
+{
+ struct adsp_ion_region *region;
+ void *vaddr = addr;
+ int ret;
+ ret = adsp_ion_lookup_vaddr(module, &vaddr, len, ®ion);
+ if (ret) {
+ MM_ERR("not patching %s (paddr & kvaddr)," \
+ " lookup (%p, %ld) failed\n",
+ module->name, vaddr, len);
+ return ret;
+ }
+ if ((region->ion_flag == CACHED) && region->handle) {
+ len = ((((len) + 31) & (~31)) + 32);
+ ret = msm_ion_do_cache_op(region->client, region->handle,
+ (void *)paddr, len, cmd);
+ }
+ return ret;
+}
+int adsp_ion_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
unsigned long *kvaddr, unsigned long len,
struct file **filp, unsigned long *offset)
{
- struct adsp_pmem_region *region;
+ struct adsp_ion_region *region;
void *vaddr = *addr;
unsigned long *paddr = (unsigned long *)addr;
int ret;
- ret = adsp_pmem_lookup_vaddr(module, addr, len, ®ion);
+ ret = adsp_ion_lookup_vaddr(module, addr, len, ®ion);
if (ret) {
MM_ERR("not patching %s (paddr & kvaddr),"
" lookup (%p, %ld) failed\n",
@@ -228,12 +302,12 @@
int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr,
unsigned long len)
{
- struct adsp_pmem_region *region;
+ struct adsp_ion_region *region;
void *vaddr = *addr;
unsigned long *paddr = (unsigned long *)addr;
int ret;
- ret = adsp_pmem_lookup_vaddr(module, addr, len, ®ion);
+ ret = adsp_ion_lookup_vaddr(module, addr, len, ®ion);
if (ret) {
MM_ERR("not patching %s, lookup (%p, %ld) failed\n",
module->name, vaddr, len);
@@ -281,7 +355,7 @@
goto end;
}
- mutex_lock(&adev->module->pmem_regions_lock);
+ mutex_lock(&adev->module->ion_regions_lock);
if (adsp_verify_cmd(adev->module, cmd.queue, cmd_data, cmd.len)) {
MM_ERR("module %s: verify failed.\n", adev->module->name);
rc = -EINVAL;
@@ -291,7 +365,7 @@
wmb();
rc = msm_adsp_write(adev->module, cmd.queue, cmd_data, cmd.len);
end:
- mutex_unlock(&adev->module->pmem_regions_lock);
+ mutex_unlock(&adev->module->ion_regions_lock);
if (cmd.len > 256)
kfree(cmd_data);
@@ -309,14 +383,14 @@
return yes || adev->abort;
}
-static int adsp_pmem_lookup_paddr(struct msm_adsp_module *module, void **addr,
- struct adsp_pmem_region **region)
+static int adsp_ion_lookup_paddr(struct msm_adsp_module *module, void **addr,
+ struct adsp_ion_region **region)
{
struct hlist_node *node;
unsigned long paddr = (unsigned long)(*addr);
- struct adsp_pmem_region *region_elt;
+ struct adsp_ion_region *region_elt;
- hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+ hlist_for_each_entry(region_elt, node, &module->ion_regions, list) {
if (paddr >= region_elt->paddr &&
paddr < region_elt->paddr + region_elt->len) {
*region = region_elt;
@@ -328,12 +402,12 @@
int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr)
{
- struct adsp_pmem_region *region;
+ struct adsp_ion_region *region;
unsigned long paddr = (unsigned long)(*addr);
unsigned long *vaddr = (unsigned long *)addr;
int ret;
- ret = adsp_pmem_lookup_paddr(module, addr, ®ion);
+ ret = adsp_ion_lookup_paddr(module, addr, ®ion);
if (ret) {
MM_ERR("not patching %s, paddr %p lookup failed\n",
module->name, vaddr);
@@ -429,20 +503,23 @@
return rc;
}
-static int adsp_pmem_del(struct msm_adsp_module *module)
+static int adsp_ion_del(struct msm_adsp_module *module)
{
struct hlist_node *node, *tmp;
- struct adsp_pmem_region *region;
+ struct adsp_ion_region *region;
- mutex_lock(&module->pmem_regions_lock);
- hlist_for_each_safe(node, tmp, &module->pmem_regions) {
- region = hlist_entry(node, struct adsp_pmem_region, list);
+ mutex_lock(&module->ion_regions_lock);
+ hlist_for_each_safe(node, tmp, &module->ion_regions) {
+ region = hlist_entry(node, struct adsp_ion_region, list);
hlist_del(node);
- put_pmem_file(region->file);
+ MM_INFO("adsp_ion_del: module %s: fd %d, vaddr Ox%x, len %d\n",
+ module->name, region->fd, (unsigned int)region->vaddr,
+ (int)region->len);
+ free_ion_region(region->client, region->handle);
kfree(region);
}
- mutex_unlock(&module->pmem_regions_lock);
- BUG_ON(!hlist_empty(&module->pmem_regions));
+ mutex_unlock(&module->ion_regions_lock);
+ BUG_ON(!hlist_empty(&module->ion_regions));
return 0;
}
@@ -479,10 +556,10 @@
}
case ADSP_IOCTL_REGISTER_PMEM: {
- struct adsp_pmem_info info;
+ struct adsp_ion_info info;
if (copy_from_user(&info, (void *) arg, sizeof(info)))
return -EFAULT;
- return adsp_pmem_add(adev->module, &info);
+ return adsp_ion_add(adev->module, &info);
}
case ADSP_IOCTL_ABORT_EVENT_READ:
@@ -491,7 +568,7 @@
break;
case ADSP_IOCTL_UNREGISTER_PMEM:
- return adsp_pmem_del(adev->module);
+ return adsp_ion_del(adev->module);
default:
break;
@@ -510,7 +587,7 @@
/* clear module before putting it to avoid race with open() */
adev->module = NULL;
- rc = adsp_pmem_del(module);
+ rc = adsp_ion_del(module);
msm_adsp_put(module);
return rc;
@@ -581,8 +658,8 @@
MM_INFO("opened module '%s' adev %p\n", adev->name, adev);
filp->private_data = adev;
adev->abort = 0;
- INIT_HLIST_HEAD(&adev->module->pmem_regions);
- mutex_init(&adev->module->pmem_regions_lock);
+ INIT_HLIST_HEAD(&adev->module->ion_regions);
+ mutex_init(&adev->module->ion_regions_lock);
return 0;
}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
index 492fa0e..af259b5 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
@@ -3,7 +3,7 @@
* Verificion code for aDSP VDEC packets from userspace.
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2010, 2012 Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -55,7 +55,7 @@
MM_DBG("virt %x %x\n", (unsigned int)phys_addr,
(unsigned int)phys_size);
if (phys_addr) {
- if (adsp_pmem_fixup_kvaddr(module, &phys_addr,
+ if (adsp_ion_fixup_kvaddr(module, &phys_addr,
&kvaddr, phys_size, filp, offset)) {
MM_ERR("ah%x al%x sh%x sl%x addr %x size %x\n",
*high, *low, size_high,
@@ -77,6 +77,7 @@
static int verify_vdec_pkt_cmd(struct msm_adsp_module *module,
void *cmd_data, size_t cmd_size)
{
+ void *phys_addr;
unsigned short cmd_id = ((unsigned short *)cmd_data)[0];
viddec_cmd_subframe_pkt *pkt;
unsigned long subframe_pkt_addr;
@@ -89,7 +90,6 @@
unsigned short frame_buffer_size_high, frame_buffer_size_low;
struct file *filp = NULL;
unsigned long offset = 0;
- struct pmem_addr pmem_addr;
unsigned long Codec_Id = 0;
MM_DBG("cmd_size %d cmd_id %d cmd_data %x\n", cmd_size, cmd_id,
@@ -102,6 +102,8 @@
return -1;
pkt = (viddec_cmd_subframe_pkt *)cmd_data;
+ phys_addr = high_low_short_to_ptr(pkt->subframe_packet_high,
+ pkt->subframe_packet_low);
if (pmem_fixup_high_low(&(pkt->subframe_packet_high),
&(pkt->subframe_packet_low),
@@ -114,16 +116,12 @@
return -1;
Codec_Id = pkt->codec_selection_word;
/*Invalidate cache before accessing the cached pmem buffer*/
- if (filp) {
- pmem_addr.vaddr = subframe_pkt_addr;
- pmem_addr.length = (((subframe_pkt_size*2) + 31) & (~31)) + 32;
- pmem_addr.offset = offset;
- if (pmem_cache_maint (filp, PMEM_INV_CACHES, &pmem_addr)) {
- MM_ERR("Cache operation failed for phys addr high %x"
- " addr low %x\n", pkt->subframe_packet_high,
- pkt->subframe_packet_low);
- return -EINVAL;
- }
+ if (adsp_ion_do_cache_op(module, phys_addr, (void *)subframe_pkt_addr,
+ subframe_pkt_size*2, offset, ION_IOC_INV_CACHES)){
+ MM_ERR("Cache operation failed for" \
+ " phys addr high %x addr low %x\n",
+ pkt->subframe_packet_high, pkt->subframe_packet_low);
+ return -EINVAL;
}
/* deref those ptrs and check if they are a frame header packet */
frame_header_pkt = (unsigned short *)subframe_pkt_addr;
@@ -241,19 +239,14 @@
frame_buffer_low += 2;
}
}
- /*Flush the cached pmem subframe packet before sending to DSP*/
- if (filp) {
- pmem_addr.vaddr = subframe_pkt_addr;
- pmem_addr.length = MAX_FLUSH_SIZE;
- pmem_addr.offset = offset;
- if (pmem_cache_maint(filp, PMEM_CLEAN_CACHES, &pmem_addr)) {
- MM_ERR("Cache operation failed for phys addr high %x"
- " addr low %x\n", pkt->subframe_packet_high,
- pkt->subframe_packet_low);
- return -1;
- }
+ /*Flush the cached mem subframe packet before sending to DSP*/
+ if (adsp_ion_do_cache_op(module, phys_addr, (void *)subframe_pkt_addr,
+ MAX_FLUSH_SIZE, offset, ION_IOC_CLEAN_CACHES)){
+ MM_ERR("Cache operation failed for" \
+ " phys addr high %x addr low %x\n",
+ pkt->subframe_packet_high, pkt->subframe_packet_low);
+ return -EINVAL;
}
-
return 0;
}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c
index 936b7af..290a14c 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c
@@ -3,7 +3,7 @@
* Verificion code for aDSP VENC packets from userspace.
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2012 Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -53,7 +53,7 @@
phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low);
MM_DBG("virt %x %x\n", (unsigned int)phys_addr,
(unsigned int)phys_size);
- if (adsp_pmem_fixup_kvaddr(module, &phys_addr, &kvaddr, phys_size,
+ if (adsp_ion_fixup_kvaddr(module, &phys_addr, &kvaddr, phys_size,
NULL, NULL)) {
MM_ERR("ah%x al%x sh%x sl%x addr %x size %x\n",
*high, *low, size_high,
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index 725819f..15e0590 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -31,10 +31,10 @@
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/earlysuspend.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
#include <linux/msm_audio_aac.h>
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
@@ -181,6 +181,9 @@
int eq_needs_commit;
audpp_cmd_cfg_object_params_eqalizer eq;
audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
static int auddec_dsp_config(struct audio *audio, int enable);
@@ -1508,10 +1511,11 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audaac_reset_event_queue(audio);
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->read_phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
@@ -1653,8 +1657,13 @@
{
struct audio *audio = NULL;
int rc, dec_attrb, decid, index, offset = 0;
- unsigned pmem_sz = DMASZ;
+ unsigned mem_sz = DMASZ;
struct audaac_event *e_node = NULL;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_aac_" + 5];
@@ -1696,61 +1705,92 @@
}
audio->dec_id = decid & MSM_AUD_DECODER_MASK;
- while (pmem_sz >= DMASZ_MIN) {
- MM_DBG("pmemsz = %d\n", pmem_sz);
- audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
- if (audio->phys) {
- audio->map_v_write = ioremap(audio->phys, pmem_sz);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write buffers, \
- freeing instance 0x%08x\n",
- (int)audio);
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- }
- audio->data = audio->map_v_write;
- MM_DBG("write buf: phy addr 0x%08x kernel addr \
- 0x%08x\n", audio->phys, (int)audio->data);
- break;
- } else if (pmem_sz == DMASZ_MIN) {
- MM_ERR("could not allocate write buffers, freeing \
- instance 0x%08x\n", (int)audio);
- rc = -ENOMEM;
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- } else
- pmem_sz >>= 1;
- }
- audio->out_dma_sz = pmem_sz;
-
- audio->read_phys = allocate_contiguous_ebi_nomap(PCM_BUFSZ_MIN *
- PCM_BUF_MAX_COUNT, SZ_4K);
- if (!audio->read_phys) {
- MM_ERR("could not allocate read buffers, freeing instance \
- 0x%08x\n", (int)audio);
+ client = msm_ion_client_create(UINT_MAX, "Audio_AAC_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
rc = -ENOMEM;
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
+ goto client_create_error;
}
- audio->map_v_read = ioremap(audio->read_phys,
- PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
+ audio->client = client;
+
+ MM_DBG("allocating mem sz = %d\n", mem_sz);
+ handle = ion_alloc(client, mem_sz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client, handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers,freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ audio->out_dma_sz = mem_sz;
+
+ mem_sz = (PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
+ MM_DBG("allocating mem sz = %d\n", mem_sz);
+ handle = ion_alloc(client, mem_sz,
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate I/P buffers\n");
+ rc = -ENOMEM;
+ goto input_buff_alloc_error;
+ }
+
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto input_buff_get_phys_error;
+ } else {
+ MM_INFO("out Got valid phy: %x sz: %x\n",
+ (unsigned int) audio->read_phys, (unsigned int) len);
+ }
+ audio->read_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto input_buff_get_flags_error;
+ }
+
+ audio->map_v_read = ion_map_kernel(client,
+ handle, ionflag);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read buffers, freeing instance \
0x%08x\n", (int)audio);
rc = -ENOMEM;
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- free_contiguous_memory_by_paddr(audio->read_phys);
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
+ goto input_buff_map_error;
}
audio->read_data = audio->map_v_read;
MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
@@ -1873,10 +1913,20 @@
done:
return rc;
err:
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->read_phys);
+ ion_unmap_kernel(client, audio->input_buff_handle);
+input_buff_map_error:
+input_buff_get_flags_error:
+input_buff_get_phys_error:
+ ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
audpp_adec_free(audio->dec_id);
kfree(audio);
return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index 79a828a..99e10a4 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -32,8 +32,8 @@
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/msm_audio_aac.h>
-#include <linux/android_pmem.h>
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include "audmgr.h"
@@ -147,6 +147,9 @@
int enabled;
int running;
int stopped; /* set when stopped, cleared on flush */
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
struct audio_frame {
@@ -1248,16 +1251,17 @@
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
(audio->out_data)) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->out_phys);
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
audio->out_data = NULL;
}
if (audio->data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
audio->data = NULL;
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
return 0;
}
@@ -1270,6 +1274,11 @@
int rc;
int encid;
int dma_size = 0;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
mutex_lock(&audio->lock);
if (audio->opened) {
@@ -1352,52 +1361,103 @@
audaac_in_flush(audio);
audaac_out_flush(audio);
- audio->phys = allocate_contiguous_ebi_nomap(dma_size, SZ_4K);
- if (audio->phys) {
- audio->map_v_read = ioremap(
- audio->phys, dma_size);
- if (IS_ERR(audio->map_v_read)) {
- MM_ERR("could not map DMA buffers\n");
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- goto evt_error;
- }
- audio->data = audio->map_v_read;
- } else {
- MM_ERR("could not allocate read buffers\n");
+
+ client = msm_ion_client_create(UINT_MAX, "Audio_AAC_in_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
rc = -ENOMEM;
- goto evt_error;
+ goto client_create_error;
}
- MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
- (int) audio->data, (int) audio->phys);
+ audio->client = client;
+
+ MM_DBG("allocating mem sz = %d\n", dma_size);
+ handle = ion_alloc(client, dma_size, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_read)) {
+ MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_read;
+ MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
audio->out_data = NULL;
if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
- audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE,
- SZ_4K);
- if (!audio->out_phys) {
- MM_ERR("could not allocate write buffers\n");
+
+ MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
+ handle = ion_alloc(client, BUFFER_SIZE,
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate I/P buffers\n");
rc = -ENOMEM;
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
- goto evt_error;
- } else {
- audio->map_v_write = ioremap(
- audio->out_phys, BUFFER_SIZE);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write phys address\n");
- rc = -ENOMEM;
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
- free_contiguous_memory_by_paddr(\
- audio->out_phys);
- goto evt_error;
- }
- audio->out_data = audio->map_v_write;
- MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
- audio->out_phys, (int)audio->out_data);
+ goto input_buff_alloc_error;
}
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto input_buff_get_phys_error;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ }
+ audio->out_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto input_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client,
+ handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto input_buff_map_error;
+ }
+ audio->out_data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ (unsigned int)addr,
+ (unsigned int)audio->out_data);
+
/* Initialize buffer */
audio->out[0].data = audio->out_data + 0;
audio->out[0].addr = audio->out_phys + 0;
@@ -1419,7 +1479,19 @@
done:
mutex_unlock(&audio->lock);
return rc;
-evt_error:
+input_buff_map_error:
+input_buff_get_flags_error:
+input_buff_get_phys_error:
+ ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
msm_adsp_put(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
msm_adsp_put(audio->audpre);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 1a1002e..45fa045 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -39,10 +39,10 @@
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/earlysuspend.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
@@ -179,6 +179,9 @@
int eq_needs_commit;
audpp_cmd_cfg_object_params_eqalizer eq;
audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
struct audpp_cmd_cfg_adec_params_amrnb {
@@ -784,6 +787,10 @@
uint16_t enable_mask;
int enable;
int prev_state;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ int len = 0;
MM_DBG("cmd = %d\n", cmd);
@@ -970,23 +977,53 @@
MM_DBG("allocate PCM buf %d\n",
config.buffer_count *
config.buffer_size);
- audio->read_phys = allocate_contiguous_ebi_nomap(
- config.buffer_size *
- config.buffer_count,
- SZ_4K);
- if (!audio->read_phys) {
+ handle = ion_alloc(audio->client,
+ (config.buffer_size *
+ config.buffer_count),
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to alloc I/P buffs\n");
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
break;
- }
- audio->map_v_read = ioremap(
- audio->read_phys,
- config.buffer_size *
- config.buffer_count);
+ }
+
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(audio->client ,
+ handle, &addr, &len);
+ if (rc) {
+ MM_ERR("Invalid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) audio->read_phys,
+ (unsigned int) len);
+ }
+ audio->read_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(audio->client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ }
+ audio->map_v_read = ion_map_kernel(
+ audio->client,
+ handle, ionflag);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read buf\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(
- audio->read_phys);
} else {
uint8_t index;
uint32_t offset = 0;
@@ -1295,12 +1332,13 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audamrnb_reset_event_queue(audio);
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- if (audio->read_data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->read_phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
+ if (audio->input_buff_handle != NULL) {
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
@@ -1439,6 +1477,12 @@
struct audio *audio = NULL;
int rc, dec_attrb, decid, i;
struct audamrnb_event *e_node = NULL;
+ unsigned mem_sz = DMASZ;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+ int len = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_amrnb_" + 5];
@@ -1482,30 +1526,50 @@
audio->dec_id = decid & MSM_AUD_DECODER_MASK;
- audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
- if (!audio->phys) {
- MM_ERR("could not allocate write buffers, freeing instance \
- 0x%08x\n", (int)audio);
+ client = msm_ion_client_create(UINT_MAX, "Audio_AMR_NB_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
rc = -ENOMEM;
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- } else {
- audio->map_v_write = ioremap(
- audio->phys, DMASZ);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write buffers, freeing \
- instance 0x%08x freeing\n", (int)audio);
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- }
- audio->data = audio->map_v_write;
- MM_DBG("write buf: phy addr 0x%08x kernel addr \
- 0x%08x\n", audio->phys, (int)audio->data);
+ goto client_create_error;
}
+ audio->client = client;
+
+ handle = ion_alloc(client, mem_sz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client, handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
rc = audmgr_open(&audio->audmgr);
@@ -1536,6 +1600,8 @@
goto err;
}
+ audio->input_buff_handle = NULL;
+
mutex_init(&audio->lock);
mutex_init(&audio->write_lock);
mutex_init(&audio->read_lock);
@@ -1590,8 +1656,14 @@
done:
return rc;
err:
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
audpp_adec_free(audio->dec_id);
kfree(audio);
return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index ac2b5ca..39578c1 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -36,8 +36,8 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/msm_audio_amrnb.h>
-#include <linux/android_pmem.h>
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include "audmgr.h"
@@ -151,6 +151,9 @@
uint8_t enabled;
uint8_t running;
uint8_t stopped; /* set when stopped, cleared on flush */
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+
};
struct audio_frame {
@@ -1207,8 +1210,8 @@
audio->opened = 0;
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
(audio->out_data)) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->out_phys);
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
audio->out_data = NULL;
}
if (audio->data) {
@@ -1221,6 +1224,7 @@
dma_size, audio->data, audio->phys);
audio->data = NULL;
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
return 0;
}
@@ -1233,6 +1237,11 @@
int32_t rc;
int encid;
int32_t dma_size = 0;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
mutex_lock(&audio->lock);
if (audio->opened) {
@@ -1320,34 +1329,60 @@
goto evt_error;
}
+ client = msm_ion_client_create(UINT_MAX, "Audio_AMRNB_in_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
+ rc = -ENOMEM;
+ goto client_create_error;
+ }
+ audio->client = client;
+
audio->out_data = NULL;
if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
- audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE,
- SZ_4K);
- if (!audio->out_phys) {
- MM_ERR("could not allocate write buffers\n");
+ MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
+ handle = ion_alloc(client, BUFFER_SIZE,
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate write buffers\n");
rc = -ENOMEM;
- dma_free_coherent(NULL,
- dma_size, audio->data, audio->phys);
- goto evt_error;
- } else {
- audio->map_v_write = ioremap(
- audio->out_phys, BUFFER_SIZE);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write phys address\n");
- rc = -ENOMEM;
- dma_free_coherent(NULL,
- dma_size, audio->data, audio->phys);
- free_contiguous_memory_by_paddr(\
- audio->out_phys);
- goto evt_error;
- }
- audio->out_data = audio->map_v_write;
- MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
- audio->out_phys,
- (uint32_t)audio->out_data);
+ goto input_buff_alloc_error;
}
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto input_buff_get_phys_error;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ }
+ audio->out_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto input_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client,
+ handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto input_buff_map_error;
+ }
+ audio->out_data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ (unsigned int)addr,
+ (unsigned int)audio->out_data);
+
/* Initialize buffer */
audio->out[0].data = audio->out_data + 0;
audio->out[0].addr = audio->out_phys + 0;
@@ -1369,6 +1404,14 @@
done:
mutex_unlock(&audio->lock);
return rc;
+input_buff_map_error:
+input_buff_get_phys_error:
+input_buff_get_flags_error:
+ ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
+ dma_free_coherent(NULL, dma_size, audio->data, audio->phys);
evt_error:
msm_adsp_put(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index b85b153..66b9354 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -38,10 +38,10 @@
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/earlysuspend.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
@@ -180,6 +180,9 @@
int eq_needs_commit;
audpp_cmd_cfg_object_params_eqalizer eq;
audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
static int auddec_dsp_config(struct audio *audio, int enable);
@@ -773,6 +776,10 @@
uint16_t enable_mask;
int enable;
int prev_state;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ int len = 0;
MM_DBG("cmd = %d\n", cmd);
@@ -966,23 +973,53 @@
if ((config.pcm_feedback) && (!audio->read_data)) {
MM_DBG("allocate PCM buf %d\n", config.buffer_count *
config.buffer_size);
- audio->read_phys = allocate_contiguous_ebi_nomap(
- config.buffer_size *
- config.buffer_count,
- SZ_4K);
- if (!audio->read_phys) {
+ handle = ion_alloc(audio->client,
+ (config.buffer_size *
+ config.buffer_count),
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to alloc I/P buffs\n");
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
break;
- }
- audio->map_v_read = ioremap(
- audio->read_phys,
- config.buffer_size *
- config.buffer_count);
+ }
+
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(audio->client ,
+ handle, &addr, &len);
+ if (rc) {
+ MM_ERR("Invalid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) audio->read_phys,
+ (unsigned int) len);
+ }
+ audio->read_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(audio->client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ }
+ audio->map_v_read = ion_map_kernel(
+ audio->client,
+ handle, ionflag);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map mem for read buf\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(
- audio->read_phys);
} else {
uint8_t index;
uint32_t offset = 0;
@@ -1024,7 +1061,8 @@
}
/* Only useful in tunnel-mode */
-static int audamrwb_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+static int audamrwb_fsync(struct file *file, loff_t a, loff_t b,
+ int datasync)
{
struct audio *audio = file->private_data;
struct buffer *frame;
@@ -1363,12 +1401,13 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audamrwb_reset_event_queue(audio);
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- if (audio->read_data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->read_phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
+ if (audio->input_buff_handle != NULL) {
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
@@ -1509,8 +1548,14 @@
static int audamrwb_open(struct inode *inode, struct file *file)
{
struct audio *audio = NULL;
- int rc, dec_attrb, decid, i;
+ int rc = 0, dec_attrb, decid, i;
struct audamrwb_event *e_node = NULL;
+ unsigned mem_sz = DMASZ;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+ int len = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_amrwb_" + 5];
@@ -1545,30 +1590,49 @@
audio->dec_id = decid & MSM_AUD_DECODER_MASK;
- audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
- if (!audio->phys) {
- MM_ERR("could not allocate write buffers, freeing instance \
- 0x%08x\n", (int)audio);
+ client = msm_ion_client_create(UINT_MAX, "Audio_AMR_WB_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
rc = -ENOMEM;
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- } else {
- audio->map_v_write = ioremap(audio->phys, DMASZ);
-
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write buffers, freeing \
- instance 0x%08x\n", (int)audio);
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- }
- audio->data = audio->map_v_write;
- MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
- audio->phys, (int)audio->data);
+ goto client_create_error;
}
+ audio->client = client;
+
+ handle = ion_alloc(client, mem_sz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ goto output_buff_alloc_error;
+ }
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client, handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
rc = audmgr_open(&audio->audmgr);
@@ -1599,6 +1663,7 @@
goto err;
}
+ audio->input_buff_handle = NULL;
mutex_init(&audio->lock);
mutex_init(&audio->write_lock);
mutex_init(&audio->read_lock);
@@ -1658,8 +1723,14 @@
done:
return rc;
err:
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
audpp_adec_free(audio->dec_id);
kfree(audio);
return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 489929b..1d4148a 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -33,10 +33,10 @@
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/earlysuspend.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
@@ -175,6 +175,9 @@
int eq_needs_commit;
audpp_cmd_cfg_object_params_eqalizer eq;
audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
static int auddec_dsp_config(struct audio *audio, int enable);
@@ -770,6 +773,10 @@
uint16_t enable_mask;
int enable;
int prev_state;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ int len = 0;
MM_DBG("cmd = %d\n", cmd);
@@ -955,25 +962,54 @@
MM_DBG("allocate PCM buf %d\n",
config.buffer_count *
config.buffer_size);
- audio->read_phys =
- allocate_contiguous_ebi_nomap(
- config.buffer_size *
- config.buffer_count,
- SZ_4K);
- if (!audio->read_phys) {
+ handle = ion_alloc(audio->client,
+ (config.buffer_size *
+ config.buffer_count),
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to alloc I/P buffs\n");
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
break;
}
- audio->map_v_read = ioremap(
- audio->read_phys,
- config.buffer_size *
- config.buffer_count);
+
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(audio->client ,
+ handle, &addr, &len);
+ if (rc) {
+ MM_ERR("Invalid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) audio->read_phys,
+ (unsigned int) len);
+ }
+ audio->read_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(audio->client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ }
+ audio->map_v_read = ion_map_kernel(
+ audio->client,
+ handle, ionflag);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map mem"
" for read buf\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(
- audio->read_phys);
} else {
uint8_t index;
uint32_t offset = 0;
@@ -1287,12 +1323,13 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audevrc_reset_event_queue(audio);
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- if (audio->read_data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->read_phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
+ if (audio->input_buff_handle != NULL) {
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
@@ -1431,6 +1468,13 @@
struct audio *audio = NULL;
int rc, dec_attrb, decid, i;
struct audevrc_event *e_node = NULL;
+ unsigned mem_sz = DMASZ;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+ int len = 0;
+
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_evrc_" + 5];
@@ -1473,29 +1517,50 @@
audio->dec_id = decid & MSM_AUD_DECODER_MASK;
- audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
- if (!audio->phys) {
- MM_ERR("could not allocate write buffers, freeing instance \
- 0x%08x\n", (int)audio);
+ client = msm_ion_client_create(UINT_MAX, "Audio_EVRC_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
rc = -ENOMEM;
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- } else {
- audio->map_v_write = ioremap(audio->phys, DMASZ);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write buffers, freeing \
- instance 0x%08x\n", (int)audio);
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- }
- audio->data = audio->map_v_write;
- MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
- audio->phys, (int)audio->data);
+ goto client_create_error;
}
+ audio->client = client;
+
+ handle = ion_alloc(client, mem_sz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client, handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
rc = audmgr_open(&audio->audmgr);
@@ -1527,6 +1592,8 @@
goto err;
}
+ audio->input_buff_handle = NULL;
+
/* Initialize all locks of audio instance */
mutex_init(&audio->lock);
mutex_init(&audio->write_lock);
@@ -1582,8 +1649,14 @@
done:
return rc;
err:
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
audpp_adec_free(audio->dec_id);
kfree(audio);
return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index e13b072..e955c4b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -33,6 +33,7 @@
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include <asm/atomic.h>
#include <asm/ioctls.h>
@@ -150,6 +151,9 @@
int enabled;
int running;
int stopped; /* set when stopped, cleared on flush */
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
struct audio_frame {
@@ -1003,7 +1007,8 @@
spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
-static int audevrc_in_fsync(struct file *file,loff_t a, loff_t b, int datasync)
+static int audevrc_in_fsync(struct file *file, loff_t a, loff_t b,
+ int datasync)
{
struct audio_evrc_in *audio = file->private_data;
@@ -1190,15 +1195,16 @@
audio->opened = 0;
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
(audio->out_data)) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->out_phys);
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
audio->out_data = NULL;
}
if (audio->data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
audio->data = NULL;
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
return 0;
}
@@ -1211,6 +1217,11 @@
int rc;
int encid;
int dma_size = 0;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
mutex_lock(&audio->lock);
if (audio->opened) {
@@ -1290,51 +1301,101 @@
audevrc_in_flush(audio);
audevrc_out_flush(audio);
- audio->phys = allocate_contiguous_ebi_nomap(dma_size, SZ_4K);
- if (!audio->phys) {
- MM_ERR("could not allocate physical read buffers\n");
+ client = msm_ion_client_create(UINT_MAX, "Audio_EVRC_in_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
rc = -ENOMEM;
- goto evt_error;
- } else {
- audio->map_v_read = ioremap(audio->phys, dma_size);
- if (IS_ERR(audio->map_v_read)) {
- MM_ERR("could not map physical address\n");
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- goto evt_error;
- }
- audio->data = audio->map_v_read;
- MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
- audio->phys, (int)audio->data);
+ goto client_create_error;
}
+ audio->client = client;
+
+ MM_DBG("allocating mem sz = %d\n", dma_size);
+ handle = ion_alloc(client, dma_size, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_read)) {
+ MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_read;
+ MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
audio->out_data = NULL;
if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
- audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE,
- SZ_4K);
- if (!audio->out_phys) {
- MM_ERR("could not allocate physical write buffers\n");
+ MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
+ handle = ion_alloc(client, BUFFER_SIZE,
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate I/P buffers\n");
rc = -ENOMEM;
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
- goto evt_error;
- } else {
- audio->map_v_write = ioremap(
- audio->out_phys, BUFFER_SIZE);
-
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write phys address\n");
- rc = -ENOMEM;
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
- free_contiguous_memory_by_paddr(\
- audio->out_phys);
- goto evt_error;
- }
- audio->out_data = audio->map_v_write;
- MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
- audio->out_phys, (int)audio->out_data);
+ goto input_buff_alloc_error;
}
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto input_buff_alloc_error;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ }
+ audio->out_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto input_buff_alloc_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client,
+ handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto input_buff_map_error;
+ }
+ audio->out_data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ (unsigned int)addr,
+ (unsigned int)audio->out_data);
+
/* Initialize buffer */
audio->out[0].data = audio->out_data + 0;
audio->out[0].addr = audio->out_phys + 0;
@@ -1356,7 +1417,17 @@
done:
mutex_unlock(&audio->lock);
return rc;
-evt_error:
+input_buff_map_error:
+ ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
msm_adsp_put(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
msm_adsp_put(audio->audpre);
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index 8754337..14a9e57 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -37,8 +37,8 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/earlysuspend.h>
+#include <linux/ion.h>
#include <linux/list.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
@@ -137,9 +137,9 @@
union msm_audio_event_payload payload;
};
-struct audlpa_pmem_region {
+struct audlpa_ion_region {
struct list_head list;
- struct file *file;
+ struct ion_handle *handle;
int fd;
void *vaddr;
unsigned long paddr;
@@ -217,9 +217,10 @@
struct mutex get_event_lock;
int event_abort;
- struct list_head pmem_region_queue;
+ struct list_head ion_region_queue;
int buffer_count;
int buffer_size;
+ struct ion_client *client;
};
static int auddec_dsp_config(struct audio *audio, int enable);
@@ -227,7 +228,7 @@
static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
static void audpcm_post_event(struct audio *audio, int type,
union msm_audio_event_payload payload);
-static unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up);
static void audpcm_async_send_data(struct audio *audio,
unsigned needed);
@@ -679,7 +680,7 @@
if (drv_evt && drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
mutex_lock(&audio->lock);
- audlpa_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ audlpa_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
drv_evt->payload.aio_buf.buf_len, 0);
mutex_unlock(&audio->lock);
}
@@ -689,94 +690,118 @@
return rc;
}
-static int audlpa_pmem_check(struct audio *audio,
+static int audlpa_ion_check(struct audio *audio,
void *vaddr, unsigned long len)
{
- struct audlpa_pmem_region *region_elt;
- struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+ struct audlpa_ion_region *region_elt;
+ struct audlpa_ion_region t = {.vaddr = vaddr, .len = len };
- list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
OVERLAPS(region_elt, &t)) {
- MM_ERR("region (vaddr %p len %ld)"
+ MM_ERR("[%p]:region (vaddr %p len %ld)"
" clashes with registered region"
" (vaddr %p paddr %p len %ld)\n",
- vaddr, len,
+ audio, vaddr, len,
region_elt->vaddr,
- (void *)region_elt->paddr,
- region_elt->len);
+ (void *)region_elt->paddr, region_elt->len);
return -EINVAL;
}
}
return 0;
}
-
-static int audlpa_pmem_add(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audlpa_ion_add(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- unsigned long paddr, kvaddr, len;
- struct file *file;
- struct audlpa_pmem_region *region;
+ ion_phys_addr_t paddr;
+ size_t len;
+ unsigned long kvaddr;
+ struct audlpa_ion_region *region;
int rc = -EINVAL;
+ struct ion_handle *handle;
+ unsigned long ionflag;
- MM_DBG("\n"); /* Macro prints the file name and function */
+ MM_ERR("\n"); /* Macro prints the file name and function */
region = kmalloc(sizeof(*region), GFP_KERNEL);
if (!region) {
rc = -ENOMEM;
goto end;
}
-
- if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
- kfree(region);
- goto end;
+ handle = ion_import_dma_buf(audio->client, info->fd);
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_err("%s: could not get handle of the given fd\n", __func__);
+ goto import_error;
}
-
- rc = audlpa_pmem_check(audio, info->vaddr, len);
+ rc = ion_handle_get_flags(audio->client, handle, &ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n", __func__);
+ goto flag_error;
+ }
+ kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag);
+ if (IS_ERR_OR_NULL((void *)kvaddr)) {
+ pr_err("%s: could not get virtual address\n", __func__);
+ goto map_error;
+ }
+ rc = ion_phys(audio->client, handle, &paddr, &len);
+ if (rc) {
+ pr_err("%s: could not get physical address\n", __func__);
+ goto ion_error;
+ }
+ rc = audlpa_ion_check(audio, info->vaddr, len);
if (rc < 0) {
- put_pmem_file(file);
- kfree(region);
- goto end;
+ MM_ERR("audpcm_ion_check failed\n");
+ goto ion_error;
}
-
+ region->handle = handle;
region->vaddr = info->vaddr;
region->fd = info->fd;
region->paddr = paddr;
region->kvaddr = kvaddr;
region->len = len;
- region->file = file;
region->ref_cnt = 0;
- MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
- region->vaddr, region->len);
- list_add_tail(®ion->list, &audio->pmem_region_queue);
+ MM_DBG("[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+ audio, region->paddr, region->vaddr,
+ region->len, region->kvaddr);
+ list_add_tail(®ion->list, &audio->ion_region_queue);
+
+ return rc;
+
+ion_error:
+ ion_unmap_kernel(audio->client, handle);
+map_error:
+flag_error:
+ ion_free(audio->client, handle);
+import_error:
+ kfree(region);
end:
return rc;
}
-static int audlpa_pmem_remove(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audlpa_ion_remove(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
struct list_head *ptr, *next;
int rc = -EINVAL;
- MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audlpa_ion_region, list);
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audlpa_pmem_region, list);
-
- if ((region->fd == info->fd) &&
+ if (region != NULL && (region->fd == info->fd) &&
(region->vaddr == info->vaddr)) {
if (region->ref_cnt) {
- MM_DBG("region %p in use ref_cnt %d\n",
- region, region->ref_cnt);
+ MM_DBG("%s[%p]:region %p in use ref_cnt %d\n",
+ __func__, audio, region,
+ region->ref_cnt);
break;
}
MM_DBG("remove region fd %d vaddr %p\n",
info->fd, info->vaddr);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
rc = 0;
break;
@@ -786,23 +811,20 @@
return rc;
}
-static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
- unsigned long len, struct audlpa_pmem_region **region)
+static int audlpa_ion_lookup_vaddr(struct audio *audio, void *addr,
+ unsigned long len, struct audlpa_ion_region **region)
{
- struct audlpa_pmem_region *region_elt;
-
+ struct audlpa_ion_region *region_elt;
int match_count = 0;
-
*region = NULL;
/* returns physical address or zero */
- list_for_each_entry(region_elt, &audio->pmem_region_queue,
- list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len) {
/* offset since we could pass vaddr inside a registerd
- * pmem buffer
+ * ion buffer
*/
match_count++;
@@ -812,31 +834,33 @@
}
if (match_count > 1) {
- MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
- list_for_each_entry(region_elt,
- &audio->pmem_region_queue, list) {
+ MM_ERR("%s[%p]:multiple hits for vaddr %p, len %ld\n",
+ __func__, audio, addr, len);
+ list_for_each_entry(region_elt, &audio->ion_region_queue,
+ list) {
if (addr >= region_elt->vaddr &&
- addr < region_elt->vaddr + region_elt->len &&
- addr + len <= region_elt->vaddr + region_elt->len)
- MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+ addr < region_elt->vaddr + region_elt->len &&
+ addr + len <= region_elt->vaddr + region_elt->len)
+ MM_ERR("\t%s[%p]:%p, %ld --> %p\n",
+ __func__, audio,
+ region_elt->vaddr,
region_elt->len,
(void *)region_elt->paddr);
}
}
-
return *region ? 0 : -1;
}
-
-unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
unsigned long paddr;
int ret;
- ret = audlpa_pmem_lookup_vaddr(audio, addr, len, ®ion);
+ ret = audlpa_ion_lookup_vaddr(audio, addr, len, ®ion);
if (ret) {
- MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+ MM_ERR("%s[%p]:lookup (%p, %ld) failed\n",
+ __func__, audio, addr, len);
return 0;
}
if (ref_up)
@@ -870,10 +894,9 @@
buf_node->buf.buf_addr, buf_node->buf.buf_len,
buf_node->buf.data_len);
- buf_node->paddr = audlpa_pmem_fixup(
+ buf_node->paddr = audlpa_ion_fixup(
audio, buf_node->buf.buf_addr,
buf_node->buf.buf_len, 1);
-
if (dir) {
/* write */
if (!buf_node->paddr ||
@@ -1042,23 +1065,23 @@
rc = audpp_pause(audio->dec_id, (int) arg);
break;
- case AUDIO_REGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_REGISTER_PMEM\n");
+ case AUDIO_REGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_ERR("AUDIO_REGISTER_ION\n");
if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audlpa_pmem_add(audio, &info);
+ rc = audlpa_ion_add(audio, &info);
break;
}
- case AUDIO_DEREGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+ case AUDIO_DEREGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_ERR("AUDIO_DEREGISTER_ION\n");
if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audlpa_pmem_remove(audio, &info);
+ rc = audlpa_ion_remove(audio, &info);
break;
}
@@ -1175,7 +1198,8 @@
return rc;
}
-int audlpa_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+int audlpa_fsync(struct file *file, loff_t a, loff_t b,
+ int datasync)
{
struct audio *audio = file->private_data;
@@ -1185,21 +1209,21 @@
return audlpa_async_fsync(audio);
}
-static void audpcm_reset_pmem_region(struct audio *audio)
+static void audpcm_reset_ion_region(struct audio *audio)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
struct list_head *ptr, *next;
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audlpa_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audlpa_ion_region, list);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
}
return;
}
-
static int audio_release(struct inode *inode, struct file *file)
{
struct audio *audio = file->private_data;
@@ -1210,7 +1234,7 @@
if (audio->rmt_resource_released == 0)
rmt_put_resource(audio);
audpcm_async_flush(audio);
- audpcm_reset_pmem_region(audio);
+ audpcm_reset_ion_region(audio);
msm_adsp_put(audio->audplay);
audpp_adec_free(audio->dec_id);
@@ -1221,16 +1245,12 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audpcm_reset_event_queue(audio);
- MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
- if (audio->data) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- }
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
debugfs_remove(audio->dentry);
#endif
+ ion_client_destroy(audio->client);
kfree(audio);
return 0;
}
@@ -1416,7 +1436,7 @@
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->write_wait);
INIT_LIST_HEAD(&audio->out_queue);
- INIT_LIST_HEAD(&audio->pmem_region_queue);
+ INIT_LIST_HEAD(&audio->ion_region_queue);
INIT_LIST_HEAD(&audio->free_event_queue);
INIT_LIST_HEAD(&audio->event_queue);
init_waitqueue_head(&audio->wait);
@@ -1456,6 +1476,14 @@
break;
}
}
+
+ audio->client = msm_ion_client_create(UINT_MAX, "Audio_LPA_Client");
+ if (IS_ERR_OR_NULL(audio->client)) {
+ pr_err("Unable to create ION client\n");
+ goto err;
+ }
+ MM_DBG("Ion client created\n");
+
done:
return rc;
err:
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index 9346107..427dc8f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -31,10 +31,10 @@
#include <linux/delay.h>
#include <linux/earlysuspend.h>
#include <linux/list.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
@@ -136,9 +136,9 @@
union msm_audio_event_payload payload;
};
-struct audmp3_pmem_region {
+struct audmp3_ion_region {
struct list_head list;
- struct file *file;
+ struct ion_handle *handle;
int fd;
void *vaddr;
unsigned long paddr;
@@ -241,13 +241,16 @@
struct mutex get_event_lock;
int event_abort;
- struct list_head pmem_region_queue; /* protected by lock */
+ struct list_head ion_region_queue; /* protected by lock */
struct audmp3_drv_operations drv_ops;
int eq_enable;
int eq_needs_commit;
audpp_cmd_cfg_object_params_eqalizer eq;
audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
static int auddec_dsp_config(struct audio *audio, int enable);
@@ -259,7 +262,7 @@
static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
static void audmp3_post_event(struct audio *audio, int type,
union msm_audio_event_payload payload);
-static unsigned long audmp3_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audmp3_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up);
static int rmt_put_resource(struct audio *audio)
@@ -1021,7 +1024,7 @@
if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE ||
drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
mutex_lock(&audio->lock);
- audmp3_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ audmp3_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
drv_evt->payload.aio_buf.buf_len, 0);
mutex_unlock(&audio->lock);
}
@@ -1036,13 +1039,13 @@
return rc;
}
-static int audmp3_pmem_check(struct audio *audio,
+static int audmp3_ion_check(struct audio *audio,
void *vaddr, unsigned long len)
{
- struct audmp3_pmem_region *region_elt;
- struct audmp3_pmem_region t = { .vaddr = vaddr, .len = len };
+ struct audmp3_ion_region *region_elt;
+ struct audmp3_ion_region t = { .vaddr = vaddr, .len = len };
- list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
OVERLAPS(region_elt, &t)) {
MM_ERR("region (vaddr %p len %ld)"
@@ -1059,13 +1062,17 @@
return 0;
}
-static int audmp3_pmem_add(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audmp3_ion_add(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- unsigned long paddr, kvaddr, len;
- struct file *file;
- struct audmp3_pmem_region *region;
+ ion_phys_addr_t paddr;
+ size_t len;
+ unsigned long kvaddr;
+ struct audmp3_ion_region *region;
int rc = -EINVAL;
+ struct ion_handle *handle;
+ unsigned long ionflag;
+ void *temp_ptr;
MM_DBG("\n"); /* Macro prints the file name and function */
region = kmalloc(sizeof(*region), GFP_KERNEL);
@@ -1075,55 +1082,84 @@
goto end;
}
- if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
- kfree(region);
- goto end;
+ handle = ion_import_dma_buf(audio->client, info->fd);
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_err("%s: could not get handle of the given fd\n", __func__);
+ goto import_error;
}
- rc = audmp3_pmem_check(audio, info->vaddr, len);
+ rc = ion_handle_get_flags(audio->client, handle, &ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n", __func__);
+ goto flag_error;
+ }
+
+ temp_ptr = ion_map_kernel(audio->client, handle, ionflag);
+ if (IS_ERR_OR_NULL(temp_ptr)) {
+ pr_err("%s: could not get virtual address\n", __func__);
+ goto map_error;
+ }
+ kvaddr = (unsigned long) temp_ptr;
+
+ rc = ion_phys(audio->client, handle, &paddr, &len);
+ if (rc) {
+ pr_err("%s: could not get physical address\n", __func__);
+ goto ion_error;
+ }
+
+ rc = audmp3_ion_check(audio, info->vaddr, len);
if (rc < 0) {
- put_pmem_file(file);
- kfree(region);
- goto end;
+ MM_ERR("audpcm_ion_check failed\n");
+ goto ion_error;
}
+ region->handle = handle;
region->vaddr = info->vaddr;
region->fd = info->fd;
region->paddr = paddr;
region->kvaddr = kvaddr;
region->len = len;
- region->file = file;
region->ref_cnt = 0;
- MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
- region->vaddr, region->len);
- list_add_tail(®ion->list, &audio->pmem_region_queue);
+ MM_DBG("[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+ audio, region->paddr, region->vaddr,
+ region->len, region->kvaddr);
+ list_add_tail(®ion->list, &audio->ion_region_queue);
+ return rc;
+
+ion_error:
+ ion_unmap_kernel(audio->client, handle);
+map_error:
+flag_error:
+ ion_free(audio->client, handle);
+import_error:
+ kfree(region);
end:
return rc;
}
-static int audmp3_pmem_remove(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audmp3_ion_remove(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- struct audmp3_pmem_region *region;
+ struct audmp3_ion_region *region;
struct list_head *ptr, *next;
int rc = -EINVAL;
- MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audmp3_ion_region, list);
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audmp3_pmem_region, list);
-
- if ((region->fd == info->fd) &&
+ if (region != NULL && (region->fd == info->fd) &&
(region->vaddr == info->vaddr)) {
if (region->ref_cnt) {
- MM_DBG("region %p in use ref_cnt %d\n",
- region, region->ref_cnt);
+ MM_DBG("%s[%p]:region %p in use ref_cnt %d\n",
+ __func__, audio, region,
+ region->ref_cnt);
break;
}
- MM_DBG("remove region fd %d vaddr %p \n",
- info->fd, info->vaddr);
+ MM_DBG("remove region fd %d vaddr %p\n",
+ info->fd, info->vaddr);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
rc = 0;
break;
@@ -1133,23 +1169,20 @@
return rc;
}
-static int audmp3_pmem_lookup_vaddr(struct audio *audio, void *addr,
- unsigned long len, struct audmp3_pmem_region **region)
+static int audmp3_ion_lookup_vaddr(struct audio *audio, void *addr,
+ unsigned long len, struct audmp3_ion_region **region)
{
- struct audmp3_pmem_region *region_elt;
-
+ struct audmp3_ion_region *region_elt;
int match_count = 0;
-
*region = NULL;
/* returns physical address or zero */
- list_for_each_entry(region_elt, &audio->pmem_region_queue,
- list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len) {
/* offset since we could pass vaddr inside a registerd
- * pmem buffer
+ * ion buffer
*/
match_count++;
@@ -1159,29 +1192,31 @@
}
if (match_count > 1) {
- MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
- list_for_each_entry(region_elt,
- &audio->pmem_region_queue, list) {
+ MM_ERR("%s[%p]:multiple hits for vaddr %p, len %ld\n",
+ __func__, audio, addr, len);
+ list_for_each_entry(region_elt, &audio->ion_region_queue,
+ list) {
if (addr >= region_elt->vaddr &&
- addr < region_elt->vaddr + region_elt->len &&
- addr + len <= region_elt->vaddr + region_elt->len)
- MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+ addr < region_elt->vaddr + region_elt->len &&
+ addr + len <= region_elt->vaddr + region_elt->len)
+ MM_ERR("\t%s[%p]:%p, %ld --> %p\n",
+ __func__, audio,
+ region_elt->vaddr,
region_elt->len,
(void *)region_elt->paddr);
}
}
-
return *region ? 0 : -1;
}
-unsigned long audmp3_pmem_fixup(struct audio *audio, void *addr,
+unsigned long audmp3_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up)
{
- struct audmp3_pmem_region *region;
+ struct audmp3_ion_region *region;
unsigned long paddr;
int ret;
- ret = audmp3_pmem_lookup_vaddr(audio, addr, len, ®ion);
+ ret = audmp3_ion_lookup_vaddr(audio, addr, len, ®ion);
if (ret) {
MM_ERR("lookup (%p, %ld) failed\n", addr, len);
return 0;
@@ -1217,7 +1252,7 @@
buf_node->buf.buf_addr, buf_node->buf.buf_len,
buf_node->buf.data_len);
- buf_node->paddr = audmp3_pmem_fixup(
+ buf_node->paddr = audmp3_ion_fixup(
audio, buf_node->buf.buf_addr,
buf_node->buf.buf_len, 1);
@@ -1276,6 +1311,10 @@
uint16_t enable_mask;
int enable;
int prev_state;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ int len = 0;
MM_DBG("cmd = %d\n", cmd);
@@ -1481,25 +1520,50 @@
MM_DBG("allocate PCM buffer %d\n",
config.buffer_count *
config.buffer_size);
- audio->read_phys =
- allocate_contiguous_ebi_nomap(
- config.buffer_size *
- config.buffer_count,
- SZ_4K);
- if (!audio->read_phys) {
+
+ handle = ion_alloc(audio->client,
+ (config.buffer_size *
+ config.buffer_count),
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to alloc I/P buffs\n");
rc = -ENOMEM;
break;
}
- audio->map_v_read = ioremap(
- audio->read_phys,
- config.buffer_size *
- config.buffer_count);
+
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(audio->client ,
+ handle, &addr, &len);
+ if (rc) {
+ MM_ERR("Invalid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ rc = -ENOMEM;
+ break;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) audio->read_phys,
+ (unsigned int) len);
+ }
+ audio->read_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(audio->client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags\n");
+ rc = -ENOMEM;
+ break;
+ }
+
+ audio->map_v_read = ion_map_kernel(
+ audio->client,
+ handle, ionflag);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(
- audio->read_phys);
+ ion_free(audio->client, handle);
} else {
uint8_t index;
uint32_t offset = 0;
@@ -1539,23 +1603,23 @@
rc = audpp_pause(audio->dec_id, (int) arg);
break;
- case AUDIO_REGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_REGISTER_PMEM\n");
+ case AUDIO_REGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_DBG("AUDIO_REGISTER_ION\n");
if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audmp3_pmem_add(audio, &info);
+ rc = audmp3_ion_add(audio, &info);
break;
}
- case AUDIO_DEREGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+ case AUDIO_DEREGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_DBG("AUDIO_DEREGISTER_ION\n");
if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audmp3_pmem_remove(audio, &info);
+ rc = audmp3_ion_remove(audio, &info);
break;
}
case AUDIO_ASYNC_WRITE:
@@ -1939,16 +2003,16 @@
}
return rc;
}
-
-static void audmp3_reset_pmem_region(struct audio *audio)
+static void audmp3_reset_ion_region(struct audio *audio)
{
- struct audmp3_pmem_region *region;
+ struct audmp3_ion_region *region;
struct list_head *ptr, *next;
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audmp3_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audmp3_ion_region, list);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
}
@@ -1966,7 +2030,7 @@
rmt_put_resource(audio);
audio->drv_ops.out_flush(audio);
audio->drv_ops.in_flush(audio);
- audmp3_reset_pmem_region(audio);
+ audmp3_reset_ion_region(audio);
msm_adsp_put(audio->audplay);
audpp_adec_free(audio->dec_id);
@@ -1977,20 +2041,18 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audmp3_reset_event_queue(audio);
- MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
- if (audio->data) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- }
- if (audio->read_data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->read_phys);
- }
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
debugfs_remove(audio->dentry);
#endif
+ if (!(audio->drv_status & ADRV_STATUS_AIO_INTF)) {
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
+ }
+ ion_client_destroy(audio->client);
kfree(audio);
return 0;
}
@@ -2129,7 +2191,13 @@
struct audio *audio = NULL;
int rc, i, dec_attrb, decid;
struct audmp3_event *e_node = NULL;
- unsigned pmem_sz = DMASZ_MAX;
+ unsigned mem_sz = DMASZ_MAX;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+ int len = 0;
+
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_mp3_" + 5];
@@ -2171,43 +2239,57 @@
}
audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+ client = msm_ion_client_create(UINT_MAX, "Audio_MP3_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
+ rc = -ENOMEM;
+ goto client_create_error;
+ }
+ audio->client = client;
+
/* Non AIO interface */
if (!(file->f_flags & O_NONBLOCK)) {
- while (pmem_sz >= DMASZ_MIN) {
- MM_DBG("pmemsz = %d\n", pmem_sz);
- audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
- SZ_4K);
- if (audio->phys) {
- audio->map_v_write = ioremap(
- audio->phys, pmem_sz);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write \
- buffers, freeing instance \
- 0x%08x\n", (int)audio);
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(
- audio->phys);
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- }
- audio->data = audio->map_v_write;
- MM_DBG("write buf: phy addr 0x%08x kernel addr\
- 0x%08x\n", audio->phys,\
- (int)audio->data);
- break;
- } else if (pmem_sz == DMASZ_MIN) {
- MM_ERR("could not allocate write buffers, \
- freeing instance 0x%08x\n",
- (int)audio);
- rc = -ENOMEM;
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- } else
- pmem_sz >>= 1;
+
+ MM_DBG("memsz = %d\n", mem_sz);
+
+ handle = ion_alloc(client, mem_sz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
}
- audio->out_dma_sz = pmem_sz;
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ audio->out_dma_sz = mem_sz;
}
if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
@@ -2276,7 +2358,7 @@
init_waitqueue_head(&audio->read_wait);
INIT_LIST_HEAD(&audio->out_queue);
INIT_LIST_HEAD(&audio->in_queue);
- INIT_LIST_HEAD(&audio->pmem_region_queue);
+ INIT_LIST_HEAD(&audio->ion_region_queue);
INIT_LIST_HEAD(&audio->free_event_queue);
INIT_LIST_HEAD(&audio->event_queue);
init_waitqueue_head(&audio->wait);
@@ -2315,13 +2397,18 @@
break;
}
}
+
done:
return rc;
err:
- if (audio->data) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- }
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_flags_error:
+output_buff_get_phys_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
audpp_adec_free(audio->dec_id);
kfree(audio);
return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
index 9b524b4..158dd46 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.c
@@ -425,6 +425,8 @@
set_voc_mode_msg.min_rate = cpu_to_be32(audio->rate_type);
set_voc_mode_msg.max_rate = cpu_to_be32(audio->rate_type);
+ MM_DBG("audio->mvs_mode %d audio->rate_type %d\n",
+ audio->mvs_mode, audio->rate_type);
msm_rpc_setup_req(&set_voc_mode_msg.rpc_hdr,
audio->rpc_prog,
audio->rpc_ver,
@@ -923,10 +925,14 @@
MM_DBG("UL AMR frame_type %d\n",
be32_to_cpu(*args));
- } else if ((frame_mode == MVS_FRAME_MODE_PCM_UL) ||
- (frame_mode == MVS_FRAME_MODE_VOC_TX)) {
- /* PCM and EVRC don't have frame_type */
+ } else if (frame_mode == MVS_FRAME_MODE_PCM_UL) {
+ /* PCM doesn't have frame_type */
buf_node->frame.frame_type = 0;
+ } else if (frame_mode == MVS_FRAME_MODE_VOC_TX) {
+ /* Extracting EVRC current buffer frame rate*/
+ buf_node->frame.frame_type = be32_to_cpu(*args);
+ pr_debug("%s: UL EVRC frame_type %d\n",
+ __func__, be32_to_cpu(*args));
} else if (frame_mode == MVS_FRAME_MODE_G711_UL) {
/* Extract G711 frame type. */
buf_node->frame.frame_type = be32_to_cpu(*args);
@@ -1056,7 +1062,7 @@
cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
} else if (frame_mode == MVS_FRAME_MODE_VOC_RX) {
dl_reply.cdc_param.gnr_arg.param1 =
- cpu_to_be32(audio->rate_type);
+ cpu_to_be32(buf_node->frame.frame_type);
dl_reply.cdc_param.gnr_arg.param2 = 0;
dl_reply.cdc_param.\
gnr_arg.valid_pkt_status_ptr =
@@ -1488,7 +1494,8 @@
case AUDIO_GET_MVS_CONFIG: {
struct msm_audio_mvs_config config;
- MM_DBG("IOCTL GET_MVS_CONFIG\n");
+ MM_DBG("GET_MVS_CONFIG mvs_mode %d rate_type %d\n",
+ config.mvs_mode, config.rate_type);
mutex_lock(&audio->lock);
config.mvs_mode = audio->mvs_mode;
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 49c781f..880de09 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -38,7 +38,7 @@
#include <linux/delay.h>
#include <linux/earlysuspend.h>
#include <linux/list.h>
-#include <linux/android_pmem.h>
+#include <linux/ion.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
@@ -134,11 +134,10 @@
union msm_audio_event_payload payload;
};
-struct audpcm_pmem_region {
+struct audpcm_ion_region {
struct list_head list;
- struct file *file;
+ struct ion_handle *handle;
int fd;
- void *vaddr_ref;
void *vaddr;
unsigned long paddr;
unsigned long kvaddr;
@@ -222,8 +221,10 @@
struct mutex get_event_lock;
int event_abort;
- struct list_head pmem_region_queue;
+ struct list_head ion_region_queue;
struct audpcm_drv_operations drv_ops;
+ struct ion_client *client;
+ struct ion_handle *output_buff_handle;
};
static int auddec_dsp_config(struct audio *audio, int enable);
@@ -232,7 +233,7 @@
static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
static void audpcm_post_event(struct audio *audio, int type,
union msm_audio_event_payload payload);
-static unsigned long audpcm_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audpcm_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up);
static int rmt_put_resource(struct audio *audio)
@@ -762,7 +763,7 @@
if (drv_evt && drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
mutex_lock(&audio->lock);
- audpcm_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ audpcm_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
drv_evt->payload.aio_buf.buf_len, 0);
mutex_unlock(&audio->lock);
}
@@ -772,104 +773,118 @@
return rc;
}
-static int audpcm_pmem_check(struct audio *audio,
+static int audpcm_ion_check(struct audio *audio,
void *vaddr, unsigned long len)
{
- struct audpcm_pmem_region *region_elt;
- struct audpcm_pmem_region t = { .vaddr = vaddr, .len = len };
+ struct audpcm_ion_region *region_elt;
+ struct audpcm_ion_region t = {.vaddr = vaddr, .len = len };
- list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
OVERLAPS(region_elt, &t)) {
- MM_ERR("region (vaddr %p len %ld)"
+ MM_ERR("[%p]:region (vaddr %p len %ld)"
" clashes with registered region"
" (vaddr %p paddr %p len %ld)\n",
- vaddr, len,
+ audio, vaddr, len,
region_elt->vaddr,
- (void *)region_elt->paddr,
- region_elt->len);
+ (void *)region_elt->paddr, region_elt->len);
return -EINVAL;
}
}
return 0;
}
-
-static int audpcm_pmem_add(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audpcm_ion_add(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- unsigned long paddr, kvaddr, len;
- struct file *file;
- struct audpcm_pmem_region *region;
- struct vm_area_struct *vma;
+ ion_phys_addr_t paddr;
+ size_t len;
+ unsigned long kvaddr;
+ struct audpcm_ion_region *region;
int rc = -EINVAL;
+ struct ion_handle *handle;
+ unsigned long ionflag;
- MM_DBG("\n"); /* Macro prints the file name and function */
+ MM_ERR("\n"); /* Macro prints the file name and function */
region = kmalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
- if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
- kfree(region);
- return -EINVAL;
+ if (!region) {
+ rc = -ENOMEM;
+ goto end;
}
-
- vma = find_vma_intersection(current->active_mm,
- (unsigned long) info->vaddr, (unsigned long) info->vaddr+1);
-
- if (vma && ((vma->vm_end - vma->vm_start) == len)) {
- rc = audpcm_pmem_check(audio, (void *) vma->vm_start, len);
- if (rc < 0) {
- put_pmem_file(file);
- kfree(region);
- return rc;
- }
- region->vaddr = (void *) vma->vm_start;
- region->vaddr_ref = info->vaddr;
- MM_DBG("Valid VMA region vma->vm_start = 0x%8x \
- vma->vm_end = 0x%8x\n", (int) vma->vm_start,
- (int) vma->vm_end);
- } else {
- MM_ERR("No valid VMA region found\n");
- put_pmem_file(file);
- kfree(region);
- return rc;
+ handle = ion_import_dma_buf(audio->client, info->fd);
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_err("%s: could not get handle of the given fd\n", __func__);
+ goto import_error;
}
+ rc = ion_handle_get_flags(audio->client, handle, &ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n", __func__);
+ goto flag_error;
+ }
+ kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag);
+ if (IS_ERR_OR_NULL((void *)kvaddr)) {
+ pr_err("%s: could not get virtual address\n", __func__);
+ goto map_error;
+ }
+ rc = ion_phys(audio->client, handle, &paddr, &len);
+ if (rc) {
+ pr_err("%s: could not get physical address\n", __func__);
+ goto ion_error;
+ }
+ rc = audpcm_ion_check(audio, info->vaddr, len);
+ if (rc < 0) {
+ MM_ERR("audpcm_ion_check failed\n");
+ goto ion_error;
+ }
+ region->handle = handle;
+ region->vaddr = info->vaddr;
region->fd = info->fd;
region->paddr = paddr;
region->kvaddr = kvaddr;
region->len = len;
- region->file = file;
region->ref_cnt = 0;
- MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
- region->vaddr, region->len);
- list_add_tail(®ion->list, &audio->pmem_region_queue);
+ MM_DBG("[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+ audio, region->paddr, region->vaddr,
+ region->len, region->kvaddr);
+ list_add_tail(®ion->list, &audio->ion_region_queue);
+
+ return rc;
+
+ion_error:
+ ion_unmap_kernel(audio->client, handle);
+map_error:
+flag_error:
+ ion_free(audio->client, handle);
+import_error:
+ kfree(region);
+end:
return rc;
}
-static int audpcm_pmem_remove(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audpcm_ion_remove(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- struct audpcm_pmem_region *region;
+ struct audpcm_ion_region *region;
struct list_head *ptr, *next;
int rc = -EINVAL;
- MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audpcm_ion_region, list);
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audpcm_pmem_region, list);
-
- if ((region->fd == info->fd) &&
- (region->vaddr_ref == info->vaddr)) {
+ if (region != NULL && (region->fd == info->fd) &&
+ (region->vaddr == info->vaddr)) {
if (region->ref_cnt) {
- MM_DBG("region %p in use ref_cnt %d\n",
- region, region->ref_cnt);
+ MM_DBG("%s[%p]:region %p in use ref_cnt %d\n",
+ __func__, audio, region,
+ region->ref_cnt);
break;
}
- MM_DBG("remove region fd %d vaddr %p \n", info->fd,
- info->vaddr);
+ MM_DBG("remove region fd %d vaddr %p\n",
+ info->fd, info->vaddr);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
rc = 0;
break;
@@ -879,24 +894,22 @@
return rc;
}
-static int audpcm_pmem_lookup_vaddr(struct audio *audio, void *addr,
- unsigned long len, struct audpcm_pmem_region **region)
+static int audpcm_ion_lookup_vaddr(struct audio *audio, void *addr,
+ unsigned long len, struct audpcm_ion_region **region)
{
- struct audpcm_pmem_region *region_elt;
-
+ struct audpcm_ion_region *region_elt;
int match_count = 0;
-
*region = NULL;
/* returns physical address or zero */
- list_for_each_entry(region_elt, &audio->pmem_region_queue,
- list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len) {
/* offset since we could pass vaddr inside a registerd
- * pmem buffer
+ * ion buffer
*/
+
match_count++;
if (!*region)
*region = region_elt;
@@ -904,31 +917,33 @@
}
if (match_count > 1) {
- MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
- list_for_each_entry(region_elt,
- &audio->pmem_region_queue, list) {
+ MM_ERR("%s[%p]:multiple hits for vaddr %p, len %ld\n",
+ __func__, audio, addr, len);
+ list_for_each_entry(region_elt, &audio->ion_region_queue,
+ list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len)
- MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+ MM_ERR("\t%s[%p]:%p, %ld --> %p\n",
+ __func__, audio,
+ region_elt->vaddr,
region_elt->len,
(void *)region_elt->paddr);
}
}
-
return *region ? 0 : -1;
}
-
-static unsigned long audpcm_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audpcm_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up)
{
- struct audpcm_pmem_region *region;
+ struct audpcm_ion_region *region;
unsigned long paddr;
int ret;
- ret = audpcm_pmem_lookup_vaddr(audio, addr, len, ®ion);
+ ret = audpcm_ion_lookup_vaddr(audio, addr, len, ®ion);
if (ret) {
- MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+ MM_ERR("%s[%p]:lookup (%p, %ld) failed\n",
+ __func__, audio, addr, len);
return 0;
}
if (ref_up)
@@ -961,7 +976,7 @@
buf_node, dir, buf_node->buf.buf_addr,
buf_node->buf.buf_len, buf_node->buf.data_len);
- buf_node->paddr = audpcm_pmem_fixup(
+ buf_node->paddr = audpcm_ion_fixup(
audio, buf_node->buf.buf_addr,
buf_node->buf.buf_len, 1);
if (dir) {
@@ -1125,23 +1140,23 @@
rc = audpp_pause(audio->dec_id, (int) arg);
break;
- case AUDIO_REGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_REGISTER_PMEM\n");
+ case AUDIO_REGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_ERR("AUDIO_REGISTER_ION\n");
if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audpcm_pmem_add(audio, &info);
+ rc = audpcm_ion_add(audio, &info);
break;
}
- case AUDIO_DEREGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+ case AUDIO_DEREGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_ERR("AUDIO_DEREGISTER_ION\n");
if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audpcm_pmem_remove(audio, &info);
+ rc = audpcm_ion_remove(audio, &info);
break;
}
@@ -1340,15 +1355,16 @@
return rc;
}
-static void audpcm_reset_pmem_region(struct audio *audio)
+static void audpcm_reset_ion_region(struct audio *audio)
{
- struct audpcm_pmem_region *region;
+ struct audpcm_ion_region *region;
struct list_head *ptr, *next;
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audpcm_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audpcm_ion_region, list);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
}
@@ -1365,7 +1381,7 @@
if (audio->rmt_resource_released == 0)
rmt_put_resource(audio);
audio->drv_ops.out_flush(audio);
- audpcm_reset_pmem_region(audio);
+ audpcm_reset_ion_region(audio);
msm_adsp_put(audio->audplay);
audpp_adec_free(audio->dec_id);
@@ -1376,16 +1392,12 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audpcm_reset_event_queue(audio);
- MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
- if (audio->data) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- }
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
debugfs_remove(audio->dentry);
#endif
+ ion_client_destroy(audio->client);
kfree(audio);
return 0;
}
@@ -1506,7 +1518,13 @@
struct audio *audio = NULL;
int rc, i, dec_attrb, decid;
struct audpcm_event *e_node = NULL;
- unsigned pmem_sz = DMASZ_MAX;
+ unsigned mem_sz = DMASZ_MAX;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+ int len = 0;
+
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
@@ -1543,44 +1561,57 @@
}
audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+ client = msm_ion_client_create(UINT_MAX, "Audio_PCM_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
+ rc = -ENOMEM;
+ goto client_create_error;
+ }
+ audio->client = client;
+
/* Non AIO interface */
if (!(file->f_flags & O_NONBLOCK)) {
- while (pmem_sz >= DMASZ_MIN) {
- MM_DBG("pmemsz = %d\n", pmem_sz);
- audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
- SZ_4K);
- if (audio->phys) {
- audio->map_v_write = ioremap(
- audio->phys, pmem_sz);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write\
- buffers\n");
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(
- audio->phys);
- audpp_adec_free(audio->dec_id);
- MM_DBG("audio instance 0x%08x\
- freeing\n", (int)audio);
- kfree(audio);
- goto done;
- }
- audio->data = audio->map_v_write;
- MM_DBG("write buf: phy addr 0x%08x kernel addr\
- 0x%08x\n", audio->phys,\
- (int)audio->data);
- break;
- } else if (pmem_sz == DMASZ_MIN) {
- MM_ERR("could not allocate write buffers\n");
- rc = -ENOMEM;
- audpp_adec_free(audio->dec_id);
- MM_DBG("audio instance 0x%08x freeing\n",\
- (int)audio);
- kfree(audio);
- goto done;
- } else
- pmem_sz >>= 1;
+
+ MM_DBG("memsz = %d\n", mem_sz);
+
+ handle = ion_alloc(client, mem_sz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
}
- audio->out_dma_sz = pmem_sz;
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ audio->out_dma_sz = mem_sz;
}
rc = audmgr_open(&audio->audmgr);
@@ -1631,7 +1662,7 @@
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->write_wait);
INIT_LIST_HEAD(&audio->out_queue);
- INIT_LIST_HEAD(&audio->pmem_region_queue);
+ INIT_LIST_HEAD(&audio->ion_region_queue);
INIT_LIST_HEAD(&audio->free_event_queue);
INIT_LIST_HEAD(&audio->event_queue);
init_waitqueue_head(&audio->wait);
@@ -1674,10 +1705,14 @@
done:
return rc;
err:
- if (audio->data) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- }
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_flags_error:
+output_buff_get_phys_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
audpp_adec_free(audio->dec_id);
MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 851980d..716dbd2 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -2,7 +2,7 @@
*
* pcm audio input device
*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c,
* Copyright (C) 2008 Google, Inc.
@@ -26,6 +26,7 @@
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/dma-mapping.h>
+#include <linux/ion.h>
#include <linux/delay.h>
@@ -114,6 +115,8 @@
* All the coeff should be passed from user space */
int iir_enable;
audpreproc_cmd_cfg_iir_tuning_filter_params iir_cfg;
+ struct ion_client *client;
+ struct ion_handle *output_buff_handle;
};
static int audpcm_in_dsp_enable(struct audio_in *audio, int enable);
@@ -764,9 +767,11 @@
audio->audpre = NULL;
audio->opened = 0;
if (audio->data) {
- free_contiguous_memory((void *)audio->data);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
audio->data = NULL;
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
return 0;
}
@@ -777,6 +782,11 @@
{
struct audio_in *audio = &the_audio_in;
int rc;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
int encid;
mutex_lock(&audio->lock);
@@ -827,23 +837,53 @@
audpcm_in_flush(audio);
- audio->data = allocate_contiguous_memory(DMASZ, MEMTYPE_EBI1,
- SZ_4K, 0);
- if (!audio->data) {
- MM_ERR("could not allocate read buffers\n");
+ client = msm_ion_client_create(UINT_MAX, "Audio_PCM_in_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
rc = -ENOMEM;
- goto evt_error;
- } else {
- audio->phys = memory_pool_node_paddr(audio->data);
- if (!audio->phys) {
- MM_ERR("could not get physical address\n");
- rc = -ENOMEM;
- free_contiguous_memory(audio->data);
- goto evt_error;
- }
- MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
- audio->phys, (int)audio->data);
+ goto client_create_error;
}
+ audio->client = client;
+
+ MM_DBG("allocating mem sz = %d\n", DMASZ);
+ handle = ion_alloc(client, DMASZ, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto output_buff_get_flags_error;
+ }
+
+ audio->data = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->data)) {
+ MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
file->private_data = audio;
audio->opened = 1;
@@ -851,7 +891,13 @@
done:
mutex_unlock(&audio->lock);
return rc;
-evt_error:
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
msm_adsp_put(audio->audrec);
msm_adsp_put(audio->audpre);
audpreproc_aenc_free(audio->enc_id);
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index f436759..dc257cd 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -34,10 +34,10 @@
#include <linux/debugfs.h>
#include <linux/earlysuspend.h>
#include <linux/list.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
@@ -170,6 +170,9 @@
int eq_needs_commit;
audpp_cmd_cfg_object_params_eqalizer eq;
audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
static int auddec_dsp_config(struct audio *audio, int enable);
@@ -767,6 +770,10 @@
uint16_t enable_mask;
int enable;
int prev_state;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ int len = 0;
MM_DBG("cmd = %d\n", cmd);
@@ -956,24 +963,53 @@
if ((config.pcm_feedback) && (!audio->read_data)) {
MM_DBG("allocate PCM buf %d\n",
config.buffer_count * config.buffer_size);
- audio->read_phys =
- allocate_contiguous_ebi_nomap(
- config.buffer_size *
- config.buffer_count,
- SZ_4K);
- if (!audio->read_phys) {
+ handle = ion_alloc(audio->client,
+ (config.buffer_size *
+ config.buffer_count),
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to alloc I/P buffs\n");
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
break;
}
- audio->map_v_read = ioremap(
- audio->read_phys,
- config.buffer_size *
- config.buffer_count);
+
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(audio->client ,
+ handle, &addr, &len);
+ if (rc) {
+ MM_ERR("Invalid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) audio->read_phys,
+ (unsigned int) len);
+ }
+ audio->read_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(audio->client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ }
+ audio->map_v_read = ion_map_kernel(
+ audio->client,
+ handle, ionflag);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read buf\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(
- audio->read_phys);
} else {
uint8_t index;
uint32_t offset = 0;
@@ -1019,7 +1055,8 @@
}
/* Only useful in tunnel-mode */
-static int audqcelp_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+static int audqcelp_fsync(struct file *file, loff_t a, loff_t b,
+ int datasync)
{
struct audio *audio = file->private_data;
int rc = 0;
@@ -1287,12 +1324,13 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audqcelp_reset_event_queue(audio);
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- if (audio->read_data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->read_phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
+ if (audio->input_buff_handle != NULL) {
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
@@ -1431,6 +1469,12 @@
struct audio *audio = NULL;
int rc, dec_attrb, decid, i;
struct audqcelp_event *e_node = NULL;
+ unsigned mem_sz = DMASZ;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+ int len = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_qcelp_" + 5];
@@ -1471,29 +1515,50 @@
}
audio->dec_id = decid & MSM_AUD_DECODER_MASK;
- audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
- if (!audio->phys) {
- MM_ERR("could not allocate write buffers, freeing instance \
- 0x%08x\n", (int)audio);
+ client = msm_ion_client_create(UINT_MAX, "Audio_QCELP_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
rc = -ENOMEM;
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- } else {
- audio->map_v_write = ioremap(audio->phys, DMASZ);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write buffers, freeing \
- instance 0x%08x\n", (int)audio);
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- }
- audio->data = audio->map_v_write;
- MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
- audio->phys, (int)audio->data);
+ goto client_create_error;
}
+ audio->client = client;
+
+ handle = ion_alloc(client, mem_sz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client, handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
rc = audmgr_open(&audio->audmgr);
@@ -1524,6 +1589,8 @@
goto err;
}
+ audio->input_buff_handle = NULL;
+
/* Initialize all locks of audio instance */
mutex_init(&audio->lock);
mutex_init(&audio->write_lock);
@@ -1580,8 +1647,14 @@
done:
return rc;
err:
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
audpp_adec_free(audio->dec_id);
kfree(audio);
return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index 92036e5..99a169d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -33,6 +33,7 @@
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include <asm/atomic.h>
#include <asm/ioctls.h>
@@ -151,6 +152,9 @@
int enabled;
int running;
int stopped; /* set when stopped, cleared on flush */
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
struct audio_frame {
@@ -1004,7 +1008,8 @@
spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
-static int audqcelp_in_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+static int audqcelp_in_fsync(struct file *file, loff_t a, loff_t b,
+ int datasync)
{
struct audio_qcelp_in *audio = file->private_data;
@@ -1192,16 +1197,17 @@
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
(audio->out_data)) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->out_phys);
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
audio->out_data = NULL;
}
if (audio->data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
audio->data = NULL;
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
return 0;
}
@@ -1214,6 +1220,11 @@
int rc;
int encid;
int dma_size = 0;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
mutex_lock(&audio->lock);
if (audio->opened) {
@@ -1293,52 +1304,101 @@
audqcelp_in_flush(audio);
audqcelp_out_flush(audio);
- audio->phys = allocate_contiguous_ebi_nomap(dma_size, SZ_4K);
- if (!audio->phys) {
- MM_ERR("could not allocate physical read buffers\n");
+ client = msm_ion_client_create(UINT_MAX, "Audio_QCELP_in_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
rc = -ENOMEM;
- goto evt_error;
- } else {
- audio->map_v_read = ioremap(audio->phys, dma_size);
- if (IS_ERR(audio->map_v_read)) {
- MM_ERR("could not map physical address\n");
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- goto evt_error;
- }
- audio->data = audio->map_v_read;
- MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
- audio->phys, (int)audio->data);
+ goto client_create_error;
}
+ audio->client = client;
+
+ MM_DBG("allocating mem sz = %d\n", dma_size);
+ handle = ion_alloc(client, dma_size, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_read)) {
+ MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_read;
+ MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
audio->out_data = NULL;
if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
- audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE,
- SZ_4K);
- if (!audio->out_phys) {
- MM_ERR("could not allocate physical write buffers\n");
+ MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
+ handle = ion_alloc(client, BUFFER_SIZE,
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate I/P buffers\n");
rc = -ENOMEM;
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
- goto evt_error;
- } else {
- audio->map_v_write = ioremap(
- audio->out_phys, BUFFER_SIZE);
-
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write phys address\n");
- rc = -ENOMEM;
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
- free_contiguous_memory_by_paddr(\
- audio->out_phys);
- goto evt_error;
- }
- audio->out_data = audio->map_v_write;
- MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
- audio->out_phys, (int)audio->out_data);
+ goto input_buff_alloc_error;
}
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto input_buff_get_phys_error;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ }
+ audio->out_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto input_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client,
+ handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto input_buff_map_error;
+ }
+ audio->out_data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ (unsigned int)addr,
+ (unsigned int)audio->out_data);
+
/* Initialize buffer */
audio->out[0].data = audio->out_data + 0;
audio->out[0].addr = audio->out_phys + 0;
@@ -1360,7 +1420,19 @@
done:
mutex_unlock(&audio->lock);
return rc;
-evt_error:
+input_buff_map_error:
+input_buff_get_flags_error:
+input_buff_get_phys_error:
+ ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
msm_adsp_put(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
msm_adsp_put(audio->audpre);
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index 162a6f1..e28e704 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -37,11 +37,11 @@
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/earlysuspend.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
#include <linux/msm_audio_wma.h>
#include <linux/memory_alloc.h>
+#include <linux/ion.h>
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
@@ -187,6 +187,9 @@
int eq_needs_commit;
audpp_cmd_cfg_object_params_eqalizer eq;
audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
static int auddec_dsp_config(struct audio *audio, int enable);
@@ -815,6 +818,10 @@
uint16_t enable_mask;
int enable;
int prev_state;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ int len = 0;
MM_DBG("cmd = %d\n", cmd);
@@ -1034,24 +1041,54 @@
MM_DBG("allocate PCM buffer %d\n",
config.buffer_count *
config.buffer_size);
- audio->read_phys =
- allocate_contiguous_ebi_nomap(
- config.buffer_size *
- config.buffer_count,
- SZ_4K);
- if (!audio->read_phys) {
+ handle = ion_alloc(audio->client,
+ (config.buffer_size *
+ config.buffer_count),
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to alloc I/P buffs\n");
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
break;
}
- audio->map_v_read = ioremap(
- audio->read_phys,
- config.buffer_size *
- config.buffer_count);
+
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(audio->client ,
+ handle, &addr, &len);
+ if (rc) {
+ MM_ERR("Invalid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) audio->read_phys,
+ (unsigned int) len);
+ }
+ audio->read_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(audio->client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ }
+
+ audio->map_v_read = ion_map_kernel(
+ audio->client,
+ handle, ionflag);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(
- audio->read_phys);
} else {
uint8_t index;
uint32_t offset = 0;
@@ -1098,7 +1135,8 @@
}
/* Only useful in tunnel-mode */
-static int audio_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+static int audio_fsync(struct file *file, loff_t a, loff_t b,
+ int datasync)
{
struct audio *audio = file->private_data;
struct buffer *frame;
@@ -1433,12 +1471,13 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audwma_reset_event_queue(audio);
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- if (audio->read_data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->read_phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
+ if (audio->input_buff_handle != NULL) {
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
@@ -1580,8 +1619,13 @@
{
struct audio *audio = NULL;
int rc, dec_attrb, decid, i;
- unsigned pmem_sz = DMASZ_MAX;
+ unsigned mem_sz = DMASZ_MAX;
struct audwma_event *e_node = NULL;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+ int len = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_wma_" + 5];
@@ -1624,36 +1668,52 @@
}
audio->dec_id = decid & MSM_AUD_DECODER_MASK;
- while (pmem_sz >= DMASZ_MIN) {
- MM_DBG("pmemsz = %d\n", pmem_sz);
- audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
- if (audio->phys) {
- audio->map_v_write = ioremap(audio->phys, pmem_sz);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write buffers, \
- freeing instance 0x%08x\n",
- (int)audio);
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- }
- audio->data = audio->map_v_write;
- MM_DBG("write buf: phy addr 0x%08x kernel addr \
- 0x%08x\n", audio->phys, (int)audio->data);
- break;
- } else if (pmem_sz == DMASZ_MIN) {
- MM_ERR("could not allocate write buffers, freeing \
- instance 0x%08x\n", (int)audio);
- rc = -ENOMEM;
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- } else
- pmem_sz >>= 1;
+ client = msm_ion_client_create(UINT_MAX, "Audio_WMA_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
+ rc = -ENOMEM;
+ goto client_create_error;
}
- audio->out_dma_sz = pmem_sz;
+ audio->client = client;
+
+ handle = ion_alloc(client, mem_sz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client, handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ audio->out_dma_sz = mem_sz;
if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
rc = audmgr_open(&audio->audmgr);
@@ -1684,6 +1744,7 @@
goto err;
}
+ audio->input_buff_handle = NULL;
mutex_init(&audio->lock);
mutex_init(&audio->write_lock);
mutex_init(&audio->read_lock);
@@ -1748,8 +1809,14 @@
done:
return rc;
err:
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
audpp_adec_free(audio->dec_id);
kfree(audio);
return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index 641b1c7..87afcf0 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -36,11 +36,11 @@
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/earlysuspend.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
#include <linux/memory_alloc.h>
#include <linux/msm_audio_wmapro.h>
+#include <linux/ion.h>
#include <mach/msm_adsp.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
@@ -186,6 +186,9 @@
int eq_needs_commit;
audpp_cmd_cfg_object_params_eqalizer eq;
audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
};
static int auddec_dsp_config(struct audio *audio, int enable);
@@ -803,6 +806,10 @@
uint16_t enable_mask;
int enable;
int prev_state;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ int len = 0;
MM_DBG("cmd = %d\n", cmd);
@@ -1031,25 +1038,54 @@
MM_DBG("allocate PCM buffer %d\n",
config.buffer_count *
config.buffer_size);
- audio->read_phys =
- allocate_contiguous_ebi_nomap(
- config.buffer_size *
- config.buffer_count,
- SZ_4K);
- if (!audio->read_phys) {
+ handle = ion_alloc(audio->client,
+ (config.buffer_size *
+ config.buffer_count),
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to alloc I/P buffs\n");
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
break;
}
- audio->map_v_read = ioremap(
- audio->read_phys,
- config.buffer_size *
- config.buffer_count);
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(audio->client ,
+ handle, &addr, &len);
+ if (rc) {
+ MM_ERR("Invalid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) audio->read_phys,
+ (unsigned int) len);
+ }
+ audio->read_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(audio->client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ }
+
+ audio->map_v_read = ion_map_kernel(
+ audio->client,
+ handle, ionflag);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(
- audio->read_phys);
} else {
uint8_t index;
uint32_t offset = 0;
@@ -1096,7 +1132,8 @@
}
/* Only useful in tunnel-mode */
-static int audio_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+static int audio_fsync(struct file *file, loff_t a, loff_t b,
+ int datasync)
{
struct audio *audio = file->private_data;
struct buffer *frame;
@@ -1429,12 +1466,13 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audwmapro_reset_event_queue(audio);
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- if (audio->read_data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->read_phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
+ if (audio->input_buff_handle != NULL) {
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
@@ -1576,8 +1614,13 @@
{
struct audio *audio = NULL;
int rc, dec_attrb, decid, i;
- unsigned pmem_sz = DMASZ_MAX;
+ unsigned mem_sz = DMASZ_MAX;
struct audwmapro_event *e_node = NULL;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+ int len = 0;
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
char name[sizeof "msm_wmapro_" + 5];
@@ -1620,36 +1663,52 @@
}
audio->dec_id = decid & MSM_AUD_DECODER_MASK;
- while (pmem_sz >= DMASZ_MIN) {
- MM_DBG("pmemsz = %d\n", pmem_sz);
- audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
- if (audio->phys) {
- audio->map_v_write = ioremap(audio->phys, pmem_sz);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write buffers, \
- freeing instance 0x%08x\n",
- (int)audio);
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- }
- audio->data = audio->map_v_write;
- MM_DBG("write buf: phy addr 0x%08x kernel addr \
- 0x%08x\n", audio->phys, (int)audio->data);
- break;
- } else if (pmem_sz == DMASZ_MIN) {
- MM_ERR("could not allocate write buffers, freeing \
- instance 0x%08x\n", (int)audio);
- rc = -ENOMEM;
- audpp_adec_free(audio->dec_id);
- kfree(audio);
- goto done;
- } else
- pmem_sz >>= 1;
+ client = msm_ion_client_create(UINT_MAX, "Audio_WMA_PRO_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
+ rc = -ENOMEM;
+ goto client_create_error;
}
- audio->out_dma_sz = pmem_sz;
+ audio->client = client;
+
+ handle = ion_alloc(client, mem_sz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client, handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ audio->out_dma_sz = mem_sz;
rc = audmgr_open(&audio->audmgr);
if (rc) {
@@ -1677,6 +1736,7 @@
goto err;
}
+ audio->input_buff_handle = NULL;
mutex_init(&audio->lock);
mutex_init(&audio->write_lock);
mutex_init(&audio->read_lock);
@@ -1735,8 +1795,14 @@
done:
return rc;
err:
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
audpp_adec_free(audio->dec_id);
kfree(audio);
return rc;
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index f9edfc9..667ede0 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -1105,8 +1105,8 @@
static int __init msm_rpmrs_l2_init(void)
{
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064() ||
- cpu_is_msm8627()) {
+ if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+ cpu_is_apq8064() || cpu_is_msm8627()) {
msm_pm_set_l2_flush_flag(0);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index c37943c..08af4d4 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -259,6 +259,9 @@
/* 9625 IDs */
[134] = MSM_CPU_9625,
+ /* 8930AA ID */
+ [142] = MSM_CPU_8930AA,
+
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
considered as unknown CPU. */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index fb560ba..9d2aedc 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -136,8 +136,8 @@
reg = saw_bases[cpu];
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064() ||
- cpu_is_msm8627()) {
+ if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+ cpu_is_apq8064() || cpu_is_msm8627()) {
val = 0xA4;
reg += 0x14;
timeout = 512;
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index fcb8517..5f5a02b 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -38,8 +38,10 @@
VIDEO_DOMAIN,
VIDEO_DOMAIN,
CAMERA_DOMAIN,
- DISPLAY_DOMAIN,
- ROTATOR_DOMAIN,
+ DISPLAY_READ_DOMAIN,
+ DISPLAY_WRITE_DOMAIN,
+ ROTATOR_SRC_DOMAIN,
+ ROTATOR_DST_DOMAIN,
0xFFFFFFFF
};
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 03db126..a9a25b3 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -568,8 +568,8 @@
n_restart_orders = ARRAY_SIZE(orders_8x60_all);
}
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
- cpu_is_apq8064() || cpu_is_msm8627()) {
+ if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+ cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627()) {
if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
restart_orders = restart_orders_8960_sglte;
n_restart_orders =
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index fcbd432..8d31683 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -964,8 +964,8 @@
if (!smp_processor_id())
return 0;
- if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064()
- || cpu_is_msm8930() || cpu_is_msm8627())
+ if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
+ cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627())
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
if (__get_cpu_var(first_boot)) {
@@ -1062,7 +1062,7 @@
gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
} else if (cpu_is_msm8960() || cpu_is_apq8064() || cpu_is_msm8930() ||
- cpu_is_msm8627()) {
+ cpu_is_msm8930aa() || cpu_is_msm8627()) {
global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
dgt->freq = 6750000;
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
@@ -1071,7 +1071,8 @@
gpt->freq = 32765;
gpt_hz = 32765;
sclk_hz = 32765;
- if (!cpu_is_msm8930() && !cpu_is_msm8627()) {
+ if (!cpu_is_msm8930() && !cpu_is_msm8930aa() &&
+ !cpu_is_msm8627()) {
gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
}
@@ -1122,8 +1123,8 @@
ce->irq = clock->irq;
if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
- cpu_is_msm8930() || cpu_is_msm9615() ||
- cpu_is_msm8625() || cpu_is_msm8627()) {
+ cpu_is_msm8930() || cpu_is_msm8930aa() ||
+ cpu_is_msm9615() || cpu_is_msm8625() || cpu_is_msm8627()) {
clock->percpu_evt = alloc_percpu(struct clock_event_device *);
if (!clock->percpu_evt) {
pr_err("msm_timer_init: memory allocation "
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 1c0f14b..74416e5 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -133,6 +133,7 @@
case MSM_CPU_8064:
return APQ8064_TOOLS_ID;
case MSM_CPU_8930:
+ case MSM_CPU_8930AA:
return MSM8930_TOOLS_ID;
case MSM_CPU_8974:
return MSM8974_TOOLS_ID;
@@ -157,6 +158,7 @@
case MSM_CPU_8960:
case MSM_CPU_8064:
case MSM_CPU_8930:
+ case MSM_CPU_8930AA:
case MSM_CPU_8627:
case MSM_CPU_9615:
case MSM_CPU_8974:
@@ -175,8 +177,8 @@
{
if (driver->use_device_tree)
return 1;
- else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
- cpu_is_apq8064() || cpu_is_msm8627())
+ else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+ cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627())
return 1;
else
return 0;
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 8650e83..e783a1a 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -97,6 +97,7 @@
#define ROTATOR_REVISION_NONE 0xffffffff
uint32_t rotator_hw_revision;
+static char rot_iommu_split_domain;
/*
* rotator_hw_revision:
@@ -174,6 +175,7 @@
unsigned long *start, unsigned long *len,
struct ion_handle **pihdl)
{
+ int domain;
if (!msm_rotator_dev->client)
return -EINVAL;
@@ -185,8 +187,13 @@
pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl,
ion_share_dma_buf(msm_rotator_dev->client, *pihdl));
+ if (rot_iommu_split_domain)
+ domain = src ? ROTATOR_SRC_DOMAIN : ROTATOR_DST_DOMAIN;
+ else
+ domain = ROTATOR_SRC_DOMAIN;
+
if (ion_map_iommu(msm_rotator_dev->client,
- *pihdl, ROTATOR_DOMAIN, GEN_POOL,
+ *pihdl, domain, GEN_POOL,
SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
pr_err("ion_map_iommu() failed\n");
return -EINVAL;
@@ -862,17 +869,24 @@
}
-static void put_img(struct file *p_file, struct ion_handle *p_ihdl)
+static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
+ unsigned char src)
{
#ifdef CONFIG_ANDROID_PMEM
if (p_file != NULL)
put_pmem_file(p_file);
#endif
+
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
if (!IS_ERR_OR_NULL(p_ihdl)) {
+ int domain;
+ if (rot_iommu_split_domain)
+ domain = src ? ROTATOR_SRC_DOMAIN : ROTATOR_DST_DOMAIN;
+ else
+ domain = ROTATOR_SRC_DOMAIN;
pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
ion_unmap_iommu(msm_rotator_dev->client,
- p_ihdl, ROTATOR_DOMAIN, GEN_POOL);
+ p_ihdl, domain, GEN_POOL);
ion_free(msm_rotator_dev->client, p_ihdl);
}
@@ -1162,15 +1176,15 @@
#endif
schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
do_rotate_unlock_mutex:
- put_img(dstp1_file, dstp1_ihdl);
- put_img(srcp1_file, srcp1_ihdl);
- put_img(dstp0_file, dstp0_ihdl);
+ put_img(dstp1_file, dstp1_ihdl, 0);
+ put_img(srcp1_file, srcp1_ihdl, 1);
+ put_img(dstp0_file, dstp0_ihdl, 0);
/* only source may use frame buffer */
if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
fput_light(srcp0_file, ps0_need);
else
- put_img(srcp0_file, srcp0_ihdl);
+ put_img(srcp0_file, srcp0_ihdl, 1);
mutex_unlock(&msm_rotator_dev->rotator_lock);
dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
__func__, rc);
@@ -1492,6 +1506,7 @@
pdata = pdev->dev.platform_data;
number_of_clks = pdata->number_of_clocks;
+ rot_iommu_split_domain = pdata->rot_iommu_split_domain;
msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
mutex_init(&msm_rotator_dev->imem_lock);
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index 5539950..f268f33 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -31,11 +31,21 @@
#include <mach/mpm.h>
#include "gpio-msm-common.h"
+#ifdef CONFIG_GPIO_MSM_V3
+enum msm_tlmm_register {
+ SDC4_HDRV_PULL_CTL = 0x0, /* NOT USED */
+ SDC3_HDRV_PULL_CTL = 0x0, /* NOT USED */
+ SDC2_HDRV_PULL_CTL = 0x2048,
+ SDC1_HDRV_PULL_CTL = 0x2044,
+};
+#else
enum msm_tlmm_register {
SDC4_HDRV_PULL_CTL = 0x20a0,
SDC3_HDRV_PULL_CTL = 0x20a4,
+ SDC2_HDRV_PULL_CTL = 0x0, /* NOT USED */
SDC1_HDRV_PULL_CTL = 0x20a0,
};
+#endif
struct tlmm_field_cfg {
enum msm_tlmm_register reg;
@@ -49,17 +59,24 @@
{SDC3_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC3_CLK */
{SDC3_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC3_CMD */
{SDC3_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC3_DATA */
+ {SDC2_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC2_CLK */
+ {SDC2_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC2_CMD */
+ {SDC2_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC2_DATA */
{SDC1_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC1_CLK */
{SDC1_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC1_CMD */
{SDC1_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC1_DATA */
};
static const struct tlmm_field_cfg tlmm_pull_cfgs[] = {
+ {SDC4_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC4_CLK */
{SDC4_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC4_CMD */
{SDC4_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC4_DATA */
{SDC3_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC3_CLK */
{SDC3_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC3_CMD */
{SDC3_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC3_DATA */
+ {SDC2_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC2_CLK */
+ {SDC2_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC2_CMD */
+ {SDC2_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC2_DATA */
{SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK */
{SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD */
{SDC1_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC1_DATA */
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 4e34e89..c31f0f0 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -807,6 +807,7 @@
mutex_unlock(&client->lock);
return vaddr;
}
+EXPORT_SYMBOL(ion_map_kernel);
void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle)
{
@@ -819,6 +820,7 @@
mutex_unlock(&buffer->lock);
mutex_unlock(&client->lock);
}
+EXPORT_SYMBOL(ion_unmap_kernel);
static int check_vaddr_bounds(unsigned long start, unsigned long end)
{
@@ -884,6 +886,7 @@
return ret;
}
+EXPORT_SYMBOL(ion_do_cache_op);
static int ion_debug_client_show(struct seq_file *s, void *unused)
{
@@ -1041,6 +1044,7 @@
kfree(client->name);
kfree(client);
}
+EXPORT_SYMBOL(ion_client_destroy);
int ion_handle_get_flags(struct ion_client *client, struct ion_handle *handle,
unsigned long *flags)
@@ -1104,6 +1108,7 @@
mutex_unlock(&client->lock);
return table;
}
+EXPORT_SYMBOL(ion_sg_table);
static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,
enum dma_data_direction direction)
@@ -1307,6 +1312,7 @@
}
return fd;
}
+EXPORT_SYMBOL(ion_share_dma_buf);
struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
{
@@ -1343,6 +1349,7 @@
dma_buf_put(dmabuf);
return handle;
}
+EXPORT_SYMBOL(ion_import_dma_buf);
static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
@@ -1791,6 +1798,7 @@
mutex_unlock(&dev->lock);
return ret_val;
}
+EXPORT_SYMBOL(ion_secure_heap);
int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version,
void *data)
@@ -1818,6 +1826,7 @@
mutex_unlock(&dev->lock);
return ret_val;
}
+EXPORT_SYMBOL(ion_unsecure_heap);
static int ion_debug_leak_show(struct seq_file *s, void *unused)
{
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index c33089d..38b1b67 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -570,7 +570,7 @@
patchid = 1;
else
patchid = 0;
- } else if (cpu_is_msm8930() || cpu_is_msm8627()) {
+ } else if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
/* A305 */
majorid = 0;
@@ -636,7 +636,8 @@
static unsigned int
adreno_getchipid(struct kgsl_device *device)
{
- if (cpu_is_apq8064() || cpu_is_msm8930() || cpu_is_msm8627())
+ if (cpu_is_apq8064() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+ cpu_is_msm8627())
return a3xx_getchipid(device);
else
return a2xx_getchipid(device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index c8a7a71..d6c5e66 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -181,7 +181,7 @@
/* Trustzone is only valid for some SOCs */
if (!(cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
- cpu_is_msm8930() || cpu_is_msm8627()))
+ cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()))
return -EINVAL;
priv = pwrscale->priv = kzalloc(sizeof(struct tz_priv), GFP_KERNEL);
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 63120da..5703d88 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -11,7 +11,7 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
EXTRA_CFLAGS += -Idrivers/media/video/msm/server
- obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
+ obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o msm_vfe_stats_buf.o
obj-$(CONFIG_MSM_CAMERA) += server/ eeprom/ sensors/ actuators/ csi/
obj-$(CONFIG_MSM_CPP) += cpp/
obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index c3e8321..08278ff 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -131,6 +131,8 @@
uint32_t id;
uint32_t buffer;
uint32_t frameCounter;
+ int32_t buf_idx;
+ int32_t fd;
};
struct msm_free_buf {
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 5c61cdb..5fcb62b 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -406,12 +406,14 @@
struct msm_stats_buf stats;
struct isp_msg_stats *isp_stats = (struct isp_msg_stats *)arg;
+ memset(&stats, 0, sizeof(stats));
isp_event->isp_data.isp_msg.msg_id = isp_stats->id;
isp_event->isp_data.isp_msg.frame_id =
isp_stats->frameCounter;
- stats.buffer = msm_pmem_stats_ptov_lookup(pmctl,
- isp_stats->buffer,
- &(stats.fd));
+ stats.buffer = isp_stats->buffer;
+ stats.fd = isp_stats->fd;
+ /* buf_idx used for O(0) lookup */
+ stats.buf_idx = isp_stats->buf_idx;
switch (isp_stats->id) {
case MSG_ID_STATS_AEC:
stats.aec.buff = stats.buffer;
@@ -453,8 +455,8 @@
kmalloc(sizeof(struct msm_stats_buf),
GFP_ATOMIC);
if (!stats_buf) {
- pr_err("%s: out of memory.\n",
- __func__);
+ pr_err("%s: out of memory. stats_id = %d\n",
+ __func__, isp_stats->id);
rc = -ENOMEM;
} else {
*stats_buf = stats;
@@ -550,7 +552,6 @@
struct msm_cam_media_controller *mctl, void __user *arg)
{
struct msm_vfe_cfg_cmd cfgcmd;
- struct msm_pmem_region region[8];
struct axidata axi_data;
if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
@@ -562,103 +563,13 @@
CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type);
switch (cfgcmd.cmd_type) {
case CMD_STATS_AF_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_AF, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_AEC_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_AEC, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_AWB_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_AWB, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_AEC_AWB_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_AEC_AWB, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_IHIST_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_IHIST, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_RS_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_RS, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_CS_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_CS, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
+ return msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
case CMD_GENERAL:
case CMD_STATS_DISABLE:
return msm_isp_subdev_ioctl(sd, &cfgcmd,
@@ -764,6 +675,62 @@
return rc;
}
+static int msm_vfe_stats_buf_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd,
+ struct msm_cam_media_controller *mctl,
+ void __user *arg)
+{
+ struct msm_vfe_cfg_cmd cfgcmd;
+ int rc = 0;
+ switch (cmd) {
+ case MSM_CAM_IOCTL_STATS_REQBUF: {
+ struct msm_stats_reqbuf reqbuf;
+ if (copy_from_user(&reqbuf, arg,
+ sizeof(struct msm_stats_reqbuf))) {
+ ERR_COPY_FROM_USER();
+ return -EFAULT;
+ }
+ cfgcmd.cmd_type = VFE_CMD_STATS_REQBUF;
+ cfgcmd.value = (void *)&reqbuf;
+ cfgcmd.length = sizeof(struct msm_stats_reqbuf);
+ rc = msm_isp_subdev_ioctl(sd, &cfgcmd, (void *)mctl->client);
+ break;
+ }
+ case MSM_CAM_IOCTL_STATS_ENQUEUEBUF: {
+ struct msm_stats_buf_info buf_info;
+
+ if (copy_from_user(&buf_info, arg,
+ sizeof(struct msm_stats_buf_info))) {
+ ERR_COPY_FROM_USER();
+ return -EFAULT;
+ }
+ cfgcmd.cmd_type = VFE_CMD_STATS_ENQUEUEBUF;
+ cfgcmd.value = (void *)&buf_info;
+ cfgcmd.length = sizeof(struct msm_stats_buf_info);
+ rc = msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
+ break;
+ }
+ case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ: {
+ struct msm_stats_flush_bufq bufq_info;
+
+ if (copy_from_user(&bufq_info, arg,
+ sizeof(struct msm_stats_flush_bufq))) {
+ ERR_COPY_FROM_USER();
+ return -EFAULT;
+ }
+ cfgcmd.cmd_type = VFE_CMD_STATS_FLUSH_BUFQ;
+ cfgcmd.value = (void *)&bufq_info;
+ cfgcmd.length = sizeof(struct msm_stats_flush_bufq);
+ rc = msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
+ break;
+ }
+ default:
+ rc = -1;
+ break;
+ }
+ CDBG("%s\n", __func__);
+ return rc;
+}
/* config function simliar to origanl msm_ioctl_config*/
static int msm_isp_config(struct msm_cam_media_controller *pmctl,
unsigned int cmd, unsigned long arg)
@@ -789,6 +756,12 @@
rc = msm_put_stats_buffer(sd, pmctl, argp);
break;
+ case MSM_CAM_IOCTL_STATS_REQBUF:
+ case MSM_CAM_IOCTL_STATS_ENQUEUEBUF:
+ case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ:
+ rc = msm_vfe_stats_buf_ioctl(sd, cmd, pmctl, argp);
+ break;
+
default:
break;
}
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index fa985ce..2331fcc 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -365,6 +365,229 @@
"DEMOSAICV3_UPDATE",
};
+
+static unsigned long vfe31_stats_dqbuf(enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_meta_buf *buf = NULL;
+ int rc = 0;
+ rc = vfe31_ctrl->stats_ops.dqbuf(vfe31_ctrl->stats_ops.stats_ctrl,
+ stats_type, &buf);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+ return buf->paddr;
+}
+
+static unsigned long vfe31_stats_flush_enqueue(
+ enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ int rc = 0;
+ int i;
+ /*
+ * Passing NULL for ion client as the buffers are already
+ * mapped at this stage, client is not required, flush all
+ * the buffers, and buffers move to PREPARE state
+ */
+
+ rc = vfe31_ctrl->stats_ops.bufq_flush(
+ vfe31_ctrl->stats_ops.stats_ctrl, stats_type, NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+
+ /* Queue all the buffers back to QUEUED state */
+ bufq = vfe31_ctrl->stats_ctrl.bufq[stats_type];
+ for (i = 0; i < bufq->num_bufs; i++) {
+ stats_buf = &bufq->bufs[i];
+ rc = vfe31_ctrl->stats_ops.enqueue_buf(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ &(stats_buf->info), NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return rc;
+ }
+ }
+ return 0L;
+}
+
+static int vfe_stats_awb_buf_init(
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq awb ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq awb ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_aec_buf_init(
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq aec ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase +
+ VFE_BUS_STATS_AEC_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq aec pong buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase +
+ VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_af_buf_init(
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ rc = vfe31_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ return -EINVAL;
+ }
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq af ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq af pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_ihist_buf_init(
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq ihist ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq ihist pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq rs ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq rs pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq cs ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq cs pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
+ return 0;
+}
+
static void vfe31_stop(void)
{
uint8_t axiBusyFlag = true;
@@ -600,101 +823,6 @@
return 0;
}
-static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
- vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
-static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR);
-
- vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
-static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
-
- vfe31_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
-static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
-
- vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
-static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
-
- vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
-static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
-
- vfe31_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
static void msm_camera_io_dump2(void __iomem *addr, int size)
{
char line_str[BUFF_SIZE_128], *p_str;
@@ -1388,6 +1516,12 @@
break;
case VFE_CMD_STATS_AE_START:
+ rc = vfe_stats_aec_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AEC",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1408,6 +1542,12 @@
cmdp, (vfe31_cmd[cmd->id].length));
break;
case VFE_CMD_STATS_AF_START:
+ rc = vfe_stats_af_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AF",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1428,6 +1568,12 @@
cmdp, (vfe31_cmd[cmd->id].length));
break;
case VFE_CMD_STATS_AWB_START:
+ rc = vfe_stats_awb_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AWB",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1449,6 +1595,12 @@
break;
case VFE_CMD_STATS_IHIST_START:
+ rc = vfe_stats_ihist_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of IHIST",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1470,6 +1622,12 @@
break;
case VFE_CMD_STATS_RS_START:
+ rc = vfe_stats_rs_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of RS",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1487,6 +1645,12 @@
break;
case VFE_CMD_STATS_CS_START:
+ rc = vfe_stats_cs_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of CS",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1987,6 +2151,12 @@
old_val &= ~AF_BF_ENABLE_MASK;
msm_camera_io_w(old_val,
vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ rc = vfe31_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ return -EINVAL;
+ }
break;
case VFE_CMD_STATS_IHIST_STOP:
@@ -2172,76 +2342,6 @@
return rc;
}
-static void vfe31_stats_af_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->af_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->afStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_awb_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->awb_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->awbStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_aec_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->aec_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->aecStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->ihist_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->ihistStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-static void vfe31_stats_rs_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->rs_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->rsStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-static void vfe31_stats_cs_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->cs_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->csStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
static inline void vfe31_read_irq_status(struct vfe31_irq_status *out)
{
uint32_t *temp;
@@ -2810,7 +2910,8 @@
static void
vfe_send_stats_msg(uint32_t bufAddress, uint32_t statsNum)
{
- unsigned long flags;
+ int rc = 0;
+ void *vaddr = NULL;
/* fill message with right content. */
/* @todo This is causing issues, need further investigate */
/* spin_lock_irqsave(&ctrl->state_lock, flags); */
@@ -2821,55 +2922,72 @@
switch (statsNum) {
case STATS_AE_NUM:{
msgStats.id = MSG_ID_STATS_AEC;
- spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
- vfe31_ctrl->aecStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AEC, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
case STATS_AF_NUM:{
msgStats.id = MSG_ID_STATS_AF;
- spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
- vfe31_ctrl->afStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AF, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
case STATS_AWB_NUM: {
msgStats.id = MSG_ID_STATS_AWB;
- spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
- vfe31_ctrl->awbStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AWB, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
case STATS_IHIST_NUM: {
msgStats.id = MSG_ID_STATS_IHIST;
- spin_lock_irqsave(&vfe31_ctrl->ihist_ack_lock, flags);
- vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->ihist_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_IHIST, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
case STATS_RS_NUM: {
msgStats.id = MSG_ID_STATS_RS;
- spin_lock_irqsave(&vfe31_ctrl->rs_ack_lock, flags);
- vfe31_ctrl->rsStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->rs_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_RS, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
case STATS_CS_NUM: {
msgStats.id = MSG_ID_STATS_CS;
- spin_lock_irqsave(&vfe31_ctrl->cs_ack_lock, flags);
- vfe31_ctrl->csStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->cs_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_CS, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
default:
goto stats_done;
}
-
- v4l2_subdev_notify(&vfe31_ctrl->subdev,
- NOTIFY_VFE_MSG_STATS,
- &msgStats);
+ if (rc == 0) {
+ msgStats.buffer = (uint32_t)vaddr;
+ v4l2_subdev_notify(&vfe31_ctrl->subdev,
+ NOTIFY_VFE_MSG_STATS, &msgStats);
+ } else {
+ pr_err("%s: paddr to idx mapping error, stats_id = %d,\n"
+ "paddr = 0x%d\n", __func__,
+ msgStats.id, msgStats.buffer);
+ }
stats_done:
/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
return;
@@ -2901,17 +3019,18 @@
static void vfe31_process_stats_ae_irq(void)
{
unsigned long flags;
- spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
- if (!(vfe31_ctrl->aecStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe31_ctrl->aecStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AE_NUM,
- vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe31_ctrl->aecStatsControl.bufToRender,
STATS_AE_NUM);
} else{
- spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe31_ctrl->aecStatsControl.droppedStatsFrameCount);
@@ -2921,17 +3040,18 @@
static void vfe31_process_stats_awb_irq(void)
{
unsigned long flags;
- spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
- if (!(vfe31_ctrl->awbStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe31_ctrl->awbStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AWB_NUM,
- vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe31_ctrl->awbStatsControl.bufToRender,
STATS_AWB_NUM);
} else{
- spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe31_ctrl->awbStatsControl.droppedStatsFrameCount);
@@ -2941,17 +3061,18 @@
static void vfe31_process_stats_af_irq(void)
{
unsigned long flags;
- spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
- if (!(vfe31_ctrl->afStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe31_ctrl->afStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AF_NUM,
- vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe31_ctrl->afStatsControl.bufToRender,
STATS_AF_NUM);
} else{
- spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
vfe31_ctrl->afStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe31_ctrl->afStatsControl.droppedStatsFrameCount);
@@ -2960,27 +3081,35 @@
static void vfe31_process_stats_ihist_irq(void)
{
- if (!(vfe31_ctrl->ihistStatsControl.ackPending)) {
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe31_ctrl->ihistStatsControl.bufToRender =
- vfe31_process_stats_irq_common(STATS_IHIST_NUM,
- vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
-
+ vfe31_process_stats_irq_common(STATS_IHIST_NUM,
+ addr);
vfe_send_stats_msg(vfe31_ctrl->ihistStatsControl.bufToRender,
- STATS_IHIST_NUM);
+ STATS_IHIST_NUM);
} else {
vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
- vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount);
+ vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount);
}
}
static void vfe31_process_stats_rs_irq(void)
{
- if (!(vfe31_ctrl->rsStatsControl.ackPending)) {
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe31_ctrl->rsStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_RS_NUM,
- vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
-
+ addr);
vfe_send_stats_msg(vfe31_ctrl->rsStatsControl.bufToRender,
STATS_RS_NUM);
} else {
@@ -2992,12 +3121,29 @@
static void vfe31_process_stats_cs_irq(void)
{
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe31_ctrl->csStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_CS_NUM,
+ addr);
+ vfe_send_stats_msg(
+ vfe31_ctrl->csStatsControl.bufToRender,
+ STATS_CS_NUM);
+ } else {
+ vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->csStatsControl.droppedStatsFrameCount);
+ }
if (!(vfe31_ctrl->csStatsControl.ackPending)) {
vfe31_ctrl->csStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_CS_NUM,
- vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
-
- vfe_send_stats_msg(vfe31_ctrl->csStatsControl.bufToRender,
+ vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+ vfe_send_stats_msg(
+ vfe31_ctrl->csStatsControl.bufToRender,
STATS_CS_NUM);
} else {
vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3010,15 +3156,16 @@
{
unsigned long flags;
int32_t process_stats = false;
+ uint32_t addr;
CDBG("%s, stats = 0x%x\n", __func__, status_bits);
- spin_lock_irqsave(&vfe31_ctrl->comp_stats_ack_lock, flags);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
- if (!vfe31_ctrl->aecStatsControl.ackPending) {
- vfe31_ctrl->aecStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+ if (addr) {
vfe31_ctrl->aecStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AE_NUM,
- vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else{
vfe31_ctrl->aecStatsControl.bufToRender = 0;
@@ -3029,11 +3176,11 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
- if (!vfe31_ctrl->awbStatsControl.ackPending) {
- vfe31_ctrl->awbStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+ if (addr) {
vfe31_ctrl->awbStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AWB_NUM,
- vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else{
vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
@@ -3045,11 +3192,11 @@
if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
- if (!vfe31_ctrl->afStatsControl.ackPending) {
- vfe31_ctrl->afStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+ if (addr) {
vfe31_ctrl->afStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AF_NUM,
- vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe31_ctrl->afStatsControl.bufToRender = 0;
@@ -3060,11 +3207,11 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
- if (!vfe31_ctrl->ihistStatsControl.ackPending) {
- vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+ if (addr) {
vfe31_ctrl->ihistStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_IHIST_NUM,
- vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
@@ -3075,11 +3222,11 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
- if (!vfe31_ctrl->rsStatsControl.ackPending) {
- vfe31_ctrl->rsStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+ if (!addr) {
vfe31_ctrl->rsStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_RS_NUM,
- vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++;
@@ -3091,11 +3238,11 @@
if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
- if (!vfe31_ctrl->csStatsControl.ackPending) {
- vfe31_ctrl->csStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+ if (addr) {
vfe31_ctrl->csStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_CS_NUM,
- vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3105,13 +3252,91 @@
vfe31_ctrl->csStatsControl.bufToRender = 0;
}
- spin_unlock_irqrestore(&vfe31_ctrl->comp_stats_ack_lock, flags);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
if (process_stats)
vfe_send_comp_stats_msg(status_bits);
return;
}
+static long vfe_stats_bufq_sub_ioctl(struct msm_vfe_cfg_cmd *cmd,
+ void *ion_client)
+{
+ long rc = 0;
+ switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ if (!vfe31_ctrl->stats_ops.stats_ctrl) {
+ /* stats_ctrl has not been init yet */
+ rc = msm_stats_buf_ops_init(&vfe31_ctrl->stats_ctrl,
+ (struct ion_client *)ion_client,
+ &vfe31_ctrl->stats_ops);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats ops", __func__);
+ goto end;
+ }
+ rc = vfe31_ctrl->stats_ops.stats_ctrl_init(
+ &vfe31_ctrl->stats_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats_ctrl ops", __func__);
+ memset(&vfe31_ctrl->stats_ops, 0,
+ sizeof(vfe31_ctrl->stats_ops));
+ goto end;
+ }
+ if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats reqbuf input size = %d,\n"
+ "struct size = %d, mis match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_reqbuf));
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+ rc = vfe31_ctrl->stats_ops.reqbuf(&vfe31_ctrl->stats_ctrl,
+ (struct msm_stats_reqbuf *)cmd->value,
+ vfe31_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats enqueuebuf input size = %d,\n"
+ "struct size = %d, mis match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_buf_info));
+ rc = -EINVAL ;
+ goto end;
+ }
+ rc = vfe31_ctrl->stats_ops.enqueue_buf(&vfe31_ctrl->stats_ctrl,
+ (struct msm_stats_buf_info *)cmd->value,
+ vfe31_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_FLUSH_BUFQ: {
+ struct msm_stats_flush_bufq *flush_req = NULL;
+ flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+ if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats flush queue input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_flush_bufq));
+ rc = -EINVAL ;
+ goto end;
+ }
+ rc = vfe31_ctrl->stats_ops.bufq_flush(&vfe31_ctrl->stats_ctrl,
+ (enum msm_stats_enum_type)flush_req->stats_type,
+ vfe31_ctrl->stats_ops.client);
+ }
+ break;
+ default:
+ rc = -1;
+ pr_err("%s: cmd_type %d not supported", __func__,
+ cmd->cmd_type);
+ break;
+ }
+end:
+ return rc;
+}
+
static void vfe31_process_stats_irq(uint32_t *irqstatus)
{
uint32_t status_bits = VFE_COM_STATUS & *irqstatus;
@@ -3334,44 +3559,55 @@
void *data = vfe_params->data;
long rc = 0;
- uint32_t i = 0;
struct vfe_cmd_stats_buf *scfg = NULL;
- struct msm_pmem_region *regptr = NULL;
struct vfe_cmd_stats_ack *sack = NULL;
- if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
- cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
- cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
- cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
- if (NULL != cmd->value) {
- if (copy_from_user(&vfecmd,
- (void __user *)(cmd->value),
- sizeof(vfecmd))) {
- pr_err("%s %d: copy_from_user failed\n",
- __func__, __LINE__);
- return -EFAULT;
- }
- }
- } else {
- /* here eith stats release or frame release. */
+
+ switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ case VFE_CMD_STATS_FLUSH_BUFQ:
+ /* for easy porting put in one envelope */
+ rc = vfe_stats_bufq_sub_ioctl(cmd, vfe_params->data);
+ return rc;
+ default:
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+ cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+ if (copy_from_user(&vfecmd,
+ (void __user *)(cmd->value),
+ sizeof(vfecmd))) {
+ pr_err("%s %d: copy_from_user failed\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ } else {
+ /* here eith stats release or frame release. */
if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
/* then must be stats release. */
- if (!data)
+ if (!data) {
+ pr_err("%s: data = NULL, cmd->cmd_type = %d",
+ __func__, cmd->cmd_type);
return -EFAULT;
+ }
sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
GFP_ATOMIC);
- if (!sack)
+ if (!sack) {
+ pr_err("%s: no mem for cmd->cmd_type = %d",
+ __func__, cmd->cmd_type);
return -ENOMEM;
+ }
sack->nextStatsBuf = *(uint32_t *)data;
}
- }
+ }
CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
@@ -3381,53 +3617,7 @@
(cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
(cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
- struct axidata *axid;
- axid = data;
- if (!axid) {
- rc = -EFAULT;
- goto vfe31_config_done;
- }
-
- scfg =
- kmalloc(sizeof(struct vfe_cmd_stats_buf),
- GFP_ATOMIC);
- if (!scfg) {
- rc = -ENOMEM;
- goto vfe31_config_done;
- }
- regptr = axid->region;
- if (axid->bufnum1 > 0) {
- for (i = 0; i < axid->bufnum1; i++) {
- scfg->statsBuf[i] =
- (uint32_t)(regptr->paddr);
- regptr++;
- }
- }
- /* individual */
- switch (cmd->cmd_type) {
- case CMD_STATS_AEC_ENABLE:
- rc = vfe_stats_aec_buf_init(scfg);
- break;
- case CMD_STATS_AF_ENABLE:
- rc = vfe_stats_af_buf_init(scfg);
- break;
- case CMD_STATS_AWB_ENABLE:
- rc = vfe_stats_awb_buf_init(scfg);
- break;
- case CMD_STATS_IHIST_ENABLE:
- rc = vfe_stats_ihist_buf_init(scfg);
- break;
- case CMD_STATS_RS_ENABLE:
- rc = vfe_stats_rs_buf_init(scfg);
- break;
- case CMD_STATS_CS_ENABLE:
- rc = vfe_stats_cs_buf_init(scfg);
- break;
- default:
- pr_err("%s Unsupported cmd type %d",
- __func__, cmd->cmd_type);
- break;
- }
+ scfg = NULL;
goto vfe31_config_done;
}
switch (cmd->cmd_type) {
@@ -3459,36 +3649,6 @@
case CMD_SNAP_BUF_RELEASE:
break;
- case CMD_STATS_AEC_BUF_RELEASE: {
- vfe31_stats_aec_ack(sack);
- }
- break;
-
- case CMD_STATS_AF_BUF_RELEASE: {
- vfe31_stats_af_ack(sack);
- }
- break;
-
- case CMD_STATS_AWB_BUF_RELEASE: {
- vfe31_stats_awb_ack(sack);
- }
- break;
-
- case CMD_STATS_IHIST_BUF_RELEASE: {
- vfe31_stats_ihist_ack(sack);
- }
- break;
-
- case CMD_STATS_RS_BUF_RELEASE: {
- vfe31_stats_rs_ack(sack);
- }
- break;
-
- case CMD_STATS_CS_BUF_RELEASE: {
- vfe31_stats_cs_ack(sack);
- }
- break;
-
case CMD_AXI_CFG_PRIM: {
uint32_t *axio = NULL;
axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
@@ -3607,6 +3767,7 @@
pr_err("%s Unsupported AXI configuration %x ", __func__,
cmd->cmd_type);
break;
+ }
}
vfe31_config_done:
kfree(scfg);
@@ -3714,17 +3875,10 @@
spin_lock_init(&vfe31_ctrl->stop_flag_lock);
spin_lock_init(&vfe31_ctrl->state_lock);
+ spin_lock_init(&vfe31_ctrl->stats_bufq_lock);
spin_lock_init(&vfe31_ctrl->io_lock);
spin_lock_init(&vfe31_ctrl->update_ack_lock);
spin_lock_init(&vfe31_ctrl->tasklet_lock);
-
- spin_lock_init(&vfe31_ctrl->aec_ack_lock);
- spin_lock_init(&vfe31_ctrl->awb_ack_lock);
- spin_lock_init(&vfe31_ctrl->af_ack_lock);
- spin_lock_init(&vfe31_ctrl->ihist_ack_lock);
- spin_lock_init(&vfe31_ctrl->rs_ack_lock);
- spin_lock_init(&vfe31_ctrl->cs_ack_lock);
- spin_lock_init(&vfe31_ctrl->comp_stats_ack_lock);
spin_lock_init(&vfe31_ctrl->sd_notify_lock);
INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.h b/drivers/media/video/msm/msm_vfe31_v4l2.h
index 739d157..2cba995 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.h
@@ -15,6 +15,7 @@
#define __MSM_VFE31_V4L2_H__
#include <linux/bitops.h>
+#include "msm_vfe_stats_buf.h"
#ifndef TRUE
#define TRUE 1
@@ -862,14 +863,7 @@
spinlock_t update_ack_lock;
spinlock_t state_lock;
spinlock_t io_lock;
-
- spinlock_t aec_ack_lock;
- spinlock_t awb_ack_lock;
- spinlock_t af_ack_lock;
- spinlock_t ihist_ack_lock;
- spinlock_t rs_ack_lock;
- spinlock_t cs_ack_lock;
- spinlock_t comp_stats_ack_lock;
+ spinlock_t stats_bufq_lock;
uint32_t extlen;
void *extdata;
@@ -930,6 +924,8 @@
uint32_t frame_skip_cnt;
uint32_t frame_skip_pattern;
uint32_t snapshot_frame_cnt;
+ struct msm_stats_bufq_ctrl stats_ctrl;
+ struct msm_stats_ops stats_ops;
};
enum VFE31_STATS_NUM {
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 3ac4c6a..621a016 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -624,116 +624,248 @@
return 0;
}
-static uint32_t vfe_stats_awb_buf_init(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static unsigned long vfe32_stats_dqbuf(struct vfe32_ctrl_type *vfe32_ctrl,
+ enum msm_stats_enum_type stats_type)
{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
+ struct msm_stats_meta_buf *buf = NULL;
+ int rc = 0;
+ rc = vfe32_ctrl->stats_ops.dqbuf(
+ vfe32_ctrl->stats_ops.stats_ctrl, stats_type, &buf);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+ return buf->paddr;
+}
- addr = ptr[0];
+static unsigned long vfe32_stats_flush_enqueue(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ int rc = 0;
+ int i;
+
+ /*
+ * Passing NULL for ion client as the buffers are already
+ * mapped at this stage, client is not required, flush all
+ * the buffers, and buffers move to PREPARE state
+ */
+
+ rc = vfe32_ctrl->stats_ops.bufq_flush(
+ vfe32_ctrl->stats_ops.stats_ctrl, stats_type, NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+ /* Queue all the buffers back to QUEUED state */
+ bufq = vfe32_ctrl->stats_ctrl.bufq[stats_type];
+ for (i = 0; i < bufq->num_bufs; i++) {
+ stats_buf = &bufq->bufs[i];
+ rc = vfe32_ctrl->stats_ops.enqueue_buf(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ &(stats_buf->info), NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return rc;
+ }
+ }
+ return 0L;
+}
+
+static int vfe_stats_awb_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq awb ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AWB_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq awb ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AWB_WR_PONG_ADDR);
- vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_aec_buf_init(
+static int vfe_stats_aec_buf_init(
struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
{
- uint32_t *ptr = in->statsBuf;
uint32_t addr;
+ unsigned long flags;
- addr = ptr[0];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq aec ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AEC_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq aec pong buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AEC_WR_PONG_ADDR);
-
- vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_af_buf_init(
+static int vfe_stats_af_buf_init(
struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
{
- uint32_t *ptr = in->statsBuf;
uint32_t addr;
+ unsigned long flags;
+ int rc = 0;
- addr = ptr[0];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ rc = vfe32_stats_flush_enqueue(vfe32_ctrl, MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ return -EINVAL;
+ }
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq af ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AF_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq af pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AF_WR_PONG_ADDR);
- vfe32_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_ihist_buf_init(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_ihist_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ struct vfe_cmd_stats_buf *in)
{
- uint32_t *ptr = in->statsBuf;
uint32_t addr;
+ unsigned long flags;
- addr = ptr[0];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq ihist ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_HIST_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq ihist pong buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_HIST_WR_PONG_ADDR);
- vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_rs_buf_init(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_rs_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ struct vfe_cmd_stats_buf *in)
{
- uint32_t *ptr = in->statsBuf;
uint32_t addr;
+ unsigned long flags;
- addr = ptr[0];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq rs ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_RS_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq rs pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_RS_WR_PONG_ADDR);
-
- vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_cs_buf_init(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_cs_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ struct vfe_cmd_stats_buf *in)
{
- uint32_t *ptr = in->statsBuf;
uint32_t addr;
-
- addr = ptr[0];
+ unsigned long flags;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq cs ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_CS_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq cs pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_CS_WR_PONG_ADDR);
-
- vfe32_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
@@ -1614,6 +1746,12 @@
break;
case VFE_CMD_STATS_AE_START: {
+ rc = vfe_stats_aec_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AEC",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1637,6 +1775,12 @@
}
break;
case VFE_CMD_STATS_AF_START: {
+ rc = vfe_stats_af_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AF",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1660,6 +1804,12 @@
}
break;
case VFE_CMD_STATS_AWB_START: {
+ rc = vfe_stats_awb_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AWB",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1684,6 +1834,12 @@
break;
case VFE_CMD_STATS_IHIST_START: {
+ rc = vfe_stats_ihist_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of IHIST",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1709,6 +1865,12 @@
case VFE_CMD_STATS_RS_START: {
+ rc = vfe_stats_rs_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of RS",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1728,6 +1890,12 @@
break;
case VFE_CMD_STATS_CS_START: {
+ rc = vfe_stats_cs_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of CS",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -2430,6 +2598,12 @@
old_val &= ~AF_BF_ENABLE_MASK;
msm_camera_io_w(old_val,
vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ rc = vfe32_stats_flush_enqueue(vfe32_ctrl, MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ return -EINVAL;
+ }
}
break;
@@ -2808,82 +2982,6 @@
return rc;
}
-static void vfe32_stats_af_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->af_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->afStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_awb_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->awb_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->awbStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_aec_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->aec_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->aecStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_ihist_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->ihist_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->ihistStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-static void vfe32_stats_rs_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->rs_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->rsStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-static void vfe32_stats_cs_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->cs_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->csStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
static inline void vfe32_read_irq_status(
struct axi_ctrl_t *axi_ctrl, struct vfe32_irq_status *out)
{
@@ -3653,70 +3751,87 @@
return returnAddr;
}
-static void
-vfe_send_stats_msg(struct vfe32_ctrl_type *vfe32_ctrl,
+static void vfe_send_stats_msg(
+ struct vfe32_ctrl_type *vfe32_ctrl,
uint32_t bufAddress, uint32_t statsNum)
{
- unsigned long flags;
+ int rc = 0;
+ void *vaddr = NULL;
/* fill message with right content. */
/* @todo This is causing issues, need further investigate */
/* spin_lock_irqsave(&ctrl->state_lock, flags); */
struct isp_msg_stats msgStats;
msgStats.frameCounter = vfe32_ctrl->share_ctrl->vfeFrameId;
msgStats.buffer = bufAddress;
-
switch (statsNum) {
case statsAeNum:{
msgStats.id = MSG_ID_STATS_AEC;
- spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
- vfe32_ctrl->aecStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AEC, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
case statsAfNum:{
msgStats.id = MSG_ID_STATS_AF;
- spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
- vfe32_ctrl->afStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AF, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
case statsAwbNum: {
msgStats.id = MSG_ID_STATS_AWB;
- spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
- vfe32_ctrl->awbStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AWB, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
case statsIhistNum: {
msgStats.id = MSG_ID_STATS_IHIST;
- spin_lock_irqsave(&vfe32_ctrl->ihist_ack_lock, flags);
- vfe32_ctrl->ihistStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->ihist_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_IHIST, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
case statsRsNum: {
msgStats.id = MSG_ID_STATS_RS;
- spin_lock_irqsave(&vfe32_ctrl->rs_ack_lock, flags);
- vfe32_ctrl->rsStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->rs_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_RS, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
case statsCsNum: {
msgStats.id = MSG_ID_STATS_CS;
- spin_lock_irqsave(&vfe32_ctrl->cs_ack_lock, flags);
- vfe32_ctrl->csStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->cs_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_CS, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
default:
goto stats_done;
}
-
- v4l2_subdev_notify(&vfe32_ctrl->subdev,
- NOTIFY_VFE_MSG_STATS,
- &msgStats);
+ if (rc == 0) {
+ msgStats.buffer = (uint32_t)vaddr;
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
+ NOTIFY_VFE_MSG_STATS,
+ &msgStats);
+ } else {
+ pr_err("%s: paddr to idx mapping error, stats_id = %d, paddr = 0x%d",
+ __func__, msgStats.id, msgStats.buffer);
+ }
stats_done:
/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
return;
@@ -3751,17 +3866,18 @@
static void vfe32_process_stats_ae_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
- spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
- if (!(vfe32_ctrl->aecStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->aecStatsControl.bufToRender =
vfe32_process_stats_irq_common(vfe32_ctrl, statsAeNum,
- vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe32_ctrl,
vfe32_ctrl->aecStatsControl.bufToRender, statsAeNum);
} else{
- spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
vfe32_ctrl->aecStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe32_ctrl->aecStatsControl.droppedStatsFrameCount);
@@ -3771,17 +3887,18 @@
static void vfe32_process_stats_awb_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
- spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
- if (!(vfe32_ctrl->awbStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->awbStatsControl.bufToRender =
vfe32_process_stats_irq_common(vfe32_ctrl, statsAwbNum,
- vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe32_ctrl,
vfe32_ctrl->awbStatsControl.bufToRender, statsAwbNum);
} else{
- spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe32_ctrl->awbStatsControl.droppedStatsFrameCount);
@@ -3791,17 +3908,18 @@
static void vfe32_process_stats_af_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
- spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
- if (!(vfe32_ctrl->afStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->afStatsControl.bufToRender =
vfe32_process_stats_irq_common(vfe32_ctrl, statsAfNum,
- vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe32_ctrl,
vfe32_ctrl->afStatsControl.bufToRender, statsAfNum);
} else{
- spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
vfe32_ctrl->afStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe32_ctrl->afStatsControl.droppedStatsFrameCount);
@@ -3810,11 +3928,15 @@
static void vfe32_process_stats_ihist_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
- if (!(vfe32_ctrl->ihistStatsControl.ackPending)) {
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->ihistStatsControl.bufToRender =
vfe32_process_stats_irq_common(
- vfe32_ctrl, statsIhistNum,
- vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
+ vfe32_ctrl, statsIhistNum, addr);
vfe_send_stats_msg(vfe32_ctrl,
vfe32_ctrl->ihistStatsControl.bufToRender,
@@ -3828,10 +3950,15 @@
static void vfe32_process_stats_rs_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
- if (!(vfe32_ctrl->rsStatsControl.ackPending)) {
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->rsStatsControl.bufToRender =
vfe32_process_stats_irq_common(vfe32_ctrl, statsRsNum,
- vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe32_ctrl,
vfe32_ctrl->rsStatsControl.bufToRender, statsRsNum);
@@ -3844,13 +3971,19 @@
static void vfe32_process_stats_cs_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
- if (!(vfe32_ctrl->csStatsControl.ackPending)) {
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->csStatsControl.bufToRender =
vfe32_process_stats_irq_common(vfe32_ctrl, statsCsNum,
- vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
+ addr);
- vfe_send_stats_msg(vfe32_ctrl,
- vfe32_ctrl->csStatsControl.bufToRender, statsCsNum);
+ vfe_send_stats_msg(vfe32_ctrl,
+ vfe32_ctrl->csStatsControl.bufToRender,
+ statsCsNum);
} else {
vfe32_ctrl->csStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
@@ -3863,16 +3996,17 @@
{
unsigned long flags;
int32_t process_stats = false;
- CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+ uint32_t addr;
- spin_lock_irqsave(&vfe32_ctrl->comp_stats_ack_lock, flags);
+ CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
- if (!vfe32_ctrl->aecStatsControl.ackPending) {
- vfe32_ctrl->aecStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_AEC);
+ if (addr) {
vfe32_ctrl->aecStatsControl.bufToRender =
vfe32_process_stats_irq_common(
- vfe32_ctrl, statsAeNum,
- vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
+ vfe32_ctrl, statsAeNum, addr);
process_stats = true;
} else{
vfe32_ctrl->aecStatsControl.bufToRender = 0;
@@ -3883,12 +4017,13 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
- if (!vfe32_ctrl->awbStatsControl.ackPending) {
- vfe32_ctrl->awbStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_AWB);
+ if (addr) {
vfe32_ctrl->awbStatsControl.bufToRender =
vfe32_process_stats_irq_common(
vfe32_ctrl, statsAwbNum,
- vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else{
vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++;
@@ -3898,14 +4033,14 @@
vfe32_ctrl->awbStatsControl.bufToRender = 0;
}
-
if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
- if (!vfe32_ctrl->afStatsControl.ackPending) {
- vfe32_ctrl->afStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_AF);
+ if (addr) {
vfe32_ctrl->afStatsControl.bufToRender =
vfe32_process_stats_irq_common(
vfe32_ctrl, statsAfNum,
- vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe32_ctrl->afStatsControl.bufToRender = 0;
@@ -3916,12 +4051,13 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
- if (!vfe32_ctrl->ihistStatsControl.ackPending) {
- vfe32_ctrl->ihistStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_IHIST);
+ if (addr) {
vfe32_ctrl->ihistStatsControl.bufToRender =
vfe32_process_stats_irq_common(
vfe32_ctrl, statsIhistNum,
- vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe32_ctrl->ihistStatsControl.droppedStatsFrameCount++;
@@ -3932,12 +4068,13 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
- if (!vfe32_ctrl->rsStatsControl.ackPending) {
- vfe32_ctrl->rsStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_RS);
+ if (addr) {
vfe32_ctrl->rsStatsControl.bufToRender =
vfe32_process_stats_irq_common(
vfe32_ctrl, statsRsNum,
- vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe32_ctrl->rsStatsControl.droppedStatsFrameCount++;
@@ -3948,12 +4085,13 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
- if (!vfe32_ctrl->csStatsControl.ackPending) {
- vfe32_ctrl->csStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_CS);
+ if (addr) {
vfe32_ctrl->csStatsControl.bufToRender =
vfe32_process_stats_irq_common(
vfe32_ctrl, statsCsNum,
- vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe32_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3962,8 +4100,7 @@
} else {
vfe32_ctrl->csStatsControl.bufToRender = 0;
}
-
- spin_unlock_irqrestore(&vfe32_ctrl->comp_stats_ack_lock, flags);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
if (process_stats)
vfe_send_comp_stats_msg(vfe32_ctrl, status_bits);
@@ -4259,6 +4396,88 @@
return 0;
}
+static long vfe_stats_bufq_sub_ioctl(
+ struct vfe32_ctrl_type *vfe_ctrl,
+ struct msm_vfe_cfg_cmd *cmd, void *ion_client)
+{
+ long rc = 0;
+ switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ if (!vfe_ctrl->stats_ops.stats_ctrl) {
+ /* stats_ctrl has not been init yet */
+ rc = msm_stats_buf_ops_init(&vfe_ctrl->stats_ctrl,
+ (struct ion_client *)ion_client,
+ &vfe_ctrl->stats_ops);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats ops", __func__);
+ goto end;
+ }
+ rc = vfe_ctrl->stats_ops.stats_ctrl_init(&vfe_ctrl->stats_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats_ctrl ops", __func__);
+ memset(&vfe_ctrl->stats_ops, 0,
+ sizeof(vfe_ctrl->stats_ops));
+ goto end;
+ }
+ if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats reqbuf input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_reqbuf));
+ rc = -EINVAL ;
+ goto end;
+ }
+ }
+ rc = vfe_ctrl->stats_ops.reqbuf(
+ &vfe_ctrl->stats_ctrl,
+ (struct msm_stats_reqbuf *)cmd->value,
+ vfe_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats enqueuebuf input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_buf_info));
+ rc = -EINVAL;
+ goto end;
+ }
+ rc = vfe_ctrl->stats_ops.enqueue_buf(
+ &vfe_ctrl->stats_ctrl,
+ (struct msm_stats_buf_info *)cmd->value,
+ vfe_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_FLUSH_BUFQ:
+ {
+ struct msm_stats_flush_bufq *flush_req = NULL;
+ flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+ if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats flush queue input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_flush_bufq));
+ rc = -EINVAL;
+ goto end;
+ }
+ rc = vfe_ctrl->stats_ops.bufq_flush(
+ &vfe_ctrl->stats_ctrl,
+ (enum msm_stats_enum_type)flush_req->stats_type,
+ vfe_ctrl->stats_ops.client);
+ }
+ break;
+ default:
+ rc = -1;
+ pr_err("%s: cmd_type %d not supported", __func__,
+ cmd->cmd_type);
+ break;
+ }
+end:
+ return rc;
+}
+
static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int subdev_cmd, void *arg)
{
@@ -4273,9 +4492,7 @@
void *data = vfe_params->data;
long rc = 0;
- uint32_t i = 0;
struct vfe_cmd_stats_buf *scfg = NULL;
- struct msm_pmem_region *regptr = NULL;
struct vfe_cmd_stats_ack *sack = NULL;
if (!vfe32_ctrl->share_ctrl->vfebase) {
@@ -4283,151 +4500,100 @@
return -EFAULT;
}
- if (cmd->cmd_type == CMD_VFE_PROCESS_IRQ) {
+ switch (cmd->cmd_type) {
+ case CMD_VFE_PROCESS_IRQ:
vfe32_process_irq(vfe32_ctrl, (uint32_t) data);
return rc;
- } else if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
- cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
- cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
- cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
- if (copy_from_user(&vfecmd,
- (void __user *)(cmd->value),
- sizeof(vfecmd))) {
- pr_err("%s %d: copy_from_user failed\n", __func__,
- __LINE__);
- return -EFAULT;
- }
- } else {
- /* here eith stats release or frame release. */
+ case VFE_CMD_STATS_REQBUF:
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ case VFE_CMD_STATS_FLUSH_BUFQ:
+ /* for easy porting put in one envelope */
+ rc = vfe_stats_bufq_sub_ioctl(vfe32_ctrl,
+ cmd, vfe_params->data);
+ return rc;
+ default:
if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
- cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
- /* then must be stats release. */
- if (!data)
- return -EFAULT;
- sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+ cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+ if (copy_from_user(&vfecmd,
+ (void __user *)(cmd->value),
+ sizeof(vfecmd))) {
+ pr_err("%s %d: copy_from_user failed\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ } else {
+ /* here eith stats release or frame release. */
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
+ /* then must be stats release. */
+ if (!data) {
+ pr_err("%s: data = NULL, cmd->cmd_type = %d",
+ __func__, cmd->cmd_type);
+ return -EFAULT;
+ }
+ sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
GFP_ATOMIC);
- if (!sack)
- return -ENOMEM;
-
- sack->nextStatsBuf = *(uint32_t *)data;
- }
- }
-
- CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
-
- if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_AWB_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
- struct axidata *axid;
- axid = data;
- if (!axid) {
- rc = -EFAULT;
- goto vfe32_config_done;
- }
-
- scfg =
- kmalloc(sizeof(struct vfe_cmd_stats_buf),
- GFP_ATOMIC);
- if (!scfg) {
- rc = -ENOMEM;
- goto vfe32_config_done;
- }
- regptr = axid->region;
- if (axid->bufnum1 > 0) {
- for (i = 0; i < axid->bufnum1; i++) {
- scfg->statsBuf[i] =
- (uint32_t)(regptr->paddr);
- regptr++;
+ if (!sack) {
+ pr_err("%s: no mem for cmd->cmd_type = %d",
+ __func__, cmd->cmd_type);
+ return -ENOMEM;
+ }
+ sack->nextStatsBuf = *(uint32_t *)data;
}
}
- /* individual */
- switch (cmd->cmd_type) {
- case CMD_STATS_AEC_ENABLE:
- rc = vfe_stats_aec_buf_init(vfe32_ctrl, scfg);
- break;
- case CMD_STATS_AF_ENABLE:
- rc = vfe_stats_af_buf_init(vfe32_ctrl, scfg);
- break;
- case CMD_STATS_AWB_ENABLE:
- rc = vfe_stats_awb_buf_init(vfe32_ctrl, scfg);
- break;
- case CMD_STATS_IHIST_ENABLE:
- rc = vfe_stats_ihist_buf_init(vfe32_ctrl, scfg);
- break;
- case CMD_STATS_RS_ENABLE:
- rc = vfe_stats_rs_buf_init(vfe32_ctrl, scfg);
- break;
- case CMD_STATS_CS_ENABLE:
- rc = vfe_stats_cs_buf_init(vfe32_ctrl, scfg);
- break;
- default:
- pr_err("%s Unsupported cmd type %d",
- __func__, cmd->cmd_type);
- break;
+ CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+ if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AWB_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+ scfg = NULL;
+ /* individual */
+ goto vfe32_config_done;
}
- goto vfe32_config_done;
- }
- switch (cmd->cmd_type) {
- case CMD_GENERAL:
- rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
+ switch (cmd->cmd_type) {
+ case CMD_GENERAL:
+ rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
break;
- case CMD_CONFIG_PING_ADDR: {
- int path = *((int *)cmd->value);
- struct vfe32_output_ch *outch =
- vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
- outch->ping = *((struct msm_free_buf *)data);
- }
+ case CMD_CONFIG_PING_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+ outch->ping = *((struct msm_free_buf *)data);
+ }
+ break;
+ case CMD_CONFIG_PONG_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+ outch->pong = *((struct msm_free_buf *)data);
+ }
break;
- case CMD_CONFIG_PONG_ADDR: {
- int path = *((int *)cmd->value);
- struct vfe32_output_ch *outch =
- vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
- outch->pong = *((struct msm_free_buf *)data);
- }
+ case CMD_CONFIG_FREE_BUF_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+ outch->free_buf = *((struct msm_free_buf *)data);
+ }
break;
-
- case CMD_CONFIG_FREE_BUF_ADDR: {
- int path = *((int *)cmd->value);
- struct vfe32_output_ch *outch =
- vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
- outch->free_buf = *((struct msm_free_buf *)data);
- }
+ case CMD_SNAP_BUF_RELEASE:
break;
- case CMD_SNAP_BUF_RELEASE:
+ default:
+ pr_err("%s Unsupported AXI configuration %x ", __func__,
+ cmd->cmd_type);
break;
- case CMD_STATS_AEC_BUF_RELEASE:
- vfe32_stats_aec_ack(vfe32_ctrl, sack);
- break;
- case CMD_STATS_AF_BUF_RELEASE:
- vfe32_stats_af_ack(vfe32_ctrl, sack);
- break;
- case CMD_STATS_AWB_BUF_RELEASE:
- vfe32_stats_awb_ack(vfe32_ctrl, sack);
- break;
-
- case CMD_STATS_IHIST_BUF_RELEASE:
- vfe32_stats_ihist_ack(vfe32_ctrl, sack);
- break;
- case CMD_STATS_RS_BUF_RELEASE:
- vfe32_stats_rs_ack(vfe32_ctrl, sack);
- break;
- case CMD_STATS_CS_BUF_RELEASE:
- vfe32_stats_cs_ack(vfe32_ctrl, sack);
- break;
- default:
- pr_err("%s Unsupported AXI configuration %x ", __func__,
- cmd->cmd_type);
- break;
+ }
}
vfe32_config_done:
kfree(scfg);
@@ -4542,14 +4708,7 @@
spin_lock_init(&vfe32_ctrl->io_lock);
spin_lock_init(&vfe32_ctrl->update_ack_lock);
spin_lock_init(&vfe32_ctrl->start_ack_lock);
-
- spin_lock_init(&vfe32_ctrl->aec_ack_lock);
- spin_lock_init(&vfe32_ctrl->awb_ack_lock);
- spin_lock_init(&vfe32_ctrl->af_ack_lock);
- spin_lock_init(&vfe32_ctrl->ihist_ack_lock);
- spin_lock_init(&vfe32_ctrl->rs_ack_lock);
- spin_lock_init(&vfe32_ctrl->cs_ack_lock);
- spin_lock_init(&vfe32_ctrl->comp_stats_ack_lock);
+ spin_lock_init(&vfe32_ctrl->stats_bufq_lock);
vfe32_ctrl->update_linear = false;
vfe32_ctrl->update_rolloff = false;
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index c41df09..542bbf8 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -14,6 +14,7 @@
#define __MSM_VFE32_H__
#include <linux/bitops.h>
+#include "msm_vfe_stats_buf.h"
#define TRUE 1
#define FALSE 0
@@ -912,8 +913,6 @@
#define VFE32_OUTPUT_MODE_TERTIARY2 BIT(11)
struct vfe_stats_control {
- uint8_t ackPending;
- uint32_t nextFrameAddrBuf;
uint32_t droppedStatsFrameCount;
uint32_t bufToRender;
};
@@ -966,15 +965,7 @@
spinlock_t start_ack_lock;
spinlock_t state_lock;
spinlock_t io_lock;
-
- spinlock_t aec_ack_lock;
- spinlock_t awb_ack_lock;
- spinlock_t af_ack_lock;
- spinlock_t ihist_ack_lock;
- spinlock_t rs_ack_lock;
- spinlock_t cs_ack_lock;
- spinlock_t comp_stats_ack_lock;
-
+ spinlock_t stats_bufq_lock;
uint32_t extlen;
void *extdata;
@@ -1013,6 +1004,8 @@
uint32_t frame_skip_cnt;
uint32_t frame_skip_pattern;
uint32_t snapshot_frame_cnt;
+ struct msm_stats_bufq_ctrl stats_ctrl;
+ struct msm_stats_ops stats_ops;
};
#define statsAeNum 0
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 398621f..5fef610 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -351,6 +351,221 @@
static uint32_t raw_mode;
static struct vfe2x_ctrl_type *vfe2x_ctrl;
+static unsigned long vfe2x_stats_dqbuf(enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_meta_buf *buf = NULL;
+ int rc = 0;
+
+ rc = vfe2x_ctrl->stats_ops.dqbuf(vfe2x_ctrl->stats_ops.stats_ctrl,
+ stats_type, &buf);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0;
+ }
+ return buf->paddr;
+}
+
+static unsigned long vfe2x_stats_flush_enqueue(
+ enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ int rc = 0;
+ int i;
+
+ /*
+ * Passing NULL for ion client as the buffers are already
+ * mapped at this stage, client is not required, flush all
+ * the buffers, and buffers move to PREPARE state
+ */
+ rc = vfe2x_ctrl->stats_ops.bufq_flush(
+ vfe2x_ctrl->stats_ops.stats_ctrl,
+ stats_type, NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+
+ /* Queue all the buffers back to QUEUED state */
+ bufq = vfe2x_ctrl->stats_ctrl.bufq[stats_type];
+ for (i = 0; i < bufq->num_bufs; i++) {
+ stats_buf = &bufq->bufs[i];
+ rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+ vfe2x_ctrl->stats_ops.stats_ctrl,
+ &(stats_buf->info), NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return rc;
+ }
+ }
+ return 0L;
+}
+
+static int vfe2x_stats_buf_init(enum msm_stats_enum_type type)
+{
+ unsigned long flags;
+ int i = 0, rc = 0;
+ if (type == MSM_STATS_TYPE_AF) {
+ spin_lock_irqsave(&vfe2x_ctrl->stats_bufq_lock, flags);
+ rc = vfe2x_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock,
+ flags);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock, flags);
+ }
+ for (i = 0; i < 3; i++) {
+ spin_lock_irqsave(&vfe2x_ctrl->stats_bufq_lock, flags);
+ if (type == MSM_STATS_TYPE_AE_AW)
+ vfe2x_ctrl->stats_we_buf_ptr[i] =
+ vfe2x_stats_dqbuf(type);
+ else
+ vfe2x_ctrl->stats_af_buf_ptr[i] =
+ vfe2x_stats_dqbuf(type);
+ spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock, flags);
+ if (!vfe2x_ctrl->stats_we_buf_ptr[i]) {
+ pr_err("%s: dq error type %d ", __func__, type);
+ return -ENOMEM;
+ }
+ }
+ return rc;
+}
+
+static unsigned long vfe2x_stats_enqueuebuf(
+ struct msm_stats_buf_info *info, struct vfe_stats_ack *sack)
+{
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ struct msm_stats_meta_buf *buf = NULL;
+ int rc = 0;
+
+ bufq = vfe2x_ctrl->stats_ctrl.bufq[info->type];
+ stats_buf = &bufq->bufs[info->buf_idx];
+
+ CDBG("vfe2x_stats_enqueuebuf: %d\n", stats_buf->state);
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_INITIALIZED ||
+ stats_buf->state == MSM_STATS_BUFFER_STATE_PREPARED) {
+ rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+ &vfe2x_ctrl->stats_ctrl,
+ info, vfe2x_ctrl->stats_ops.client);
+ if (rc < 0) {
+ pr_err("%s: enqueue_buf (type = %d), index : %d, err = %d",
+ __func__, info->type, info->buf_idx, rc);
+ return rc;
+ }
+
+ } else {
+ rc = vfe2x_ctrl->stats_ops.querybuf(
+ vfe2x_ctrl->stats_ops.stats_ctrl, info, &buf);
+ if (rc < 0) {
+ pr_err("%s: querybuf (type = %d), index : %d, err = %d",
+ __func__, info->type, info->buf_idx, rc);
+ return rc;
+ }
+ stats_buf->state = MSM_STATS_BUFFER_STATE_DEQUEUED;
+ if (info->type == MSM_STATS_TYPE_AE_AW) {
+ sack->header = VFE_STATS_WB_EXP_ACK;
+ sack->bufaddr = (void *)(uint32_t *)buf->paddr;
+ } else if (info->type == MSM_STATS_TYPE_AF) {
+ sack->header = VFE_STATS_AUTOFOCUS_ACK;
+ sack->bufaddr = (void *)(uint32_t *)buf->paddr;
+ } else
+ pr_err("%s: Invalid stats: should never come here\n", __func__);
+ }
+ return 0L;
+}
+
+static long vfe2x_stats_bufq_sub_ioctl(struct msm_vfe_cfg_cmd *cmd,
+ void *ion_client)
+{
+ long rc = 0;
+
+ switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ if (!vfe2x_ctrl->stats_ops.stats_ctrl) {
+ /* stats_ctrl has not been init yet */
+ rc = msm_stats_buf_ops_init(
+ &vfe2x_ctrl->stats_ctrl,
+ (struct ion_client *)ion_client,
+ &vfe2x_ctrl->stats_ops);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats ops", __func__);
+ goto end;
+ }
+ rc = vfe2x_ctrl->stats_ops.stats_ctrl_init(
+ &vfe2x_ctrl->stats_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats_ctrl ops",
+ __func__);
+ memset(&vfe2x_ctrl->stats_ops, 0,
+ sizeof(vfe2x_ctrl->stats_ops));
+ goto end;
+ }
+ if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats reqbuf input size = %d,\n"
+ "struct size = %d, mismatch\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_reqbuf));
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+ rc = vfe2x_ctrl->stats_ops.reqbuf(
+ &vfe2x_ctrl->stats_ctrl,
+ (struct msm_stats_reqbuf *)cmd->value,
+ vfe2x_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_ENQUEUEBUF: {
+ if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats enqueuebuf input size = %d,\n"
+ "struct size = %d, mismatch\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_buf_info));
+ rc = -EINVAL;
+ goto end;
+ }
+ rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+ &vfe2x_ctrl->stats_ctrl,
+ (struct msm_stats_buf_info *)cmd->value,
+ vfe2x_ctrl->stats_ops.client);
+ }
+ break;
+ case VFE_CMD_STATS_FLUSH_BUFQ: {
+ struct msm_stats_flush_bufq *flush_req = NULL;
+ flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+ if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats flush queue input size = %d,\n"
+ "struct size = %d, mismatch\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_flush_bufq));
+ rc = -EINVAL;
+ goto end;
+ }
+ rc = vfe2x_ctrl->stats_ops.bufq_flush(
+ &vfe2x_ctrl->stats_ctrl,
+ (enum msm_stats_enum_type)flush_req->stats_type,
+ vfe2x_ctrl->stats_ops.client);
+ }
+ break;
+ default:
+ rc = -1;
+ pr_err("%s: cmd_type %d not supported",
+ __func__, cmd->cmd_type);
+ break;
+ }
+end:
+ return rc;
+}
+
static void vfe2x_send_isp_msg(
struct vfe2x_ctrl_type *vctrl,
uint32_t isp_msg_id)
@@ -384,11 +599,26 @@
static void vfe_send_stats_msg(uint32_t buf_addr, uint32_t msg_id)
{
struct isp_msg_stats msg_stats;
+ void *vaddr = NULL;
+ int rc;
msg_stats.frameCounter = vfe2x_ctrl->vfeFrameId;
msg_stats.buffer = buf_addr;
msg_stats.id = msg_id;
+ if (MSG_ID_STATS_AWB_AEC == msg_id)
+ rc = vfe2x_ctrl->stats_ops.dispatch(
+ vfe2x_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AE_AW, buf_addr,
+ &msg_stats.buf_idx, &vaddr, &msg_stats.fd,
+ vfe2x_ctrl->stats_ops.client);
+ else if (MSG_ID_STATS_AF == msg_id)
+ rc = vfe2x_ctrl->stats_ops.dispatch(
+ vfe2x_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AF, buf_addr,
+ &msg_stats.buf_idx, &vaddr, &msg_stats.fd,
+ vfe2x_ctrl->stats_ops.client);
+
v4l2_subdev_notify(&vfe2x_ctrl->subdev,
NOTIFY_VFE_MSG_STATS,
&msg_stats);
@@ -979,21 +1209,54 @@
CDBG("msm_vfe_subdev_ioctl is called\n");
if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
- cmd->cmd_type != CMD_VFE_BUFFER_RELEASE) {
+ cmd->cmd_type != CMD_VFE_BUFFER_RELEASE &&
+ cmd->cmd_type != VFE_CMD_STATS_REQBUF &&
+ cmd->cmd_type != VFE_CMD_STATS_FLUSH_BUFQ &&
+ cmd->cmd_type != VFE_CMD_STATS_ENQUEUEBUF) {
if (copy_from_user(&vfecmd,
- (void __user *)(cmd->value),
- sizeof(vfecmd))) {
+ (void __user *)(cmd->value),
+ sizeof(vfecmd))) {
pr_err("copy_from_user in msm_vfe_subdev_ioctl fail\n");
return -EFAULT;
}
}
-
switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ case VFE_CMD_STATS_FLUSH_BUFQ:
+ /* for easy porting put in one envelope */
+ rc = vfe2x_stats_bufq_sub_ioctl(cmd, vfe_params->data);
+ return rc;
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats enqueuebuf input size = %d,\n"
+ "struct size = %d, mitch match\n",\
+ __func__, cmd->length,
+ sizeof(struct msm_stats_buf_info));
+ rc = -EINVAL;
+ return rc;
+ }
+ sack.header = 0;
+ sack.bufaddr = NULL;
+ rc = vfe2x_stats_enqueuebuf(cmd->value, &sack);
+ if (rc < 0) {
+ pr_err("%s: error", __func__);
+ rc = -EINVAL;
+ return rc;
+ }
+ if (sack.header != 0 && sack.bufaddr != NULL) {
+ queue = QDSP_CMDQUEUE;
+ vfecmd.length = sizeof(struct vfe_stats_ack) - 4;
+ cmd_data = &sack;
+ } else {
+ return 0;
+ }
+ break;
case CMD_VFE_BUFFER_RELEASE: {
if (!(vfe2x_ctrl->vfe_started) || op_mode == 1)
return 0;
@@ -1041,7 +1304,6 @@
}
return 0;
- case CMD_STATS_AEC_AWB_ENABLE:
case CMD_STATS_AXI_CFG: {
axid = data;
if (!axid) {
@@ -1096,15 +1358,49 @@
}
}
break;
- case CMD_STATS_AF_ENABLE:
- case CMD_STATS_AF_AXI_CFG: {
- CDBG("CMD_STATS_AF_ENABLE CMD_STATS_AF_AXI_CFG\n");
- axid = data;
- if (!axid) {
- rc = -EFAULT;
+ case CMD_STATS_AEC_AWB_ENABLE: {
+ pr_err("CMD_STATS_AEC_AWB_ENABLE\n");
+ scfg =
+ kmalloc(sizeof(struct vfe_stats_we_cfg),
+ GFP_ATOMIC);
+ if (!scfg) {
+ rc = -ENOMEM;
goto config_failure;
}
+ if (copy_from_user((char *)scfg + 4,
+ (void __user *)(vfecmd.value),
+ vfecmd.length)) {
+
+ rc = -EFAULT;
+ goto config_done;
+ }
+
+ header = cmds_map[vfecmd.id].vfe_id;
+ queue = cmds_map[vfecmd.id].queue;
+ if (header == -1 && queue == -1) {
+ rc = -EFAULT;
+ goto config_failure;
+ }
+ *(uint32_t *)scfg = header;
+ rc = vfe2x_stats_buf_init(MSM_STATS_TYPE_AE_AW);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AWB",
+ __func__);
+ goto config_failure;
+ }
+ scfg->wb_expstatoutputbuffer[0] =
+ (void *)vfe2x_ctrl->stats_we_buf_ptr[0];
+ scfg->wb_expstatoutputbuffer[1] =
+ (void *)vfe2x_ctrl->stats_we_buf_ptr[1];
+ scfg->wb_expstatoutputbuffer[2] =
+ (void *)vfe2x_ctrl->stats_we_buf_ptr[2];
+ cmd_data = scfg;
+ }
+ break;
+ case CMD_STATS_AF_ENABLE:
+ case CMD_STATS_AF_AXI_CFG: {
+ CDBG("CMD_STATS_AF_ENABLE CMD_STATS_AF_AXI_CFG\n");
sfcfg =
kmalloc(sizeof(struct vfe_stats_af_cfg),
GFP_ATOMIC);
@@ -1122,9 +1418,6 @@
goto config_done;
}
- CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
- axid->bufnum1, sfcfg->af_enable);
-
header = cmds_map[vfecmd.id].vfe_id;
queue = cmds_map[vfecmd.id].queue;
if (header == -1 && queue == -1) {
@@ -1132,27 +1425,16 @@
goto config_failure;
}
*(uint32_t *)sfcfg = header;
- CDBG("Number of buffers = %d\n", axid->bufnum1);
- if (axid->bufnum1 > 0) {
- regptr = &axid->region[0];
-
- for (i = 0; i < axid->bufnum1; i++) {
-
- CDBG("STATS_ENABLE, phy = 0x%lx\n",
- regptr->paddr);
-
- sfcfg->af_outbuf[i] =
- (void *)regptr->paddr;
-
- regptr++;
- }
-
- cmd_data = sfcfg;
-
- } else {
- rc = -EINVAL;
- goto config_done;
+ rc = vfe2x_stats_buf_init(MSM_STATS_TYPE_AF);
+ sfcfg->af_outbuf[0] = (void *)vfe2x_ctrl->stats_af_buf_ptr[0];
+ sfcfg->af_outbuf[1] = (void *)vfe2x_ctrl->stats_af_buf_ptr[1];
+ sfcfg->af_outbuf[2] = (void *)vfe2x_ctrl->stats_af_buf_ptr[2];
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AWB",
+ __func__);
+ goto config_failure;
}
+ cmd_data = sfcfg;
}
break;
case CMD_SNAP_BUF_RELEASE:
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
index 2f2d3c6..b7d6806 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
@@ -16,6 +16,7 @@
#include <mach/camera.h>
#include <linux/list.h>
#include "msm.h"
+#include "msm_vfe_stats_buf.h"
struct cmd_id_map {
uint32_t isp_id;
@@ -111,6 +112,11 @@
spinlock_t sd_notify_lock;
uint32_t reconfig_vfe;
uint32_t zsl_mode;
+ spinlock_t stats_bufq_lock;
+ struct msm_stats_bufq_ctrl stats_ctrl;
+ struct msm_stats_ops stats_ops;
+ unsigned long stats_we_buf_ptr[3];
+ unsigned long stats_af_buf_ptr[3];
} __packed;
struct vfe_frame_extra {
diff --git a/drivers/media/video/msm/msm_vfe_stats_buf.c b/drivers/media/video/msm/msm_vfe_stats_buf.c
new file mode 100644
index 0000000..9e8f285
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe_stats_buf.c
@@ -0,0 +1,509 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+#include <linux/android_pmem.h>
+#include <media/msm_camera.h>
+#include <media/msm_isp.h>
+#include "msm.h"
+#include "msm_vfe_stats_buf.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+ #define D(fmt, args...) pr_debug("msm_stats: " fmt, ##args)
+#else
+ #define D(fmt, args...) do {} while (0)
+#endif
+
+static int msm_stats_init(struct msm_stats_bufq_ctrl *stats_ctrl)
+{
+ int rc = 0;
+ /* cannot get spinlock here */
+ if (stats_ctrl->init_done > 0) {
+ pr_err("%s: already initialized stats ctrl. no op", __func__);
+ return 0;
+ }
+ memset(stats_ctrl, 0, sizeof(struct msm_stats_bufq_ctrl));
+ spin_lock_init(&stats_ctrl->lock);
+ stats_ctrl->init_done = 1;
+ return rc;
+}
+
+static int msm_stats_reqbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_reqbuf *reqbuf,
+ struct ion_client *client)
+{
+ int rc = 0;
+ struct msm_stats_bufq *bufq;
+ struct msm_stats_meta_buf *bufs;
+ int idx = reqbuf->stats_type;
+ int i;
+
+ D("%s: type : %d, buf num : %d\n", __func__,
+ reqbuf->stats_type, reqbuf->num_buf);
+ if (reqbuf->num_buf > 0) {
+ if (stats_ctrl->bufq[idx]) {
+ /* already in use. Error */
+ pr_err("%s: stats type %d aleady requested",
+ __func__, reqbuf->stats_type);
+ rc = -EEXIST;
+ goto end;
+ } else {
+ /* good case */
+ bufq = (struct msm_stats_bufq *)
+ kzalloc(
+ sizeof(struct msm_stats_bufq),
+ GFP_KERNEL);
+ if (!bufq) {
+ /* no memory */
+ rc = -ENOMEM;
+ pr_err("%s: no mem for stats type %d",
+ __func__, reqbuf->stats_type);
+ goto end;
+ }
+ bufs = (struct msm_stats_meta_buf *)
+ kzalloc((reqbuf->num_buf *
+ sizeof(struct msm_stats_meta_buf)),
+ GFP_KERNEL);
+ if (!bufs) {
+ /* no memory */
+ rc = -ENOMEM;
+ pr_err("%s: no mem for stats buf, stats type = %d",
+ __func__, reqbuf->stats_type);
+ kfree(bufq);
+ goto end;
+ }
+ /* init bufq list head */
+ INIT_LIST_HEAD(&bufq->head);
+ /* set the meta buf state to initialized */
+ bufq->num_bufs = reqbuf->num_buf;
+ for (i = 0; i < reqbuf->num_buf; i++)
+ bufs[i].state =
+ MSM_STATS_BUFFER_STATE_INITIALIZED;
+ bufq->bufs = bufs;
+ bufq->num_bufs = reqbuf->num_buf;
+ bufq->type = reqbuf->stats_type;
+ stats_ctrl->bufq[idx] = bufq;
+ /* done reqbuf (larger than zero case) */
+ goto end;
+ }
+ } else if (reqbuf->num_buf == 0) {
+ if (stats_ctrl->bufq[idx] == NULL) {
+ /* double free case? */
+ pr_err("%s: stats type %d aleady freed",
+ __func__, reqbuf->stats_type);
+ rc = -ENXIO;
+ goto end;
+ } else {
+ /* good case. need to de-reqbuf */
+ kfree(stats_ctrl->bufq[idx]->bufs);
+ kfree(stats_ctrl->bufq[idx]);
+ stats_ctrl->bufq[idx] = NULL;
+ goto end;
+ }
+ } else {
+ /* error case */
+ pr_err("%s: stats type = %d, req_num_buf = %d, error",
+ __func__, reqbuf->stats_type, reqbuf->num_buf);
+ rc = -EPERM;
+ goto end;
+ }
+end:
+ return rc;
+}
+static int msm_stats_deinit(struct msm_stats_bufq_ctrl *stats_ctrl)
+{
+ int rc = 0;
+ int i;
+
+ if (stats_ctrl->init_done == 0) {
+ pr_err("%s: not inited yet. no op", __func__);
+ return 0;
+ }
+ /* safe guard in case deallocate memory not done yet. */
+ for (i = 0; i < MSM_STATS_TYPE_MAX; i++) {
+ if (stats_ctrl->bufq[i]) {
+ if (stats_ctrl->bufq[i]->bufs) {
+ rc = -1;
+ pr_err("%s: stats type = %d, buf not freed yet",
+ __func__, i);
+ BUG_ON(stats_ctrl->bufq[i]->bufs);
+ } else {
+ rc = -1;
+ pr_err("%s: stats type = %d, bufq not freed yet",
+ __func__, i);
+ BUG_ON(stats_ctrl->bufq[i]);
+ }
+ }
+ }
+ memset(stats_ctrl, 0, sizeof(struct msm_stats_bufq_ctrl));
+ return rc;
+}
+
+#ifdef CONFIG_ANDROID_PMEM
+static int msm_stats_check_pmem_info(struct msm_stats_buf_info *info, int len)
+{
+ if (info->offset < len &&
+ info->offset + info->len <= len &&
+ info->planar0_off < len && info->planar1_off < len)
+ return 0;
+
+ pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
+ __func__,
+ info->offset,
+ info->len,
+ info->planar0_off,
+ info->planar1_off,
+ len);
+ return -EINVAL;
+}
+#endif
+
+static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info, struct ion_client *client)
+{
+ unsigned long paddr;
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+ unsigned long kvstart;
+ struct file *file;
+#endif
+ int rc = 0;
+ unsigned long len;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+
+ D("%s: type : %d, buf num : %d\n", __func__,
+ info->type, info->buf_idx);
+
+ bufq = stats_ctrl->bufq[info->type];
+ stats_buf = &bufq->bufs[info->buf_idx];
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_UNUSED) {
+ pr_err("%s: need reqbuf first, stats type = %d",
+ __func__, info->type);
+ rc = -1;
+ goto out1;
+ }
+ if (stats_buf->state != MSM_STATS_BUFFER_STATE_INITIALIZED) {
+ D("%s: stats already mapped, no op, stats type = %d",
+ __func__, info->type);
+ goto out1;
+ }
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ stats_buf->handle = ion_import_dma_buf(client, info->fd);
+ if (IS_ERR_OR_NULL(stats_buf->handle)) {
+ rc = -EINVAL;
+ pr_err("%s: stats_buf has null/error ION handle %p",
+ __func__, stats_buf->handle);
+ goto out1;
+ }
+ if (ion_map_iommu(client, stats_buf->handle,
+ CAMERA_DOMAIN, GEN_POOL, SZ_4K,
+ 0, &paddr, &len, UNCACHED, 0) < 0) {
+ rc = -EINVAL;
+ pr_err("%s: cannot map address", __func__);
+ goto out2;
+ }
+#elif CONFIG_ANDROID_PMEM
+ rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
+ if (rc < 0) {
+ pr_err("%s: get_pmem_file fd %d error %d\n",
+ __func__, info->fd, rc);
+ goto out1;
+ }
+ stats_buf->file = file;
+#else
+ paddr = 0;
+ file = NULL;
+ kvstart = 0;
+#endif
+ if (!info->len)
+ info->len = len;
+ rc = msm_stats_check_pmem_info(info, len);
+ if (rc < 0) {
+ pr_err("%s: msm_stats_check_pmem_info err = %d", __func__, rc);
+ goto out3;
+ }
+ paddr += info->offset;
+ len = info->len;
+ stats_buf->paddr = paddr;
+ stats_buf->len = len;
+ memcpy(&stats_buf->info, info, sizeof(stats_buf->info));
+ D("%s Adding buf to list with type %d\n", __func__,
+ stats_buf->info.type);
+ D("%s pmem_stats address is 0x%ld\n", __func__, paddr);
+ stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+ return 0;
+out3:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(client, stats_buf->handle, CAMERA_DOMAIN, GEN_POOL);
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+out2:
+ ion_free(client, stats_buf->handle);
+#elif CONFIG_ANDROID_PMEM
+ put_pmem_file(stats_buf->file);
+#endif
+out1:
+ return rc;
+}
+static int msm_stats_buf_unprepare(struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type, int buf_idx,
+ struct ion_client *client)
+{
+ int rc = 0;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+
+ D("%s: type : %d, idx : %d\n", __func__, stats_type, buf_idx);
+ bufq = stats_ctrl->bufq[stats_type];
+ stats_buf = &bufq->bufs[buf_idx];
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_UNUSED) {
+ pr_err("%s: need reqbuf first, stats type = %d",
+ __func__, stats_type);
+ rc = -1;
+ goto end;
+ }
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_INITIALIZED) {
+ D("%s: stats already mapped, no op, stats type = %d",
+ __func__, stats_type);
+ goto end;
+ }
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(client, stats_buf->handle,
+ CAMERA_DOMAIN, GEN_POOL);
+ ion_free(client, stats_buf->handle);
+#else
+ put_pmem_file(stats_buf->file);
+#endif
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) {
+ /* buf queued need delete from list */
+ D("%s: delete stats buf, type = %d, idx = %d",
+ __func__, stats_type, buf_idx);
+ list_del_init(&stats_buf->list);
+ }
+end:
+ return rc;
+}
+
+static int msm_stats_bufq_flush(struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type, struct ion_client *client)
+{
+ int rc = 0;
+ int i;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+
+ D("%s: type : %d\n", __func__, stats_type);
+ bufq = stats_ctrl->bufq[stats_type];
+
+ for (i = 0; i < bufq->num_bufs; i++) {
+ stats_buf = &bufq->bufs[i];
+ switch (stats_buf->state) {
+ case MSM_STATS_BUFFER_STATE_QUEUED:
+ /* buf queued in stats free queue */
+ stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+ list_del_init(&stats_buf->list);
+ break;
+ case MSM_STATS_BUFFER_STATE_DEQUEUED:
+ /* if stats buf in VFE reset the state */
+ stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+ break;
+ case MSM_STATS_BUFFER_STATE_DISPATCHED:
+ /* if stats buf in userspace reset the state */
+ stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+ break;
+ default:
+ break;
+ }
+ }
+ return rc;
+}
+
+static int msm_stats_dqbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ struct msm_stats_meta_buf **pp_stats_buf)
+{
+ int rc = 0;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+
+ D("%s: type : %d\n", __func__, stats_type);
+ *pp_stats_buf = NULL;
+ bufq = stats_ctrl->bufq[stats_type];
+
+ list_for_each_entry(stats_buf, &bufq->head, list) {
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) {
+ /* found one buf */
+ list_del_init(&stats_buf->list);
+ *pp_stats_buf = stats_buf;
+ break;
+ }
+ }
+ if (!(*pp_stats_buf)) {
+ pr_err("%s: no free stats buf, type = %d",
+ __func__, stats_type);
+ rc = -1;
+ return rc;
+ }
+ stats_buf->state = MSM_STATS_BUFFER_STATE_DEQUEUED;
+ return rc;
+}
+
+
+static int msm_stats_querybuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info,
+ struct msm_stats_meta_buf **pp_stats_buf)
+{
+ int rc = 0;
+ struct msm_stats_bufq *bufq = NULL;
+
+ *pp_stats_buf = NULL;
+ D("%s: stats type : %d, buf_idx : %d", __func__, info->type,
+ info->buf_idx);
+ bufq = stats_ctrl->bufq[info->type];
+ *pp_stats_buf = &bufq->bufs[info->buf_idx];
+
+ return rc;
+}
+
+static int msm_stats_qbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ int buf_idx)
+{
+ int rc = 0;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ D("%s: stats type : %d, buf_idx : %d", __func__, stats_type,
+ buf_idx);
+
+ bufq = stats_ctrl->bufq[stats_type];
+ if (!bufq) {
+ pr_err("%s: null bufq, stats type = %d", __func__, stats_type);
+ rc = -1;
+ goto end;
+ }
+ if (buf_idx >= bufq->num_bufs) {
+ pr_err("%s: stats type = %d, its idx %d larger than buf count %d",
+ __func__, stats_type, buf_idx, bufq->num_bufs);
+ rc = -1;
+ goto end;
+ }
+ stats_buf = &bufq->bufs[buf_idx];
+ switch (stats_buf->state) {
+ case MSM_STATS_BUFFER_STATE_PREPARED:
+ case MSM_STATS_BUFFER_STATE_DEQUEUED:
+ case MSM_STATS_BUFFER_STATE_DISPATCHED:
+ stats_buf->state = MSM_STATS_BUFFER_STATE_QUEUED;
+ list_add_tail(&stats_buf->list, &bufq->head);
+ break;
+ default:
+ pr_err("%s: incorrect state = %d, stats type = %d, cannot qbuf",
+ __func__, stats_buf->state, stats_type);
+ rc = -1;
+ break;
+ }
+end:
+ return rc;
+}
+
+static int msm_stats_buf_dispatch(struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ unsigned long phy_addr, int *buf_idx,
+ void **vaddr, int *fd,
+ struct ion_client *client)
+{
+ int rc = 0;
+ int i;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ D("%s: stats type : %d\n", __func__, stats_type);
+
+ *buf_idx = -1;
+ *vaddr = NULL;
+ *fd = 0;
+ bufq = stats_ctrl->bufq[stats_type];
+ for (i = 0; i < bufq->num_bufs; i++) {
+ if (bufq->bufs[i].paddr == phy_addr) {
+ stats_buf = &bufq->bufs[i];
+ *buf_idx = i;
+ *vaddr = stats_buf->info.vaddr;
+ *fd = stats_buf->info.fd;
+ break;
+ }
+ }
+ if (!stats_buf) {
+ pr_err("%s: no match, phy_addr = 0x%ld, stats_type = %d",
+ __func__, phy_addr, stats_type);
+ return -EFAULT;
+ }
+ switch (stats_buf->state) {
+ case MSM_STATS_BUFFER_STATE_DEQUEUED:
+ stats_buf->state = MSM_STATS_BUFFER_STATE_DISPATCHED;
+ break;
+ default:
+ pr_err("%s: type = %d, idx = %d, cur_state = %d,\n"
+ "cannot set state to DISPATCHED\n",
+ __func__, stats_type, *buf_idx, stats_buf->state);
+ rc = -EFAULT;
+ break;
+ }
+ return rc;
+}
+static int msm_stats_enqueue_buf(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info, struct ion_client *client)
+{
+ int rc = 0;
+ rc = msm_stats_buf_prepare(stats_ctrl, info, client);
+ if (rc < 0) {
+ pr_err("%s: buf_prepare failed, rc = %d", __func__, rc);
+ return -EINVAL;
+ }
+ rc = msm_stats_qbuf(stats_ctrl, info->type, info->buf_idx);
+ if (rc < 0) {
+ pr_err("%s: msm_stats_qbuf failed, rc = %d", __func__, rc);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+int msm_stats_buf_ops_init(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct ion_client *client, struct msm_stats_ops *ops)
+{
+ ops->stats_ctrl = stats_ctrl;
+ ops->client = client;
+ ops->enqueue_buf = msm_stats_enqueue_buf;
+ ops->qbuf = msm_stats_qbuf;
+ ops->dqbuf = msm_stats_dqbuf;
+ ops->bufq_flush = msm_stats_bufq_flush;
+ ops->buf_unprepare = msm_stats_buf_unprepare;
+ ops->buf_prepare = msm_stats_buf_prepare;
+ ops->reqbuf = msm_stats_reqbuf;
+ ops->querybuf = msm_stats_querybuf;
+ ops->dispatch = msm_stats_buf_dispatch;
+ ops->stats_ctrl_init = msm_stats_init;
+ ops->stats_ctrl_deinit = msm_stats_deinit;
+ return 0;
+}
+
diff --git a/drivers/media/video/msm/msm_vfe_stats_buf.h b/drivers/media/video/msm/msm_vfe_stats_buf.h
new file mode 100644
index 0000000..18fd425
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe_stats_buf.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MSM_STATS_BUF_H_
+#define _MSM_STATS_BUF_H_
+
+enum msm_stats_buffer_state {
+ MSM_STATS_BUFFER_STATE_UNUSED, /* not used */
+ MSM_STATS_BUFFER_STATE_INITIALIZED, /* REQBUF done */
+ MSM_STATS_BUFFER_STATE_PREPARED, /* BUF mapped */
+ MSM_STATS_BUFFER_STATE_QUEUED, /* buf queued */
+ MSM_STATS_BUFFER_STATE_DEQUEUED, /* in use in VFE */
+ MSM_STATS_BUFFER_STATE_DISPATCHED, /* sent to userspace */
+};
+
+struct msm_stats_meta_buf {
+ struct list_head list;
+ enum msm_stats_buffer_state state;
+ int type;
+ int fd;
+ uint32_t offset;
+ unsigned long paddr;
+ unsigned long len;
+ struct file *file;
+ struct msm_stats_buf_info info;
+ struct ion_handle *handle;
+};
+
+struct msm_stats_bufq {
+ struct list_head head;
+ int num_bufs;
+ int type;
+ struct msm_stats_meta_buf *bufs;
+};
+
+
+struct msm_stats_bufq_ctrl {
+ /* not use spin lock for now. Assume vfe holds spin lock */
+ spinlock_t lock;
+ int init_done;
+ struct msm_stats_bufq *bufq[MSM_STATS_TYPE_MAX];
+};
+
+struct msm_stats_ops {
+ struct msm_stats_bufq_ctrl *stats_ctrl;
+ struct ion_client *client;
+ int (*enqueue_buf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info,
+ struct ion_client *client);
+ int (*qbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ int buf_idx);
+ int (*dqbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ struct msm_stats_meta_buf **pp_stats_buf);
+ int (*bufq_flush) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ struct ion_client *client);
+ int (*buf_unprepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ int buf_idx,
+ struct ion_client *client);
+ int (*buf_prepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info,
+ struct ion_client *client);
+ int (*reqbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_reqbuf *reqbuf,
+ struct ion_client *client);
+ int (*dispatch) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ unsigned long phy_addr, int *buf_idx, void **vaddr, int *fd,
+ struct ion_client *client);
+ int (*querybuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info,
+ struct msm_stats_meta_buf **pp_stats_buf);
+ int (*stats_ctrl_init) (struct msm_stats_bufq_ctrl *stats_ctrl);
+ int (*stats_ctrl_deinit) (struct msm_stats_bufq_ctrl *stats_ctrl);
+};
+
+int msm_stats_buf_ops_init(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct ion_client *client, struct msm_stats_ops *ops);
+
+#endif /* _MSM_STATS_BUF_H_ */
diff --git a/drivers/media/video/msm/sensors/ov8825_v4l2.c b/drivers/media/video/msm/sensors/ov8825_v4l2.c
index 9f09208..1ae3dfd 100644
--- a/drivers/media/video/msm/sensors/ov8825_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov8825_v4l2.c
@@ -236,6 +236,7 @@
{0x3619, 0x00},
{0x361a, 0xB0},
{0x361b, 0x04},
+ {0x361c, 0x07},
{0x3701, 0x44},
{0x370b, 0x01},
{0x370c, 0x50},
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index c198815..4c27f19 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -23,6 +23,7 @@
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/time.h>
+#include <mach/board.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
@@ -54,6 +55,7 @@
struct ion_client *ion_client;
bool secure_device;
bool in_use;
+ bool mdp_iommu_split_domain;
};
struct mem_info {
@@ -287,10 +289,28 @@
mdp_mregion->cookie = 0;
mdp_mregion->ion_handle = enc_mregion->ion_handle;
- rc = ion_map_iommu(wfd_dev->ion_client, mdp_mregion->ion_handle,
- DISPLAY_DOMAIN, GEN_POOL, SZ_4K,
+ if (wfd_dev->mdp_iommu_split_domain) {
+ if (wfd_dev->secure_device) {
+ rc = ion_phys(wfd_dev->ion_client,
+ mdp_mregion->ion_handle,
+ (unsigned long *)&mdp_mregion->paddr,
+ (size_t *)&mdp_mregion->size);
+ } else {
+ rc = ion_map_iommu(wfd_dev->ion_client,
+ mdp_mregion->ion_handle,
+ DISPLAY_WRITE_DOMAIN, GEN_POOL, SZ_4K,
+ 0, (unsigned long *)&mdp_mregion->paddr,
+ (unsigned long *)&mdp_mregion->size,
+ 0, 0);
+ }
+ } else {
+ rc = ion_map_iommu(wfd_dev->ion_client,
+ mdp_mregion->ion_handle,
+ DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K,
0, (unsigned long *)&mdp_mregion->paddr,
(unsigned long *)&mdp_mregion->size, 0, 0);
+ }
+
if (rc) {
WFD_MSG_ERR("Failed to map to mdp\n");
mdp_mregion->kvaddr = NULL;
@@ -360,10 +380,20 @@
WFD_MSG_ERR("Failed to free buffers "
"from encoder\n");
- if (mpair->mdp->paddr)
- ion_unmap_iommu(wfd_dev->ion_client,
+ if (mpair->mdp->paddr) {
+ if (wfd_dev->mdp_iommu_split_domain) {
+ if (!wfd_dev->secure_device)
+ ion_unmap_iommu(wfd_dev->
+ ion_client,
+ mpair->mdp->ion_handle,
+ DISPLAY_WRITE_DOMAIN,
+ GEN_POOL);
+ } else {
+ ion_unmap_iommu(wfd_dev->ion_client,
mpair->mdp->ion_handle,
- DISPLAY_DOMAIN, GEN_POOL);
+ DISPLAY_READ_DOMAIN, GEN_POOL);
+ }
+ }
if (mpair->enc->paddr)
ion_unmap_iommu(wfd_dev->ion_client,
@@ -1467,6 +1497,7 @@
int rc = 0, c = 0;
struct wfd_device *wfd_dev; /* Should be taken as an array*/
struct ion_client *ion_client = NULL;
+ struct msm_wfd_platform_data *wfd_priv;
WFD_MSG_DBG("__wfd_probe: E\n");
wfd_dev = kzalloc(sizeof(*wfd_dev)*WFD_NUM_DEVICES, GFP_KERNEL);
@@ -1476,6 +1507,13 @@
rc = -ENOMEM;
goto err_v4l2_probe;
}
+
+ wfd_priv = pdev->dev.platform_data;
+ if (wfd_priv && wfd_priv->wfd_check_mdp_iommu_split) {
+ wfd_dev->mdp_iommu_split_domain =
+ wfd_priv->wfd_check_mdp_iommu_split();
+ }
+
pdev->dev.platform_data = (void *) wfd_dev;
ion_client = msm_ion_client_create(-1, "wfd");
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 0c26027..09c7215 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -202,6 +202,14 @@
.type = OUTPUT_PORT,
},
{
+ .name = "VC1",
+ .description = "VC-1 compressed format",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
.name = "H264",
.description = "H264 compressed format",
.fourcc = V4L2_PIX_FMT_H264,
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 63f23eb..e835aaa 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -23,7 +23,7 @@
#define MIN_NUM_OUTPUT_BUFFERS 2
#define MAX_NUM_OUTPUT_BUFFERS 8
#define MIN_BIT_RATE 64
-#define MAX_BIT_RATE 8000
+#define MAX_BIT_RATE 20000
#define DEFAULT_BIT_RATE 64
#define BIT_RATE_STEP 1
#define MIN_FRAME_RATE 1
@@ -37,6 +37,7 @@
#define B_FRAME_QP 30
#define MAX_INTRA_REFRESH_MBS 300
#define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
+#define CODING V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY
static const char *const mpeg_video_rate_control[] = {
"No Rate Control",
@@ -79,7 +80,7 @@
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 10*MAX_FRAME_RATE,
- .default_value = 0,
+ .default_value = DEFAULT_FRAME_RATE,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
@@ -174,6 +175,26 @@
.qmenu = h264_video_entropy_cabac_model,
},
{
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+ .name = "MPEG4 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ .maximum = CODING,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+ .name = "MPEG4 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ },
+ {
.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
.name = "H264 Profile",
.type = V4L2_CTRL_TYPE_MENU,
@@ -385,14 +406,17 @@
static struct hal_intra_period
venc_intra_period = {2*DEFAULT_FRAME_RATE-1 , 0};
static struct hal_profile_level
- venc_profile_level = {V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
- V4L2_MPEG_VIDEO_H264_LEVEL_1_0};
+ venc_h264_profile_level = {HAL_H264_PROFILE_BASELINE,
+ HAL_H264_LEVEL_1};
+static struct hal_profile_level
+ venc_mpeg4_profile_level = {HAL_H264_PROFILE_BASELINE,
+ HAL_H264_LEVEL_1};
static struct hal_h264_entropy_control
- venc_h264_entropy_control = {V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
- V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0};
+ venc_h264_entropy_control = {HAL_H264_ENTROPY_CAVLC,
+ HAL_H264_CABAC_MODEL_0};
static struct hal_multi_slice_control
- venc_multi_slice_control = {V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE ,
- 0};
+ venc_multi_slice_control = {HAL_MULTI_SLICE_OFF ,
+ 0};
static const struct msm_vidc_format venc_formats[] = {
{
@@ -717,6 +741,57 @@
venc_h264_entropy_control.entropy_mode;
pdata = &h264_entropy_control;
break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ switch (control.value) {
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+ control.value = HAL_MPEG4_PROFILE_SIMPLE;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+ control.value = HAL_MPEG4_PROFILE_ADVANCEDSIMPLE;
+ break;
+ default:
+ break;
+ }
+ profile_level.profile = control.value;
+ venc_mpeg4_profile_level.profile = control.value;
+ profile_level.level = venc_mpeg4_profile_level.level;
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ switch (control.value) {
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
+ control.value = HAL_MPEG4_LEVEL_0;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
+ control.value = HAL_MPEG4_LEVEL_0b;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
+ control.value = HAL_MPEG4_LEVEL_1;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
+ control.value = HAL_MPEG4_LEVEL_2;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
+ control.value = HAL_MPEG4_LEVEL_3;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
+ control.value = HAL_MPEG4_LEVEL_4;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
+ control.value = HAL_MPEG4_LEVEL_5;
+ break;
+ default:
+ break;
+ }
+ profile_level.level = control.value;
+ venc_mpeg4_profile_level.level = control.value;
+ profile_level.profile = venc_mpeg4_profile_level.profile;
+ pdata = &profile_level;
+ break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
@@ -747,8 +822,8 @@
break;
}
profile_level.profile = control.value;
- venc_profile_level.profile = control.value;
- profile_level.level = venc_profile_level.level;
+ venc_h264_profile_level.profile = control.value;
+ profile_level.level = venc_h264_profile_level.level;
pdata = &profile_level;
pr_debug("\nprofile: %d\n",
profile_level.profile);
@@ -810,8 +885,9 @@
break;
}
profile_level.level = control.value;
- venc_profile_level.level = control.value;
- profile_level.profile = venc_profile_level.profile;
+ venc_h264_profile_level.level = control.value;
+ profile_level.profile = venc_h264_profile_level.profile;
+ pdata = &profile_level;
pdata = &profile_level;
pr_debug("\nLevel: %d\n",
profile_level.level);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index ba5fdc4..a5cff9c 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -25,6 +25,11 @@
__rc; \
})
+#define V4L2_EVENT_SEQ_CHANGED_SUFFICIENT \
+ V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT
+#define V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT \
+ V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT
+
struct msm_vidc_core *get_vidc_core(int core_id)
{
struct msm_vidc_core *core;
@@ -199,9 +204,20 @@
struct msm_vidc_cb_event *event_notify;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
- dqevent.type = V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED;
dqevent.id = 0;
event_notify = (struct msm_vidc_cb_event *) response->data;
+ switch (event_notify->hal_event_type) {
+ case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
+ dqevent.type =
+ V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ break;
+ case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
+ dqevent.type =
+ V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ break;
+ default:
+ break;
+ }
inst->reconfig_height = event_notify->height;
inst->reconfig_width = event_notify->width;
inst->in_reconfig = true;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index b3ea92a..332bbac 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -793,6 +793,12 @@
HAL_UNUSED_FLUSH = 0x10000000,
};
+enum hal_event_type {
+ HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES,
+ HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES,
+ HAL_UNUSED_SEQCHG = 0x10000000,
+};
+
/* HAL Response */
enum command_response {
@@ -843,6 +849,7 @@
u32 status;
u32 height;
u32 width;
+ u32 hal_event_type;
};
/* Data callback structure */
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index b08fc7d..0c3d4ad 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -50,4 +50,14 @@
help
No-Data-Path BAM is used to improve BAM performance.
+config QPNP_PWM
+ depends on SPMI
+ depends on OF_SPMI
+ tristate "Qualcomm QPNP LPG/PWM support"
+ help
+ This driver supports PWM/LPG devices in Qualcomm PMIC chips which
+ comply with QPNP. QPNP is a SPMI based PMIC implementation. These
+ devices support Pulse Width Modulation output with user generated
+ patterns. They share a lookup table with size of 64 entries.
+
endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 92eb492..6deb6ee 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_MSM_SSBI) += ssbi.o
obj-$(CONFIG_USB_BAM) += usb_bam.o
obj-$(CONFIG_SPS) += sps/
+obj-$(CONFIG_QPNP_PWM) += qpnp-pwm.o
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
new file mode 100644
index 0000000..c9cd0e0
--- /dev/null
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -0,0 +1,1661 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+/*
+ * Qualcomm QPNP Pulse Width Modulation (PWM) driver
+ *
+ * The HW module is also called LPG (Light Pattern Generator).
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/spmi.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/radix-tree.h>
+#include <linux/qpnp/pwm.h>
+
+#define QPNP_LPG_DRIVER_NAME "qcom,qpnp-pwm"
+
+/* LPG Control for LPG_PATTERN_CONFIG */
+#define QPNP_RAMP_DIRECTION_SHIFT 4
+#define QPNP_RAMP_DIRECTION_MASK 0x10
+#define QPNP_PATTERN_REPEAT_SHIFT 3
+#define QPNP_PATTERN_REPEAT_MASK 0x08
+#define QPNP_RAMP_TOGGLE_SHIFT 2
+#define QPNP_RAMP_TOGGLE_MASK 0x04
+#define QPNP_EN_PAUSE_HI_SHIFT 1
+#define QPNP_EN_PAUSE_HI_MASK 0x02
+#define QPNP_EN_PAUSE_LO_MASK 0x01
+
+/* LPG Control for LPG_PWM_SIZE_CLK */
+#define QPNP_PWM_SIZE_SHIFT 4
+#define QPNP_PWM_SIZE_MASK 0x30
+#define QPNP_PWM_FREQ_CLK_SELECT_SHIFT 0
+#define QPNP_PWM_FREQ_CLK_SELECT_MASK 0x03
+#define QPNP_PWM_SIZE_9_BIT 0x03
+
+#define QPNP_SET_PWM_CLK(val, clk, pwm_size) \
+do { \
+ val = (clk + 1) & QPNP_PWM_FREQ_CLK_SELECT_MASK; \
+ val |= ((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT : 0) << \
+ QPNP_PWM_SIZE_SHIFT) & QPNP_PWM_SIZE_MASK; \
+} while (0)
+
+#define QPNP_GET_PWM_SIZE(reg) ((reg & QPNP_PWM_SIZE_MASK) \
+ >> QPNP_PWM_SIZE_SHIFT)
+
+/* LPG Control for LPG_PWM_FREQ_PREDIV_CLK */
+#define QPNP_PWM_FREQ_PRE_DIVIDE_SHIFT 5
+#define QPNP_PWM_FREQ_PRE_DIVIDE_MASK 0x60
+#define QPNP_PWM_FREQ_EXP_MASK 0x07
+
+#define QPNP_SET_PWM_FREQ_PREDIV(val, pre_div, pre_div_exp) \
+do { \
+ val = (pre_div << QPNP_PWM_FREQ_PRE_DIVIDE_SHIFT) & \
+ QPNP_PWM_FREQ_PRE_DIVIDE_MASK; \
+ val |= pre_div_exp & QPNP_PWM_FREQ_EXP_MASK; \
+} while (0)
+
+/* LPG Control for LPG_PWM_TYPE_CONFIG */
+#define QPNP_EN_GLITCH_REMOVAL_SHIFT 5
+#define QPNP_EN_GLITCH_REMOVAL_MASK 0x20
+#define QPNP_EN_FULL_SCALE_SHIFT 3
+#define QPNP_EN_FULL_SCALE_MASK 0x08
+#define QPNP_EN_PHASE_STAGGER_SHIFT 2
+#define QPNP_EN_PHASE_STAGGER_MASK 0x04
+#define QPNP_PHASE_STAGGER_MASK 0x03
+
+/* LPG Control for PWM_VALUE_LSB */
+#define QPNP_PWM_VALUE_LSB_MASK 0xFF
+
+/* LPG Control for PWM_VALUE_MSB */
+#define QPNP_PWM_VALUE_MSB_SHIFT 8
+#define QPNP_PWM_VALUE_MSB_MASK 0x01
+
+/* LPG Control for ENABLE_CONTROL */
+#define QPNP_EN_PWM_HIGH_SHIFT 7
+#define QPNP_EN_PWM_HIGH_MASK 0x80
+#define QPNP_EN_PWM_LO_SHIFT 6
+#define QPNP_EN_PWM_LO_MASK 0x40
+#define QPNP_EN_PWM_OUTPUT_SHIFT 5
+#define QPNP_EN_PWM_OUTPUT_MASK 0x20
+#define QPNP_PWM_SRC_SELECT_SHIFT 2
+#define QPNP_PWM_SRC_SELECT_MASK 0x04
+#define QPNP_PWM_EN_RAMP_GEN_SHIFT 1
+#define QPNP_PWM_EN_RAMP_GEN_MASK 0x02
+
+#define QPNP_ENABLE_PWM(value) \
+ (value |= (1 << QPNP_EN_PWM_OUTPUT_SHIFT) & QPNP_EN_PWM_OUTPUT_MASK)
+
+#define QPNP_DISABLE_PWM(value) (value &= ~QPNP_EN_PWM_OUTPUT_MASK)
+
+/* LPG Control for RAMP_CONTROL */
+#define QPNP_RAMP_START_MASK 0x01
+
+#define QPNP_ENABLE_LUT(value) (value |= QPNP_RAMP_START_MASK)
+#define QPNP_DISABLE_LUT(value) (value &= ~QPNP_RAMP_START_MASK)
+
+/* LPG Control for RAMP_STEP_DURATION_LSB */
+#define QPNP_RAMP_STEP_DURATION_LSB_MASK 0xFF
+
+/* LPG Control for RAMP_STEP_DURATION_MSB */
+#define QPNP_RAMP_STEP_DURATION_MSB_SHIFT 8
+#define QPNP_RAMP_STEP_DURATION_MSB_MASK 0x01
+
+#define QPNP_PWM_1KHZ 1024
+#define QPNP_GET_RAMP_STEP_DURATION(ramp_time_ms) \
+ ((ramp_time_ms * QPNP_PWM_1KHZ) / 1000)
+
+/* LPG Control for PAUSE_HI_MULTIPLIER_LSB */
+#define QPNP_PAUSE_HI_MULTIPLIER_LSB_MASK 0xFF
+
+/* LPG Control for PAUSE_HI_MULTIPLIER_MSB */
+#define QPNP_PAUSE_HI_MULTIPLIER_MSB_SHIFT 8
+#define QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK 0x1F
+
+/* LPG Control for PAUSE_LO_MULTIPLIER_LSB */
+#define QPNP_PAUSE_LO_MULTIPLIER_LSB_MASK 0xFF
+
+/* LPG Control for PAUSE_LO_MULTIPLIER_MSB */
+#define QPNP_PAUSE_LO_MULTIPLIER_MSB_SHIFT 8
+#define QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK 0x1F
+
+/* LPG Control for HI_INDEX */
+#define QPNP_HI_INDEX_MASK 0x3F
+
+/* LPG Control for LO_INDEX */
+#define QPNP_LO_INDEX_MASK 0x3F
+
+#define NUM_CLOCKS 3
+#define QPNP_PWM_M_MAX 7
+#define NSEC_1024HZ (NSEC_PER_SEC / 1024)
+#define NSEC_32768HZ (NSEC_PER_SEC / 32768)
+#define NSEC_19P2MHZ (NSEC_PER_SEC / 19200000)
+
+#define NUM_LPG_PRE_DIVIDE 4
+
+#define PRE_DIVIDE_1 1
+#define PRE_DIVIDE_3 3
+#define PRE_DIVIDE_5 5
+#define PRE_DIVIDE_6 6
+
+#define SPMI_LPG_REG_ADDR_BASE 0x40
+#define SPMI_LPG_REG_ADDR(b, n) (b + SPMI_LPG_REG_ADDR_BASE + (n))
+#define SPMI_MAX_BUF_LEN 8
+
+/* SPMI LPG registers */
+enum qpnp_lpg_registers_list {
+ QPNP_LPG_PATTERN_CONFIG,
+ QPNP_LPG_PWM_SIZE_CLK,
+ QPNP_LPG_PWM_FREQ_PREDIV_CLK,
+ QPNP_LPG_PWM_TYPE_CONFIG,
+ QPNP_PWM_VALUE_LSB,
+ QPNP_PWM_VALUE_MSB,
+ QPNP_ENABLE_CONTROL,
+ QPNP_RAMP_CONTROL,
+ QPNP_RAMP_STEP_DURATION_LSB = QPNP_RAMP_CONTROL + 9,
+ QPNP_RAMP_STEP_DURATION_MSB,
+ QPNP_PAUSE_HI_MULTIPLIER_LSB,
+ QPNP_PAUSE_HI_MULTIPLIER_MSB,
+ QPNP_PAUSE_LO_MULTIPLIER_LSB,
+ QPNP_PAUSE_LO_MULTIPLIER_MSB,
+ QPNP_HI_INDEX,
+ QPNP_LO_INDEX,
+ QPNP_TOTAL_LPG_SPMI_REGISTERS
+};
+
+/*
+ * Formula from HSID,
+ * pause_time (hi/lo) = (pause_cnt- 1)*(ramp_ms)
+ * OR,
+ * pause_cnt = (pause_time / ramp_ms) + 1
+ */
+#define QPNP_SET_PAUSE_CNT(to_pause_cnt, from_pause, ramp_ms) \
+ (to_pause_cnt = (from_pause / (ramp_ms ? ramp_ms : 1)) + 1)
+
+
+static unsigned int pt_t[NUM_LPG_PRE_DIVIDE][NUM_CLOCKS] = {
+ { PRE_DIVIDE_1 * NSEC_1024HZ,
+ PRE_DIVIDE_1 * NSEC_32768HZ,
+ PRE_DIVIDE_1 * NSEC_19P2MHZ,
+ },
+ { PRE_DIVIDE_3 * NSEC_1024HZ,
+ PRE_DIVIDE_3 * NSEC_32768HZ,
+ PRE_DIVIDE_3 * NSEC_19P2MHZ,
+ },
+ { PRE_DIVIDE_5 * NSEC_1024HZ,
+ PRE_DIVIDE_5 * NSEC_32768HZ,
+ PRE_DIVIDE_5 * NSEC_19P2MHZ,
+ },
+ { PRE_DIVIDE_6 * NSEC_1024HZ,
+ PRE_DIVIDE_6 * NSEC_32768HZ,
+ PRE_DIVIDE_6 * NSEC_19P2MHZ,
+ },
+};
+
+static RADIX_TREE(lpg_dev_tree, GFP_KERNEL);
+
+struct qpnp_lut_default_config {
+ u32 *duty_pct_list;
+ int size;
+ int start_idx;
+};
+
+struct qpnp_lut_config {
+ struct qpnp_lut_default_config def_config;
+ u8 *duty_pct_list;
+ int list_size;
+ int lo_index;
+ int hi_index;
+ int lut_pause_hi_cnt;
+ int lut_pause_lo_cnt;
+ int ramp_step_ms;
+ bool ramp_direction;
+ bool pattern_repeat;
+ bool ramp_toggle;
+ bool enable_pause_hi;
+ bool enable_pause_lo;
+};
+
+struct qpnp_lpg_config {
+ struct qpnp_lut_config lut_config;
+ u16 base_addr;
+ u16 lut_base_addr;
+ u16 lut_size;
+ bool bypass_lut;
+ bool lpg_configured;
+};
+
+struct qpnp_pwm_config {
+ int channel_id;
+ bool in_use;
+ const char *lable;
+ int pwm_value;
+ int pwm_period;
+ int pwm_duty;
+ struct pwm_period_config period;
+};
+
+/* Public facing structure */
+struct pwm_device {
+ struct qpnp_lpg_chip *chip;
+ struct qpnp_pwm_config pwm_config;
+};
+
+struct qpnp_lpg_chip {
+ struct spmi_device *spmi_dev;
+ struct pwm_device pwm_dev;
+ struct mutex lpg_mutex;
+ struct qpnp_lpg_config lpg_config;
+ u8 qpnp_lpg_registers[QPNP_TOTAL_LPG_SPMI_REGISTERS];
+};
+
+/* Internal functions */
+static inline void qpnp_set_pattern_config(u8 *val,
+ struct qpnp_lut_config *lut_config)
+{
+ *val = lut_config->enable_pause_lo & QPNP_EN_PAUSE_LO_MASK;
+ *val |= (lut_config->enable_pause_hi << QPNP_EN_PAUSE_HI_SHIFT) &
+ QPNP_EN_PAUSE_HI_MASK;
+ *val |= (lut_config->ramp_toggle << QPNP_RAMP_TOGGLE_SHIFT) &
+ QPNP_RAMP_TOGGLE_MASK;
+ *val |= (lut_config->pattern_repeat << QPNP_PATTERN_REPEAT_SHIFT) &
+ QPNP_PATTERN_REPEAT_MASK;
+ *val |= (lut_config->ramp_direction << QPNP_RAMP_DIRECTION_SHIFT) &
+ QPNP_RAMP_DIRECTION_MASK;
+}
+
+static inline void qpnp_set_pwm_type_config(u8 *val, bool glitch,
+ bool full_scale, bool en_phase, bool phase)
+{
+ *val = phase;
+ *val |= (en_phase << QPNP_EN_PHASE_STAGGER_SHIFT) &
+ QPNP_EN_PHASE_STAGGER_MASK;
+ *val |= (full_scale << QPNP_EN_FULL_SCALE_SHIFT) &
+ QPNP_EN_FULL_SCALE_MASK;
+ *val |= (glitch << QPNP_EN_GLITCH_REMOVAL_SHIFT) &
+ QPNP_EN_GLITCH_REMOVAL_MASK;
+}
+
+static inline void qpnp_set_control(u8 *val, bool pwm_hi, bool pwm_lo,
+ bool pwm_out, bool pwm_src, bool ramp_gen)
+{
+ *val = (ramp_gen << QPNP_PWM_EN_RAMP_GEN_SHIFT) &
+ QPNP_PWM_EN_RAMP_GEN_MASK;
+ *val |= (pwm_src << QPNP_PWM_SRC_SELECT_SHIFT) &
+ QPNP_PWM_SRC_SELECT_MASK;
+ *val |= (pwm_out << QPNP_EN_PWM_OUTPUT_SHIFT) &
+ QPNP_EN_PWM_OUTPUT_MASK;
+ *val |= (pwm_lo << QPNP_EN_PWM_LO_SHIFT) & QPNP_EN_PWM_LO_MASK;
+ *val |= (pwm_hi << QPNP_EN_PWM_HIGH_SHIFT) & QPNP_EN_PWM_HIGH_MASK;
+}
+
+#define QPNP_ENABLE_LUT_CONTROL(p_val) qpnp_set_control(p_val, 1, 1, 1, 0, 1)
+#define QPNP_ENABLE_PWM_CONTROL(p_val) qpnp_set_control(p_val, 1, 1, 0, 1, 0)
+
+static inline void qpnp_convert_to_lut_flags(int *flags,
+ struct qpnp_lut_config *l_config)
+{
+ *flags = ((l_config->ramp_direction ? PM_PWM_LUT_RAMP_UP : 0) |
+ (l_config->pattern_repeat ? PM_PWM_LUT_LOOP : 0)|
+ (l_config->ramp_toggle ? PM_PWM_LUT_REVERSE : 0) |
+ (l_config->enable_pause_hi ? PM_PWM_LUT_PAUSE_HI_EN : 0) |
+ (l_config->enable_pause_lo ? PM_PWM_LUT_PAUSE_LO_EN : 0));
+}
+
+static inline void qpnp_set_lut_params(struct lut_params *l_params,
+ struct qpnp_lut_config *l_config)
+{
+ l_params->start_idx = l_config->def_config.start_idx;
+ l_params->idx_len = l_config->def_config.size;
+ l_params->lut_pause_hi = l_config->lut_pause_hi_cnt;
+ l_params->lut_pause_lo = l_config->lut_pause_lo_cnt;
+ l_params->ramp_step_ms = l_config->ramp_step_ms;
+ qpnp_convert_to_lut_flags(&l_params->flags, l_config);
+}
+
+static void qpnp_lpg_save(u8 *u8p, u8 mask, u8 val)
+{
+ *u8p &= ~mask;
+ *u8p |= val & mask;
+}
+
+static int qpnp_lpg_save_and_write(u8 value, u8 mask, u8 *reg, u16 base_addr,
+ u16 offset, u16 size, struct qpnp_lpg_chip *chip)
+{
+ qpnp_lpg_save(reg, mask, value);
+
+ return spmi_ext_register_writel(chip->spmi_dev->ctrl,
+ chip->spmi_dev->sid, SPMI_LPG_REG_ADDR(base_addr, offset), reg, size);
+}
+
+/*
+ * PWM Frequency = Clock Frequency / (N * T)
+ * or
+ * PWM Period = Clock Period * (N * T)
+ * where
+ * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
+ * T = Pre-divide * 2^m, where m = 0..7 (exponent)
+ *
+ * This is the formula to figure out m for the best pre-divide and clock:
+ * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
+ */
+static void qpnp_lpg_calc_period(unsigned int period_us,
+ struct pwm_period_config *period)
+{
+ int n, m, clk, div;
+ int best_m, best_div, best_clk;
+ unsigned int last_err, cur_err, min_err;
+ unsigned int tmp_p, period_n;
+
+ /* PWM Period / N */
+ if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
+ period_n = (period_us * NSEC_PER_USEC) >> 6;
+ n = 6;
+ } else {
+ period_n = (period_us >> 9) * NSEC_PER_USEC;
+ n = 9;
+ }
+
+ min_err = last_err = (unsigned)(-1);
+ best_m = 0;
+ best_clk = 0;
+ best_div = 0;
+ for (clk = 0; clk < NUM_CLOCKS; clk++) {
+ for (div = 0; div < NUM_LPG_PRE_DIVIDE; div++) {
+ /* period_n = (PWM Period / N) */
+ /* tmp_p = (Pre-divide * Clock Period) * 2^m */
+ tmp_p = pt_t[div][clk];
+ for (m = 0; m <= QPNP_PWM_M_MAX; m++) {
+ if (period_n > tmp_p)
+ cur_err = period_n - tmp_p;
+ else
+ cur_err = tmp_p - period_n;
+
+ if (cur_err < min_err) {
+ min_err = cur_err;
+ best_m = m;
+ best_clk = clk;
+ best_div = div;
+ }
+
+ if (m && cur_err > last_err)
+ /* Break for bigger cur_err */
+ break;
+
+ last_err = cur_err;
+ tmp_p <<= 1;
+ }
+ }
+ }
+
+ /* Use higher resolution */
+ if (best_m >= 3 && n == 6) {
+ n += 3;
+ best_m -= 3;
+ }
+
+ period->pwm_size = n;
+ period->clk = best_clk;
+ period->pre_div = best_div;
+ period->pre_div_exp = best_m;
+}
+
+static void qpnp_lpg_calc_pwm_value(struct pwm_device *pwm,
+ unsigned int period_us,
+ unsigned int duty_us)
+{
+ unsigned int max_pwm_value, tmp;
+ struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
+
+ /* Figure out pwm_value with overflow handling */
+ tmp = 1 << (sizeof(tmp) * 8 - pwm_config->period.pwm_size);
+ if (duty_us < tmp) {
+ tmp = duty_us << pwm_config->period.pwm_size;
+ pwm_config->pwm_value = tmp / period_us;
+ } else {
+ tmp = period_us >> pwm_config->period.pwm_size;
+ pwm_config->pwm_value = duty_us / tmp;
+ }
+ max_pwm_value = (1 << pwm_config->period.pwm_size) - 1;
+ if (pwm_config->pwm_value > max_pwm_value)
+ pwm_config->pwm_value = max_pwm_value;
+}
+
+static int qpnp_lpg_change_table(struct pwm_device *pwm,
+ int duty_pct[], int raw_value)
+{
+ unsigned int pwm_value, max_pwm_value;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ struct qpnp_lut_config *lut = &chip->lpg_config.lut_config;
+ int i, pwm_size, rc;
+ int burst_size = SPMI_MAX_BUF_LEN;
+ int list_len = lut->list_size << 1;
+ int offset = lut->lo_index << 2;
+
+ pwm_size = QPNP_GET_PWM_SIZE(
+ chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) &
+ QPNP_PWM_SIZE_9_BIT ? 9 : 6;
+
+ max_pwm_value = (1 << pwm_size) - 1;
+
+ if (unlikely(lut->list_size != (lut->hi_index - lut->lo_index + 1))) {
+ pr_err("LUT internal Data structure corruption detected\n");
+ pr_err("LUT list size: %d\n", lut->list_size);
+ pr_err("However, index size is: %d\n",
+ (lut->hi_index - lut->lo_index + 1));
+ return -EINVAL;
+ }
+
+ for (i = 0; i <= lut->list_size; i++) {
+ if (raw_value)
+ pwm_value = duty_pct[i];
+ else
+ pwm_value = (duty_pct[i] << pwm_size) / 100;
+
+ if (pwm_value > max_pwm_value)
+ pwm_value = max_pwm_value;
+
+ lut->duty_pct_list[i*2] = pwm_value;
+ lut->duty_pct_list[(i*2)+1] = (pwm_value >>
+ QPNP_PWM_VALUE_MSB_SHIFT) & QPNP_PWM_VALUE_MSB_MASK;
+ }
+
+ /* Write with max allowable burst mode, each entry is of two bytes */
+ for (i = 0; i < list_len;) {
+ if (i + burst_size >= list_len)
+ burst_size = list_len - i;
+ rc = spmi_ext_register_writel(chip->spmi_dev->ctrl,
+ chip->spmi_dev->sid,
+ chip->lpg_config.lut_base_addr + offset + i,
+ lut->duty_pct_list + i, burst_size);
+ i += burst_size;
+ }
+
+ return rc;
+}
+
+static void qpnp_lpg_save_period(struct pwm_device *pwm)
+{
+ u8 mask, val;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
+
+ QPNP_SET_PWM_CLK(val, pwm_config->period.clk,
+ pwm_config->period.pwm_size);
+
+ mask = QPNP_PWM_SIZE_MASK | QPNP_PWM_FREQ_CLK_SELECT_MASK;
+
+ qpnp_lpg_save(&chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK],
+ mask, val);
+
+ QPNP_SET_PWM_FREQ_PREDIV(val, pwm_config->period.pre_div,
+ pwm_config->period.pre_div_exp);
+
+ mask = QPNP_PWM_FREQ_PRE_DIVIDE_MASK | QPNP_PWM_FREQ_EXP_MASK;
+
+ qpnp_lpg_save(&chip->qpnp_lpg_registers[QPNP_LPG_PWM_FREQ_PREDIV_CLK],
+ mask, val);
+}
+
+static int qpnp_lpg_save_pwm_value(struct pwm_device *pwm)
+{
+ unsigned int max_pwm_value;
+ int pwm_size;
+ u8 mask, value;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
+ struct qpnp_lpg_config *lpg_config = &chip->lpg_config;
+ int rc;
+
+ pwm_size = QPNP_GET_PWM_SIZE(
+ chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) &
+ QPNP_PWM_SIZE_9_BIT ? 9 : 6;
+
+ max_pwm_value = (1 << pwm_size) - 1;
+
+ if (pwm_config->pwm_value > max_pwm_value)
+ pwm_config->pwm_value = max_pwm_value;
+
+ value = pwm_config->pwm_value;
+ mask = QPNP_PWM_VALUE_LSB_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_PWM_VALUE_LSB],
+ lpg_config->base_addr, QPNP_PWM_VALUE_LSB, 1, chip);
+ if (rc)
+ return rc;
+
+ value = (pwm_config->pwm_value >> QPNP_PWM_VALUE_MSB_SHIFT) &
+ QPNP_PWM_VALUE_MSB_MASK;
+
+ mask = QPNP_PWM_VALUE_MSB_MASK;
+
+ return qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_PWM_VALUE_MSB],
+ lpg_config->base_addr, QPNP_PWM_VALUE_MSB, 1, chip);
+}
+
+static int qpnp_lpg_configure_pattern(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lut_config *lut_config = &lpg_config->lut_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ u8 value, mask;
+
+ qpnp_set_pattern_config(&value, lut_config);
+
+ mask = QPNP_RAMP_DIRECTION_MASK | QPNP_PATTERN_REPEAT_MASK |
+ QPNP_RAMP_TOGGLE_MASK | QPNP_EN_PAUSE_HI_MASK |
+ QPNP_EN_PAUSE_LO_MASK;
+
+ return qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_LPG_PATTERN_CONFIG],
+ lpg_config->base_addr, QPNP_LPG_PATTERN_CONFIG, 1, chip);
+}
+
+static int qpnp_lpg_configure_pwm(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ int rc;
+ u8 value, mask;
+
+ rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+ SPMI_LPG_REG_ADDR(lpg_config->base_addr, QPNP_LPG_PWM_SIZE_CLK),
+ &chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK], 1);
+
+ if (rc)
+ return rc;
+
+ rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+ SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+ QPNP_LPG_PWM_FREQ_PREDIV_CLK),
+ &chip->qpnp_lpg_registers[QPNP_LPG_PWM_FREQ_PREDIV_CLK], 1);
+ if (rc)
+ return rc;
+
+ qpnp_set_pwm_type_config(&value, 1, 0, 0, 0);
+
+ mask = QPNP_EN_GLITCH_REMOVAL_MASK | QPNP_EN_FULL_SCALE_MASK |
+ QPNP_EN_PHASE_STAGGER_MASK | QPNP_PHASE_STAGGER_MASK;
+
+ return qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_LPG_PWM_TYPE_CONFIG],
+ lpg_config->base_addr, QPNP_LPG_PWM_TYPE_CONFIG, 1, chip);
+}
+
+static int qpnp_pwm_configure_control(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ u8 value, mask;
+
+ QPNP_ENABLE_PWM_CONTROL(&value);
+
+ mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
+ QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
+ QPNP_PWM_EN_RAMP_GEN_MASK;
+
+ return qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
+ lpg_config->base_addr, QPNP_ENABLE_CONTROL, 1, chip);
+
+}
+
+static int qpnp_lpg_configure_control(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ u8 value, mask;
+
+ QPNP_ENABLE_LUT_CONTROL(&value);
+
+ mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
+ QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
+ QPNP_PWM_EN_RAMP_GEN_MASK;
+
+ return qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
+ lpg_config->base_addr, QPNP_ENABLE_CONTROL, 1, chip);
+
+}
+
+static int qpnp_lpg_configure_ramp_step_duration(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lut_config lut_config = lpg_config->lut_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ int rc, value;
+ u8 val, mask;
+
+ value = QPNP_GET_RAMP_STEP_DURATION(lut_config.ramp_step_ms);
+ val = value & QPNP_RAMP_STEP_DURATION_LSB_MASK;
+ mask = QPNP_RAMP_STEP_DURATION_LSB_MASK;
+
+ rc = qpnp_lpg_save_and_write(val, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_RAMP_STEP_DURATION_LSB],
+ lpg_config->base_addr, QPNP_RAMP_STEP_DURATION_LSB, 1, chip);
+ if (rc)
+ return rc;
+
+ val = (value >> QPNP_RAMP_STEP_DURATION_MSB_SHIFT) &
+ QPNP_RAMP_STEP_DURATION_MSB_MASK;
+
+ mask = QPNP_RAMP_STEP_DURATION_MSB_MASK;
+
+ return qpnp_lpg_save_and_write(val, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_RAMP_STEP_DURATION_MSB],
+ lpg_config->base_addr, QPNP_RAMP_STEP_DURATION_MSB, 1, chip);
+}
+
+static int qpnp_lpg_configure_pause(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lut_config lut_config = lpg_config->lut_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ u8 value, mask;
+ int rc = 0;
+
+ if (lut_config.enable_pause_hi) {
+ value = lut_config.lut_pause_hi_cnt;
+ mask = QPNP_PAUSE_HI_MULTIPLIER_LSB_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_LSB],
+ lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_LSB, 1, chip);
+ if (rc)
+ return rc;
+
+ value = (lut_config.lut_pause_hi_cnt >>
+ QPNP_PAUSE_HI_MULTIPLIER_MSB_SHIFT) &
+ QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK;
+
+ mask = QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_MSB],
+ lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_MSB, 1, chip);
+ } else {
+ value = 0;
+ mask = QPNP_PAUSE_HI_MULTIPLIER_LSB_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_LSB],
+ lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_LSB, 1, chip);
+ if (rc)
+ return rc;
+
+ mask = QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_MSB],
+ lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_MSB, 1, chip);
+ if (rc)
+ return rc;
+
+ }
+
+ if (lut_config.enable_pause_lo) {
+ value = lut_config.lut_pause_lo_cnt;
+ mask = QPNP_PAUSE_LO_MULTIPLIER_LSB_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_LSB],
+ lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_LSB, 1, chip);
+ if (rc)
+ return rc;
+
+ value = (lut_config.lut_pause_lo_cnt >>
+ QPNP_PAUSE_LO_MULTIPLIER_MSB_SHIFT) &
+ QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK;
+
+ mask = QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_MSB],
+ lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_MSB, 1, chip);
+ } else {
+ value = 0;
+ mask = QPNP_PAUSE_LO_MULTIPLIER_LSB_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_LSB],
+ lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_LSB, 1, chip);
+ if (rc)
+ return rc;
+
+ mask = QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_MSB],
+ lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_MSB, 1, chip);
+ return rc;
+ }
+
+ return rc;
+}
+
+static int qpnp_lpg_configure_index(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lut_config lut_config = lpg_config->lut_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ u8 value, mask;
+ int rc = 0;
+
+ value = lut_config.hi_index;
+ mask = QPNP_HI_INDEX_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_HI_INDEX],
+ lpg_config->base_addr, QPNP_HI_INDEX, 1, chip);
+ if (rc)
+ return rc;
+
+ value = lut_config.lo_index;
+ mask = QPNP_LO_INDEX_MASK;
+
+ rc = qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_LO_INDEX],
+ lpg_config->base_addr, QPNP_LO_INDEX, 1, chip);
+
+ return rc;
+}
+
+static int qpnp_lpg_change_lut(struct pwm_device *pwm)
+{
+ int rc;
+
+ rc = qpnp_lpg_configure_pattern(pwm);
+ if (rc) {
+ pr_err("Failed to configure LUT pattern");
+ return rc;
+ }
+ rc = qpnp_lpg_configure_pwm(pwm);
+ if (rc) {
+ pr_err("Failed to configure LUT pattern");
+ return rc;
+ }
+ rc = qpnp_lpg_configure_control(pwm);
+ if (rc) {
+ pr_err("Failed to configure pause registers");
+ return rc;
+ }
+ rc = qpnp_lpg_configure_ramp_step_duration(pwm);
+ if (rc) {
+ pr_err("Failed to configure duty time");
+ return rc;
+ }
+ rc = qpnp_lpg_configure_pause(pwm);
+ if (rc) {
+ pr_err("Failed to configure pause registers");
+ return rc;
+ }
+ rc = qpnp_lpg_configure_index(pwm);
+ if (rc) {
+ pr_err("Failed to configure index registers");
+ return rc;
+ }
+ return rc;
+}
+
+static int qpnp_lpg_enable_lut(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ u8 value, mask;
+
+ value = pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL];
+
+ QPNP_ENABLE_LUT(value);
+
+ mask = QPNP_RAMP_START_MASK;
+
+ return qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL],
+ lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+}
+
+static int qpnp_lpg_disable_lut(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ u8 value, mask;
+
+ value = pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL];
+
+ QPNP_DISABLE_LUT(value);
+
+ mask = QPNP_RAMP_START_MASK;
+
+ return qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL],
+ lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+}
+
+static int qpnp_lpg_enable_pwm(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ u8 value, mask;
+
+ value = pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL];
+
+ QPNP_ENABLE_PWM(value);
+
+ mask = QPNP_EN_PWM_OUTPUT_MASK;
+
+ return qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
+ lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+}
+
+static int qpnp_lpg_disable_pwm(struct pwm_device *pwm)
+{
+ struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ u8 value, mask;
+
+ value = pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL];
+
+ QPNP_DISABLE_PWM(value);
+
+ mask = QPNP_EN_PWM_OUTPUT_MASK;
+
+ return qpnp_lpg_save_and_write(value, mask,
+ &pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
+ lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+}
+
+static int _pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+{
+ struct qpnp_pwm_config *pwm_config;
+ struct qpnp_lpg_chip *chip;
+ struct pwm_period_config *period;
+ int rc;
+
+ chip = pwm->chip;
+ pwm_config = &pwm->pwm_config;
+ period = &pwm_config->period;
+
+ if (pwm_config->pwm_period != period_us) {
+ qpnp_lpg_calc_period(period_us, period);
+ qpnp_lpg_save_period(pwm);
+ pwm_config->pwm_period = period_us;
+ }
+
+ pwm_config->pwm_duty = duty_us;
+ qpnp_lpg_calc_pwm_value(pwm, period_us, duty_us);
+ rc = qpnp_lpg_save_pwm_value(pwm);
+
+ if (rc) {
+ pr_err("Could not update PWM value for channel %d rc=%d\n",
+ pwm_config->channel_id, rc);
+ return rc;
+ }
+
+ rc = qpnp_lpg_configure_pwm(pwm);
+ if (rc) {
+ pr_err("Could not configure PWM clock for\n");
+ pr_err("channel %d rc=%d\n", pwm_config->channel_id, rc);
+ return rc;
+ }
+
+ rc = qpnp_pwm_configure_control(pwm);
+ if (rc) {
+ pr_err("Could not update PWM control for");
+ pr_err("channel %d rc=%d\n", pwm_config->channel_id, rc);
+ return rc;
+ }
+
+ pwm->chip->lpg_config.lpg_configured = 1;
+
+ pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
+ (unsigned)duty_us, (unsigned)period_us,
+ pwm_config->pwm_value, 1 << period->pwm_size);
+
+ return 0;
+}
+
+static int _pwm_lut_config(struct pwm_device *pwm, int period_us,
+ int duty_pct[], struct lut_params lut_params)
+{
+ struct qpnp_lpg_config *lpg_config;
+ struct qpnp_lut_config *lut_config;
+ struct qpnp_lut_default_config *def_lut_config =
+ &lut_config->def_config;
+ struct pwm_period_config *period;
+ struct qpnp_pwm_config *pwm_config;
+ int start_idx = lut_params.start_idx;
+ int len = lut_params.idx_len;
+ int flags = lut_params.flags;
+ int raw_lut, ramp_step_ms;
+ int rc = 0;
+
+ pwm_config = &pwm->pwm_config;
+ lpg_config = &pwm->chip->lpg_config;
+ lut_config = &lpg_config->lut_config;
+ def_lut_config = &lut_config->def_config;
+
+ if ((start_idx + len) > lpg_config->lut_size) {
+ pr_err("Exceed LUT limit\n");
+ return -EINVAL;
+ }
+ if ((unsigned)period_us > PM_PWM_PERIOD_MAX ||
+ (unsigned)period_us < PM_PWM_PERIOD_MIN) {
+ pr_err("Period out of range\n");
+ return -EINVAL;
+ }
+
+ if (!pwm_config->in_use) {
+ pr_err("channel_id: %d: stale handle?\n",
+ pwm_config->channel_id);
+ return -EINVAL;
+ }
+
+ period = &pwm_config->period;
+
+ if (pwm_config->pwm_period != period_us) {
+ qpnp_lpg_calc_period(period_us, period);
+ qpnp_lpg_save_period(pwm);
+ pwm_config->pwm_period = period_us;
+ }
+
+ if (flags & PM_PWM_LUT_NO_TABLE)
+ goto after_table_write;
+
+ raw_lut = 0;
+ if (flags & PM_PWM_LUT_USE_RAW_VALUE)
+ raw_lut = 1;
+
+ lut_config->list_size = len;
+ lut_config->lo_index = start_idx;
+ lut_config->hi_index = start_idx + len - 1;
+
+ /*
+ * LUT may not be specified in device tree by default.
+ * This is the first time user is configuring it.
+ */
+ if (lpg_config->bypass_lut) {
+ def_lut_config->duty_pct_list = kzalloc(sizeof(u32) *
+ len, GFP_KERNEL);
+ if (!def_lut_config->duty_pct_list) {
+ pr_err("kzalloc failed on def_duty_pct_list\n");
+ return -ENOMEM;
+ }
+
+ lut_config->duty_pct_list = kzalloc(lpg_config->lut_size *
+ sizeof(u16), GFP_KERNEL);
+ if (!lut_config->duty_pct_list) {
+ pr_err("kzalloc failed on duty_pct_list\n");
+ kfree(def_lut_config->duty_pct_list);
+ return -ENOMEM;
+ }
+
+ def_lut_config->size = len;
+ def_lut_config->start_idx = start_idx;
+ memcpy(def_lut_config->duty_pct_list, duty_pct, len);
+
+ lpg_config->bypass_lut = 0;
+ }
+
+ rc = qpnp_lpg_change_table(pwm, duty_pct, raw_lut);
+ if (rc) {
+ pr_err("qpnp_lpg_change_table: rc=%d\n", rc);
+ return -EINVAL;
+ }
+
+after_table_write:
+ ramp_step_ms = lut_params.ramp_step_ms;
+
+ if (ramp_step_ms > PM_PWM_LUT_RAMP_STEP_TIME_MAX)
+ ramp_step_ms = PM_PWM_LUT_RAMP_STEP_TIME_MAX;
+
+ QPNP_SET_PAUSE_CNT(lut_config->lut_pause_lo_cnt,
+ lut_params.lut_pause_lo, ramp_step_ms);
+ if (lut_config->lut_pause_lo_cnt > PM_PWM_LUT_PAUSE_MAX)
+ lut_config->lut_pause_lo_cnt = PM_PWM_LUT_PAUSE_MAX;
+
+ QPNP_SET_PAUSE_CNT(lut_config->lut_pause_hi_cnt,
+ lut_params.lut_pause_hi, ramp_step_ms);
+ if (lut_config->lut_pause_hi_cnt > PM_PWM_LUT_PAUSE_MAX)
+ lut_config->lut_pause_hi_cnt = PM_PWM_LUT_PAUSE_MAX;
+
+ lut_config->ramp_step_ms = ramp_step_ms;
+
+ lut_config->ramp_direction = !!(flags & PM_PWM_LUT_RAMP_UP);
+ lut_config->pattern_repeat = !!(flags & PM_PWM_LUT_LOOP);
+ lut_config->ramp_toggle = !!(flags & PM_PWM_LUT_REVERSE);
+ lut_config->enable_pause_hi = !!(flags & PM_PWM_LUT_PAUSE_HI_EN);
+ lut_config->enable_pause_lo = !!(flags & PM_PWM_LUT_PAUSE_LO_EN);
+ lpg_config->bypass_lut = 0;
+
+ rc = qpnp_lpg_change_lut(pwm);
+
+ if (!rc)
+ lpg_config->lpg_configured = 1;
+
+ return rc;
+}
+
+/* APIs */
+/**
+ * pwm_request - request a PWM device
+ * @channel_id: PWM id or channel
+ * @lable: the label to identify the user
+ */
+struct pwm_device *pwm_request(int pwm_id, const char *lable)
+{
+ struct qpnp_lpg_chip *chip;
+ struct pwm_device *pwm;
+
+ chip = radix_tree_lookup(&lpg_dev_tree, pwm_id);
+
+ if (!chip) {
+ pr_err("Could not find PWM Device for the\n");
+ pr_err("input pwm channel %d\n", pwm_id);
+ return ERR_PTR(-EINVAL);
+ }
+
+ mutex_lock(&chip->lpg_mutex);
+
+ pwm = &chip->pwm_dev;
+
+ if (pwm->pwm_config.in_use) {
+ pr_err("PWM device associated with the");
+ pr_err("input pwm id: %d is in use by %s",
+ pwm_id, pwm->pwm_config.lable);
+ pwm = ERR_PTR(-EBUSY);
+ } else {
+ pwm->pwm_config.in_use = 1;
+ pwm->pwm_config.lable = lable;
+ }
+
+ mutex_unlock(&chip->lpg_mutex);
+
+ return pwm;
+}
+EXPORT_SYMBOL_GPL(pwm_request);
+
+/**
+ * pwm_free - free a PWM device
+ * @pwm: the PWM device
+ */
+void pwm_free(struct pwm_device *pwm)
+{
+ struct qpnp_pwm_config *pwm_config;
+
+ if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
+ pr_err("Invalid pwm handle or no pwm_chip\n");
+ return;
+ }
+
+ mutex_lock(&pwm->chip->lpg_mutex);
+
+ pwm_config = &pwm->pwm_config;
+
+ if (pwm_config->in_use) {
+ qpnp_lpg_disable_pwm(pwm);
+ qpnp_lpg_disable_lut(pwm);
+ pwm_config->in_use = 0;
+ pwm_config->lable = NULL;
+ pwm->chip->lpg_config.lpg_configured = 0;
+ }
+
+ mutex_unlock(&pwm->chip->lpg_mutex);
+}
+EXPORT_SYMBOL_GPL(pwm_free);
+
+/**
+ * pwm_config - change a PWM device configuration
+ * @pwm: the PWM device
+ * @period_us: period in microseconds
+ * @duty_us: duty cycle in microseconds
+ */
+int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+{
+ int rc;
+
+ if (pwm == NULL || IS_ERR(pwm) ||
+ duty_us > period_us ||
+ (unsigned)period_us > PM_PWM_PERIOD_MAX ||
+ (unsigned)period_us < PM_PWM_PERIOD_MIN) {
+ pr_err("Invalid pwm handle or parameters\n");
+ return -EINVAL;
+ }
+
+ if (!pwm->pwm_config.in_use)
+ return -EINVAL;
+
+ mutex_lock(&pwm->chip->lpg_mutex);
+ rc = _pwm_config(pwm, duty_us, period_us);
+ mutex_unlock(&pwm->chip->lpg_mutex);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_config);
+
+/**
+ * pwm_enable - start a PWM output toggling
+ * @pwm: the PWM device
+ */
+int pwm_enable(struct pwm_device *pwm)
+{
+ struct qpnp_pwm_config *p_config;
+ struct qpnp_lpg_chip *chip;
+ int rc = 0;
+
+ if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
+ pr_err("Invalid pwm handle or no pwm_chip\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&pwm->chip->lpg_mutex);
+
+ chip = pwm->chip;
+ p_config = &pwm->pwm_config;
+
+ if (!p_config->in_use) {
+ pr_err("channel_id: %d: stale handle?\n", p_config->channel_id);
+ rc = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (!pwm->chip->lpg_config.lpg_configured) {
+ pr_err("Request received to enable PWM for channel Id: %d\n",
+ p_config->channel_id);
+ pr_err("However, PWM isn't configured\n");
+ pr_err("falling back to defaultconfiguration\n");
+ rc = _pwm_config(pwm, p_config->pwm_duty,
+ p_config->pwm_period);
+ if (rc) {
+ pr_err("Could not apply default PWM config\n");
+ goto out_unlock;
+ }
+ }
+
+ rc = qpnp_lpg_enable_pwm(pwm);
+
+out_unlock:
+ mutex_unlock(&pwm->chip->lpg_mutex);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_enable);
+
+/**
+ * pwm_disable - stop a PWM output toggling
+ * @pwm: the PWM device
+ */
+void pwm_disable(struct pwm_device *pwm)
+{
+ struct qpnp_pwm_config *pwm_config;
+ struct qpnp_lpg_chip *chip;
+
+ if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
+ pr_err("Invalid pwm handle or no pwm_chip\n");
+ return;
+ }
+
+ mutex_lock(&pwm->chip->lpg_mutex);
+
+ chip = pwm->chip;
+ pwm_config = &pwm->pwm_config;
+
+ if (pwm_config->in_use) {
+ if (!pwm->chip->lpg_config.lpg_configured) {
+ pr_err("Request received to disable PWM for\n");
+ pr_err("channel Id: %d\n", pwm_config->channel_id);
+ pr_err("However PWM is not configured by any means\n");
+ goto out_unlock;
+ }
+ qpnp_lpg_disable_pwm(pwm);
+ }
+
+out_unlock:
+ mutex_unlock(&pwm->chip->lpg_mutex);
+}
+EXPORT_SYMBOL_GPL(pwm_disable);
+
+/**
+ * pwm_config_period - change PWM period
+ *
+ * @pwm: the PWM device
+ * @pwm_p: period in struct qpnp_lpg_period
+ */
+int pwm_config_period(struct pwm_device *pwm,
+ struct pwm_period_config *period)
+{
+ struct qpnp_pwm_config *pwm_config;
+ struct qpnp_lpg_config *lpg_config;
+ struct qpnp_lpg_chip *chip;
+ int rc = 0;
+
+ if (pwm == NULL || IS_ERR(pwm) || period == NULL)
+ return -EINVAL;
+ if (pwm->chip == NULL)
+ return -ENODEV;
+
+ mutex_lock(&pwm->chip->lpg_mutex);
+
+ chip = pwm->chip;
+ pwm_config = &pwm->pwm_config;
+ lpg_config = &chip->lpg_config;
+
+ if (!pwm_config->in_use) {
+ rc = -EINVAL;
+ goto out_unlock;
+ }
+
+ pwm_config->period.pwm_size = period->pwm_size;
+ pwm_config->period.clk = period->clk;
+ pwm_config->period.pre_div = period->pre_div;
+ pwm_config->period.pre_div_exp = period->pre_div_exp;
+
+ qpnp_lpg_save_period(pwm);
+
+ rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+ SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+ QPNP_LPG_PWM_SIZE_CLK),
+ &chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK], 1);
+
+ if (rc) {
+ pr_err("Write failed: QPNP_LPG_PWM_SIZE_CLK register, rc: %d\n",
+ rc);
+ goto out_unlock;
+ }
+
+ rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+ SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+ QPNP_LPG_PWM_FREQ_PREDIV_CLK),
+ &chip->qpnp_lpg_registers[QPNP_LPG_PWM_FREQ_PREDIV_CLK], 1);
+ if (rc) {
+ pr_err("Failed to write to QPNP_LPG_PWM_FREQ_PREDIV_CLK\n");
+ pr_err("register, rc = %d\n", rc);
+ }
+
+out_unlock:
+ mutex_unlock(&pwm->chip->lpg_mutex);
+ return rc;
+}
+EXPORT_SYMBOL(pwm_config_period);
+
+/**
+ * pwm_config_pwm_value - change a PWM device configuration
+ * @pwm: the PWM device
+ * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
+ */
+int pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value)
+{
+ struct qpnp_lpg_config *lpg_config;
+ struct qpnp_pwm_config *pwm_config;
+ int rc = 0;
+
+ if (pwm == NULL || IS_ERR(pwm))
+ return -EINVAL;
+
+ if (pwm->chip == NULL)
+ return -ENODEV;
+
+ lpg_config = &pwm->chip->lpg_config;
+ pwm_config = &pwm->pwm_config;
+
+ mutex_lock(&pwm->chip->lpg_mutex);
+
+ if (!pwm_config->in_use || !pwm_config->pwm_period) {
+ rc = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (pwm_config->pwm_value == pwm_value)
+ goto out_unlock;
+
+ pwm_config->pwm_value = pwm_value;
+
+ rc = qpnp_lpg_save_pwm_value(pwm);
+
+ if (rc)
+ pr_err("Could not update PWM value for channel %d rc=%d\n",
+ pwm_config->channel_id, rc);
+
+out_unlock:
+ mutex_unlock(&pwm->chip->lpg_mutex);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_config_pwm_value);
+
+/**
+ * pwm_lut_config - change LPG LUT device configuration
+ * @pwm: the PWM device
+ * @period_us: period in micro second
+ * @duty_pct: array of duty cycles in percent, like 20, 50.
+ * @lut_params: Lookup table parameters
+ */
+int pwm_lut_config(struct pwm_device *pwm, int period_us,
+ int duty_pct[], struct lut_params lut_params)
+{
+ int rc = 0;
+
+ if (pwm == NULL || IS_ERR(pwm) || !lut_params.idx_len) {
+ pr_err("Invalid pwm handle or idx_len=0\n");
+ return -EINVAL;
+ }
+
+ if (pwm->chip == NULL)
+ return -ENODEV;
+
+ if (duty_pct == NULL && !(lut_params.flags & PM_PWM_LUT_NO_TABLE)) {
+ pr_err("Invalid duty_pct with flag\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&pwm->chip->lpg_mutex);
+
+ rc = _pwm_lut_config(pwm, period_us, duty_pct, lut_params);
+
+ mutex_unlock(&pwm->chip->lpg_mutex);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_lut_config);
+
+/**
+ * pwm_lut_enable - control a PWM device to start/stop LUT ramp
+ * @pwm: the PWM device
+ * @start: to start (1), or stop (0)
+ */
+int pwm_lut_enable(struct pwm_device *pwm, int start)
+{
+ struct qpnp_lpg_config *lpg_config;
+ struct qpnp_pwm_config *p_config;
+ struct lut_params lut_params;
+ int rc = 0;
+
+ if (pwm == NULL || IS_ERR(pwm)) {
+ pr_err("Invalid pwm handle\n");
+ return -EINVAL;
+ }
+
+ if (pwm->chip == NULL)
+ return -ENODEV;
+
+ lpg_config = &pwm->chip->lpg_config;
+ p_config = &pwm->pwm_config;
+
+ mutex_lock(&pwm->chip->lpg_mutex);
+
+ if (start) {
+ if (!lpg_config->lpg_configured) {
+ pr_err("Request received to enable LUT for\n");
+ pr_err("LPG channel %d\n", pwm->pwm_config.channel_id);
+ pr_err("But LPG is not configured, falling back to\n");
+ pr_err(" default LUT configuration if available\n");
+
+ if (lpg_config->bypass_lut) {
+ pr_err("No default LUT configuration found\n");
+ pr_err("Use pwm_lut_config() to configure\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ qpnp_set_lut_params(&lut_params,
+ &lpg_config->lut_config);
+
+ rc = _pwm_lut_config(pwm, p_config->pwm_period,
+ (int *)lpg_config->lut_config.def_config.duty_pct_list,
+ lut_params);
+ if (rc) {
+ pr_err("Could not set the default LUT conf\n");
+ goto out;
+ }
+ }
+
+ rc = qpnp_lpg_enable_lut(pwm);
+ } else {
+ if (unlikely(!lpg_config->lpg_configured)) {
+ pr_err("LPG isn't configured\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = qpnp_lpg_disable_lut(pwm);
+ }
+
+out:
+ mutex_unlock(&pwm->chip->lpg_mutex);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_lut_enable);
+
+/* Fill in lpg device elements based on values found in device tree. */
+static int qpnp_lpg_get_dt_config(struct spmi_device *spmi,
+ struct qpnp_lpg_chip *chip)
+{
+ int rc;
+ struct resource *res;
+ struct device_node *of_node = spmi->dev.of_node;
+ struct qpnp_lpg_config *lpg_config = &chip->lpg_config;
+ struct pwm_device *pwm_dev = &chip->pwm_dev;
+ struct qpnp_lut_config *lut_config = &chip->lpg_config.lut_config;
+ struct qpnp_lut_default_config *def_lut_config =
+ &lut_config->def_config;
+
+ res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&spmi->dev, "%s: node is missing base address\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ lpg_config->base_addr = res->start;
+
+ res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&spmi->dev, "%s: node is missing LUT base address\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ lpg_config->lut_base_addr = res->start;
+ /* Each entry of LUT is of 2 bytes */
+ lpg_config->lut_size = resource_size(res) >> 1;
+
+
+ rc = of_property_read_u32(of_node, "qcom,channel-id",
+ &pwm_dev->pwm_config.channel_id);
+ if (rc) {
+ dev_err(&spmi->dev, "%s: node is missing LPG channel id",
+ __func__);
+ return rc;
+ }
+
+ rc = of_property_read_u32(of_node, "qcom,period",
+ &pwm_dev->pwm_config.pwm_period);
+ if (rc) {
+ dev_err(&spmi->dev, "%s: node is missing PWM Period value",
+ __func__);
+ return rc;
+ }
+
+ if (!of_get_property(of_node, "qcom,duty-percents",
+ &def_lut_config->size)) {
+ lpg_config->bypass_lut = 1;
+ }
+
+ if (lpg_config->bypass_lut)
+ goto read_opt_props;
+
+ rc = of_property_read_u32(of_node, "qcom,start-index",
+ &def_lut_config->start_idx);
+
+ if (rc) {
+ dev_err(&spmi->dev, "Missing start index");
+ return rc;
+ }
+
+ def_lut_config->size /= sizeof(u32);
+
+ def_lut_config->duty_pct_list = kzalloc(sizeof(u32) *
+ def_lut_config->size, GFP_KERNEL);
+ if (!def_lut_config->duty_pct_list) {
+ dev_err(&spmi->dev, "%s: kzalloc failed on duty_pct_list\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ rc = of_property_read_u32_array(of_node, "qcom,duty-percents",
+ def_lut_config->duty_pct_list, def_lut_config->size);
+ if (rc) {
+ dev_err(&spmi->dev, "invalid or missing property:\n");
+ dev_err(&spmi->dev, "qcom,duty-pcts-list\n");
+ kfree(def_lut_config->duty_pct_list);
+ return rc;
+ }
+
+ lut_config->duty_pct_list = kzalloc(lpg_config->lut_size * sizeof(u16),
+ GFP_KERNEL);
+ if (!lut_config->duty_pct_list) {
+ dev_err(&spmi->dev, "can not allocate duty pct list\n");
+ kfree(def_lut_config->duty_pct_list);
+ return -ENOMEM;
+ }
+
+read_opt_props:
+ /* Initialize optional config parameters from DT if provided */
+ of_property_read_u32(of_node, "qcom,duty",
+ &pwm_dev->pwm_config.pwm_duty);
+ of_property_read_u32(of_node, "qcom,ramp-step-duration",
+ &lut_config->ramp_step_ms);
+ of_property_read_u32(of_node, "qcom,lpg-lut-pause-hi",
+ &lut_config->lut_pause_hi_cnt);
+ of_property_read_u32(of_node, "qcom,lpg-lut-pause-lo",
+ &lut_config->lut_pause_lo_cnt);
+ of_property_read_u32(of_node, "qcom,lpg-lut-ramp-direction",
+ (u32 *)&lut_config->ramp_direction);
+ of_property_read_u32(of_node, "qcom,lpg-lut-pattern-repeat",
+ (u32 *)&lut_config->pattern_repeat);
+ of_property_read_u32(of_node, "qcom,lpg-lut-ramp-toggle",
+ (u32 *)&lut_config->ramp_toggle);
+ of_property_read_u32(of_node, "qcom,lpg-lut-enable-pause-hi",
+ (u32 *)&lut_config->enable_pause_hi);
+ of_property_read_u32(of_node, "qcom,lpg-lut-enable-pause-lo",
+ (u32 *)&lut_config->enable_pause_lo);
+
+ return 0;
+}
+
+static int __devinit qpnp_pwm_probe(struct spmi_device *spmi)
+{
+ struct qpnp_lpg_chip *chip;
+ int rc, id;
+
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ if (chip == NULL) {
+ pr_err("kzalloc() failed.\n");
+ return -ENOMEM;
+ }
+
+ mutex_init(&chip->lpg_mutex);
+
+ chip->spmi_dev = spmi;
+ chip->pwm_dev.chip = chip;
+ dev_set_drvdata(&spmi->dev, chip);
+
+ rc = qpnp_lpg_get_dt_config(spmi, chip);
+
+ if (rc)
+ goto failed_config;
+
+ id = chip->pwm_dev.pwm_config.channel_id;
+
+ rc = radix_tree_insert(&lpg_dev_tree, id, chip);
+
+ if (rc) {
+ dev_err(&spmi->dev, "%s: Failed to register LPG Channel %d\n",
+ __func__, id);
+ goto failed_insert;
+ }
+
+ return 0;
+
+failed_insert:
+ kfree(chip->lpg_config.lut_config.duty_pct_list);
+failed_config:
+ dev_set_drvdata(&spmi->dev, NULL);
+ mutex_destroy(&chip->lpg_mutex);
+ kfree(chip);
+ return rc;
+}
+
+static int __devexit qpnp_pwm_remove(struct spmi_device *spmi)
+{
+ struct qpnp_lpg_chip *chip;
+ struct qpnp_lpg_config *lpg_config;
+
+ chip = dev_get_drvdata(&spmi->dev);
+
+ dev_set_drvdata(&spmi->dev, NULL);
+
+ if (chip) {
+ lpg_config = &chip->lpg_config;
+ kfree(lpg_config->lut_config.duty_pct_list);
+ kfree(lpg_config->lut_config.def_config.duty_pct_list);
+ mutex_destroy(&chip->lpg_mutex);
+ kfree(chip);
+ }
+
+ return 0;
+}
+
+static struct of_device_id spmi_match_table[] = {
+ { .compatible = QPNP_LPG_DRIVER_NAME, },
+ {}
+};
+
+static const struct spmi_device_id qpnp_lpg_id[] = {
+ { QPNP_LPG_DRIVER_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spmi, qpnp_lpg_id);
+
+static struct spmi_driver qpnp_lpg_driver = {
+ .driver = {
+ .name = QPNP_LPG_DRIVER_NAME,
+ .of_match_table = spmi_match_table,
+ .owner = THIS_MODULE,
+ },
+ .probe = qpnp_pwm_probe,
+ .remove = __devexit_p(qpnp_pwm_remove),
+ .id_table = qpnp_lpg_id,
+};
+
+/**
+ * qpnp_lpg_init() - register spmi driver for qpnp-lpg
+ */
+int __init qpnp_lpg_init(void)
+{
+ return spmi_driver_register(&qpnp_lpg_driver);
+}
+
+static void __exit qpnp_lpg_exit(void)
+{
+ spmi_driver_unregister(&qpnp_lpg_driver);
+}
+
+MODULE_DESCRIPTION("QPNP PMIC LPG driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_LPG_DRIVER_NAME);
+
+subsys_initcall(qpnp_lpg_init);
+module_exit(qpnp_lpg_exit);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 87b307c..c95f82d 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -123,13 +123,7 @@
# - discrete ones (including all PCI-only controllers)
# - debug/dummy gadget+hcd is last.
#
-choice
- prompt "USB Peripheral Controller"
- help
- A USB device uses a controller to talk to its host.
- Systems should have only one such upstream link.
- Many controller drivers are platform-specific; these
- often need board-specific hooks.
+menu "USB Peripheral Controller"
#
# Integrated controllers
@@ -574,7 +568,7 @@
# NOTE: Please keep dummy_hcd LAST so that "real hardware" appears
# first and will be selected by default.
-endchoice
+endmenu
# Selected by UDC drivers that support high-speed operation.
config USB_GADGET_DUALSPEED
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index b5a7291..a13b5da 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1801,6 +1801,9 @@
goto err_dev;
}
+ if (pdata)
+ composite_driver.usb_core_id = pdata->usb_core_id;
+
ret = usb_composite_probe(&android_usb_driver, android_bind);
if (ret) {
pr_err("%s(): Failed to register android "
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index f353b07..5d5ee00 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -635,7 +635,7 @@
struct resource *res;
struct msm_hsic_per *mhsic;
int ret = 0;
- struct msm_hsic_peripheral_platform_data *pdata;
+ struct ci13xxx_platform_data *pdata;
dev_dbg(&pdev->dev, "msm-hsic probe\n");
@@ -654,7 +654,8 @@
the_mhsic = mhsic;
platform_set_drvdata(pdev, mhsic);
mhsic->dev = &pdev->dev;
- mhsic->pdata = pdata;
+ mhsic->pdata =
+ (struct msm_hsic_peripheral_platform_data *)pdata->prv_data;
mhsic->irq = platform_get_irq(pdev, 0);
if (mhsic->irq < 0) {
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 771dbb7..bb6bb2c 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2739,6 +2739,11 @@
{
static bool init;
struct msm_otg *motg = the_msm_otg;
+ struct usb_otg *otg = motg->phy.otg;
+
+ /* In A Host Mode, ignore received BSV interrupts */
+ if (otg->phy->state >= OTG_STATE_A_IDLE)
+ return;
if (online) {
pr_debug("PMIC: BSV set\n");
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index ea9e5ab..2cbef69 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -49,6 +49,7 @@
static struct clk *mdp_pclk;
static struct clk *mdp_lut_clk;
int mdp_rev;
+int mdp_iommu_split_domain;
static struct platform_device *mdp_init_pdev;
static struct regulator *footswitch, *hdmi_pll_fs;
@@ -2240,6 +2241,7 @@
}
mdp_rev = mdp_pdata->mdp_rev;
+ mdp_iommu_split_domain = mdp_pdata->mdp_iommu_split_domain;
rc = mdp_irq_clk_setup(pdev, mdp_pdata->cont_splash_enabled);
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index e60b24e..f8d54bd 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -42,6 +42,7 @@
extern ulong mdp4_display_intf;
extern spinlock_t mdp_spin_lock;
extern int mdp_rev;
+extern int mdp_iommu_split_domain;
extern struct mdp_csc_cfg mdp_csc_convert[4];
extern struct workqueue_struct *mdp_hist_wq;
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index ad37d2f..3afe28b 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -126,7 +126,7 @@
pr_debug("mixer %u, pipe %u, plane %u\n", pipe->mixer_num,
pipe->pipe_ndx, plane);
if (ion_map_iommu(display_iclient, *srcp_ihdl,
- DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 0, start,
+ DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K, 0, start,
len, 0, ION_IOMMU_UNMAP_DELAYED)) {
ion_free(display_iclient, *srcp_ihdl);
pr_err("ion_map_iommu() failed\n");
@@ -140,7 +140,7 @@
if (iom_pipe_info->prev_ihdl[plane]) {
ion_unmap_iommu(display_iclient,
iom_pipe_info->prev_ihdl[plane],
- DISPLAY_DOMAIN, GEN_POOL);
+ DISPLAY_READ_DOMAIN, GEN_POOL);
ion_free(display_iclient,
iom_pipe_info->prev_ihdl[plane]);
pr_debug("Previous: mixer %u, pipe %u, plane %u, "
@@ -175,7 +175,7 @@
iom_pipe_info->prev_ihdl[i]);
ion_unmap_iommu(display_iclient,
iom_pipe_info->prev_ihdl[i],
- DISPLAY_DOMAIN, GEN_POOL);
+ DISPLAY_READ_DOMAIN, GEN_POOL);
ion_free(display_iclient,
iom_pipe_info->prev_ihdl[i]);
iom_pipe_info->prev_ihdl[i] = NULL;
@@ -191,7 +191,7 @@
iom_pipe_info->ihdl[i]);
ion_unmap_iommu(display_iclient,
iom_pipe_info->ihdl[i],
- DISPLAY_DOMAIN, GEN_POOL);
+ DISPLAY_READ_DOMAIN, GEN_POOL);
ion_free(display_iclient,
iom_pipe_info->ihdl[i]);
iom_pipe_info->ihdl[i] = NULL;
@@ -424,9 +424,6 @@
if (mdp_is_in_isr == FALSE)
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- /* dma_p source */
- MDP_OUTP(MDP_BASE + 0x90004,
- (pipe->src_height << 16 | pipe->src_width));
if (pipe->blt_addr) {
#ifdef BLT_RGB565
bpp = 2; /* overlay ouput is RGB565 */
@@ -443,6 +440,9 @@
MDP_OUTP(MDP_BASE + 0x90008, pipe->srcp0_addr);
MDP_OUTP(MDP_BASE + 0x9000c, pipe->srcp0_ystride);
}
+ /* dma_p source */
+ MDP_OUTP(MDP_BASE + 0x90004,
+ (pipe->src_height << 16 | pipe->src_width));
/* dma_p dest */
MDP_OUTP(MDP_BASE + 0x90010, (pipe->dst_y << 16 | pipe->dst_x));
@@ -3120,7 +3120,6 @@
/* primary interface */
ctrl->mixer0_played++;
if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
- mdp4_overlay_reg_flush(pipe, 0);
mdp4_overlay_lcdc_start();
mdp4_overlay_lcdc_vsync_push(mfd, pipe);
if (!mfd->use_ov0_blt &&
@@ -3129,7 +3128,6 @@
}
#ifdef CONFIG_FB_MSM_MIPI_DSI
else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
- mdp4_overlay_reg_flush(pipe, 0);
mdp4_overlay_dsi_video_start();
mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
if (!mfd->use_ov0_blt &&
@@ -3182,29 +3180,54 @@
return ret;
}
-static struct {
+struct msm_iommu_ctx {
char *name;
int domain;
-} msm_iommu_ctx_names[] = {
- /* Display */
+};
+
+static struct msm_iommu_ctx msm_iommu_ctx_names[] = {
+ /* Display read*/
{
.name = "mdp_port0_cb0",
- .domain = DISPLAY_DOMAIN,
+ .domain = DISPLAY_READ_DOMAIN,
},
- /* Display */
+ /* Display read*/
{
.name = "mdp_port0_cb1",
- .domain = DISPLAY_DOMAIN,
+ .domain = DISPLAY_READ_DOMAIN,
},
- /* Display */
+ /* Display write */
{
.name = "mdp_port1_cb0",
- .domain = DISPLAY_DOMAIN,
+ .domain = DISPLAY_READ_DOMAIN,
},
- /* Display */
+ /* Display write */
{
.name = "mdp_port1_cb1",
- .domain = DISPLAY_DOMAIN,
+ .domain = DISPLAY_READ_DOMAIN,
+ },
+};
+
+static struct msm_iommu_ctx msm_iommu_split_ctx_names[] = {
+ /* Display read*/
+ {
+ .name = "mdp_port0_cb0",
+ .domain = DISPLAY_READ_DOMAIN,
+ },
+ /* Display read*/
+ {
+ .name = "mdp_port0_cb1",
+ .domain = DISPLAY_WRITE_DOMAIN,
+ },
+ /* Display write */
+ {
+ .name = "mdp_port1_cb0",
+ .domain = DISPLAY_READ_DOMAIN,
+ },
+ /* Display write */
+ {
+ .name = "mdp_port1_cb1",
+ .domain = DISPLAY_WRITE_DOMAIN,
},
};
@@ -3218,19 +3241,28 @@
void mdp4_iommu_attach(void)
{
static int done;
+ struct msm_iommu_ctx *ctx_names;
struct iommu_domain *domain;
- int i;
+ int i, arr_size;
if (!done) {
- for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
+ if (mdp_iommu_split_domain) {
+ ctx_names = msm_iommu_split_ctx_names;
+ arr_size = ARRAY_SIZE(msm_iommu_split_ctx_names);
+ } else {
+ ctx_names = msm_iommu_ctx_names;
+ arr_size = ARRAY_SIZE(msm_iommu_ctx_names);
+ }
+
+ for (i = 0; i < arr_size; i++) {
int domain_idx;
struct device *ctx = msm_iommu_get_ctx(
- msm_iommu_ctx_names[i].name);
+ ctx_names[i].name);
if (!ctx)
continue;
- domain_idx = msm_iommu_ctx_names[i].domain;
+ domain_idx = ctx_names[i].domain;
domain = msm_get_iommu_domain(domain_idx);
if (!domain)
@@ -3242,7 +3274,7 @@
WARN(1, "%s: could not attach domain %d to context %s."
" iommu programming will not occur.\n",
__func__, domain_idx,
- msm_iommu_ctx_names[i].name);
+ ctx_names[i].name);
continue;
}
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 3cdd72e..b0f3e17 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -655,7 +655,7 @@
data &= 0x01;
if (data) { /* timing generator enabled */
mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE);
- mdp4_overlay_dsi_video_wait4event(mfd, INTR_PRIMARY_VSYNC);
+ msleep(20);
}
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index d59c4a8..f426f8c 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -390,6 +390,8 @@
{
struct msmfb_writeback_data_list *temp;
bool found = false;
+ int domain;
+
if (!list_empty(&mfd->writeback_register_queue)) {
list_for_each_entry(temp,
&mfd->writeback_register_queue,
@@ -420,9 +422,14 @@
goto register_ion_fail;
}
+ if (mdp_iommu_split_domain)
+ domain = DISPLAY_WRITE_DOMAIN;
+ else
+ domain = DISPLAY_READ_DOMAIN;
+
if (ion_map_iommu(mfd->iclient,
srcp_ihdl,
- DISPLAY_DOMAIN,
+ domain,
GEN_POOL,
SZ_4K,
0,
@@ -501,7 +508,7 @@
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct msmfb_writeback_data_list *node = NULL;
- int rc = 0;
+ int rc = 0, domain;
rc = wait_event_interruptible(mfd->wait_q, is_buffer_ready(mfd));
if (rc) {
@@ -523,9 +530,14 @@
memcpy(data, &node->buf_info, sizeof(struct msmfb_data));
if (!data->iova)
if (mfd->iclient && node->ihdl) {
+ if (mdp_iommu_split_domain)
+ domain = DISPLAY_WRITE_DOMAIN;
+ else
+ domain = DISPLAY_READ_DOMAIN;
+
ion_unmap_iommu(mfd->iclient,
node->ihdl,
- DISPLAY_DOMAIN,
+ domain,
GEN_POOL);
ion_free(mfd->iclient,
node->ihdl);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index f192b12..8bd125b 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -2591,11 +2591,30 @@
buf->ihdl = ion_alloc(mfd->iclient, buffer_size, SZ_4K,
mfd->mem_hid);
if (!IS_ERR_OR_NULL(buf->ihdl)) {
- if (ion_map_iommu(mfd->iclient, buf->ihdl,
- DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 0, &addr,
- &len, 0, 0)) {
- pr_err("ion_map_iommu() failed\n");
- return -ENOMEM;
+ if (mdp_iommu_split_domain) {
+ if (mfd->mem_hid & ION_SECURE) {
+ if (ion_phys(mfd->iclient, buf->ihdl,
+ &addr, (size_t *)&len)) {
+ pr_err("%s:%d: ion_phys map failed\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+ } else {
+ if (ion_map_iommu(mfd->iclient,
+ buf->ihdl, DISPLAY_WRITE_DOMAIN,
+ GEN_POOL, SZ_4K, 0, &addr, &len,
+ 0, 0)) {
+ pr_err("ion_map_iommu() failed\n");
+ return -ENOMEM;
+ }
+ }
+ } else {
+ if (ion_map_iommu(mfd->iclient, buf->ihdl,
+ DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K,
+ 0, &addr, &len, 0, 0)) {
+ pr_err("ion_map_iommu() failed\n");
+ return -ENOMEM;
+ }
}
} else {
pr_err("%s:%d: ion_alloc failed\n", __func__,
@@ -2629,8 +2648,14 @@
if (!IS_ERR_OR_NULL(mfd->iclient)) {
if (!IS_ERR_OR_NULL(buf->ihdl)) {
- ion_unmap_iommu(mfd->iclient, buf->ihdl,
- DISPLAY_DOMAIN, GEN_POOL);
+ if (mdp_iommu_split_domain) {
+ if (!(mfd->mem_hid & ION_SECURE))
+ ion_unmap_iommu(mfd->iclient, buf->ihdl,
+ DISPLAY_WRITE_DOMAIN, GEN_POOL);
+ } else {
+ ion_unmap_iommu(mfd->iclient, buf->ihdl,
+ DISPLAY_READ_DOMAIN, GEN_POOL);
+ }
ion_free(mfd->iclient, buf->ihdl);
pr_debug("%s:%d free writeback imem\n", __func__,
__LINE__);
diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c
index 4009ffc..8999395 100644
--- a/drivers/video/msm/mdp_ppp.c
+++ b/drivers/video/msm/mdp_ppp.c
@@ -61,6 +61,7 @@
extern uint32 mdp_plv[];
extern struct semaphore mdp_ppp_mutex;
+static struct ion_client *ppp_display_iclient;
int mdp_get_bytes_per_pixel(uint32_t format,
struct msm_fb_data_type *mfd)
@@ -1276,41 +1277,69 @@
return kgsl_gem_obj_addr(img->memory_id, (int) img->priv, start, len);
}
-int get_img(struct mdp_img *img, struct fb_info *info, unsigned long *start,
- unsigned long *len, struct file **pp_file)
+int get_img(struct mdp_img *img, struct mdp_blit_req *req,
+ struct fb_info *info, unsigned long *start, unsigned long *len,
+ struct file **srcp_file, struct ion_handle **srcp_ihdl)
{
- int put_needed, ret = 0;
+ int put_needed, fb_num, ret = 0;
struct file *file;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+#endif
#ifdef CONFIG_ANDROID_PMEM
unsigned long vstart;
#endif
-#ifdef CONFIG_ANDROID_PMEM
- if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file))
- return 0;
-#endif
- file = fget_light(img->memory_id, &put_needed);
- if (file == NULL)
- return -1;
+ if (req->flags & MDP_MEMORY_ID_TYPE_FB) {
+ file = fget_light(img->memory_id, &put_needed);
+ if (file == NULL)
+ return -EINVAL;
- if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
- *start = info->fix.smem_start;
- *len = info->fix.smem_len;
- *pp_file = file;
- } else {
- ret = -1;
- fput_light(file, put_needed);
+ if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
+ fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
+ if (get_fb_phys_info(start, len, fb_num,
+ DISPLAY_SUBSYSTEM_ID)) {
+ pr_err("get_fb_phys_info() failed\n");
+ fput_light(file, put_needed);
+ } else {
+ *srcp_file = file;
+ }
+
+ return ret;
+ } else {
+ fput_light(file, put_needed);
+ }
}
- return ret;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ *srcp_ihdl = ion_import_dma_buf(mfd->iclient, img->memory_id);
+ if (IS_ERR_OR_NULL(*srcp_ihdl))
+ return PTR_ERR(*srcp_ihdl);
+
+ if (!ion_phys(mfd->iclient, *srcp_ihdl, start, (size_t *) len))
+ return ret;
+ else
+ return -EINVAL;
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+ if (!get_pmem_file(img->memory_id, start, &vstart, len, srcp_file))
+ return ret;
+ else
+ return -EINVAL;
+#endif
}
-
-void put_img(struct file *p_src_file)
+void put_img(struct file *p_src_file, struct ion_handle *p_ihdl)
{
#ifdef CONFIG_ANDROID_PMEM
if (p_src_file)
put_pmem_file(p_src_file);
#endif
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ if (!IS_ERR_OR_NULL(p_ihdl))
+ ion_free(ppp_display_iclient, p_ihdl);
+#endif
}
@@ -1318,7 +1347,8 @@
unsigned long srcp0_start, unsigned long srcp0_len,
unsigned long srcp1_start, unsigned long srcp1_len,
unsigned long dst_start, unsigned long dst_len,
- struct file *p_src_file, struct file *p_dst_file)
+ struct file *p_src_file, struct file *p_dst_file,
+ struct ion_handle **src_ihdl, struct ion_handle **dst_ihdl)
{
MDPIBUF iBuf;
u32 dst_width, dst_height;
@@ -1330,9 +1360,9 @@
req->src.format = mfd->fb_imgType;
if (mdp_ppp_verify_req(req)) {
- printk(KERN_ERR "mdp_ppp: invalid image!\n");
- put_img(p_src_file);
- put_img(p_dst_file);
+ pr_err("mdp_ppp: invalid image!\n");
+ put_img(p_src_file, *src_ihdl);
+ put_img(p_dst_file, *dst_ihdl);
return -1;
}
@@ -1402,8 +1432,8 @@
#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP303)
iBuf.mdpImg.mdpOp |= MDPOP_FG_PM_ALPHA;
#else
- put_img(p_src_file);
- put_img(p_dst_file);
+ put_img(p_src_file, *src_ihdl);
+ put_img(p_dst_file, *dst_ihdl);
return -EINVAL;
#endif
}
@@ -1413,8 +1443,8 @@
if ((req->src.format != MDP_Y_CBCR_H2V2) &&
(req->src.format != MDP_Y_CRCB_H2V2)) {
#endif
- put_img(p_src_file);
- put_img(p_dst_file);
+ put_img(p_src_file, *src_ihdl);
+ put_img(p_dst_file, *dst_ihdl);
return -EINVAL;
#ifdef CONFIG_FB_MSM_MDP31
}
@@ -1453,16 +1483,16 @@
printk(KERN_ERR
"%s: sharpening strength out of range\n",
__func__);
- put_img(p_src_file);
- put_img(p_dst_file);
+ put_img(p_src_file, *src_ihdl);
+ put_img(p_dst_file, *dst_ihdl);
return -EINVAL;
}
iBuf.mdpImg.mdpOp |= MDPOP_ASCALE | MDPOP_SHARPENING;
iBuf.mdpImg.sp_value = req->sharpening_strength & 0xff;
#else
- put_img(p_src_file);
- put_img(p_dst_file);
+ put_img(p_src_file, *src_ihdl);
+ put_img(p_dst_file, *dst_ihdl);
return -EINVAL;
#endif
}
@@ -1567,8 +1597,8 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
up(&mdp_ppp_mutex);
- put_img(p_src_file);
- put_img(p_dst_file);
+ put_img(p_src_file, *src_ihdl);
+ put_img(p_dst_file, *dst_ihdl);
return 0;
}
@@ -1578,29 +1608,36 @@
unsigned long src_len = 0;
unsigned long dst_len = 0;
struct file *p_src_file = 0 , *p_dst_file = 0;
+ struct ion_handle *src_ihdl = NULL;
+ struct ion_handle *dst_ihdl = NULL;
+ struct msm_fb_data_type *mfd = info->par;
+ ppp_display_iclient = mfd->iclient;
if (req->flags & MDP_BLIT_SRC_GEM)
get_gem_img(&req->src, &src_start, &src_len);
else
- get_img(&req->src, info, &src_start, &src_len, &p_src_file);
+ get_img(&req->src, req, info, &src_start, &src_len, &p_src_file,
+ &src_ihdl);
if (src_len == 0) {
- printk(KERN_ERR "mdp_ppp: could not retrieve image from "
+ pr_err("mdp_ppp: could not retrieve source image from "
"memory\n");
return -EINVAL;
}
if (req->flags & MDP_BLIT_DST_GEM)
get_gem_img(&req->dst, &dst_start, &dst_len);
else
- get_img(&req->dst, info, &dst_start, &dst_len, &p_dst_file);
+ get_img(&req->dst, req, info, &dst_start, &dst_len, &p_dst_file,
+ &dst_ihdl);
+
if (dst_len == 0) {
- put_img(p_src_file);
- printk(KERN_ERR "mdp_ppp: could not retrieve image from "
+ put_img(p_src_file, src_ihdl);
+ pr_err("mdp_ppp: could not retrieve destination image from "
"memory\n");
return -EINVAL;
}
return mdp_ppp_blit_addr(info, req, src_start, src_len, 0, 0, dst_start,
- dst_len, p_src_file, p_dst_file);
+ dst_len, p_src_file, p_dst_file, &src_ihdl, &dst_ihdl);
}
static struct mdp_blit_req overlay_req;
@@ -1677,7 +1714,8 @@
ret = mdp_ppp_blit_addr(info, &overlay_req,
srcp0_addr, srcp0_size, srcp1_addr, srcp1_size,
- info->fix.smem_start, info->fix.smem_len, NULL, NULL);
+ info->fix.smem_start, info->fix.smem_len, NULL, NULL,
+ NULL, NULL);
if (ret)
pr_err("%s:Blitting overlay failed(%d)\n", __func__, ret);
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 81a6e50..18ee3e6 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1326,7 +1326,7 @@
fbi->fix.smem_start = (unsigned long)fbram_phys;
msm_iommu_map_contig_buffer(fbi->fix.smem_start,
- DISPLAY_DOMAIN,
+ DISPLAY_READ_DOMAIN,
GEN_POOL,
fbi->fix.smem_len,
SZ_4K,
@@ -1334,7 +1334,7 @@
&(mfd->display_iova));
msm_iommu_map_contig_buffer(fbi->fix.smem_start,
- ROTATOR_DOMAIN,
+ ROTATOR_SRC_DOMAIN,
GEN_POOL,
fbi->fix.smem_len,
SZ_4K,
diff --git a/include/linux/msm_audio_mvs.h b/include/linux/msm_audio_mvs.h
index 1807cb0..6fe5b70 100644
--- a/include/linux/msm_audio_mvs.h
+++ b/include/linux/msm_audio_mvs.h
@@ -9,10 +9,10 @@
(AUDIO_MAX_COMMON_IOCTL_NUM + 1), unsigned)
/* MVS modes */
-#define MVS_MODE_IS733 0x1
-#define MVS_MODE_IS127 0x2
-#define MVS_MODE_4GV_NB 0x3
-#define MVS_MODE_4GV_WB 0x4
+#define MVS_MODE_IS733 0x1 /*QCELP 13K*/
+#define MVS_MODE_IS127 0x2 /*EVRC-8k*/
+#define MVS_MODE_4GV_NB 0x3 /*EVRC-B*/
+#define MVS_MODE_4GV_WB 0x4 /*EVRC-WB*/
#define MVS_MODE_AMR 0x5
#define MVS_MODE_EFR 0x6
#define MVS_MODE_FR 0x7
@@ -47,12 +47,17 @@
MVS_AMR_MODE_UNDEF
};
+/*The MVS VOC rate type is used to identify the rate of QCELP 13K(IS733),
+EVRC(IS127), 4GV, or 4GV-WB frame.*/
enum msm_audio_voc_rate {
MVS_VOC_0_RATE, /* Blank frame */
MVS_VOC_8_RATE, /* 1/8 rate */
MVS_VOC_4_RATE, /* 1/4 rate */
MVS_VOC_2_RATE, /* 1/2 rate */
- MVS_VOC_1_RATE /* Full rate */
+ MVS_VOC_1_RATE,/* Full rate */
+ MVS_VOC_ERASURE, /* erasure frame */
+ MVS_VOC_RATE_MAX,
+ MVS_VOC_RATE_UNDEF = MVS_VOC_RATE_MAX
};
enum msm_audio_amr_frame_type {
@@ -72,6 +77,11 @@
MVS_G711A_MODE_ALAW
};
+enum msm_audio_g711_mode {
+ MVS_G711_MODE_MULAW,
+ MVS_G711_MODE_ALAW
+};
+
enum mvs_g722_mode_type {
MVS_G722_MODE_01,
MVS_G722_MODE_02,
diff --git a/include/linux/msm_rotator.h b/include/linux/msm_rotator.h
index 0f15a8b..463e5ce 100644
--- a/include/linux/msm_rotator.h
+++ b/include/linux/msm_rotator.h
@@ -55,6 +55,7 @@
#ifdef CONFIG_MSM_BUS_SCALING
struct msm_bus_scale_pdata *bus_scale_table;
#endif
+ char rot_iommu_split_domain;
};
#endif
diff --git a/include/linux/qpnp/pwm.h b/include/linux/qpnp/pwm.h
new file mode 100644
index 0000000..de89a37
--- /dev/null
+++ b/include/linux/qpnp/pwm.h
@@ -0,0 +1,168 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QPNP_PWM_H__
+#define __QPNP_PWM_H__
+
+#include <linux/pwm.h>
+
+/* usec: 19.2M, n=6, m=0, pre=2 */
+#define PM_PWM_PERIOD_MIN 7
+/* 1K, n=9, m=7, pre=6 */
+#define PM_PWM_PERIOD_MAX (384 * USEC_PER_SEC)
+#define PM_PWM_LUT_RAMP_STEP_TIME_MAX 499
+#define PM_PWM_MAX_PAUSE_CNT 8191
+/*
+ * Formula from HSID,
+ * pause_time (hi/lo) = (pause_code - 1)*(duty_ms)
+ */
+#define PM_PWM_LUT_PAUSE_MAX \
+ ((PM_PWM_MAX_PAUSE_CNT - 1) * PM_PWM_LUT_RAMP_STEP_TIME_MAX) /* ms */
+
+/* Flags for Look Up Table */
+#define PM_PWM_LUT_LOOP 0x01
+#define PM_PWM_LUT_RAMP_UP 0x02
+#define PM_PWM_LUT_REVERSE 0x04
+#define PM_PWM_LUT_PAUSE_HI_EN 0x08
+#define PM_PWM_LUT_PAUSE_LO_EN 0x10
+
+#define PM_PWM_LUT_NO_TABLE 0x20
+#define PM_PWM_LUT_USE_RAW_VALUE 0x40
+
+/*
+ * PWM frequency/period control
+ *
+ * PWM Frequency = ClockFrequency / (N * T)
+ * or
+ * PWM Period = Clock Period * (N * T)
+ * where
+ * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
+ * T = Pre-divide * 2^m, m = 0..7 (exponent)
+ */
+
+/*
+ * enum pm_pwm_size - PWM bit mode selection
+ * %PM_PWM_SIZE_6BIT - Select 6 bit mode; 64 levels
+ * %PM_PWM_SIZE_9BIT - Select 9 bit mode; 512 levels
+ */
+enum pm_pwm_size {
+ PM_PWM_SIZE_6BIT = 6,
+ PM_PWM_SIZE_9BIT = 9,
+};
+
+/*
+ * enum pm_pwm_clk - PWM clock selection
+ * %PM_PWM_CLK_1KHZ - 1KHz clock
+ * %PM_PWM_CLK_32KHZ - 32KHz clock
+ * %PM_PWM_CLK_19P2MHZ - 19.2MHz clock
+ * Note: Here 1KHz = 1024Hz
+ */
+enum pm_pwm_clk {
+ PM_PWM_CLK_1KHZ,
+ PM_PWM_CLK_32KHZ,
+ PM_PWM_CLK_19P2MHZ,
+};
+
+/* PWM pre-divider selection */
+enum pm_pwm_pre_div {
+ PM_PWM_PDIV_2,
+ PM_PWM_PDIV_3,
+ PM_PWM_PDIV_5,
+ PM_PWM_PDIV_6,
+};
+
+/*
+ * struct pwm_period_config - PWM period configuration
+ * @pwm_size: enum pm_pwm_size
+ * @clk: enum pm_pwm_clk
+ * @pre_div: enum pm_pwm_pre_div
+ * @pre_div_exp: exponent of 2 as part of pre-divider: 0..7
+ */
+struct pwm_period_config {
+ enum pm_pwm_size pwm_size;
+ enum pm_pwm_clk clk;
+ enum pm_pwm_pre_div pre_div;
+ int pre_div_exp;
+};
+
+/*
+ * struct pwm_duty_cycles - PWM duty cycle info
+ * duty_pcts - pointer to an array of duty percentage for a pwm period
+ * num_duty_pcts - total entries in duty_pcts array
+ * duty_ms - duty cycle time in ms
+ * start_idx - index in the LUT
+ */
+struct pwm_duty_cycles {
+ int *duty_pcts;
+ int num_duty_pcts;
+ int duty_ms;
+ int start_idx;
+};
+
+int pwm_config_period(struct pwm_device *pwm,
+ struct pwm_period_config *pwm_p);
+
+int pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value);
+
+/*
+ * lut_params: Lookup table (LUT) parameters
+ * @start_idx: start index in lookup table from 0 to MAX-1
+ * @idx_len: number of index
+ * @pause_lo: pause time in millisecond at low index
+ * @pause_hi: pause time in millisecond at high index
+ * @ramp_step_ms: time before loading next LUT pattern in millisecond
+ * @flags: control flags
+ */
+struct lut_params {
+ int start_idx;
+ int idx_len;
+ int lut_pause_hi;
+ int lut_pause_lo;
+ int ramp_step_ms;
+ int flags;
+};
+
+int pwm_lut_config(struct pwm_device *pwm, int period_us,
+ int duty_pct[], struct lut_params lut_params);
+
+int pwm_lut_enable(struct pwm_device *pwm, int start);
+
+/* Standard APIs supported */
+/*
+ * pwm_request - request a PWM device
+ * @pwm_id: PWM id or channel
+ * @label: the label to identify the user
+ */
+
+/*
+ * pwm_free - free a PWM device
+ * @pwm: the PWM device
+ */
+
+/*
+ * pwm_config - change a PWM device configuration
+ * @pwm: the PWM device
+ * @period_us: period in microsecond
+ * @duty_us: duty cycle in microsecond
+ */
+
+/*
+ * pwm_enable - start a PWM output toggling
+ * @pwm: the PWM device
+ */
+
+/*
+ * pwm_disable - stop a PWM output toggling
+ * @pwm: the PWM device
+ */
+
+#endif /* __QPNP_PWM_H__ */
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index 6d3c3ad..bf65ebb 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -20,6 +20,7 @@
struct android_usb_platform_data {
int (*update_pid_and_serial_num)(uint32_t, const char *);
u32 swfi_latency;
+ u8 usb_core_id;
};
#endif /* __LINUX_USB_ANDROID_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 63ebdea..42f7349 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2296,10 +2296,13 @@
#define V4L2_EVENT_PRIVATE_START 0x08000000
#define V4L2_EVENT_MSM_VIDC_START (V4L2_EVENT_PRIVATE_START + 0x00001000)
-#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE (V4L2_EVENT_PRIVATE_START + 1)
-#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED \
- (V4L2_EVENT_PRIVATE_START + 2)
-#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE (V4L2_EVENT_PRIVATE_START + 3)
+#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE (V4L2_EVENT_MSM_VIDC_START + 1)
+#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT \
+ (V4L2_EVENT_MSM_VIDC_START + 2)
+#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT \
+ (V4L2_EVENT_MSM_VIDC_START + 3)
+#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE (V4L2_EVENT_MSM_VIDC_START + 4)
+
/* Payload for V4L2_EVENT_VSYNC */
struct v4l2_event_vsync {
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 81b6a40..48058e6 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -195,6 +195,24 @@
#define MSM_CAM_IOCTL_ISPIF_IO_CFG \
_IOR(MSM_CAM_IOCTL_MAGIC, 54, struct ispif_cfg_data *)
+#define MSM_CAM_IOCTL_STATS_REQBUF \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 55, struct msm_stats_reqbuf *)
+
+#define MSM_CAM_IOCTL_STATS_ENQUEUEBUF \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 56, struct msm_stats_buf_info *)
+
+#define MSM_CAM_IOCTL_STATS_FLUSH_BUFQ \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 57, struct msm_stats_flush_bufq *)
+
+struct msm_stats_reqbuf {
+ int num_buf; /* how many buffers requested */
+ int stats_type; /* stats type */
+};
+
+struct msm_stats_flush_bufq {
+ int stats_type; /* enum msm_stats_enum_type */
+};
+
struct msm_mctl_pp_cmd {
int32_t id;
uint16_t length;
@@ -515,6 +533,36 @@
#define FRAME_RAW_SNAPSHOT 4
#define FRAME_MAX 5
+enum msm_stats_enum_type {
+ MSM_STATS_TYPE_AEC, /* legacy based AEC */
+ MSM_STATS_TYPE_AF, /* legacy based AF */
+ MSM_STATS_TYPE_AWB, /* legacy based AWB */
+ MSM_STATS_TYPE_RS, /* legacy based RS */
+ MSM_STATS_TYPE_CS, /* legacy based CS */
+ MSM_STATS_TYPE_IHIST, /* legacy based HIST */
+ MSM_STATS_TYPE_SKIN, /* legacy based SKIN */
+ MSM_STATS_TYPE_BG, /* Bayer Grids */
+ MSM_STATS_TYPE_BF, /* Bayer Focus */
+ MSM_STATS_TYPE_BHIST, /* Bayer Hist */
+ MSM_STATS_TYPE_AE_AW, /* legacy stats for vfe 2.x*/
+ MSM_STATS_TYPE_MAX /* MAX */
+};
+
+struct msm_stats_buf_info {
+ int type; /* msm_stats_enum_type */
+ int fd;
+ void *vaddr;
+ uint32_t offset;
+ uint32_t len;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+ uint32_t planar0_off;
+ uint32_t planar1_off;
+ uint32_t planar2_off;
+ uint8_t active;
+ int buf_idx;
+};
+
struct msm_pmem_info {
int type;
int fd;
@@ -678,6 +726,7 @@
int length;
struct ion_handle *handle;
uint32_t frame_id;
+ int buf_idx;
};
#define MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT 0
/* video capture mode in VIDIOC_S_PARM */
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 6547795..1f3527b 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -203,6 +203,9 @@
#define VFE_CMD_CAPTURE_RAW 136
#define VFE_CMD_STOP_LIVESHOT 137
#define VFE_CMD_RECONFIG_VFE 138
+#define VFE_CMD_STATS_REQBUF 139
+#define VFE_CMD_STATS_ENQUEUEBUF 140
+#define VFE_CMD_STATS_FLUSH_BUFQ 141
struct msm_isp_cmd {
int32_t id;
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index a91c97c..0a89c11 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -1,6 +1,7 @@
/*
HIDP implementation for Linux Bluetooth stack (BlueZ).
Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
+ Copyright (c) 2012 Code Aurora Forum. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
@@ -92,6 +93,26 @@
return NULL;
}
+static struct device *hidp_get_device(struct hidp_session *session)
+{
+ bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
+ bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
+ struct device *device = NULL;
+ struct hci_dev *hdev;
+
+ hdev = hci_get_route(dst, src);
+ if (!hdev)
+ return NULL;
+
+ session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
+ if (session->conn)
+ device = &session->conn->dev;
+
+ hci_dev_put(hdev);
+
+ return device;
+}
+
static void __hidp_link_session(struct hidp_session *session)
{
__module_get(THIS_MODULE);
@@ -102,7 +123,11 @@
static void __hidp_unlink_session(struct hidp_session *session)
{
- hci_conn_put_device(session->conn);
+ struct device *dev;
+
+ dev = hidp_get_device(session);
+ if (dev)
+ hci_conn_put_device(session->conn);
list_del(&session->list);
module_put(THIS_MODULE);
@@ -635,26 +660,6 @@
return 0;
}
-static struct device *hidp_get_device(struct hidp_session *session)
-{
- bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
- bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
- struct device *device = NULL;
- struct hci_dev *hdev;
-
- hdev = hci_get_route(dst, src);
- if (!hdev)
- return NULL;
-
- session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (session->conn)
- device = &session->conn->dev;
-
- hci_dev_put(hdev);
-
- return device;
-}
-
static int hidp_setup_input(struct hidp_session *session,
struct hidp_connadd_req *req)
{
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index d07cdff..a0cad55 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1222,7 +1222,7 @@
{
int ret;
- if (!cpu_is_msm8930() && !cpu_is_msm8627()) {
+ if (!cpu_is_msm8930() && !cpu_is_msm8930aa() && !cpu_is_msm8627()) {
pr_err("%s: Not the right machine type\n", __func__);
return -ENODEV ;
}
@@ -1260,7 +1260,7 @@
static void __exit msm8930_audio_exit(void)
{
- if (!cpu_is_msm8930() && !cpu_is_msm8627()) {
+ if (!cpu_is_msm8930() && !cpu_is_msm8930aa() && !cpu_is_msm8627()) {
pr_err("%s: Not the right machine type\n", __func__);
return ;
}