Merge "ASoC: msm: Update front end dai links of mpq8064 machine driver" into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
new file mode 100644
index 0000000..9ff43a1
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
@@ -0,0 +1,31 @@
+* Low Power Management Resources
+
+The application processor in the MSM can enter several different low power
+states depending on the sleep time and on the required system resources. The
+MSM cannot enter a given low power state if that state involves turning off
+some shared resources which are required by some components of the
+system.The lpm-resources device tree node represents the shared resources
+that need to be monitored for usage requirement to check if a given low power
+state can be entered.Each resource is identified by a combination of the name,
+id,type and key which is also used by the RPM to identify a shared resource.
+
+The required nodes for lpm-resources are:
+
+- compatible: "qcom,lpm-resources"
+- reg: The numeric level id
+- qcom,name: The name of the low power resource.
+- qcom,type: The string represeting the type of resource used
+ like smps or pxo.
+- qcom,id: The id representing a device within a resource type.
+- qcom,key: The key is the specific attribute of the resource being
+ monitored.
+
+Example:
+ qcom,lpm-resources@0 {
+ reg = <0x0>;
+ qcom,name = "vdd-dig";
+ qcom,type = "smpb\0";
+ qcom,id = <0x02>;
+ qcom,key = "uv\0\0";
+ };
+
diff --git a/arch/arm/boot/dts/msmcopper-iommu.dtsi b/arch/arm/boot/dts/msmcopper-iommu.dtsi
index e0ce8ac..697136a 100644
--- a/arch/arm/boot/dts/msmcopper-iommu.dtsi
+++ b/arch/arm/boot/dts/msmcopper-iommu.dtsi
@@ -17,6 +17,7 @@
#size-cells = <1>;
ranges;
reg = <0xfda64000 0x10000>;
+ vdd-supply = <&gdsc_jpeg>;
qcom,iommu-ctx@fda6c000 {
reg = <0xfda6c000 0x1000>;
@@ -44,6 +45,7 @@
#size-cells = <1>;
ranges;
reg = <0xfd928000 0x10000>;
+ vdd-supply = <&gdsc_mdss>;
qcom,iommu-ctx@fd930000 {
reg = <0xfd930000 0x1000>;
@@ -65,6 +67,7 @@
#size-cells = <1>;
ranges;
reg = <0xfdc84000 0x10000>;
+ vdd-supply = <&gdsc_venus>;
qcom,iommu-ctx@fdc8c000 {
reg = <0xfdc8c000 0x1000>;
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 5c0384f..e6c2852 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -270,11 +270,15 @@
qcom,acpuclk@f9000000 {
compatible = "qcom,acpuclk-copper";
+ krait0-supply = <&krait0_vreg>;
+ krait1-supply = <&krait1_vreg>;
+ krait2-supply = <&krait2_vreg>;
+ krait3-supply = <&krait3_vreg>;
};
qcom,ssusb@F9200000 {
compatible = "qcom,dwc-usb3-msm";
- reg = <0xF9200000 0xCCFF>;
+ reg = <0xF9200000 0xFA000>;
interrupts = <0 131 0>;
SSUSB_VDDCX-supply = <&pm8841_s2>;
SSUSB_1p8-supply = <&pm8941_l6>;
@@ -392,4 +396,18 @@
qcom,qseecom@fe806000 {
compatible = "qcom,qseecom";
};
+
+ qcom,mdss_mdp@fd900000 {
+ cell-index = <0>;
+ compatible = "qcom,mdss_mdp";
+ reg = <0xfd900000 0x22100>;
+ interrupts = <0 72 0>;
+ };
+
+ qcom,mdss_wb_panel {
+ cell-index = <1>;
+ compatible = "qcom,mdss_wb";
+ qcom,mdss_pan_res = <640 480>;
+ qcom,mdss_pan_bpp = <24>;
+ };
};
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
index 79cb95c..6f12e31c 100644
--- a/arch/arm/boot/dts/msmcopper_pm.dtsi
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -132,6 +132,36 @@
3b 60 02 32 a0 50 0f];
};
+ qcom,lpm-resources {
+ compatible = "qcom,lpm-resources";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,lpm-resources@0 {
+ reg = <0x0>;
+ qcom,name = "vdd-dig";
+ qcom,type = "smpb\0";
+ qcom,id = <0x02>;
+ qcom,key = "uv\0\0";
+ };
+
+ qcom,lpm-resources@1 {
+ reg = <0x1>;
+ qcom,name = "vdd-mem";
+ qcom,type = "smpb\0";
+ qcom,id = <0x01>;
+ qcom,key = "uv\0\0";
+ };
+
+ qcom,lpm-resources@2 {
+ reg = <0x2>;
+ qcom,name = "pxo";
+ qcom,type = "clk0\0";
+ qcom,id = <0x00>;
+ qcom,key = "Enab";
+ };
+ };
+
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
#address-cells = <1>;
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 174a799..b14ecf8 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -1062,9 +1062,11 @@
return 0;
}
#endif
-/* before calling this function the interrupts should be disabled
- * and the irq must be disabled at gic to avoid spurious interrupts */
-bool gic_is_spi_pending(unsigned int irq)
+/*
+ * Before calling this function the interrupts should be disabled
+ * and the irq must be disabled at gic to avoid spurious interrupts
+ */
+bool gic_is_irq_pending(unsigned int irq)
{
struct irq_data *d = irq_get_irq_data(irq);
struct gic_chip_data *gic_data = &gic_data[0];
@@ -1083,9 +1085,11 @@
return (bool) (val & mask);
}
-/* before calling this function the interrupts should be disabled
- * and the irq must be disabled at gic to avoid spurious interrupts */
-void gic_clear_spi_pending(unsigned int irq)
+/*
+ * Before calling this function the interrupts should be disabled
+ * and the irq must be disabled at gic to avoid spurious interrupts
+ */
+void gic_clear_irq_pending(unsigned int irq)
{
struct gic_chip_data *gic_data = &gic_data[0];
struct irq_data *d = irq_get_irq_data(irq);
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index f6764d4..78ab155 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -155,7 +155,14 @@
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
# CONFIG_HID_SUPPORT is not set
CONFIG_USB_GADGET=y
CONFIG_USB_CI13XXX_MSM=y
@@ -168,8 +175,6 @@
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
CONFIG_SWITCH=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
@@ -221,3 +226,7 @@
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8974=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 362b4b2..57e644d 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -389,6 +389,7 @@
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_EHCI_MSM_HOST4=y
CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DEBUG=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 8f4937a..ca8a909 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -392,6 +392,7 @@
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_EHCI_MSM_HOST4=y
CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DEBUG=y
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 3fb0a1c..3783ff3 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -46,6 +46,8 @@
void gic_handle_irq(struct pt_regs *regs);
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
+bool gic_is_irq_pending(unsigned int irq);
+void gic_clear_irq_pending(unsigned int irq);
#ifdef CONFIG_ARM_GIC
void gic_set_irq_secure(unsigned int irq);
#else
@@ -56,8 +58,6 @@
{
gic_init_bases(nr, start, dist, cpu, 0);
}
-bool gic_is_spi_pending(unsigned int irq);
-void gic_clear_spi_pending(unsigned int irq);
void gic_set_irq_secure(unsigned int irq);
#endif
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index a6ec7b2..4bcbfc2 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -148,7 +148,7 @@
bool nonremovable;
unsigned int mpm_sdiowakeup_int;
unsigned int wpswitch_gpio;
- unsigned char wpswitch_polarity;
+ bool is_wpswitch_active_low;
struct msm_mmc_slot_reg_data *vreg_data;
int is_sdio_al_client;
unsigned int *sup_clk_table;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 304520b..24c57ae 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2088,6 +2088,17 @@
help
Enables support for Qualcomm Debug Subsystem.
+config MSM_QDSS_STM_DEFAULT_ENABLE
+ bool "Turn on QDSS STM Tracing by Default"
+ depends on MSM_QDSS
+ help
+ Turns on QDSS STM tracing (hardware assisted software
+ instrumentation based tracing) by default. Otherwise, tracing is
+ disabled by default but can be enabled via sysfs.
+
+ For production builds, you should probably say 'N' here to avoid
+ potential power, performance and memory penalty.
+
config MSM_QDSS_ETM_DEFAULT_ENABLE
bool "Turn on QDSS ETM Tracing by Default"
depends on MSM_QDSS
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 1896059..8315d70 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -55,7 +55,7 @@
msm-etm-objs := etm.o
obj-$(CONFIG_MSM_ETM) += msm-etm.o
-obj-$(CONFIG_MSM_QDSS) += qdss.o qdss-etb.o qdss-tpiu.o qdss-funnel.o qdss-etm.o
+obj-$(CONFIG_MSM_QDSS) += qdss.o qdss-etb.o qdss-tpiu.o qdss-funnel.o qdss-stm.o qdss-etm.o
quiet_cmd_mkrpcsym = MKCAP $@
cmd_mkrpcsym = $(PERL) $(srctree)/$(src)/mkrpcsym.pl $< $@
@@ -317,7 +317,7 @@
obj-$(CONFIG_ARCH_MSM9615) += rpm_resources.o
endif
ifdef CONFIG_MSM_RPM_SMD
- obj-$(CONFIG_ARCH_MSMCOPPER) += lpm_levels.o
+ obj-$(CONFIG_ARCH_MSMCOPPER) += lpm_levels.o lpm_resources.o
endif
obj-$(CONFIG_MSM_MPM) += mpm.o
obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o
diff --git a/arch/arm/mach-msm/acpuclock-copper.c b/arch/arm/mach-msm/acpuclock-copper.c
index f0da74c..7ba2e7d 100644
--- a/arch/arm/mach-msm/acpuclock-copper.c
+++ b/arch/arm/mach-msm/acpuclock-copper.c
@@ -62,68 +62,42 @@
.hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x4501,
.vreg[VREG_CORE] = { "krait0", 1050000, 3200000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1050000, 0,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8941_S1 },
- .vreg[VREG_DIG] = { "krait0_dig", 1050000, 0,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8941_S2 },
- .vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8941_L12 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1050000 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1050000 },
+ .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
},
[CPU1] = {
.hfpll_phys_base = 0xF909A000,
.hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x5501,
.vreg[VREG_CORE] = { "krait1", 1050000, 3200000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1050000, 0,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8941_S1 },
- .vreg[VREG_DIG] = { "krait1_dig", 1050000, 0,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8941_S2 },
- .vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8941_L12 },
+ .vreg[VREG_MEM] = { "krait1_mem", 1050000 },
+ .vreg[VREG_DIG] = { "krait1_dig", 1050000 },
+ .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
},
[CPU2] = {
.hfpll_phys_base = 0xF90AA000,
.hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x6501,
.vreg[VREG_CORE] = { "krait2", 1050000, 3200000 },
- .vreg[VREG_MEM] = { "krait2_mem", 1050000, 0,
- RPM_VREG_VOTER4,
- RPM_VREG_ID_PM8921_S1 },
- .vreg[VREG_DIG] = { "krait2_dig", 1050000, 0,
- RPM_VREG_VOTER4,
- RPM_VREG_ID_PM8921_S2 },
- .vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
- RPM_VREG_VOTER4,
- RPM_VREG_ID_PM8941_L12 },
+ .vreg[VREG_MEM] = { "krait2_mem", 1050000 },
+ .vreg[VREG_DIG] = { "krait2_dig", 1050000 },
+ .vreg[VREG_HFPLL_A] = { "krait2_hfpll", 1800000 },
},
[CPU3] = {
.hfpll_phys_base = 0xF90BA000,
.hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x7501,
.vreg[VREG_CORE] = { "krait3", 1050000, 3200000 },
- .vreg[VREG_MEM] = { "krait3_mem", 1050000, 0,
- RPM_VREG_VOTER5,
- RPM_VREG_ID_PM8941_S1 },
- .vreg[VREG_DIG] = { "krait3_dig", 1050000, 0,
- RPM_VREG_VOTER5,
- RPM_VREG_ID_PM8941_S2 },
- .vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
- RPM_VREG_VOTER5,
- RPM_VREG_ID_PM8941_L12 },
+ .vreg[VREG_MEM] = { "krait3_mem", 1050000 },
+ .vreg[VREG_DIG] = { "krait3_dig", 1050000 },
+ .vreg[VREG_HFPLL_A] = { "krait3_hfpll", 1800000 },
},
[L2] = {
.hfpll_phys_base = 0xF9016000,
.hfpll_data = &hfpll_data_l2,
.l2cpmr_iaddr = 0x0500,
- .vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8941_L12 },
+ .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
},
};
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 5682ac3..4dc47d2 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -32,6 +32,7 @@
#include <mach/socinfo.h>
#include <mach/msm-krait-l2-accessors.h>
#include <mach/rpm-regulator.h>
+#include <mach/rpm-regulator-smd.h>
#include <mach/msm_bus.h>
#include "acpuclock.h"
@@ -52,7 +53,7 @@
static DEFINE_SPINLOCK(l2_lock);
static struct drv_data {
- const struct acpu_level *acpu_freq_tbl;
+ struct acpu_level *acpu_freq_tbl;
const struct l2_level *l2_freq_tbl;
struct scalable *scalable;
u32 bus_perf_client;
@@ -92,35 +93,39 @@
udelay(1);
}
-/* Enable an already-configured HFPLL. */
-static void hfpll_enable(struct scalable *sc, bool skip_regulators)
+static void enable_rpm_vreg(struct vreg *vreg)
{
int rc;
+ if (vreg->rpm_reg) {
+ rc = rpm_regulator_enable(vreg->rpm_reg);
+ if (rc) {
+ dev_err(drv.dev, "%s regulator enable failed (%d)\n",
+ vreg->name, rc);
+ BUG();
+ }
+ }
+}
+
+static void disable_rpm_vreg(struct vreg *vreg)
+{
+ int rc;
+
+ if (vreg->rpm_reg) {
+ rc = rpm_regulator_disable(vreg->rpm_reg);
+ if (rc)
+ dev_err(drv.dev, "%s regulator disable failed (%d)\n",
+ vreg->name, rc);
+ }
+}
+
+/* Enable an already-configured HFPLL. */
+static void hfpll_enable(struct scalable *sc, bool skip_regulators)
+{
if (!skip_regulators) {
/* Enable regulators required by the HFPLL. */
- if (sc->vreg[VREG_HFPLL_A].rpm_vreg_id) {
- rc = rpm_vreg_set_voltage(
- sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
- sc->vreg[VREG_HFPLL_A].cur_vdd,
- sc->vreg[VREG_HFPLL_A].max_vdd, 0);
- if (rc)
- dev_err(drv.dev,
- "%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_A].name, rc);
- }
- if (sc->vreg[VREG_HFPLL_B].rpm_vreg_id) {
- rc = rpm_vreg_set_voltage(
- sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_B].rpm_vreg_voter,
- sc->vreg[VREG_HFPLL_B].cur_vdd,
- sc->vreg[VREG_HFPLL_B].max_vdd, 0);
- if (rc)
- dev_err(drv.dev,
- "%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_B].name, rc);
- }
+ enable_rpm_vreg(&sc->vreg[VREG_HFPLL_A]);
+ enable_rpm_vreg(&sc->vreg[VREG_HFPLL_B]);
}
/* Disable PLL bypass mode. */
@@ -147,8 +152,6 @@
/* Disable a HFPLL for power-savings or while it's being reprogrammed. */
static void hfpll_disable(struct scalable *sc, bool skip_regulators)
{
- int rc;
-
/*
* Disable the PLL output, disable test mode, enable the bypass mode,
* and assert the reset.
@@ -157,26 +160,8 @@
if (!skip_regulators) {
/* Remove voltage votes required by the HFPLL. */
- if (sc->vreg[VREG_HFPLL_B].rpm_vreg_id) {
- rc = rpm_vreg_set_voltage(
- sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_B].rpm_vreg_voter,
- 0, 0, 0);
- if (rc)
- dev_err(drv.dev,
- "%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_B].name, rc);
- }
- if (sc->vreg[VREG_HFPLL_A].rpm_vreg_id) {
- rc = rpm_vreg_set_voltage(
- sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
- 0, 0, 0);
- if (rc)
- dev_err(drv.dev,
- "%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_A].name, rc);
- }
+ disable_rpm_vreg(&sc->vreg[VREG_HFPLL_B]);
+ disable_rpm_vreg(&sc->vreg[VREG_HFPLL_A]);
}
}
@@ -228,19 +213,19 @@
set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
/* Re-program HFPLL. */
- hfpll_disable(sc, 1);
+ hfpll_disable(sc, true);
hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 1);
+ hfpll_enable(sc, true);
/* Move to HFPLL. */
set_pri_clk_src(sc, tgt_s->pri_src_sel);
} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
set_sec_clk_src(sc, tgt_s->sec_src_sel);
set_pri_clk_src(sc, tgt_s->pri_src_sel);
- hfpll_disable(sc, 0);
+ hfpll_disable(sc, false);
} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 0);
+ hfpll_enable(sc, false);
set_pri_clk_src(sc, tgt_s->pri_src_sel);
} else {
set_sec_clk_src(sc, tgt_s->sec_src_sel);
@@ -261,9 +246,8 @@
* vdd_mem should be >= vdd_dig.
*/
if (vdd_mem > sc->vreg[VREG_MEM].cur_vdd) {
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
- sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
- sc->vreg[VREG_MEM].max_vdd, 0);
+ rc = rpm_regulator_set_voltage(sc->vreg[VREG_MEM].rpm_reg,
+ vdd_mem, sc->vreg[VREG_MEM].max_vdd);
if (rc) {
dev_err(drv.dev,
"vdd_mem (cpu%d) increase failed (%d)\n",
@@ -275,9 +259,8 @@
/* Increase vdd_dig active-set vote. */
if (vdd_dig > sc->vreg[VREG_DIG].cur_vdd) {
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
- sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
- sc->vreg[VREG_DIG].max_vdd, 0);
+ rc = rpm_regulator_set_voltage(sc->vreg[VREG_DIG].rpm_reg,
+ vdd_dig, sc->vreg[VREG_DIG].max_vdd);
if (rc) {
dev_err(drv.dev,
"vdd_dig (cpu%d) increase failed (%d)\n",
@@ -336,9 +319,8 @@
/* Decrease vdd_dig active-set vote. */
if (vdd_dig < sc->vreg[VREG_DIG].cur_vdd) {
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
- sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
- sc->vreg[VREG_DIG].max_vdd, 0);
+ ret = rpm_regulator_set_voltage(sc->vreg[VREG_DIG].rpm_reg,
+ vdd_dig, sc->vreg[VREG_DIG].max_vdd);
if (ret) {
dev_err(drv.dev,
"vdd_dig (cpu%d) decrease failed (%d)\n",
@@ -353,9 +335,8 @@
* vdd_mem should be >= vdd_dig.
*/
if (vdd_mem < sc->vreg[VREG_MEM].cur_vdd) {
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
- sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
- sc->vreg[VREG_MEM].max_vdd, 0);
+ ret = rpm_regulator_set_voltage(sc->vreg[VREG_MEM].rpm_reg,
+ vdd_mem, sc->vreg[VREG_MEM].max_vdd);
if (ret) {
dev_err(drv.dev,
"vdd_mem (cpu%d) decrease failed (%d)\n",
@@ -484,7 +465,7 @@
pr_debug("Initializing HFPLL%d\n", sc - drv.scalable);
/* Disable the PLL for re-programming. */
- hfpll_disable(sc, 1);
+ hfpll_disable(sc, true);
/* Configure PLL parameters for integer mode. */
writel_relaxed(sc->hfpll_data->config_val,
@@ -492,13 +473,49 @@
writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->m_offset);
writel_relaxed(1, sc->hfpll_base + sc->hfpll_data->n_offset);
+ /* Program droop controller, if supported */
+ if (sc->hfpll_data->has_droop_ctl)
+ writel_relaxed(sc->hfpll_data->droop_val,
+ sc->hfpll_base + sc->hfpll_data->droop_offset);
+
/* Set an initial rate and enable the PLL. */
hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 0);
+ hfpll_enable(sc, false);
+}
+
+static void __init rpm_regulator_init(struct scalable *sc, enum vregs vreg,
+ int vdd, bool enable)
+{
+ int ret;
+
+ if (!sc->vreg[vreg].name)
+ return;
+
+ sc->vreg[vreg].rpm_reg = rpm_regulator_get(drv.dev,
+ sc->vreg[vreg].name);
+ if (IS_ERR(sc->vreg[vreg].rpm_reg)) {
+ dev_err(drv.dev, "rpm_regulator_get(%s) failed (%ld)\n",
+ sc->vreg[vreg].name,
+ PTR_ERR(sc->vreg[vreg].rpm_reg));
+ BUG();
+ }
+
+ ret = rpm_regulator_set_voltage(sc->vreg[vreg].rpm_reg, vdd,
+ sc->vreg[vreg].max_vdd);
+ if (ret) {
+ dev_err(drv.dev, "%s initialization failed (%d)\n",
+ sc->vreg[vreg].name, ret);
+ BUG();
+ }
+ sc->vreg[vreg].cur_vdd = vdd;
+
+ if (enable)
+ enable_rpm_vreg(&sc->vreg[vreg]);
}
/* Voltage regulator initialization. */
-static void __init regulator_init(const struct acpu_level *lvl)
+static void __init regulator_init(struct device *dev,
+ const struct acpu_level *lvl)
{
int cpu, ret;
struct scalable *sc;
@@ -507,33 +524,23 @@
vdd_mem = calculate_vdd_mem(lvl);
vdd_dig = calculate_vdd_dig(lvl);
+ rpm_regulator_init(&drv.scalable[L2], VREG_HFPLL_A,
+ drv.scalable[L2].vreg[VREG_HFPLL_A].max_vdd, false);
+ rpm_regulator_init(&drv.scalable[L2], VREG_HFPLL_B,
+ drv.scalable[L2].vreg[VREG_HFPLL_B].max_vdd, false);
+
for_each_possible_cpu(cpu) {
sc = &drv.scalable[cpu];
- /* Set initial vdd_mem vote. */
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
- sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
- sc->vreg[VREG_MEM].max_vdd, 0);
- if (ret) {
- dev_err(drv.dev, "%s initialization failed (%d)\n",
- sc->vreg[VREG_MEM].name, ret);
- BUG();
- }
- sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
-
- /* Set initial vdd_dig vote. */
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
- sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
- sc->vreg[VREG_DIG].max_vdd, 0);
- if (ret) {
- dev_err(drv.dev, "%s initialization failed (%d)\n",
- sc->vreg[VREG_DIG].name, ret);
- BUG();
- }
- sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
+ rpm_regulator_init(sc, VREG_MEM, vdd_mem, true);
+ rpm_regulator_init(sc, VREG_DIG, vdd_dig, true);
+ rpm_regulator_init(sc, VREG_HFPLL_A,
+ sc->vreg[VREG_HFPLL_A].max_vdd, false);
+ rpm_regulator_init(sc, VREG_HFPLL_B,
+ sc->vreg[VREG_HFPLL_B].max_vdd, false);
/* Setup Krait CPU regulators and initial core voltage. */
- sc->vreg[VREG_CORE].reg = regulator_get(NULL,
+ sc->vreg[VREG_CORE].reg = regulator_get(dev,
sc->vreg[VREG_CORE].name);
if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
dev_err(drv.dev, "regulator_get(%s) failed (%ld)\n",
@@ -571,10 +578,15 @@
const struct core_speed *tgt_s)
{
u32 regval;
+ void __iomem *aux_reg;
/* Program AUX source input to the secondary MUX. */
- if (sc->aux_clk_sel_addr)
- writel_relaxed(sc->aux_clk_sel, sc->aux_clk_sel_addr);
+ if (sc->aux_clk_sel_phys) {
+ aux_reg = ioremap(sc->aux_clk_sel_phys, 4);
+ BUG_ON(!aux_reg);
+ writel_relaxed(sc->aux_clk_sel, aux_reg);
+ iounmap(aux_reg);
+ }
/* Switch away from the HFPLL while it's re-initialized. */
set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
@@ -691,8 +703,27 @@
.notifier_call = acpuclk_cpu_callback,
};
+static const int krait_needs_vmin(void)
+{
+ switch (read_cpuid_id()) {
+ case 0x511F04D0: /* KR28M2A20 */
+ case 0x511F04D1: /* KR28M2A21 */
+ case 0x510F06F0: /* KR28M4A10 */
+ return 1;
+ default:
+ return 0;
+ };
+}
+
+static void krait_apply_vmin(struct acpu_level *tbl)
+{
+ for (; tbl->speed.khz != 0; tbl++)
+ if (tbl->vdd_core < 1150000)
+ tbl->vdd_core = 1150000;
+}
+
static const struct acpu_level __init *select_freq_plan(
- const struct acpu_level *const *pvs_tbl, u32 qfprom_phys)
+ struct acpu_level *const *pvs_tbl, u32 qfprom_phys)
{
const struct acpu_level *l, *max_acpu_level = NULL;
void __iomem *qfprom_base;
@@ -735,6 +766,9 @@
}
drv.acpu_freq_tbl = pvs_tbl[tbl_idx];
+ if (krait_needs_vmin())
+ krait_apply_vmin(drv.acpu_freq_tbl);
+
/* Find the max supported scaling frequency. */
for (l = drv.acpu_freq_tbl; l->speed.khz != 0; l++)
if (l->use_for_scaling)
@@ -769,7 +803,7 @@
max_acpu_level = select_freq_plan(params->pvs_acpu_freq_tbl,
params->qfprom_phys_base);
- regulator_init(max_acpu_level);
+ regulator_init(dev, max_acpu_level);
bus_init(params->bus_scale_data, max_acpu_level->l2_level->bw_level);
init_clock_sources(&drv.scalable[L2], &max_acpu_level->l2_level->speed);
for_each_online_cpu(cpu)
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index fbf1f5f..7c1d2b6 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -40,6 +40,7 @@
PLL_0 = 0,
HFPLL,
QSB,
+ PLL_8,
};
/**
@@ -91,18 +92,17 @@
* struct vreg - Voltage regulator data.
* @name: Name of requlator.
* @max_vdd: Limit the maximum-settable voltage.
- * @rpm_vreg_id: ID to use with rpm_vreg_*() APIs.
* @reg: Regulator handle.
+ * @rpm_reg: RPM Regulator handle.
* @cur_vdd: Last-set voltage in uV.
* @peak_ua: Maximum current draw expected in uA.
*/
struct vreg {
- const char name[15];
+ const char *name;
const int max_vdd;
const int peak_ua;
- const int rpm_vreg_voter;
- const int rpm_vreg_id;
struct regulator *reg;
+ struct rpm_regulator *rpm_reg;
int cur_vdd;
};
@@ -147,7 +147,7 @@
const int use_for_scaling;
const struct core_speed speed;
const struct l2_level *l2_level;
- const int vdd_core;
+ int vdd_core;
};
/**
@@ -158,6 +158,10 @@
* @n_offset: "N" value register offset from base address.
* @config_offset: Configuration register offset from base address.
* @config_val: Value to initialize the @config_offset register to.
+ * @has_droop_ctl: Indicates the presence of a voltage droop controller.
+ * @droop_offset: Droop controller register offset from base address.
+ * @droop_val: Value to initialize the @config_offset register to.
+ * @low_vdd_l_max: Maximum "L" value supported at HFPLL_VDD_LOW.
* @vdd: voltage requirements for each VDD level.
*/
struct hfpll_data {
@@ -167,6 +171,9 @@
const u32 n_offset;
const u32 config_offset;
const u32 config_val;
+ const bool has_droop_ctl;
+ const u32 droop_offset;
+ const u32 droop_val;
const u32 low_vdd_l_max;
const int vdd[NUM_HFPLL_VDD];
};
@@ -175,7 +182,7 @@
* struct scalable - Register locations and state associated with a scalable HW.
* @hfpll_phys_base: Physical base address of HFPLL register.
* @hfpll_base: Virtual base address of HFPLL registers.
- * @aux_clk_sel_addr: Virtual address of auxiliary MUX.
+ * @aux_clk_sel_phys: Physical address of auxiliary MUX.
* @aux_clk_sel: Auxiliary mux input to select at boot.
* @l2cpmr_iaddr: Indirect address of the CPMR MUX/divider CP15 register.
* @hfpll_data: Descriptive data of HFPLL hardware.
@@ -184,9 +191,9 @@
* @vreg: Array of voltage regulators needed by the scalable.
*/
struct scalable {
- const u32 hfpll_phys_base;
+ const phys_addr_t hfpll_phys_base;
void __iomem *hfpll_base;
- void __iomem *aux_clk_sel_addr;
+ const phys_addr_t aux_clk_sel_phys;
const u32 aux_clk_sel;
const u32 l2cpmr_iaddr;
const struct hfpll_data *hfpll_data;
@@ -206,10 +213,10 @@
*/
struct acpuclk_krait_params {
struct scalable *scalable;
- const struct acpu_level *pvs_acpu_freq_tbl[NUM_PVS];
+ struct acpu_level *pvs_acpu_freq_tbl[NUM_PVS];
const struct l2_level *l2_freq_tbl;
const size_t l2_freq_tbl_size;
- const u32 qfprom_phys_base;
+ const phys_addr_t qfprom_phys_base;
struct msm_bus_scale_pdata *bus_scale_data;
};
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 101a26d..5edddb5 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -473,11 +473,18 @@
}
}
+ rc = regulator_disable(reg_l11);
+ if (rc) {
+ pr_err("disable reg_l1 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+
rc = regulator_disable(reg_lvs7);
if (rc) {
pr_err("disable reg_lvs7 failed, rc=%d\n", rc);
return -ENODEV;
}
+
rc = regulator_disable(reg_l2);
if (rc) {
pr_err("disable reg_l2 failed, rc=%d\n", rc);
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index fe4beab..a53f771 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -291,7 +291,7 @@
.pin_data = &mmc_slot_pin_data[SDCC3],
.vreg_data = &mmc_slot_vreg_data[SDCC3],
.wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(17),
- .wpswitch_polarity = 1,
+ .is_wpswitch_active_low = true,
.status_gpio = 26,
.status_irq = MSM_GPIO_TO_INT(26),
.irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
@@ -354,7 +354,7 @@
if (apq8064_sdc3_pdata) {
if (!machine_is_apq8064_cdp()) {
apq8064_sdc3_pdata->wpswitch_gpio = 0;
- apq8064_sdc3_pdata->wpswitch_polarity = 0;
+ apq8064_sdc3_pdata->is_wpswitch_active_low = false;
}
if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
machine_is_mpq8064_dtv()) {
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 1d231ef..146009c 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -29,6 +29,7 @@
#include <linux/ion.h>
#include <linux/memory.h>
#include <linux/memblock.h>
+#include <linux/msm_thermal.h>
#include <linux/i2c/atmel_mxt_ts.h>
#include <linux/cyttsp-qc.h>
#include <linux/i2c/isa1200.h>
@@ -1219,6 +1220,7 @@
.name = "vibrator",
.dev_setup = isa1200_dev_setup,
.clk_enable = isa1200_clk_enable,
+ .need_pwm_clk = true,
.hap_en_gpio = ISA1200_HAP_EN_GPIO,
.hap_len_gpio = ISA1200_HAP_LEN_GPIO,
.max_timeout = 15000,
@@ -1695,11 +1697,20 @@
};
#endif
+static struct mdm_vddmin_resource mdm_vddmin_rscs = {
+ .rpm_id = MSM_RPM_ID_VDDMIN_GPIO,
+ .ap2mdm_vddmin_gpio = 30,
+ .modes = 0x03,
+ .drive_strength = 8,
+ .mdm2ap_vddmin_gpio = 80,
+};
+
static struct mdm_platform_data mdm_platform_data = {
.mdm_version = "3.0",
.ramdump_delay_ms = 2000,
.early_power_on = 1,
.sfr_query = 1,
+ .vddmin_resource = &mdm_vddmin_rscs,
.peripheral_platform_device = &apq8064_device_hsic_host,
};
@@ -1716,6 +1727,14 @@
.id = -1,
};
+static struct msm_thermal_data msm_thermal_pdata = {
+ .sensor_id = 7,
+ .poll_ms = 1000,
+ .limit_temp = 60,
+ .temp_hysteresis = 10,
+ .limit_freq = 918000,
+};
+
#define MSM_SHARED_RAM_PHYS 0x80000000
static void __init apq8064_map_io(void)
{
@@ -2864,6 +2883,7 @@
static void __init apq8064_common_init(void)
{
msm_tsens_early_init(&apq_tsens_pdata);
+ msm_thermal_init(&msm_thermal_pdata);
if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
BUG_ON(msm_rpm_init(&apq8064_rpm_data));
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index 5bee8a2..bc370ba 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -70,6 +70,8 @@
REGULATOR_SUPPLY("cam_vaf", "4-0048"),
REGULATOR_SUPPLY("cam_vana", "4-0020"),
REGULATOR_SUPPLY("cam_vaf", "4-0020"),
+ REGULATOR_SUPPLY("vdd", "12-0018"),
+ REGULATOR_SUPPLY("vdd", "12-0068"),
};
VREG_CONSUMERS(L10) = {
REGULATOR_SUPPLY("8038_l10", NULL),
@@ -186,6 +188,8 @@
REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
+ REGULATOR_SUPPLY("vddio", "12-0018"),
+ REGULATOR_SUPPLY("vlogic", "12-0068"),
};
VREG_CONSUMERS(EXT_5V) = {
REGULATOR_SUPPLY("ext_5v", NULL),
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index 5e51c5a..739b1c7 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -259,7 +259,7 @@
.wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(16),
#else
.wpswitch_gpio = 66,
- .wpswitch_polarity = 1,
+ .is_wpswitch_active_low = true,
#endif
#endif
.vreg_data = &mmc_slot_vreg_data[SDCC3],
@@ -305,7 +305,7 @@
/* SDC3: External card slot */
if (!machine_is_msm8930_cdp()) {
msm8960_sdc3_data.wpswitch_gpio = 0;
- msm8960_sdc3_data.wpswitch_polarity = 0;
+ msm8960_sdc3_data.is_wpswitch_active_low = false;
}
msm_add_sdcc(3, &msm8960_sdc3_data);
#endif
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index e075630..1f5ea52 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -42,6 +42,7 @@
#include <linux/gpio_keys.h>
#include <linux/memory.h>
#include <linux/memblock.h>
+#include <linux/msm_thermal.h>
#include <linux/slimbus/slimbus.h>
#include <linux/mfd/wcd9xxx/core.h>
@@ -78,6 +79,10 @@
#include <mach/msm_rtb.h>
#include <linux/fmem.h>
+#ifdef CONFIG_INPUT_MPU3050
+#include <linux/input/mpu3050.h>
+#endif
+
#include "timer.h"
#include "devices.h"
#include "devices-msm8x60.h"
@@ -1414,6 +1419,14 @@
};
#endif
+static int hsusb_phy_init_seq[] = {
+ 0x44, 0x80, /* set VBUS valid threshold
+ and disconnect valid threshold */
+ 0x38, 0x81, /* update DC voltage level */
+ 0x24, 0x82, /* set preemphasis and rise/fall time */
+ 0x13, 0x83, /* set source impedance adjusment */
+ -1};
+
static struct msm_otg_platform_data msm_otg_pdata = {
.mode = USB_OTG,
.otg_control = OTG_PMIC_CONTROL,
@@ -1973,6 +1986,14 @@
.id = -1,
};
+static struct msm_thermal_data msm_thermal_pdata = {
+ .sensor_id = 9,
+ .poll_ms = 1000,
+ .limit_temp = 60,
+ .temp_hysteresis = 10,
+ .limit_freq = 918000,
+};
+
#ifdef CONFIG_MSM_FAKE_BATTERY
static struct platform_device fish_battery_device = {
.name = "fish_battery",
@@ -2294,6 +2315,21 @@
int len;
};
+#ifdef CONFIG_INPUT_MPU3050
+#define MPU3050_INT_GPIO 69
+
+static struct mpu3050_gyro_platform_data mpu3050_gyro = {
+ .gpio_int = MPU3050_INT_GPIO,
+};
+
+static struct i2c_board_info __initdata mpu3050_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("mpu3050", 0x68),
+ .platform_data = &mpu3050_gyro,
+ },
+};
+#endif
+
#ifdef CONFIG_ISL9519_CHARGER
static struct isl_platform_data isl_data __initdata = {
.valid_n_gpio = 0, /* Not required when notify-by-pmic */
@@ -2323,6 +2359,14 @@
ARRAY_SIZE(isl_charger_i2c_info),
},
#endif /* CONFIG_ISL9519_CHARGER */
+#ifdef CONFIG_INPUT_MPU3050
+ {
+ I2C_FFA | I2C_FLUID,
+ MSM_8930_GSBI12_QUP_I2C_BUS_ID,
+ mpu3050_i2c_boardinfo,
+ ARRAY_SIZE(mpu3050_i2c_boardinfo),
+ },
+#endif
{
I2C_SURF | I2C_FFA | I2C_FLUID,
MSM_8930_GSBI9_QUP_I2C_BUS_ID,
@@ -2384,6 +2428,7 @@
pr_err("meminfo_init() failed!\n");
msm_tsens_early_init(&msm_tsens_pdata);
+ msm_thermal_init(&msm_thermal_pdata);
BUG_ON(msm_rpm_init(&msm8930_rpm_data));
BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
@@ -2392,6 +2437,7 @@
pr_err("Failed to initialize XO votes\n");
platform_device_register(&msm8930_device_rpm_regulator);
msm_clock_init(&msm8930_clock_init_data);
+ msm_otg_pdata.phy_init_seq = hsusb_phy_init_seq;
msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
android_usb_pdata.swfi_latency =
msm_rpmrs_levels[0].latency_us;
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index e564aff..925de45 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -138,5 +138,6 @@
#define MSM_8930_GSBI4_QUP_I2C_BUS_ID 4
#define MSM_8930_GSBI9_QUP_I2C_BUS_ID 0
#define MSM_8930_GSBI10_QUP_I2C_BUS_ID 10
+#define MSM_8930_GSBI12_QUP_I2C_BUS_ID 12
extern struct msm_rtb_platform_data msm8930_rtb_pdata;
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 22ef940..628a324 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -42,6 +42,7 @@
#include <linux/i2c/isa1200.h>
#include <linux/memory.h>
#include <linux/memblock.h>
+#include <linux/msm_thermal.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -2427,6 +2428,14 @@
.id = -1,
};
+static struct msm_thermal_data msm_thermal_pdata = {
+ .sensor_id = 0,
+ .poll_ms = 1000,
+ .limit_temp = 60,
+ .temp_hysteresis = 10,
+ .limit_freq = 918000,
+};
+
#ifdef CONFIG_MSM_FAKE_BATTERY
static struct platform_device fish_battery_device = {
.name = "fish_battery",
@@ -3044,6 +3053,7 @@
wdog_pdata->bark_time = 15000;
msm_tsens_early_init(&msm_tsens_pdata);
+ msm_thermal_init(&msm_thermal_pdata);
BUG_ON(msm_rpm_init(&msm8960_rpm_data));
BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
regulator_suppress_info_printing();
@@ -3076,6 +3086,7 @@
static void __init msm8960_rumi3_init(void)
{
msm_tsens_early_init(&msm_tsens_pdata);
+ msm_thermal_init(&msm_thermal_pdata);
BUG_ON(msm_rpm_init(&msm8960_rpm_data));
BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
regulator_suppress_info_printing();
@@ -3108,6 +3119,7 @@
pr_err("meminfo_init() failed!\n");
msm_tsens_early_init(&msm_tsens_pdata);
+ msm_thermal_init(&msm_thermal_pdata);
BUG_ON(msm_rpm_init(&msm8960_rpm_data));
BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 1089d61..568de46 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -758,10 +758,11 @@
.vbus_power = msm_hsusb_vbus_power,
.disable_reset_on_disconnect = true,
.enable_lpm_on_dev_suspend = true,
+ .core_clk_always_on_workaround = true,
};
static struct msm_hsic_peripheral_platform_data msm_hsic_peripheral_pdata = {
- .keep_core_clk_on_suspend_workaround = true,
+ .core_clk_always_on_workaround = true,
};
#define PID_MAGIC_ID 0x71432909
diff --git a/arch/arm/mach-msm/board-copper-regulator.c b/arch/arm/mach-msm/board-copper-regulator.c
index 7543872..10d5d0b 100644
--- a/arch/arm/mach-msm/board-copper-regulator.c
+++ b/arch/arm/mach-msm/board-copper-regulator.c
@@ -22,16 +22,16 @@
* regulator name consumer dev_name
*/
VREG_CONSUMERS(K0) = {
- REGULATOR_SUPPLY("krait0", NULL),
+ REGULATOR_SUPPLY("krait0", "f9000000.qcom,acpuclk"),
};
VREG_CONSUMERS(K1) = {
- REGULATOR_SUPPLY("krait1", NULL),
+ REGULATOR_SUPPLY("krait1", "f9000000.qcom,acpuclk"),
};
VREG_CONSUMERS(K2) = {
- REGULATOR_SUPPLY("krait2", NULL),
+ REGULATOR_SUPPLY("krait2", "f9000000.qcom,acpuclk"),
};
VREG_CONSUMERS(K3) = {
- REGULATOR_SUPPLY("krait3", NULL),
+ REGULATOR_SUPPLY("krait3", "f9000000.qcom,acpuclk"),
};
#define PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 4dda0b7..85241a4 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -47,6 +47,7 @@
#include "devices.h"
#include "spm.h"
#include "modem_notifier.h"
+#include "lpm_resources.h"
#define MSM_KERNEL_EBI1_MEM_SIZE 0x280000
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -443,6 +444,12 @@
CLK_DUMMY("core_clk", NULL, "f9966000.i2c", 0),
CLK_DUMMY("iface_clk", NULL, "f9966000.i2c", 0),
CLK_DUMMY("core_clk", NULL, "fe12f000.slim", OFF),
+ CLK_DUMMY("core_clk", "mdp.0", NULL, 0),
+ CLK_DUMMY("core_clk_src", "mdp.0", NULL, 0),
+ CLK_DUMMY("lut_clk", "mdp.0", NULL, 0),
+ CLK_DUMMY("vsync_clk", "mdp.0", NULL, 0),
+ CLK_DUMMY("iface_clk", "mdp.0", NULL, 0),
+ CLK_DUMMY("bus_clk", "mdp.0", NULL, 0),
};
struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -461,6 +468,7 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
+ msm_lpmrs_module_init();
rpm_regulator_smd_driver_init();
msm_spm_device_init();
regulator_stub_init();
@@ -511,6 +519,7 @@
"msm_rng", NULL),
OF_DEV_AUXDATA("qcom,qseecom", 0xFE806000, \
"qseecom", NULL),
+ OF_DEV_AUXDATA("qcom,mdss_mdp", 0xFD900000, "mdp.0", NULL),
{}
};
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 38bdeca..3ab5ba0 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -120,6 +120,21 @@
{"usb2", REG_LDO, 1800000, 1800000, 0},
};
+static struct camera_vreg_t ov5647_gpio_vreg[] = {
+ {"cam_ov5647_avdd", REG_GPIO, 0, 0, 0},
+ {"cam_ov5647_vdd", REG_GPIO, 0, 0, 0},
+};
+
+static struct camera_vreg_t ov8825_gpio_vreg[] = {
+ {"cam_ov8825_avdd", REG_GPIO, 0, 0, 0},
+ {"cam_ov8825_vdd", REG_GPIO, 0, 0, 0},
+};
+
+static struct camera_vreg_t ov7692_gpio_vreg[] = {
+ {"cam_ov7692_avdd", REG_GPIO, 0, 0, 0},
+ {"cam_ov7692_vdd", REG_GPIO, 0, 0, 0},
+};
+
static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data;
struct msm_camera_device_platform_data msm_camera_device_data_csi1[] = {
@@ -180,7 +195,6 @@
static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data = {
.sensor_name = "s5k4e1",
.sensor_reset_enable = 1,
- .pmic_gpio_enable = 0,
.pdata = &msm_camera_device_data_csi1[0],
.flash_data = &flash_s5k4e1,
.sensor_platform_info = &sensor_board_info_s5k4e1,
@@ -206,8 +220,6 @@
static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
.sensor_name = "ov7692",
.sensor_reset_enable = 0,
- .pmic_gpio_enable = 1,
- .sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
.sensor_reset = GPIO_SKU1_CAM_VGA_RESET_N,
.sensor_pwd = GPIO_SKU1_CAM_VGA_SHDN,
.pdata = &msm_camera_device_data_csi0[0],
@@ -250,8 +262,6 @@
static struct msm_camera_sensor_info msm_camera_sensor_ov5647_data = {
.sensor_name = "ov5647",
.sensor_reset_enable = 1,
- .pmic_gpio_enable = 1,
- .sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
.sensor_reset = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
.sensor_pwd = GPIO_SKU3_CAM_5MP_SHDN_N,
.pdata = &msm_camera_device_data_csi1[0],
@@ -311,7 +321,6 @@
static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
.sensor_name = "mt9e013",
.sensor_reset_enable = 1,
- .pmic_gpio_enable = 0,
.pdata = &msm_camera_device_data_csi1[1],
.flash_data = &flash_mt9e013,
.sensor_platform_info = &sensor_board_info_mt9e013,
@@ -337,7 +346,6 @@
static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
.sensor_name = "ov9726",
.sensor_reset_enable = 0,
- .pmic_gpio_enable = 0,
.pdata = &msm_camera_device_data_csi0[0],
.flash_data = &flash_ov9726,
.sensor_platform_info = &sensor_board_info_ov9726,
@@ -371,6 +379,21 @@
sensor_board_info_ov8825.num_vreg = 0;
}
+ if (machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()) {
+ sensor_board_info_ov7692.cam_vreg =
+ ov7692_gpio_vreg;
+ sensor_board_info_ov7692.num_vreg =
+ ARRAY_SIZE(ov7692_gpio_vreg);
+ sensor_board_info_ov5647.cam_vreg =
+ ov5647_gpio_vreg;
+ sensor_board_info_ov5647.num_vreg =
+ ARRAY_SIZE(ov5647_gpio_vreg);
+ sensor_board_info_ov8825.cam_vreg =
+ ov8825_gpio_vreg;
+ sensor_board_info_ov8825.num_vreg =
+ ARRAY_SIZE(ov8825_gpio_vreg);
+ }
platform_device_register(&msm_camera_server);
if (machine_is_msm8625_surf() || machine_is_msm8625_evb()
|| machine_is_msm8625_evt()
@@ -1022,6 +1045,7 @@
ARRAY_SIZE(cam_exp_i2c_info));
}
+#ifndef CONFIG_MSM_CAMERA_V4L2
#define LCD_CAMERA_LDO_2V8 35 /* SKU1&SKU3 2.8V LDO */
#define SKU3_LCD_CAMERA_LDO_1V8 40 /* SKU3 1.8V LDO */
#define SKU7_LCD_CAMERA_LDO_1V8 58 /* SKU7 1.8V LDO */
@@ -1120,6 +1144,7 @@
return rc;
}
EXPORT_SYMBOL(lcd_camera_power_onoff);
+#endif
void __init msm7627a_camera_init(void)
{
@@ -1140,7 +1165,6 @@
GPIO_SKU7_CAM_5MP_SHDN_N;
msm_camera_sensor_ov5647_data.sensor_reset =
GPIO_SKU7_CAM_5MP_CAMIF_RESET;
-
}
/* LCD and camera power (VREG & LDO) init */
@@ -1148,8 +1172,9 @@
|| machine_is_msm8625_evt()
|| machine_is_msm7627a_qrd3()
|| machine_is_msm8625_qrd7()) {
-
+#ifndef CONFIG_MSM_CAMERA_V4L2
lcd_camera_power_init();
+#endif
evb_camera_gpio_cfg();
}
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index ec168f9..22095cd 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -229,7 +229,7 @@
static int mxt_vkey_setup(void)
{
- int retval;
+ int retval = 0;
mxt_virtual_key_properties_kobj =
kobject_create_and_add("board_properties", NULL);
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 5867eef..7866fc7 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5025,6 +5025,7 @@
static struct clk_lookup msm_clocks_8064[] = {
CLK_LOOKUP("xo", cxo_a_clk.c, ""),
CLK_LOOKUP("xo", pxo_a_clk.c, ""),
+ CLK_LOOKUP("pwm_clk", cxo_clk.c, "0-0048"),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 5727c34..2dadc4c 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -588,39 +588,29 @@
static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
-static int cxo_clk_enable(struct clk *clk)
-{
- /* TODO: Remove from here once the rpm xo clock is ready. */
- return 0;
-}
+#define RPM_MISC_CLK_TYPE 0x306b6c63
+#define RPM_BUS_CLK_TYPE 0x316b6c63
+#define RPM_MEM_CLK_TYPE 0x326b6c63
-static void cxo_clk_disable(struct clk *clk)
-{
- /* TODO: Remove from here once the rpm xo clock is ready. */
- return;
-}
+#define CXO_ID 0x0
-static enum handoff cxo_clk_handoff(struct clk *clk)
-{
- /* TODO: Remove from here once the rpm xo clock is ready. */
- return HANDOFF_ENABLED_CLK;
-}
+#define PNOC_ID 0x0
+#define SNOC_ID 0x1
+#define CNOC_ID 0x2
-static struct clk_ops clk_ops_cxo = {
- .enable = cxo_clk_enable,
- .disable = cxo_clk_disable,
- .handoff = cxo_clk_handoff,
-};
+#define BIMC_ID 0x0
+#define OCMEM_ID 0x1
-static struct fixed_clk cxo_clk_src = {
- .c = {
- .rate = 19200000,
- .dbg_name = "cxo_clk_src",
- .ops = &clk_ops_cxo,
- .warned = true,
- CLK_INIT(cxo_clk_src.c),
- },
-};
+DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(cnoc_clk, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+DEFINE_CLK_RPM_SMD(ocmemgx_clk, ocmemgx_a_clk, RPM_MEM_CLK_TYPE, OCMEM_ID,
+ NULL);
+
+DEFINE_CLK_RPM_SMD_BRANCH(cxo_clk_src, cxo_a_clk_src,
+ RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
static struct pll_vote_clk gpll0_clk_src = {
.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE_REG,
@@ -715,24 +705,6 @@
},
};
-#define RPM_BUS_CLK_TYPE 0x316b6c63
-#define RPM_MEM_CLK_TYPE 0x326b6c63
-
-#define PNOC_ID 0x0
-#define SNOC_ID 0x1
-#define CNOC_ID 0x2
-
-#define BIMC_ID 0x0
-#define OCMEM_ID 0x1
-
-DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
-DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
-DEFINE_CLK_RPM_SMD(cnoc_clk, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
-
-DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
-DEFINE_CLK_RPM_SMD(ocmemgx_clk, ocmemgx_a_clk, RPM_MEM_CLK_TYPE, OCMEM_ID,
- NULL);
-
static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
@@ -746,6 +718,11 @@
static DEFINE_CLK_VOTER(ocmemgx_msmbus_clk, &ocmemgx_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_sdcc1_clk, &pnoc_clk.c, 0);
+static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, 0);
+static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, 0);
+static DEFINE_CLK_VOTER(pnoc_sdcc4_clk, &pnoc_clk.c, 0);
+
static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
F(125000000, gpll0, 1, 5, 24),
F_END
@@ -4668,12 +4645,16 @@
CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
+ CLK_LOOKUP("bus_clk", pnoc_sdcc1_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+ CLK_LOOKUP("bus_clk", pnoc_sdcc2_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
+ CLK_LOOKUP("bus_clk", pnoc_sdcc3_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
+ CLK_LOOKUP("bus_clk", pnoc_sdcc4_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
@@ -4697,10 +4678,10 @@
CLK_LOOKUP("core_clk", mdss_esc1_clk.c, ""),
CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, ""),
- CLK_LOOKUP("core_clk", mdss_mdp_clk.c, ""),
- CLK_LOOKUP("core_clk", mdss_mdp_lut_clk.c, ""),
- CLK_LOOKUP("core_clk", mdp_clk_src.c, ""),
- CLK_LOOKUP("core_clk", mdss_vsync_clk.c, ""),
+ CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
+ CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
+ CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "mdp.0"),
+ CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "mdp.0"),
CLK_LOOKUP("iface_clk", camss_cci_cci_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", camss_cci_cci_clk.c, ""),
CLK_LOOKUP("iface_clk", camss_csi0_ahb_clk.c, ""),
@@ -4759,9 +4740,10 @@
CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, ""),
CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c, ""),
CLK_LOOKUP("bus_clk", camss_vfe_vfe_ocmemnoc_clk.c, ""),
+ CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdp.0"),
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, ""),
+ 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, ""),
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index ab57cf8..e35e8d4 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -54,13 +54,15 @@
return (rc < 0) ? rc : iv.value * 1000;
}
-#define RPM_SMD_KEY_CLOCK_SET_RATE 0x007A484B
+#define RPM_SMD_KEY_RATE 0x007A484B
+#define RPM_SMD_KEY_ENABLE 0x62616E45
static int clk_rpmrs_set_rate_smd(struct rpm_clk *r, uint32_t value,
uint32_t context, int noirq)
{
+ u32 rpm_key = r->branch ? RPM_SMD_KEY_ENABLE : RPM_SMD_KEY_RATE;
struct msm_rpm_kvp kvp = {
- .key = RPM_SMD_KEY_CLOCK_SET_RATE,
+ .key = rpm_key,
.data = (void *)&value,
.length = sizeof(value),
};
@@ -272,9 +274,11 @@
if (rc < 0)
return HANDOFF_DISABLED_CLK;
- r->last_set_khz = iv.value;
- r->last_set_sleep_khz = iv.value;
- clk->rate = iv.value * 1000;
+ if (!r->branch) {
+ r->last_set_khz = iv.value;
+ r->last_set_sleep_khz = iv.value;
+ clk->rate = iv.value * 1000;
+ }
return HANDOFF_ENABLED_CLK;
}
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 66ce30e..4e01899 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -1917,6 +1917,7 @@
MSM_RPM_MAP(8064, HDMI_SWITCH, HDMI_SWITCH, 1),
MSM_RPM_MAP(8064, DDR_DMM_0, DDR_DMM, 2),
MSM_RPM_MAP(8064, QDSS_CLK, QDSS_CLK, 1),
+ MSM_RPM_MAP(8064, VDDMIN_GPIO, VDDMIN_GPIO, 1),
},
.target_status = {
MSM_RPM_STATUS_ID_MAP(8064, VERSION_MAJOR),
@@ -2050,6 +2051,7 @@
MSM_RPM_STATUS_ID_MAP(8064, PM8821_S2_1),
MSM_RPM_STATUS_ID_MAP(8064, PM8821_L1_0),
MSM_RPM_STATUS_ID_MAP(8064, PM8821_L1_1),
+ MSM_RPM_STATUS_ID_MAP(8064, VDDMIN_GPIO),
},
.target_ctrl_id = {
MSM_RPM_CTRL_MAP(8064, VERSION_MAJOR),
diff --git a/arch/arm/mach-msm/hsic_sysmon.c b/arch/arm/mach-msm/hsic_sysmon.c
index 07a9dbb..153e1b4 100644
--- a/arch/arm/mach-msm/hsic_sysmon.c
+++ b/arch/arm/mach-msm/hsic_sysmon.c
@@ -314,6 +314,8 @@
static inline void hsic_sysmon_debugfs_cleanup(void) { }
#endif
+static void hsic_sysmon_pdev_release(struct device *dev) { }
+
static int
hsic_sysmon_probe(struct usb_interface *ifc, const struct usb_device_id *id)
{
@@ -371,6 +373,7 @@
hs->pdev.name = "sys_mon";
hs->pdev.id = SYSMON_SS_EXT_MODEM;
+ hs->pdev.dev.release = hsic_sysmon_pdev_release;
platform_device_register(&hs->pdev);
pr_debug("complete");
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index be254f6..460eefc 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -183,6 +183,7 @@
enum camera_vreg_type {
REG_LDO,
REG_VS,
+ REG_GPIO,
};
struct camera_vreg_t {
@@ -290,7 +291,6 @@
enum msm_sensor_type sensor_type;
struct msm_actuator_info *actuator_info;
int pmic_gpio_enable;
- int (*sensor_lcd_gpio_onoff)(int on);
struct msm_eeprom_info *eeprom_info;
};
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index d8543f3..6d2c25a 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -94,6 +94,7 @@
VFE_MSG_V2X_CAPTURE,
VFE_MSG_OUTPUT_PRIMARY,
VFE_MSG_OUTPUT_SECONDARY,
+ VFE_MSG_OUTPUT_TERTIARY1,
};
enum vpe_resp_msg {
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index b57ae10..4bfbe61 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -15,6 +15,7 @@
#include <linux/interrupt.h>
#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
#include <mach/socinfo.h>
extern pgprot_t pgprot_kernel;
@@ -79,6 +80,7 @@
struct clk *clk;
struct clk *pclk;
const char *name;
+ struct regulator *gdsc;
};
/**
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index 997b3be..09839b2 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -13,12 +13,21 @@
#ifndef _ARCH_ARM_MACH_MSM_MDM2_H
#define _ARCH_ARM_MACH_MSM_MDM2_H
+struct mdm_vddmin_resource {
+ int rpm_id;
+ int ap2mdm_vddmin_gpio;
+ unsigned int modes;
+ unsigned int drive_strength;
+ int mdm2ap_vddmin_gpio;
+};
+
struct mdm_platform_data {
char *mdm_version;
int ramdump_delay_ms;
int soft_reset_inverted;
int early_power_on;
int sfr_query;
+ struct mdm_vddmin_resource *vddmin_resource;
struct platform_device *peripheral_platform_device;
};
diff --git a/arch/arm/mach-msm/include/mach/rpm-8064.h b/arch/arm/mach-msm/include/mach/rpm-8064.h
index c4c6b0a..39ec7ff 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8064.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8064.h
@@ -120,7 +120,9 @@
MSM_RPM_8064_SEL_HDMI_SWITCH = 83,
MSM_RPM_8064_SEL_DDR_DMM = 84,
- MSM_RPM_8064_SEL_LAST = MSM_RPM_8064_SEL_DDR_DMM,
+ MSM_RPM_8064_SEL_VDDMIN_GPIO = 89,
+
+ MSM_RPM_8064_SEL_LAST = MSM_RPM_8064_SEL_VDDMIN_GPIO,
};
/* RPM resource (4 byte) word ID enum */
@@ -287,8 +289,9 @@
MSM_RPM_8064_ID_DDR_DMM_0 = 212,
MSM_RPM_8064_ID_DDR_DMM_1 = 213,
MSM_RPM_8064_ID_QDSS_CLK = 214,
+ MSM_RPM_8064_ID_VDDMIN_GPIO = 215,
- MSM_RPM_8064_ID_LAST = MSM_RPM_8064_ID_QDSS_CLK,
+ MSM_RPM_8064_ID_LAST = MSM_RPM_8064_ID_VDDMIN_GPIO,
};
@@ -425,8 +428,9 @@
MSM_RPM_8064_STATUS_ID_DDR_DMM_1 = 128,
MSM_RPM_8064_STATUS_ID_EBI1_CH0_RANGE = 129,
MSM_RPM_8064_STATUS_ID_EBI1_CH1_RANGE = 130,
+ MSM_RPM_8064_STATUS_ID_VDDMIN_GPIO = 131,
- MSM_RPM_8064_STATUS_ID_LAST = MSM_RPM_8064_STATUS_ID_EBI1_CH1_RANGE,
+ MSM_RPM_8064_STATUS_ID_LAST = MSM_RPM_8064_STATUS_ID_VDDMIN_GPIO,
};
#endif /* __ARCH_ARM_MACH_MSM_RPM_8064_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index de4c9d9..f6b9a6e 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -460,6 +460,7 @@
MSM_RPM_ID_PM8821_S2_1,
MSM_RPM_ID_PM8821_L1_0,
MSM_RPM_ID_PM8821_L1_1,
+ MSM_RPM_ID_VDDMIN_GPIO,
MSM_RPM_ID_LAST,
};
@@ -825,6 +826,7 @@
MSM_RPM_STATUS_ID_PM8821_S2_1,
MSM_RPM_STATUS_ID_PM8821_L1_0,
MSM_RPM_STATUS_ID_PM8821_L1_1,
+ MSM_RPM_STATUS_ID_VDDMIN_GPIO,
MSM_RPM_STATUS_ID_LAST,
};
diff --git a/arch/arm/mach-msm/include/mach/stm.h b/arch/arm/mach-msm/include/mach/stm.h
new file mode 100644
index 0000000..20c4963
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/stm.h
@@ -0,0 +1,60 @@
+/* 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 __MACH_STM_H
+#define __MACH_STM_H
+
+enum {
+ OST_ENTITY_NONE = 0x0,
+ OST_ENTITY_FTRACE_EVENTS = 0x1,
+ OST_ENTITY_TRACE_PRINTK = 0x2,
+ OST_ENTITY_TRACE_MARKER = 0x4,
+ OST_ENTITY_DEV_NODE = 0x8,
+ OST_ENTITY_ALL = 0xF,
+};
+
+enum {
+ STM_OPTION_NONE = 0x0,
+ STM_OPTION_TIMESTAMPED = 0x08,
+ STM_OPTION_GUARANTEED = 0x80,
+};
+
+#define stm_log_inv(entity_id, proto_id, data, size) \
+ stm_trace(STM_OPTION_NONE, entity_id, proto_id, data, size)
+
+#define stm_log_inv_ts(entity_id, proto_id, data, size) \
+ stm_trace(STM_OPTION_TIMESTAMPED, entity_id, proto_id, \
+ data, size)
+
+#define stm_log_gtd(entity_id, proto_id, data, size) \
+ stm_trace(STM_OPTION_GUARANTEED, entity_id, proto_id, \
+ data, size)
+
+#define stm_log_gtd_ts(entity_id, proto_id, data, size) \
+ stm_trace(STM_OPTION_GUARANTEED | STM_OPTION_TIMESTAMPED, \
+ entity_id, proto_id, data, size)
+
+#define stm_log(entity_id, data, size) \
+ stm_log_inv_ts(entity_id, 0, data, size)
+
+#ifdef CONFIG_MSM_QDSS
+extern int stm_trace(uint32_t options, uint8_t entity_id, uint8_t proto_id,
+ const void *data, uint32_t size);
+#else
+static inline int stm_trace(uint32_t options, uint8_t entity_id,
+ uint8_t proto_id, const void *data, uint32_t size)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index a7e06ba..e92b5c5 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -47,31 +47,57 @@
unsigned long page_size,
int cached)
{
- int i, ret_value = 0;
- unsigned long order = get_order(page_size);
- unsigned long aligned_size = ALIGN(size, page_size);
- unsigned long nrpages = aligned_size >> (PAGE_SHIFT + order);
+ int ret = 0;
+ int i = 0;
unsigned long phy_addr = ALIGN(virt_to_phys(iommu_dummy), page_size);
unsigned long temp_iova = start_iova;
+ if (page_size == SZ_4K) {
+ struct scatterlist *sglist;
+ unsigned int nrpages = PFN_ALIGN(size) >> PAGE_SHIFT;
+ struct page *dummy_page = phys_to_page(phy_addr);
- for (i = 0; i < nrpages; i++) {
- int ret = iommu_map(domain, temp_iova, phy_addr, page_size,
- cached);
- if (ret) {
- pr_err("%s: could not map %lx in domain %p, error: %d\n",
- __func__, start_iova, domain, ret);
- ret_value = -EAGAIN;
+ sglist = vmalloc(sizeof(*sglist) * nrpages);
+ if (!sglist) {
+ ret = -ENOMEM;
goto out;
}
- temp_iova += page_size;
+
+ sg_init_table(sglist, nrpages);
+
+ for (i = 0; i < nrpages; i++)
+ sg_set_page(&sglist[i], dummy_page, PAGE_SIZE, 0);
+
+ ret = iommu_map_range(domain, temp_iova, sglist, size, cached);
+ if (ret) {
+ pr_err("%s: could not map extra %lx in domain %p\n",
+ __func__, start_iova, domain);
+ }
+
+ vfree(sglist);
+ } else {
+ unsigned long order = get_order(page_size);
+ unsigned long aligned_size = ALIGN(size, page_size);
+ unsigned long nrpages = aligned_size >> (PAGE_SHIFT + order);
+
+ for (i = 0; i < nrpages; i++) {
+ ret = iommu_map(domain, temp_iova, phy_addr, page_size,
+ cached);
+ if (ret) {
+ pr_err("%s: could not map %lx in domain %p, error: %d\n",
+ __func__, start_iova, domain, ret);
+ ret = -EAGAIN;
+ goto out;
+ }
+ temp_iova += page_size;
+ }
}
- return ret_value;
+ return ret;
out:
for (; i > 0; --i) {
temp_iova -= page_size;
iommu_unmap(domain, start_iova, page_size);
}
- return ret_value;
+ return ret;
}
void msm_iommu_unmap_extra(struct iommu_domain *domain,
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index a1f5ff5..e65f71c 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -18,17 +18,32 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <mach/mpm.h>
-#include "rpm_resources.h"
+#include "lpm_resources.h"
#include "pm.h"
static struct msm_rpmrs_level *msm_lpm_levels;
static int msm_lpm_level_count;
-static int msm_lpm_enter_sleep(uint32_t sclk_count, void *limits,
+static void msm_lpm_level_update(void)
+{
+ unsigned int lpm_level;
+ struct msm_rpmrs_level *level = NULL;
+
+ for (lpm_level = 0; lpm_level < msm_lpm_level_count; lpm_level++) {
+ level = &msm_lpm_levels[lpm_level];
+ level->available =
+ !msm_lpm_level_beyond_limit(&level->rs_limits);
+ }
+}
+
+int msm_lpm_enter_sleep(uint32_t sclk_count, void *limits,
bool from_idle, bool notify_rpm)
{
- /* TODO */
- return 0;
+ int ret = 0;
+
+ ret = msm_lpmrs_enter_sleep((struct msm_rpmrs_limits *)limits,
+ from_idle, notify_rpm);
+ return ret;
}
static void msm_lpm_exit_sleep(void *limits, bool from_idle,
@@ -38,14 +53,7 @@
return;
}
-static bool msm_rpmrs_irqs_detectable(struct msm_rpmrs_limits *limits,
- bool irqs_detect, bool gpio_detect)
-{
- /* TODO */
- return true;
-}
-
-void msm_rpmrs_show_resources(void)
+void msm_lpm_show_resources(void)
{
/* TODO */
return;
@@ -80,18 +88,13 @@
{
unsigned int cpu = smp_processor_id();
struct msm_rpmrs_level *best_level = NULL;
- bool irqs_detectable = false;
- bool gpio_detectable = false;
uint32_t pwr;
int i;
if (!msm_lpm_levels)
return NULL;
- if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
- irqs_detectable = msm_mpm_irqs_detectable(from_idle);
- gpio_detectable = msm_mpm_gpio_irqs_detectable(from_idle);
- }
+ msm_lpm_level_update();
for (i = 0; i < msm_lpm_level_count; i++) {
struct msm_rpmrs_level *level = &msm_lpm_levels[i];
@@ -105,10 +108,6 @@
if (latency_us < level->latency_us)
continue;
- if (!msm_rpmrs_irqs_detectable(&level->rs_limits,
- irqs_detectable, gpio_detectable))
- continue;
-
if (sleep_us <= 1) {
pwr = level->energy_overhead;
} else if (sleep_us <= level->time_overhead_us) {
@@ -192,7 +191,7 @@
ret = of_property_read_u32(node, key, &val);
if (ret)
goto fail;
- level->rs_limits.vdd_dig = val;
+ level->rs_limits.vdd_dig_lower_bound = val;
key = "qcom,vdd-mem-upper-bound";
ret = of_property_read_u32(node, key, &val);
@@ -204,7 +203,7 @@
ret = of_property_read_u32(node, key, &val);
if (ret)
goto fail;
- level->rs_limits.vdd_mem = val;
+ level->rs_limits.vdd_mem_lower_bound = val;
key = "qcom,latency-us";
ret = of_property_read_u32(node, key, &val);
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
new file mode 100644
index 0000000..f57f974
--- /dev/null
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -0,0 +1,865 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/cpu.h>
+#include <mach/mpm.h>
+#include <linux/notifier.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include "spm.h"
+#include "lpm_resources.h"
+#include "rpm-notifier.h"
+#include <mach/rpm-smd.h>
+#include "idle.h"
+
+/*Debug Definitions*/
+enum {
+ MSM_LPMRS_DEBUG_RPM = BIT(0),
+ MSM_LPMRS_DEBUG_PXO = BIT(1),
+ MSM_LPMRS_DEBUG_VDD_DIG = BIT(2),
+ MSM_LPMRS_DEBUG_VDD_MEM = BIT(3),
+ MSM_LPMRS_DEBUG_L2 = BIT(4),
+ MSM_LPMRS_DEBUG_LVLS = BIT(5),
+};
+
+static int msm_lpm_debug_mask;
+module_param_named(
+ debug_mask, msm_lpm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static bool msm_lpm_get_rpm_notif = true;
+
+/*Macros*/
+#define VDD_DIG_ACTIVE (950000)
+#define VDD_MEM_ACTIVE (1050000)
+#define MAX_RS_NAME (16)
+#define MAX_RS_SIZE (4)
+#define IS_RPM_CTL(rs) \
+ (!strncmp(rs->name, "rpm_ctl", MAX_RS_NAME))
+
+static bool msm_lpm_beyond_limits_vdd_dig(struct msm_rpmrs_limits *limits);
+static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits);
+static void msm_lpm_flush_vdd_dig(int notify_rpm);
+static void msm_lpm_notify_vdd_dig(struct msm_rpm_notifier_data
+ *rpm_notifier_cb);
+
+static bool msm_lpm_beyond_limits_vdd_mem(struct msm_rpmrs_limits *limits);
+static void msm_lpm_aggregate_vdd_mem(struct msm_rpmrs_limits *limits);
+static void msm_lpm_flush_vdd_mem(int notify_rpm);
+static void msm_lpm_notify_vdd_mem(struct msm_rpm_notifier_data
+ *rpm_notifier_cb);
+
+static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits);
+static void msm_lpm_aggregate_pxo(struct msm_rpmrs_limits *limits);
+static void msm_lpm_flush_pxo(int notify_rpm);
+static void msm_lpm_notify_pxo(struct msm_rpm_notifier_data
+ *rpm_notifier_cb);
+
+
+static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits);
+static void msm_lpm_flush_l2(int notify_rpm);
+static void msm_lpm_aggregate_l2(struct msm_rpmrs_limits *limits);
+
+static void msm_lpm_flush_rpm_ctl(int notify_rpm);
+
+static int msm_lpm_rpm_callback(struct notifier_block *rpm_nb,
+ unsigned long action, void *rpm_notif);
+
+static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+ unsigned long action, void *hcpu);
+
+static ssize_t msm_lpm_resource_attr_show(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf);
+static ssize_t msm_lpm_resource_attr_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count);
+
+
+#define RPMRS_ATTR(_name) \
+ __ATTR(_name, S_IRUGO|S_IWUSR, \
+ msm_lpm_resource_attr_show, msm_lpm_resource_attr_store)
+
+/*Data structures*/
+struct msm_lpm_rs_data {
+ uint32_t type;
+ uint32_t id;
+ uint32_t key;
+ uint32_t value;
+ uint32_t default_value;
+ struct msm_rpm_request *handle;
+};
+
+struct msm_lpm_resource {
+ struct msm_lpm_rs_data rs_data;
+ uint32_t sleep_value;
+ char name[MAX_RS_NAME];
+
+ uint32_t enable_low_power;
+ bool valid;
+
+ bool (*beyond_limits)(struct msm_rpmrs_limits *limits);
+ void (*aggregate)(struct msm_rpmrs_limits *limits);
+ void (*flush)(int notify_rpm);
+ void (*notify)(struct msm_rpm_notifier_data *rpm_notifier_cb);
+ struct kobj_attribute ko_attr;
+};
+
+
+static struct msm_lpm_resource msm_lpm_l2 = {
+ .name = "l2",
+ .beyond_limits = msm_lpm_beyond_limits_l2,
+ .aggregate = msm_lpm_aggregate_l2,
+ .flush = msm_lpm_flush_l2,
+ .notify = NULL,
+ .valid = true,
+ .rs_data = {
+ .value = MSM_LPM_L2_CACHE_ACTIVE,
+ .default_value = MSM_LPM_L2_CACHE_ACTIVE,
+ },
+ .ko_attr = RPMRS_ATTR(l2),
+};
+
+static struct msm_lpm_resource msm_lpm_vdd_dig = {
+ .name = "vdd-dig",
+ .beyond_limits = msm_lpm_beyond_limits_vdd_dig,
+ .aggregate = msm_lpm_aggregate_vdd_dig,
+ .flush = msm_lpm_flush_vdd_dig,
+ .notify = msm_lpm_notify_vdd_dig,
+ .valid = false,
+ .rs_data = {
+ .value = VDD_DIG_ACTIVE,
+ .default_value = VDD_DIG_ACTIVE,
+ },
+ .ko_attr = RPMRS_ATTR(vdd_dig),
+};
+
+static struct msm_lpm_resource msm_lpm_vdd_mem = {
+ .name = "vdd-mem",
+ .beyond_limits = msm_lpm_beyond_limits_vdd_mem,
+ .aggregate = msm_lpm_aggregate_vdd_mem,
+ .flush = msm_lpm_flush_vdd_mem,
+ .notify = msm_lpm_notify_vdd_mem,
+ .valid = false,
+ .rs_data = {
+ .value = VDD_MEM_ACTIVE,
+ .default_value = VDD_MEM_ACTIVE,
+ },
+ .ko_attr = RPMRS_ATTR(vdd_mem),
+};
+
+static struct msm_lpm_resource msm_lpm_pxo = {
+ .name = "pxo",
+ .beyond_limits = msm_lpm_beyond_limits_pxo,
+ .aggregate = msm_lpm_aggregate_pxo,
+ .flush = msm_lpm_flush_pxo,
+ .notify = msm_lpm_notify_pxo,
+ .valid = false,
+ .rs_data = {
+ .value = MSM_LPM_PXO_ON,
+ .default_value = MSM_LPM_PXO_ON,
+ },
+ .ko_attr = RPMRS_ATTR(pxo),
+};
+
+static struct msm_lpm_resource *msm_lpm_resources[] = {
+ &msm_lpm_vdd_dig,
+ &msm_lpm_vdd_mem,
+ &msm_lpm_pxo,
+ &msm_lpm_l2,
+};
+
+static struct msm_lpm_resource msm_lpm_rpm_ctl = {
+ .name = "rpm_ctl",
+ .beyond_limits = NULL,
+ .aggregate = NULL,
+ .flush = msm_lpm_flush_rpm_ctl,
+ .valid = true,
+ .ko_attr = RPMRS_ATTR(rpm_ctl),
+};
+
+static struct notifier_block msm_lpm_rpm_nblk = {
+ .notifier_call = msm_lpm_rpm_callback,
+};
+
+static struct notifier_block __refdata msm_lpm_cpu_nblk = {
+ .notifier_call = msm_lpm_cpu_callback,
+};
+
+static DEFINE_SPINLOCK(msm_lpm_sysfs_lock);
+
+/* Attribute Definitions */
+static struct attribute *msm_lpm_attributes[] = {
+ &msm_lpm_vdd_dig.ko_attr.attr,
+ &msm_lpm_vdd_mem.ko_attr.attr,
+ &msm_lpm_pxo.ko_attr.attr,
+ &msm_lpm_l2.ko_attr.attr,
+ NULL,
+};
+
+static struct attribute_group msm_lpm_attribute_group = {
+ .attrs = msm_lpm_attributes,
+};
+
+static struct attribute *msm_lpm_rpm_ctl_attribute[] = {
+ &msm_lpm_rpm_ctl.ko_attr.attr,
+ NULL,
+};
+
+static struct attribute_group msm_lpm_rpm_ctl_attr_group = {
+ .attrs = msm_lpm_rpm_ctl_attribute,
+};
+
+#define GET_RS_FROM_ATTR(attr) \
+ (container_of(attr, struct msm_lpm_resource, ko_attr))
+
+/* RPM */
+static struct msm_rpm_request *msm_lpm_create_rpm_request
+ (uint32_t rsc_type, uint32_t rsc_id)
+{
+ struct msm_rpm_request *handle = NULL;
+
+ handle = msm_rpm_create_request(MSM_RPM_CTX_SLEEP_SET,
+ rsc_type,
+ rsc_id, 1);
+ return handle;
+}
+
+static int msm_lpm_send_sleep_data(struct msm_rpm_request *handle,
+ uint32_t key, uint8_t *value)
+{
+ int ret = 0;
+
+ if (!handle)
+ return ret;
+
+ ret = msm_rpm_add_kvp_data_noirq(handle, key, value, MAX_RS_SIZE);
+
+ if (ret < 0) {
+ pr_err("%s: Error adding kvp data key %u, size %d\n",
+ __func__, key, MAX_RS_SIZE);
+ return ret;
+ }
+
+ ret = msm_rpm_send_request_noirq(handle);
+ if (ret < 0) {
+ pr_err("%s: Error sending RPM request key %u, handle 0x%x\n",
+ __func__, key, (unsigned int)handle);
+ return ret;
+ }
+ if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_RPM)
+ pr_info("Rs key %u, value %u, size %d\n", key,
+ *(unsigned int *)value, MAX_RS_SIZE);
+ return ret;
+}
+
+/* RPM Notifier */
+static int msm_lpm_rpm_callback(struct notifier_block *rpm_nb,
+ unsigned long action,
+ void *rpm_notif)
+{
+ int i;
+ struct msm_lpm_resource *rs = NULL;
+ struct msm_rpm_notifier_data *rpm_notifier_cb =
+ (struct msm_rpm_notifier_data *)rpm_notif;
+
+ if (!msm_lpm_get_rpm_notif)
+ return NOTIFY_DONE;
+
+ if (!(rpm_nb && rpm_notif))
+ return NOTIFY_BAD;
+
+ for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
+ rs = msm_lpm_resources[i];
+ if (rs && rs->valid && rs->notify)
+ rs->notify(rpm_notifier_cb);
+ }
+
+ return NOTIFY_OK;
+}
+
+/* SYSFS */
+static ssize_t msm_lpm_resource_attr_show(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct kernel_param kp;
+ unsigned long flags;
+ unsigned int temp;
+ int rc;
+
+ spin_lock_irqsave(&msm_lpm_sysfs_lock, flags);
+ temp = GET_RS_FROM_ATTR(attr)->enable_low_power;
+ spin_unlock_irqrestore(&msm_lpm_sysfs_lock, flags);
+
+ kp.arg = &temp;
+ rc = param_get_uint(buf, &kp);
+
+ if (rc > 0) {
+ strlcat(buf, "\n", PAGE_SIZE);
+ rc++;
+ }
+
+ return rc;
+}
+
+static ssize_t msm_lpm_resource_attr_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct kernel_param kp;
+ unsigned long flags;
+ unsigned int temp;
+ int rc;
+
+ kp.arg = &temp;
+ rc = param_set_uint(buf, &kp);
+ if (rc)
+ return rc;
+
+ spin_lock_irqsave(&msm_lpm_sysfs_lock, flags);
+ GET_RS_FROM_ATTR(attr)->enable_low_power = temp;
+
+ if (IS_RPM_CTL(GET_RS_FROM_ATTR(attr))) {
+ struct msm_lpm_resource *rs = GET_RS_FROM_ATTR(attr);
+ rs->flush(false);
+ }
+
+ spin_unlock_irqrestore(&msm_lpm_sysfs_lock, flags);
+
+ return count;
+}
+
+/* lpm resource handling functions */
+/* Common */
+static void msm_lpm_notify_common(struct msm_rpm_notifier_data *rpm_notifier_cb,
+ struct msm_lpm_resource *rs)
+{
+ if ((rpm_notifier_cb->rsc_type == rs->rs_data.type) &&
+ (rpm_notifier_cb->rsc_id == rs->rs_data.id) &&
+ (rpm_notifier_cb->key == rs->rs_data.key)) {
+ BUG_ON(rpm_notifier_cb->size > MAX_RS_SIZE);
+
+ if (rs->valid) {
+ if (rpm_notifier_cb->value)
+ memcpy(&rs->rs_data.value,
+ rpm_notifier_cb->value, rpm_notifier_cb->size);
+ else
+ rs->rs_data.value = rs->rs_data.default_value;
+
+ if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_RPM)
+ pr_info("Notification received Rs %s value %u\n",
+ rs->name, rs->rs_data.value);
+ }
+ }
+}
+
+/* L2 */
+static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits)
+{
+ uint32_t l2;
+ bool ret = true;
+ struct msm_lpm_resource *rs = &msm_lpm_l2;
+
+ if (rs->valid) {
+ uint32_t l2_buf = rs->rs_data.value;
+
+ if (rs->enable_low_power == 1)
+ l2 = MSM_LPM_L2_CACHE_GDHS;
+ else if (rs->enable_low_power == 2)
+ l2 = MSM_LPM_L2_CACHE_HSFS_OPEN;
+ else
+ l2 = MSM_LPM_L2_CACHE_ACTIVE ;
+
+ if (l2_buf > l2)
+ l2 = l2_buf;
+ ret = (l2 > limits->l2_cache);
+
+ if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_L2)
+ pr_info("%s: l2 buf %u, l2 %u, limits %u\n",
+ __func__, l2_buf, l2, limits->l2_cache);
+ }
+ return ret;
+}
+
+static void msm_lpm_aggregate_l2(struct msm_rpmrs_limits *limits)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_l2;
+
+ if (rs->valid)
+ rs->sleep_value = limits->l2_cache;
+}
+
+static void msm_lpm_flush_l2(int notify_rpm)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_l2;
+ int lpm;
+ int rc;
+
+ switch (rs->sleep_value) {
+ case MSM_LPM_L2_CACHE_HSFS_OPEN:
+ lpm = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+ msm_pm_set_l2_flush_flag(1);
+ break;
+ case MSM_LPM_L2_CACHE_GDHS:
+ lpm = MSM_SPM_L2_MODE_GDHS;
+ break;
+ case MSM_LPM_L2_CACHE_RETENTION:
+ lpm = MSM_SPM_L2_MODE_RETENTION;
+ break;
+ default:
+ case MSM_LPM_L2_CACHE_ACTIVE:
+ lpm = MSM_SPM_L2_MODE_DISABLED;
+ break;
+ }
+
+ rc = msm_spm_l2_set_low_power_mode(lpm, notify_rpm);
+
+ if (rc < 0)
+ pr_err("%s: Failed to set L2 low power mode %d",
+ __func__, lpm);
+
+ if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_L2)
+ pr_info("%s: Requesting low power mode %d\n",
+ __func__, lpm);
+}
+
+/* RPM CTL */
+static void msm_lpm_flush_rpm_ctl(int notify_rpm)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_rpm_ctl;
+ msm_lpm_send_sleep_data(rs->rs_data.handle,
+ rs->rs_data.key,
+ (uint8_t *)&rs->sleep_value);
+}
+
+/*VDD Dig*/
+static bool msm_lpm_beyond_limits_vdd_dig(struct msm_rpmrs_limits *limits)
+{
+ bool ret = true;
+ struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
+
+ if (rs->valid) {
+ uint32_t vdd_buf = rs->rs_data.value;
+ uint32_t vdd_dig = rs->enable_low_power ? rs->enable_low_power :
+ rs->rs_data.default_value;
+
+ if (vdd_buf > vdd_dig)
+ vdd_dig = vdd_buf;
+
+ ret = (vdd_dig > limits->vdd_dig_upper_bound);
+
+ if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_VDD_DIG)
+ pr_info("%s:buf %d vdd dig %d limits%d\n",
+ __func__, vdd_buf, vdd_dig,
+ limits->vdd_dig_upper_bound);
+ }
+ return ret;
+}
+
+static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
+
+ if (rs->valid) {
+ uint32_t vdd_buf = rs->rs_data.value;
+ if (limits->vdd_dig_lower_bound > vdd_buf)
+ rs->sleep_value = limits->vdd_dig_lower_bound;
+ else
+ rs->sleep_value = vdd_buf;
+ }
+}
+
+static void msm_lpm_flush_vdd_dig(int notify_rpm)
+{
+ if (notify_rpm) {
+ struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
+ msm_lpm_send_sleep_data(rs->rs_data.handle,
+ rs->rs_data.key,
+ (uint8_t *)&rs->sleep_value);
+ }
+}
+
+static void msm_lpm_notify_vdd_dig(struct msm_rpm_notifier_data
+ *rpm_notifier_cb)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
+ msm_lpm_notify_common(rpm_notifier_cb, rs);
+}
+
+/*VDD Mem*/
+static bool msm_lpm_beyond_limits_vdd_mem(struct msm_rpmrs_limits *limits)
+{
+ bool ret = true;
+ struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
+
+ if (rs->valid) {
+ uint32_t vdd_buf = rs->rs_data.value;
+ uint32_t vdd_mem = rs->enable_low_power ? rs->enable_low_power :
+ rs->rs_data.default_value;
+
+ if (vdd_buf > vdd_mem)
+ vdd_mem = vdd_buf;
+
+ ret = (vdd_mem > limits->vdd_mem_upper_bound);
+
+ if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_VDD_MEM)
+ pr_info("%s:buf %d vdd mem %d limits%d\n",
+ __func__, vdd_buf, vdd_mem,
+ limits->vdd_mem_upper_bound);
+ }
+ return ret;
+}
+
+static void msm_lpm_aggregate_vdd_mem(struct msm_rpmrs_limits *limits)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
+
+ if (rs->valid) {
+ uint32_t vdd_buf = rs->rs_data.value;
+ if (limits->vdd_mem_lower_bound > vdd_buf)
+ rs->sleep_value = limits->vdd_mem_lower_bound;
+ else
+ rs->sleep_value = vdd_buf;
+ }
+}
+
+static void msm_lpm_flush_vdd_mem(int notify_rpm)
+{
+ if (notify_rpm) {
+ struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
+ msm_lpm_send_sleep_data(rs->rs_data.handle,
+ rs->rs_data.key,
+ (uint8_t *)&rs->sleep_value);
+ }
+}
+
+static void msm_lpm_notify_vdd_mem(struct msm_rpm_notifier_data
+ *rpm_notifier_cb)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
+ msm_lpm_notify_common(rpm_notifier_cb, rs);
+}
+
+/*PXO*/
+static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits)
+{
+ bool ret = true;
+ struct msm_lpm_resource *rs = &msm_lpm_pxo;
+
+ if (rs->valid) {
+ uint32_t pxo_buf = rs->rs_data.value;
+ uint32_t pxo = rs->enable_low_power ? MSM_LPM_PXO_OFF :
+ rs->rs_data.default_value;
+
+ if (pxo_buf > pxo)
+ pxo = pxo_buf;
+
+ ret = (pxo > limits->pxo);
+
+ if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_PXO)
+ pr_info("%s:pxo buf %d pxo %d limits pxo %d\n",
+ __func__, pxo_buf, pxo, limits->pxo);
+ }
+ return ret;
+}
+
+static void msm_lpm_aggregate_pxo(struct msm_rpmrs_limits *limits)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_pxo;
+
+ if (rs->valid) {
+ uint32_t pxo_buf = rs->rs_data.value;
+ if (limits->pxo > pxo_buf)
+ rs->sleep_value = limits->pxo;
+ else
+ rs->sleep_value = pxo_buf;
+
+ if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_PXO)
+ pr_info("%s: pxo buf %d sleep value %d\n",
+ __func__, pxo_buf, rs->sleep_value);
+ }
+}
+
+static void msm_lpm_flush_pxo(int notify_rpm)
+{
+ if (notify_rpm) {
+ struct msm_lpm_resource *rs = &msm_lpm_pxo;
+ msm_lpm_send_sleep_data(rs->rs_data.handle,
+ rs->rs_data.key,
+ (uint8_t *)&rs->sleep_value);
+ }
+}
+
+static void msm_lpm_notify_pxo(struct msm_rpm_notifier_data
+ *rpm_notifier_cb)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_pxo;
+ msm_lpm_notify_common(rpm_notifier_cb, rs);
+}
+
+/* MPM
+static bool msm_lpm_use_mpm(struct msm_rpmrs_limits *limits)
+{
+ return ((limits->pxo == MSM_LPM_PXO_OFF) ||
+ (limits->vdd_dig_lower_bound <= VDD_DIG_RET_HIGH));
+}*/
+
+/* LPM levels interface */
+bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits)
+{
+ int i;
+ struct msm_lpm_resource *rs;
+ bool beyond_limit = false;
+
+ for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
+ rs = msm_lpm_resources[i];
+ if (rs->beyond_limits && rs->beyond_limits(limits)) {
+ beyond_limit = true;
+ if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_LVLS)
+ pr_info("%s: %s beyond limit", __func__,
+ rs->name);
+ break;
+ }
+ }
+
+ return beyond_limit;
+}
+
+int msm_lpmrs_enter_sleep(struct msm_rpmrs_limits *limits,
+ bool from_idle, bool notify_rpm)
+{
+ int ret = 0;
+ int i;
+ struct msm_lpm_resource *rs = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
+ rs = msm_lpm_resources[i];
+ if (rs->aggregate)
+ rs->aggregate(limits);
+ }
+
+ msm_lpm_get_rpm_notif = false;
+ for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
+ rs = msm_lpm_resources[i];
+ if (rs->flush)
+ rs->flush(notify_rpm);
+ }
+ msm_lpm_get_rpm_notif = true;
+
+ /* MPM Enter sleep
+ if (msm_lpm_use_mpm(limits))
+ msm_mpm_enter_sleep(from_idle);*/
+
+ return ret;
+}
+
+void msm_lpmrs_exit_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
+ bool from_idle, bool notify_rpm)
+{
+ /* MPM exit sleep
+ if (msm_lpm_use_mpm(limits))
+ msm_mpm_exit_sleep(from_idle);*/
+}
+
+static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+ unsigned long action, void *hcpu)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_l2;
+ switch (action) {
+ case CPU_ONLINE_FROZEN:
+ case CPU_ONLINE:
+ if (num_online_cpus() > 1)
+ rs->rs_data.value = MSM_LPM_L2_CACHE_ACTIVE;
+ break;
+ case CPU_DEAD_FROZEN:
+ case CPU_DEAD:
+ if (num_online_cpus() == 1)
+ rs->rs_data.value = MSM_LPM_L2_CACHE_GDHS;
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+/* RPM CTL */
+static int __devinit msm_lpm_init_rpm_ctl(void)
+{
+ struct msm_lpm_resource *rs = &msm_lpm_rpm_ctl;
+
+ rs->rs_data.handle = msm_rpm_create_request(
+ MSM_RPM_CTX_ACTIVE_SET,
+ rs->rs_data.type,
+ rs->rs_data.id, 1);
+ if (!rs->rs_data.handle)
+ return -EIO;
+
+ rs->valid = true;
+ return 0;
+}
+
+static int __devinit msm_lpm_resource_sysfs_add(void)
+{
+ struct kobject *module_kobj = NULL;
+ struct kobject *low_power_kobj = NULL;
+ struct kobject *mode_kobj = NULL;
+ int rc = 0;
+
+ module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+ if (!module_kobj) {
+ pr_err("%s: cannot find kobject for module %s\n",
+ __func__, KBUILD_MODNAME);
+ rc = -ENOENT;
+ goto resource_sysfs_add_exit;
+ }
+
+ low_power_kobj = kobject_create_and_add(
+ "enable_low_power", module_kobj);
+ if (!low_power_kobj) {
+ pr_err("%s: cannot create kobject\n", __func__);
+ rc = -ENOMEM;
+ goto resource_sysfs_add_exit;
+ }
+
+ mode_kobj = kobject_create_and_add(
+ "mode", module_kobj);
+ if (!mode_kobj) {
+ pr_err("%s: cannot create kobject\n", __func__);
+ rc = -ENOMEM;
+ goto resource_sysfs_add_exit;
+ }
+
+ rc = sysfs_create_group(low_power_kobj, &msm_lpm_attribute_group);
+ if (rc) {
+ pr_err("%s: cannot create kobject attribute group\n", __func__);
+ goto resource_sysfs_add_exit;
+ }
+
+ rc = sysfs_create_group(mode_kobj, &msm_lpm_rpm_ctl_attr_group);
+ if (rc) {
+ pr_err("%s: cannot create kobject attribute group\n", __func__);
+ goto resource_sysfs_add_exit;
+ }
+
+resource_sysfs_add_exit:
+ if (rc) {
+ if (low_power_kobj)
+ sysfs_remove_group(low_power_kobj,
+ &msm_lpm_attribute_group);
+ kobject_del(low_power_kobj);
+ kobject_del(mode_kobj);
+ }
+
+ return rc;
+}
+
+late_initcall(msm_lpm_resource_sysfs_add);
+
+static int __devinit msm_lpmrs_probe(struct platform_device *pdev)
+{
+ struct device_node *node = NULL;
+ char *key = NULL;
+ int ret = 0;
+
+ for_each_child_of_node(pdev->dev.of_node, node) {
+ struct msm_lpm_resource *rs = NULL;
+ const char *val;
+ int i;
+
+ key = "qcom,name";
+ ret = of_property_read_string(node, key, &val);
+ if (ret) {
+ pr_err("Cannot read string\n");
+ goto fail;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
+ char *lpmrs_name = msm_lpm_resources[i]->name;
+ if (!msm_lpm_resources[i]->valid &&
+ !strncmp(val, lpmrs_name, strnlen(lpmrs_name,
+ MAX_RS_NAME))) {
+ rs = msm_lpm_resources[i];
+ break;
+ }
+ }
+
+ if (!rs) {
+ pr_err("LPM resource not found\n");
+ continue;
+ }
+
+ key = "qcom,type";
+ ret = of_property_read_u32(node, key, &rs->rs_data.type);
+ if (ret) {
+ pr_err("Failed to read type\n");
+ goto fail;
+ }
+
+ key = "qcom,id";
+ ret = of_property_read_u32(node, key, &rs->rs_data.id);
+ if (ret) {
+ pr_err("Failed to read id\n");
+ goto fail;
+ }
+
+ key = "qcom,key";
+ ret = of_property_read_u32(node, key, &rs->rs_data.key);
+ if (ret) {
+ pr_err("Failed to read key\n");
+ goto fail;
+ }
+
+ rs->rs_data.handle = msm_lpm_create_rpm_request(
+ rs->rs_data.type, rs->rs_data.id);
+
+ if (!rs->rs_data.handle) {
+ pr_err("%s: Failed to allocate handle for %s\n",
+ __func__, rs->name);
+ ret = -1;
+ goto fail;
+ }
+
+ rs->valid = true;
+ }
+ msm_rpm_register_notifier(&msm_lpm_rpm_nblk);
+ msm_lpm_init_rpm_ctl();
+ register_hotcpu_notifier(&msm_lpm_cpu_nblk);
+ /* For UP mode, set the default to HSFS OPEN*/
+ if (num_possible_cpus() == 1) {
+ msm_lpm_l2.rs_data.default_value = MSM_LPM_L2_CACHE_HSFS_OPEN;
+ msm_lpm_l2.rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
+ }
+ return 0;
+fail:
+ return ret;
+}
+
+static struct of_device_id msm_lpmrs_match_table[] = {
+ {.compatible = "qcom,lpm-resources"},
+ {},
+};
+
+static struct platform_driver msm_lpmrs_driver = {
+ .probe = msm_lpmrs_probe,
+ .driver = {
+ .name = "lpm-resources",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_lpmrs_match_table,
+ },
+};
+
+int __init msm_lpmrs_module_init(void)
+{
+ return platform_driver_register(&msm_lpmrs_driver);
+}
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
new file mode 100644
index 0000000..9973fbf
--- /dev/null
+++ b/arch/arm/mach-msm/lpm_resources.h
@@ -0,0 +1,128 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
+#define __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
+
+#include "pm.h"
+
+enum {
+ MSM_LPM_PXO_OFF = 0,
+ MSM_LPM_PXO_ON = 1,
+};
+
+enum {
+ MSM_LPM_L2_CACHE_HSFS_OPEN = 0,
+ MSM_LPM_L2_CACHE_GDHS = 1,
+ MSM_LPM_L2_CACHE_RETENTION = 2,
+ MSM_LPM_L2_CACHE_ACTIVE = 3,
+};
+
+struct msm_rpmrs_limits {
+ uint32_t pxo;
+ uint32_t l2_cache;
+ uint32_t vdd_mem_upper_bound;
+ uint32_t vdd_mem_lower_bound;
+ uint32_t vdd_dig_upper_bound;
+ uint32_t vdd_dig_lower_bound;
+
+ uint32_t latency_us[NR_CPUS];
+ uint32_t power[NR_CPUS];
+};
+
+struct msm_rpmrs_level {
+ enum msm_pm_sleep_mode sleep_mode;
+ struct msm_rpmrs_limits rs_limits;
+ bool available;
+ uint32_t latency_us;
+ uint32_t steady_state_power;
+ uint32_t energy_overhead;
+ uint32_t time_overhead_us;
+};
+
+#ifdef CONFIG_MSM_RPM_SMD
+
+/**
+ * msm_lpm_level_beyond_limit() - Check if the resources in a low power level
+ * is beyond the limits of the driver votes received for those resources.This
+ * function is used by lpm_levels to eliminate any low power level that cannot
+ * be entered.
+ *
+ * @limits: pointer to the resource limits of a low power level.
+ *
+ * returns true if the resource limits are beyond driver resource votes.
+ * false otherwise.
+ */
+bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_lpmrs_enter_sleep() - Enter sleep flushes the sleep votes of low power
+ * resources to the RPM driver, also configure the MPM if needed depending
+ * on the low power mode being entered. L2 low power mode is also set in
+ * this function.
+
+ * @limits: pointer to the resource limits of the low power mode being entered.
+ * @from_idle: bool to determine if this call being made as a part of
+ * idle power collapse.
+ * @notify_rpm: bool that informs if this is an RPM notified power collapse.
+ *
+ * returns 0 on success.
+ */
+int msm_lpmrs_enter_sleep(struct msm_rpmrs_limits *limits,
+ bool from_idle, bool notify_rpm);
+
+/**
+ * msm_lpmrs_exit_sleep() - Exit sleep, reset the MPM and L2 mode.
+ * @ sclk_count - Sleep Clock count.
+ * @ limits: pointer to resource limits of the most recent low power mode.
+ * @from_idle: bool to determine if this call being made as a part of
+ * idle power collapse.
+ * @notify_rpm: bool that informs if this is an RPM notified power collapse.
+ */
+void msm_lpmrs_exit_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
+ bool from_idle, bool notify_rpm);
+/**
+ * msm_lpmrs_module_init() - Init function that parses the device tree to
+ * get the low power resource attributes and registers with RPM driver for
+ * callback notification.
+ *
+ * returns 0 on success.
+ */
+int __init msm_lpmrs_module_init(void);
+
+#else
+static inline bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits)
+{
+ return true;
+}
+
+static inline int msm_lpmrs_enter_sleep(struct msm_rpmrs_limits *limits,
+ bool from_idle, bool notify_rpm)
+{
+ return 0;
+}
+
+static inline void msm_lpmrs_exit_sleep(uint32_t sclk_count,
+ struct msm_rpmrs_limits *limits, bool from_idle,
+ bool notify_rpm)
+{
+ return;
+}
+
+static inline int __init msm_lpmrs_module_init(void)
+{
+ return 0;
+}
+#endif /* CONFIG_MSM_RPM_SMD */
+
+#endif
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 74bf25d..921f062 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -36,6 +36,7 @@
#include <mach/restart.h>
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>
+#include <mach/rpm.h>
#include <linux/msm_charm.h>
#include "msm_watchdog.h"
#include "mdm_private.h"
@@ -65,6 +66,57 @@
#define SFR_MAX_RETRIES 10
#define SFR_RETRY_INTERVAL 1000
+static irqreturn_t mdm_vddmin_change(int irq, void *dev_id)
+{
+ int value = gpio_get_value(
+ mdm_drv->pdata->vddmin_resource->mdm2ap_vddmin_gpio);
+
+ if (value == 0)
+ pr_info("External Modem entered Vddmin\n");
+ else
+ pr_info("External Modem exited Vddmin\n");
+
+ return IRQ_HANDLED;
+}
+
+static void mdm_setup_vddmin_gpios(void)
+{
+ struct msm_rpm_iv_pair req;
+ struct mdm_vddmin_resource *vddmin_res;
+ int irq, ret;
+
+ /* This resource may not be supported by some platforms. */
+ vddmin_res = mdm_drv->pdata->vddmin_resource;
+ if (!vddmin_res)
+ return;
+
+ req.id = vddmin_res->rpm_id;
+ req.value = ((uint32_t)vddmin_res->ap2mdm_vddmin_gpio & 0x0000FFFF)
+ << 16;
+ req.value |= ((uint32_t)vddmin_res->modes & 0x000000FF) << 8;
+ req.value |= (uint32_t)vddmin_res->drive_strength & 0x000000FF;
+
+ msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
+
+ /* Monitor low power gpio from mdm */
+ irq = MSM_GPIO_TO_INT(vddmin_res->mdm2ap_vddmin_gpio);
+ if (irq < 0) {
+ pr_err("%s: could not get LPM POWER IRQ resource.\n",
+ __func__);
+ goto error_end;
+ }
+
+ ret = request_threaded_irq(irq, NULL, mdm_vddmin_change,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "mdm lpm", NULL);
+
+ if (ret < 0)
+ pr_err("%s: MDM LPM IRQ#%d request failed with error=%d",
+ __func__, irq, ret);
+error_end:
+ return;
+}
+
static void mdm_restart_reason_fn(struct work_struct *work)
{
int ret, ntries = 0;
@@ -566,6 +618,8 @@
*/
if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 1);
+ /* Register VDDmin gpios with RPM */
+ mdm_setup_vddmin_gpios();
/* Perform early powerup of the external modem in order to
* allow tabla devices to be found.
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 3671916..a4b9b51 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -131,7 +131,7 @@
fabric->pdata->id, fabric->pdata->len);
fabric->hw_data = fabric->fabdev.hw_algo.allocate_hw_data(pdev,
fabric->pdata);
- if (ZERO_OR_NULL_PTR(fabric->hw_data)) {
+ if (ZERO_OR_NULL_PTR(fabric->hw_data) && fabric->pdata->ahb == 0) {
MSM_BUS_ERR("Couldn't allocate hw_data for fab: %d\n",
fabric->fabdev.id);
goto error;
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 915047a..b31d94b 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -86,7 +86,7 @@
c->irq_mask(d);
local_irq_disable();
/* Clear the IRQ from the ENABLE_SET */
- gic_clear_spi_pending(irq);
+ gic_clear_irq_pending(irq);
local_irq_enable();
}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index 9253056..fbd94c5 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -42,13 +42,16 @@
struct asm_aac_cfg aac_cfg;
struct msm_audio_aac_config *aac_config;
uint32_t sbr_ps = 0x00;
+ aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
+ aac_cfg.ch_cfg = aac_config->channel_configuration;
+ aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
audio->ac->session);
if (audio->feedback == NON_TUNNEL_MODE) {
/* Configure PCM output block */
- rc = q6asm_enc_cfg_blk_pcm(audio->ac,
- 0, /*native sampling rate*/
- 0 /*native channel count*/);
+ rc = q6asm_enc_cfg_blk_pcm_native(audio->ac,
+ aac_cfg.sample_rate,
+ aac_cfg.ch_cfg);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
@@ -58,7 +61,6 @@
rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
if (rc < 0)
pr_err("sbr-ps enable failed\n");
- aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
if (aac_config->sbr_ps_on_flag)
aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
else if (aac_config->sbr_on_flag)
@@ -87,8 +89,6 @@
aac_config->aac_scalefactor_data_resilience_flag;
aac_cfg.spectral_data_resilience =
aac_config->aac_spectral_data_resilience_flag;
- aac_cfg.ch_cfg = aac_config->channel_configuration;
- aac_cfg.sample_rate = audio->pcm_cfg.sample_rate;
pr_debug("%s:format=%x aot=%d ch=%d sr=%d\n",
__func__, aac_cfg.format,
@@ -146,16 +146,14 @@
AUDIO_AAC_DUAL_MONO_PL_PR) ||
(aac_config->dual_mono_mode >
AUDIO_AAC_DUAL_MONO_PL_SR)) {
- pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid"
- "dual_mono mode =%d\n", __func__,
- aac_config->dual_mono_mode);
+ pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid dual_mono mode =%d\n",
+ __func__, aac_config->dual_mono_mode);
} else {
/* convert the data from user into sce_left
* and sce_right based on the definitions
*/
- pr_debug("%s: AUDIO_SET_AAC_CONFIG: modify"
- "dual_mono mode =%d\n", __func__,
- aac_config->dual_mono_mode);
+ pr_debug("%s: AUDIO_SET_AAC_CONFIG: modify dual_mono mode =%d\n",
+ __func__, aac_config->dual_mono_mode);
switch (aac_config->dual_mono_mode) {
case AUDIO_AAC_DUAL_MONO_PL_PR:
sce_left = 1;
@@ -178,8 +176,8 @@
rc = q6asm_cfg_dual_mono_aac(audio->ac,
sce_left, sce_right);
if (rc < 0)
- pr_err("%s: asm cmd dualmono failed"
- " rc=%d\n", __func__, rc);
+ pr_err("%s: asm cmd dualmono failed rc=%d\n",
+ __func__, rc);
} break;
}
break;
@@ -212,8 +210,8 @@
audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
GFP_KERNEL);
if (audio->codec_cfg == NULL) {
- pr_err("%s: Could not allocate memory for aac"
- "config\n", __func__);
+ pr_err("%s: Could not allocate memory for aac config\n",
+ __func__);
kfree(audio);
return -ENOMEM;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 6a99be2..fdc596d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -33,7 +33,7 @@
return 0;
}
-ssize_t audio_aio_debug_read(struct file *file, char __user * buf,
+ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
const int debug_bufmax = 4096;
@@ -67,7 +67,7 @@
}
#endif
-static int insert_eos_buf(struct q6audio_aio *audio,
+int insert_eos_buf(struct q6audio_aio *audio,
struct audio_aio_buffer_node *buf_node)
{
struct dec_meta_out *eos_buf = buf_node->kvaddr;
@@ -93,7 +93,7 @@
sizeof(meta_data->meta_out_dsp[0]);
}
-static void extract_meta_out_info(struct q6audio_aio *audio,
+void extract_meta_out_info(struct q6audio_aio *audio,
struct audio_aio_buffer_node *buf_node, int dir)
{
struct dec_meta_out *meta_data = buf_node->kvaddr;
@@ -114,8 +114,7 @@
&buf_node->meta_info.meta_out,
sizeof(struct dec_meta_out));
meta_data->meta_out_dsp[0].nflags = 0x00000000;
- pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x,"
- "num_frames = %d\n",
+ pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x, num_frames = %d\n",
__func__, audio,
((struct dec_meta_out *)buf_node->kvaddr)->\
meta_out_dsp[0].msw_ts,
@@ -293,8 +292,8 @@
kfree(used_buf);
if (list_empty(&audio->out_queue) &&
(audio->drv_status & ADRV_STATUS_FSYNC)) {
- pr_debug("%s[%p]: list is empty, reached EOS in"
- "Tunnel\n", __func__, audio);
+ pr_debug("%s[%p]: list is empty, reached EOS in Tunnel\n",
+ __func__, audio);
wake_up(&audio->write_wait);
}
} else {
@@ -304,60 +303,6 @@
}
}
-/* Read buffer from DSP / Handle Ack from DSP */
-void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
- uint32_t *payload)
-{
- unsigned long flags;
- union msm_audio_event_payload event_payload;
- struct audio_aio_buffer_node *filled_buf;
-
- /* No active flush in progress */
- if (audio->rflush)
- return;
-
- /* Statistics of read */
- atomic_add(payload[2], &audio->in_bytes);
- atomic_add(payload[7], &audio->in_samples);
-
- spin_lock_irqsave(&audio->dsp_lock, flags);
- BUG_ON(list_empty(&audio->in_queue));
- filled_buf = list_first_entry(&audio->in_queue,
- struct audio_aio_buffer_node, list);
- if (token == (filled_buf->token)) {
- list_del(&filled_buf->list);
- spin_unlock_irqrestore(&audio->dsp_lock, flags);
- event_payload.aio_buf = filled_buf->buf;
- /* Read done Buffer due to flush/normal condition
- after EOS event, so append EOS buffer */
- if (audio->eos_rsp == 0x1) {
- event_payload.aio_buf.data_len =
- insert_eos_buf(audio, filled_buf);
- /* Reset flag back to indicate eos intimated */
- audio->eos_rsp = 0;
- } else {
- filled_buf->meta_info.meta_out.num_of_frames =
- payload[7];
- event_payload.aio_buf.data_len = payload[2] + \
- payload[3] + \
- sizeof(struct dec_meta_out);
- pr_debug("%s[%p]:nr of frames 0x%8x len=%d\n",
- __func__, audio,
- filled_buf->meta_info.meta_out.num_of_frames,
- event_payload.aio_buf.data_len);
- extract_meta_out_info(audio, filled_buf, 0);
- audio->eos_rsp = 0;
- }
- audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
- event_payload);
- kfree(filled_buf);
- } else {
- pr_err("%s[%p]:expected=%lx ret=%x\n",
- __func__, audio, filled_buf->token, token);
- spin_unlock_irqrestore(&audio->dsp_lock, flags);
- }
-}
-
/* ------------------- device --------------------- */
void audio_aio_async_out_flush(struct q6audio_aio *audio)
{
@@ -404,8 +349,8 @@
/* Forcefull send o/p eos buffer after flush, if no eos response
* received by dsp even after sending eos command */
if ((audio->eos_rsp != 1) && audio->eos_flag) {
- pr_debug("%s[%p]: send eos on o/p buffer during"
- "flush\n", __func__, audio);
+ pr_debug("%s[%p]: send eos on o/p buffer during flush\n",
+ __func__, audio);
payload.aio_buf = buf_node->buf;
payload.aio_buf.data_len =
insert_eos_buf(audio, buf_node);
@@ -716,9 +661,7 @@
list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
OVERLAPS(region_elt, &t)) {
- pr_err("%s[%p]:region (vaddr %p len %ld)"
- " clashes with registered region"
- " (vaddr %p paddr %p len %ld)\n",
+ pr_err("%s[%p]:region (vaddr %p len %ld) clashes with registered region (vaddr %p paddr %p len %ld)\n",
__func__, audio, vaddr, len,
region_elt->vaddr,
(void *)region_elt->paddr, region_elt->len);
@@ -870,8 +813,7 @@
struct audio_client *ac;
struct audio_aio_write_param param;
- pr_debug("%s[%p]: Send write buff %p phy %lx len %d"
- "meta_enable = %d\n",
+ pr_debug("%s[%p]: Send write buff %p phy %lx len %d meta_enable = %d\n",
__func__, audio, buf_node, buf_node->paddr,
buf_node->buf.data_len,
audio->buf_cfg.meta_info_enable);
@@ -973,8 +915,8 @@
return -EFAULT;
}
- pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len"
- "%d\n", __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
+ pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len %d\n",
+ __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
buf_node->buf.buf_len, buf_node->buf.data_len);
buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
buf_node->buf.buf_len, 1,
@@ -1335,8 +1277,8 @@
break;
}
if (audio->feedback != NON_TUNNEL_MODE) {
- pr_err("%s[%p]:Not sufficient permission to"
- "change the playback mode\n", __func__, audio);
+ pr_err("%s[%p]:Not sufficient permission to change the playback mode\n",
+ __func__, audio);
rc = -EACCES;
mutex_unlock(&audio->lock);
break;
@@ -1379,8 +1321,8 @@
break;
}
case AUDIO_GET_BUF_CFG: {
- pr_debug("%s[%p]:session id %d: Get-buf-cfg: meta[%d]"
- "framesperbuf[%d]\n", __func__, audio,
+ pr_debug("%s[%p]:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
+ __func__, audio,
audio->ac->session, audio->buf_cfg.meta_info_enable,
audio->buf_cfg.frames_per_buf);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index 77288da..4a65304 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -195,6 +195,12 @@
void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
uint32_t *payload);
+int insert_eos_buf(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node);
+
+void extract_meta_out_info(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node, int dir);
+
int audio_aio_open(struct q6audio_aio *audio, struct file *file);
int audio_aio_enable(struct q6audio_aio *audio);
void audio_aio_post_event(struct q6audio_aio *audio, int type,
@@ -206,6 +212,6 @@
void audio_aio_async_in_flush(struct q6audio_aio *audio);
#ifdef CONFIG_DEBUG_FS
ssize_t audio_aio_debug_open(struct inode *inode, struct file *file);
-ssize_t audio_aio_debug_read(struct file *file, char __user * buf,
+ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
index 112de62..078eea8 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
@@ -97,9 +97,8 @@
"payload[2] = %d, payload[3] = %d\n", __func__,
audio, payload[0], payload[1], payload[2],
payload[3]);
- pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
- "sr(prev) = %d, chl(prev) = %d,",
- __func__, audio, audio->pcm_cfg.sample_rate,
+ pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, sr(prev) = %d, chl(prev) = %d,",
+ __func__, audio, audio->pcm_cfg.sample_rate,
audio->pcm_cfg.channel_count);
audio->pcm_cfg.sample_rate = payload[0];
audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
@@ -111,3 +110,57 @@
break;
}
}
+
+/* Read buffer from DSP / Handle Ack from DSP */
+void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
+ uint32_t *payload)
+{
+ unsigned long flags;
+ union msm_audio_event_payload event_payload;
+ struct audio_aio_buffer_node *filled_buf;
+
+ /* No active flush in progress */
+ if (audio->rflush)
+ return;
+
+ /* Statistics of read */
+ atomic_add(payload[2], &audio->in_bytes);
+ atomic_add(payload[7], &audio->in_samples);
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ BUG_ON(list_empty(&audio->in_queue));
+ filled_buf = list_first_entry(&audio->in_queue,
+ struct audio_aio_buffer_node, list);
+ if (token == (filled_buf->token)) {
+ list_del(&filled_buf->list);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ event_payload.aio_buf = filled_buf->buf;
+ /* Read done Buffer due to flush/normal condition
+ after EOS event, so append EOS buffer */
+ if (audio->eos_rsp == 0x1) {
+ event_payload.aio_buf.data_len =
+ insert_eos_buf(audio, filled_buf);
+ /* Reset flag back to indicate eos intimated */
+ audio->eos_rsp = 0;
+ } else {
+ filled_buf->meta_info.meta_out.num_of_frames =
+ payload[7];
+ event_payload.aio_buf.data_len = payload[2] + \
+ payload[3] + \
+ sizeof(struct dec_meta_out);
+ pr_debug("%s[%p]:nr of frames 0x%8x len=%d\n",
+ __func__, audio,
+ filled_buf->meta_info.meta_out.num_of_frames,
+ event_payload.aio_buf.data_len);
+ extract_meta_out_info(audio, filled_buf, 0);
+ audio->eos_rsp = 0;
+ }
+ audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
+ event_payload);
+ kfree(filled_buf);
+ } else {
+ pr_err("%s[%p]:expected=%lx ret=%x\n",
+ __func__, audio, filled_buf->token, token);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ }
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
index aab7b19..ad4fc6f 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
@@ -91,14 +91,13 @@
break;
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
-
pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0]-sr = %d, payload[1]-chl = %d, payload[2] = %d, payload[3] = %d\n",
__func__, audio, payload[0],
payload[1], payload[2], payload[3]);
pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, sr(prev) = %d, chl(prev) = %d,",
- __func__, audio, audio->pcm_cfg.sample_rate,
- audio->pcm_cfg.channel_count);
+ __func__, audio, audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
audio->pcm_cfg.sample_rate = payload[0];
audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
@@ -110,3 +109,61 @@
break;
}
}
+
+/* Read buffer from DSP / Handle Ack from DSP */
+void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
+ uint32_t *payload)
+{
+ unsigned long flags;
+ union msm_audio_event_payload event_payload;
+ struct audio_aio_buffer_node *filled_buf;
+ pr_debug("%s\n", __func__);
+
+ /* No active flush in progress */
+ if (audio->rflush)
+ return;
+
+ /* Statistics of read */
+ atomic_add(payload[4], &audio->in_bytes);
+ atomic_add(payload[9], &audio->in_samples);
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ BUG_ON(list_empty(&audio->in_queue));
+ filled_buf = list_first_entry(&audio->in_queue,
+ struct audio_aio_buffer_node, list);
+
+ pr_debug("%s token: 0x[%d], filled_buf->token: 0x[%lu]",
+ __func__, token, filled_buf->token);
+ if (token == (filled_buf->token)) {
+ list_del(&filled_buf->list);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ event_payload.aio_buf = filled_buf->buf;
+ /* Read done Buffer due to flush/normal condition
+ after EOS event, so append EOS buffer */
+ if (audio->eos_rsp == 0x1) {
+ event_payload.aio_buf.data_len =
+ insert_eos_buf(audio, filled_buf);
+ /* Reset flag back to indicate eos intimated */
+ audio->eos_rsp = 0;
+ } else {
+ filled_buf->meta_info.meta_out.num_of_frames\
+ = payload[9];
+ event_payload.aio_buf.data_len = payload[4]\
+ + payload[5] + sizeof(struct dec_meta_out);
+ pr_debug("%s[%p]:nr of frames 0x%8x len=%d\n",
+ __func__, audio,
+ filled_buf->meta_info.meta_out.num_of_frames,
+ event_payload.aio_buf.data_len);
+ extract_meta_out_info(audio, filled_buf, 0);
+ audio->eos_rsp = 0;
+ }
+ pr_debug("%s, posting read done to the app here\n", __func__);
+ audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
+ event_payload);
+ kfree(filled_buf);
+ } else {
+ pr_err("%s[%p]:expected=%lx ret=%x\n",
+ __func__, audio, filled_buf->token, token);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ }
+}
diff --git a/arch/arm/mach-msm/qdss-stm.c b/arch/arm/mach-msm/qdss-stm.c
new file mode 100644
index 0000000..9ce6318
--- /dev/null
+++ b/arch/arm/mach-msm/qdss-stm.c
@@ -0,0 +1,595 @@
+/* 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/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+#include <mach/stm.h>
+
+#include "qdss-priv.h"
+
+#define stm_writel(stm, val, off) \
+ __raw_writel((val), stm.base + off)
+#define stm_readl(stm, val, off) \
+ __raw_readl(stm.base + off)
+
+#define NR_STM_CHANNEL (32)
+#define BYTES_PER_CHANNEL (256)
+
+enum {
+ STM_PKT_TYPE_DATA = 0x98,
+ STM_PKT_TYPE_FLAG = 0xE8,
+ STM_PKT_TYPE_TRIG = 0xF8,
+};
+
+enum {
+ STM_OPTION_MARKED = 0x10,
+};
+
+#define STM_TRACE_BUF_SIZE (1024)
+
+#define OST_START_TOKEN (0x30)
+#define OST_VERSION (0x1)
+
+#define stm_channel_addr(ch) \
+ (stm.chs.base + (ch * BYTES_PER_CHANNEL))
+#define stm_channel_off(type, opts) (type & ~opts)
+
+#define STM_LOCK() \
+do { \
+ mb(); \
+ stm_writel(stm, 0x0, CS_LAR); \
+} while (0)
+#define STM_UNLOCK() \
+do { \
+ stm_writel(stm, CS_UNLOCK_MAGIC, CS_LAR); \
+ mb(); \
+} while (0)
+
+#define STMSPER (0xE00)
+#define STMSPTER (0xE20)
+#define STMTCSR (0xE80)
+#define STMSYNCR (0xE90)
+
+#ifdef CONFIG_MSM_QDSS_STM_DEFAULT_ENABLE
+static int stm_boot_enable = 1;
+#else
+static int stm_boot_enable;
+#endif
+
+module_param_named(
+ stm_boot_enable, stm_boot_enable, int, S_IRUGO
+);
+
+static int stm_boot_nr_channel;
+
+module_param_named(
+ stm_boot_nr_channel, stm_boot_nr_channel, int, S_IRUGO
+);
+
+struct channel_space {
+ void __iomem *base;
+ unsigned long *bitmap;
+};
+
+struct stm_ctx {
+ void __iomem *base;
+ bool enabled;
+ struct qdss_source *src;
+ struct device *dev;
+ struct kobject *kobj;
+ uint32_t entity;
+ struct channel_space chs;
+};
+
+static struct stm_ctx stm = {
+ .entity = OST_ENTITY_ALL,
+};
+
+
+static void __stm_enable(void)
+{
+ STM_UNLOCK();
+
+ stm_writel(stm, 0x80, STMSYNCR);
+ stm_writel(stm, 0xFFFFFFFF, STMSPTER);
+ stm_writel(stm, 0xFFFFFFFF, STMSPER);
+ stm_writel(stm, 0x30003, STMTCSR);
+
+ STM_LOCK();
+}
+
+static int stm_enable(void)
+{
+ int ret;
+
+ if (stm.enabled) {
+ dev_err(stm.dev, "STM tracing already enabled\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = qdss_enable(stm.src);
+ if (ret)
+ goto err;
+
+ __stm_enable();
+
+ stm.enabled = true;
+
+ dev_info(stm.dev, "STM tracing enabled\n");
+ return 0;
+
+err:
+ return ret;
+}
+
+static void __stm_disable(void)
+{
+ STM_UNLOCK();
+
+ stm_writel(stm, 0x30000, STMTCSR);
+ stm_writel(stm, 0x0, STMSPER);
+ stm_writel(stm, 0x0, STMSPTER);
+
+ STM_LOCK();
+}
+
+static int stm_disable(void)
+{
+ int ret;
+
+ if (!stm.enabled) {
+ dev_err(stm.dev, "STM tracing already disabled\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ __stm_disable();
+
+ qdss_disable(stm.src);
+
+ stm.enabled = false;
+
+ dev_info(stm.dev, "STM tracing disabled\n");
+ return 0;
+
+err:
+ return ret;
+}
+
+static uint32_t stm_channel_alloc(uint32_t off)
+{
+ uint32_t ch;
+
+ do {
+ ch = find_next_zero_bit(stm.chs.bitmap, NR_STM_CHANNEL, off);
+ } while ((ch < NR_STM_CHANNEL) && test_and_set_bit(ch, stm.chs.bitmap));
+
+ return ch;
+}
+
+static void stm_channel_free(uint32_t ch)
+{
+ clear_bit(ch, stm.chs.bitmap);
+}
+
+static int stm_send(void *addr, const void *data, uint32_t size)
+{
+ uint64_t prepad = 0;
+ uint64_t postpad = 0;
+ char *pad;
+ uint8_t off, endoff;
+ uint32_t len = size;
+
+ /* only 64bit writes are supported, we rely on the compiler to
+ * generate STRD instruction for the casted 64bit assignments
+ */
+
+ off = (unsigned long)data & 0x7;
+
+ if (off) {
+ endoff = 8 - off;
+ pad = (char *)&prepad;
+ pad += off;
+
+ while (endoff && size) {
+ *pad++ = *(char *)data++;
+ endoff--;
+ size--;
+ }
+ *(volatile uint64_t __force *)addr = prepad;
+ }
+
+ /* now we are 64bit aligned */
+ while (size >= 8) {
+ *(volatile uint64_t __force *)addr = *(uint64_t *)data;
+ data += 8;
+ size -= 8;
+ }
+
+ if (size) {
+ pad = (char *)&postpad;
+
+ while (size) {
+ *pad++ = *(char *)data++;
+ size--;
+ }
+ *(volatile uint64_t __force *)addr = postpad;
+ }
+
+ return roundup(len + off, 8);
+}
+
+static int stm_trace_ost_header(unsigned long ch_addr, uint32_t options,
+ uint8_t entity_id, uint8_t proto_id,
+ const void *payload_data, uint32_t payload_size)
+{
+ void *addr;
+ uint8_t prepad_size;
+ uint64_t header;
+ char *hdr;
+
+ hdr = (char *)&header;
+
+ hdr[0] = OST_START_TOKEN;
+ hdr[1] = OST_VERSION;
+ hdr[2] = entity_id;
+ hdr[3] = proto_id;
+ prepad_size = (unsigned long)payload_data & 0x7;
+ *(uint32_t *)(hdr + 4) = (prepad_size << 24) | payload_size;
+
+ /* for 64bit writes, header is expected to be of the D32M, D32M */
+ options |= STM_OPTION_MARKED;
+ options &= ~STM_OPTION_TIMESTAMPED;
+ addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
+
+ return stm_send(addr, &header, sizeof(header));
+}
+
+static int stm_trace_data(unsigned long ch_addr, uint32_t options,
+ const void *data, uint32_t size)
+{
+ void *addr;
+
+ options &= ~STM_OPTION_TIMESTAMPED;
+ addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
+
+ return stm_send(addr, data, size);
+}
+
+static int stm_trace_ost_tail(unsigned long ch_addr, uint32_t options)
+{
+ void *addr;
+ uint64_t tail = 0x0;
+
+ addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_FLAG, options));
+
+ return stm_send(addr, &tail, sizeof(tail));
+}
+
+static inline int __stm_trace(uint32_t options, uint8_t entity_id,
+ uint8_t proto_id, const void *data, uint32_t size)
+{
+ int len = 0;
+ uint32_t ch;
+ unsigned long ch_addr;
+
+ /* allocate channel and get the channel address */
+ ch = stm_channel_alloc(0);
+ ch_addr = (unsigned long)stm_channel_addr(ch);
+
+ /* send the ost header */
+ len += stm_trace_ost_header(ch_addr, options, entity_id, proto_id, data,
+ size);
+
+ /* send the payload data */
+ len += stm_trace_data(ch_addr, options, data, size);
+
+ /* send the ost tail */
+ len += stm_trace_ost_tail(ch_addr, options);
+
+ /* we are done, free the channel */
+ stm_channel_free(ch);
+
+ return len;
+}
+
+/**
+ * stm_trace - trace the binary or string data through STM
+ * @options: tracing options - guaranteed, timestamped, etc
+ * @entity_id: entity representing the trace data
+ * @proto_id: protocol id to distinguish between different binary formats
+ * @data: pointer to binary or string data buffer
+ * @size: size of data to send
+ *
+ * Packetizes the data as the payload to an OST packet and sends it over STM
+ *
+ * CONTEXT:
+ * Can be called from any context.
+ *
+ * RETURNS:
+ * number of bytes transfered over STM
+ */
+int stm_trace(uint32_t options, uint8_t entity_id, uint8_t proto_id,
+ const void *data, uint32_t size)
+{
+ /* we don't support sizes more than 24bits (0 to 23) */
+ if (!(stm.enabled && (stm.entity & entity_id) &&
+ (size < 0x1000000)))
+ return 0;
+
+ return __stm_trace(options, entity_id, proto_id, data, size);
+}
+EXPORT_SYMBOL(stm_trace);
+
+static ssize_t stm_write(struct file *file, const char __user *data,
+ size_t size, loff_t *ppos)
+{
+ char *buf;
+
+ if (!stm.enabled)
+ return -EINVAL;
+
+ if (!(stm.entity & OST_ENTITY_DEV_NODE))
+ return size;
+
+ if (size > STM_TRACE_BUF_SIZE)
+ size = STM_TRACE_BUF_SIZE;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, data, size)) {
+ kfree(buf);
+ dev_dbg(stm.dev, "%s: copy_from_user failed\n", __func__);
+ return -EFAULT;
+ }
+
+ __stm_trace(STM_OPTION_TIMESTAMPED, OST_ENTITY_DEV_NODE, 0, buf, size);
+
+ kfree(buf);
+
+ return size;
+}
+
+static const struct file_operations stm_fops = {
+ .owner = THIS_MODULE,
+ .write = stm_write,
+ .llseek = no_llseek,
+};
+
+static struct miscdevice stm_misc = {
+ .name = "msm_stm",
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &stm_fops,
+};
+
+#define STM_ATTR(__name) \
+static struct kobj_attribute __name##_attr = \
+ __ATTR(__name, S_IRUGO | S_IWUSR, __name##_show, __name##_store)
+
+static ssize_t enabled_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ int ret = 0;
+ unsigned long val;
+
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+
+ if (val)
+ ret = stm_enable();
+ else
+ ret = stm_disable();
+
+ if (ret)
+ return ret;
+ return n;
+}
+static ssize_t enabled_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ unsigned long val = stm.enabled;
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+STM_ATTR(enabled);
+
+static ssize_t entity_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned long val;
+
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+
+ stm.entity = val;
+ return n;
+}
+static ssize_t entity_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ unsigned long val = stm.entity;
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+STM_ATTR(entity);
+
+static int __devinit stm_sysfs_init(void)
+{
+ int ret;
+
+ stm.kobj = kobject_create_and_add("stm", qdss_get_modulekobj());
+ if (!stm.kobj) {
+ dev_err(stm.dev, "failed to create STM sysfs kobject\n");
+ ret = -ENOMEM;
+ goto err_create;
+ }
+
+ ret = sysfs_create_file(stm.kobj, &enabled_attr.attr);
+ if (ret) {
+ dev_err(stm.dev, "failed to create STM sysfs enabled attr\n");
+ goto err_file;
+ }
+
+ if (sysfs_create_file(stm.kobj, &entity_attr.attr))
+ dev_err(stm.dev, "failed to create STM sysfs entity attr\n");
+
+ return 0;
+err_file:
+ kobject_put(stm.kobj);
+err_create:
+ return ret;
+}
+
+static void __devexit stm_sysfs_exit(void)
+{
+ sysfs_remove_file(stm.kobj, &entity_attr.attr);
+ sysfs_remove_file(stm.kobj, &enabled_attr.attr);
+ kobject_put(stm.kobj);
+}
+
+static int __devinit stm_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *res;
+ size_t res_size, bitmap_size;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -EINVAL;
+ goto err_res0;
+ }
+
+ stm.base = ioremap_nocache(res->start, resource_size(res));
+ if (!stm.base) {
+ ret = -EINVAL;
+ goto err_ioremap0;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ ret = -EINVAL;
+ goto err_res1;
+ }
+
+ if (stm_boot_nr_channel) {
+ res_size = min((resource_size_t)(stm_boot_nr_channel *
+ BYTES_PER_CHANNEL), resource_size(res));
+ bitmap_size = stm_boot_nr_channel * sizeof(long);
+ } else {
+ res_size = min((resource_size_t)(NR_STM_CHANNEL *
+ BYTES_PER_CHANNEL), resource_size(res));
+ bitmap_size = NR_STM_CHANNEL * sizeof(long);
+ }
+
+ stm.chs.bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!stm.chs.bitmap) {
+ ret = -ENOMEM;
+ goto err_bitmap;
+ }
+
+ stm.chs.base = ioremap_nocache(res->start, res_size);
+ if (!stm.chs.base) {
+ ret = -EINVAL;
+ goto err_ioremap1;
+ }
+
+ stm.dev = &pdev->dev;
+
+ ret = misc_register(&stm_misc);
+ if (ret)
+ goto err_misc;
+
+ stm.src = qdss_get("msm_stm");
+ if (IS_ERR(stm.src)) {
+ ret = PTR_ERR(stm.src);
+ goto err_qdssget;
+ }
+
+ ret = stm_sysfs_init();
+ if (ret)
+ goto err_sysfs;
+
+ if (stm_boot_enable)
+ stm_enable();
+
+ dev_info(stm.dev, "STM initialized\n");
+ return 0;
+
+err_sysfs:
+ qdss_put(stm.src);
+err_qdssget:
+ misc_deregister(&stm_misc);
+err_misc:
+ iounmap(stm.chs.base);
+err_ioremap1:
+ kfree(stm.chs.bitmap);
+err_bitmap:
+err_res1:
+ iounmap(stm.base);
+err_ioremap0:
+err_res0:
+ dev_err(stm.dev, "STM init failed\n");
+ return ret;
+}
+
+static int __devexit stm_remove(struct platform_device *pdev)
+{
+ if (stm.enabled)
+ stm_disable();
+ stm_sysfs_exit();
+ qdss_put(stm.src);
+ misc_deregister(&stm_misc);
+ iounmap(stm.chs.base);
+ kfree(stm.chs.bitmap);
+ iounmap(stm.base);
+
+ return 0;
+}
+
+static struct platform_driver stm_driver = {
+ .probe = stm_probe,
+ .remove = __devexit_p(stm_remove),
+ .driver = {
+ .name = "msm_stm",
+ },
+};
+
+static int __init stm_init(void)
+{
+ return platform_driver_register(&stm_driver);
+}
+module_init(stm_init);
+
+static void __exit stm_exit(void)
+{
+ platform_driver_unregister(&stm_driver);
+}
+module_exit(stm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight System Trace Macrocell driver");
diff --git a/arch/arm/mach-msm/rpm.c b/arch/arm/mach-msm/rpm.c
index 44e50dd..5ab484e2 100644
--- a/arch/arm/mach-msm/rpm.c
+++ b/arch/arm/mach-msm/rpm.c
@@ -275,13 +275,13 @@
int rc;
do {
- while (!gic_is_spi_pending(msm_rpm_data.irq_ack) &&
+ while (!gic_is_irq_pending(msm_rpm_data.irq_ack) &&
msm_rpm_request) {
if (allow_async_completion)
spin_unlock(&msm_rpm_irq_lock);
- if (gic_is_spi_pending(msm_rpm_data.irq_err))
+ if (gic_is_irq_pending(msm_rpm_data.irq_err))
msm_rpm_err_fatal();
- gic_clear_spi_pending(msm_rpm_data.irq_err);
+ gic_clear_irq_pending(msm_rpm_data.irq_err);
udelay(1);
if (allow_async_completion)
spin_lock(&msm_rpm_irq_lock);
@@ -291,7 +291,7 @@
break;
rc = msm_rpm_process_ack_interrupt();
- gic_clear_spi_pending(msm_rpm_data.irq_ack);
+ gic_clear_irq_pending(msm_rpm_data.irq_ack);
} while (rc);
}
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index ac48990..6052918 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -297,6 +297,9 @@
__asmeq("%1", "r0")
__asmeq("%2", "r1")
__asmeq("%3", "r2")
+#ifdef REQUIRES_SEC
+ ".arch_extension sec\n"
+#endif
"smc #0 @ switch to secure world\n"
: "=r" (r0)
: "r" (r0), "r" (r1), "r" (r2)
@@ -329,6 +332,9 @@
__asmeq("%2", "r1")
__asmeq("%3", "r2")
__asmeq("%4", "r3")
+#ifdef REQUIRES_SEC
+ ".arch_extension sec\n"
+#endif
"smc #0 @ switch to secure world\n"
: "=r" (r0)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3));
@@ -356,6 +362,9 @@
__asmeq("%4", "r1")
__asmeq("%5", "r2")
__asmeq("%6", "r3")
+#ifdef REQUIRES_SEC
+ ".arch_extension sec\n"
+#endif
"smc #0 @ switch to secure world\n"
: "=r" (r0), "=r" (r1), "=r" (r2)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5));
@@ -388,6 +397,9 @@
__asmeq("%1", "r1")
__asmeq("%2", "r0")
__asmeq("%3", "r1")
+#ifdef REQUIRES_SEC
+ ".arch_extension sec\n"
+#endif
"smc #0 @ switch to secure world\n"
: "=r" (r0), "=r" (r1)
: "r" (r0), "r" (r1)
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 5cbf888..2860055 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -16,6 +16,7 @@
#include <linux/diagchar.h>
#include <linux/sched.h>
#include <linux/err.h>
+#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
@@ -115,6 +116,23 @@
queue_work(driver->diag_wq, &(driver->diag_read_smd_dci_work));
}
+void diag_dci_notify_client(int peripheral_mask)
+{
+ int i, stat;
+
+ /* Notify the DCI process that the peripheral DCI Channel is up */
+ for (i = 0; i < MAX_DCI_CLIENT; i++) {
+ if (driver->dci_notify_tbl[i].list & peripheral_mask) {
+ pr_debug("diag: sending signal now\n");
+ stat = send_sig(driver->dci_notify_tbl[i].signal_type,
+ driver->dci_notify_tbl[i].client, 0);
+ if (stat)
+ pr_err("diag: Err send sig stat: %d\n", stat);
+ break;
+ }
+ } /* end of loop for all DCI clients */
+}
+
static int diag_dci_probe(struct platform_device *pdev)
{
int err = 0;
@@ -125,6 +143,8 @@
if (err)
pr_err("diag: cannot open DCI port, Id = %d, err ="
" %d\n", pdev->id, err);
+ else
+ diag_dci_notify_client(DIAG_CON_MPSS);
}
return err;
}
@@ -302,6 +322,12 @@
if (driver->dci_tbl == NULL)
goto err;
}
+ if (driver->dci_notify_tbl == NULL) {
+ driver->dci_notify_tbl = kzalloc(MAX_DCI_CLIENT *
+ sizeof(struct dci_notification_tbl), GFP_KERNEL);
+ if (driver->dci_notify_tbl == NULL)
+ goto err;
+ }
if (driver->apps_dci_buf == NULL) {
driver->apps_dci_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
if (driver->apps_dci_buf == NULL)
@@ -316,6 +342,7 @@
err:
pr_err("diag: Could not initialize diag DCI buffers");
kfree(driver->dci_tbl);
+ kfree(driver->dci_notify_tbl);
kfree(driver->apps_dci_buf);
kfree(driver->buf_in_dci);
kfree(driver->write_ptr_dci);
@@ -328,6 +355,7 @@
driver->ch_dci = 0;
platform_driver_unregister(&msm_diag_dci_driver);
kfree(driver->dci_tbl);
+ kfree(driver->dci_notify_tbl);
kfree(driver->apps_dci_buf);
kfree(driver->buf_in_dci);
kfree(driver->write_ptr_dci);
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index cc6e0cf..c0b82df 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -22,6 +22,12 @@
int tag;
};
+struct dci_notification_tbl {
+ struct task_struct *client;
+ uint16_t list; /* bit mask */
+ int signal_type;
+};
+
#define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */
#define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */
#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7e7b514..6a7b931 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -18,6 +18,7 @@
#include <linux/mempool.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
+#include <linux/sched.h>
#include <mach/msm_smd.h>
#include <asm/atomic.h>
#include <asm/mach-types.h>
@@ -139,6 +140,7 @@
int use_device_tree;
/* DCI related variables */
struct diag_dci_tbl *dci_tbl;
+ struct dci_notification_tbl *dci_notify_tbl;
int dci_tag;
int dci_client_id;
struct mutex dci_mutex;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index d6a6e66..547f42f 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -343,6 +343,7 @@
int success = -1;
void *temp_buf;
uint16_t support_list = 0;
+ struct dci_notification_tbl *notify_params;
if (iocmd == DIAG_IOCTL_COMMAND_REG) {
struct bindpkt_params_per_process *pkt_params =
@@ -413,13 +414,23 @@
} else if (iocmd == DIAG_IOCTL_DCI_REG) {
if (driver->dci_state == DIAG_DCI_NO_REG)
return DIAG_DCI_NO_REG;
- /* use the 'list' later on to notify user space */
if (driver->num_dci_client >= MAX_DCI_CLIENT)
return DIAG_DCI_NO_REG;
+ notify_params = (struct dci_notification_tbl *) ioarg;
mutex_lock(&driver->dci_mutex);
driver->num_dci_client++;
pr_debug("diag: id = %d\n", driver->dci_client_id);
driver->dci_client_id++;
+ for (i = 0; i < MAX_DCI_CLIENT; i++) {
+ if (driver->dci_notify_tbl[i].client == NULL) {
+ driver->dci_notify_tbl[i].client = current;
+ driver->dci_notify_tbl[i].list =
+ notify_params->list;
+ driver->dci_notify_tbl[i].signal_type =
+ notify_params->signal_type;
+ break;
+ }
+ }
mutex_unlock(&driver->dci_mutex);
return driver->dci_client_id;
} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
@@ -433,6 +444,12 @@
success = i;
}
}
+ for (i = 0; i < MAX_DCI_CLIENT; i++) {
+ if (driver->dci_notify_tbl[i].client == current) {
+ driver->dci_notify_tbl[i].client = NULL;
+ break;
+ }
+ }
/* if any registrations were deleted successfully OR a valid
client_id was sent in DEINIT call , then its DCI client */
if (success >= 0 || ioarg)
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index fdff32e..826ba9a 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -122,7 +122,7 @@
}
EXPORT_SYMBOL(clkdev_add);
-void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
+void clkdev_add_table(struct clk_lookup *cl, size_t num)
{
mutex_lock(&clocks_mutex);
while (num--) {
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index bd58b4e..f5ee1d7 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -509,6 +509,6 @@
#define RBBM_BLOCK_ID_MARB_3 0x2b
/* RBBM_CLOCK_CTL default value */
-#define A3XX_RBBM_CLOCK_CTL_DEFAULT 0x00000000
+#define A3XX_RBBM_CLOCK_CTL_DEFAULT 0xBFFFFFFF
#endif
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 4991a2e..f5cb888 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -267,7 +267,7 @@
KGSL_IOMMU_CONTEXT_USER))
goto done;
- if (adreno_is_a225(adreno_dev))
+ if (cpu_is_msm8960())
cmds += adreno_add_change_mh_phys_limit_cmds(cmds, 0xFFFFF000,
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
@@ -362,7 +362,7 @@
}
}
- if (adreno_is_a225(adreno_dev))
+ if (cpu_is_msm8960())
cmds += adreno_add_change_mh_phys_limit_cmds(cmds,
reg_map_desc[num_iommu_units - 1]->gpuaddr - PAGE_SIZE,
device->mmu.setstate_memory.gpuaddr +
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 58a0963..a6b4210 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2558,11 +2558,6 @@
{
struct kgsl_device *device = &adreno_dev->dev;
- /* Reset the core */
- adreno_regwrite(device, A3XX_RBBM_SW_RESET_CMD,
- 0x00000001);
- msleep(20);
-
/* Set up 16 deep read/write request queues */
adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
@@ -2612,6 +2607,10 @@
adreno_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
(1 << 16) | 0xFFF);
+ /* Enable Clock gating */
+ adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL,
+ A3XX_RBBM_CLOCK_CTL_DEFAULT);
+
}
/* Defined in adreno_a3xx_snapshot.c */
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index 60aab64..a3bee4d 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -285,6 +285,9 @@
remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS,
64, 44);
+ /* Disable Clock gating temporarily for the debug bus to work */
+ adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, 0x00);
+
/* VPC memory */
snapshot = kgsl_snapshot_add_section(device,
KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
@@ -321,5 +324,9 @@
snapshot = a3xx_snapshot_debugbus(device, snapshot, remain);
+ /* Enable Clock gating */
+ adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL,
+ A3XX_RBBM_CLOCK_CTL_DEFAULT);
+
return snapshot;
}
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e42c7b6..d20cf7e 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/iommu.h>
#include <linux/msm_kgsl.h>
+#include <mach/socinfo.h>
#include "kgsl.h"
#include "kgsl_device.h"
@@ -268,14 +269,17 @@
struct kgsl_iommu *iommu = mmu->priv;
int i, j;
- BUG_ON(mmu->hwpagetable == NULL);
- BUG_ON(mmu->hwpagetable->priv == NULL);
-
- iommu_pt = mmu->hwpagetable->priv;
-
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ iommu_pt = mmu->defaultpagetable->priv;
for (j = 0; j < iommu_unit->dev_count; j++) {
+ /*
+ * If there is a 2nd default pagetable then priv domain
+ * is attached with this pagetable
+ */
+ if (mmu->priv_bank_table &&
+ (KGSL_IOMMU_CONTEXT_PRIV == j))
+ iommu_pt = mmu->priv_bank_table->priv;
if (iommu_unit->dev[j].attached) {
iommu_detach_device(iommu_pt->domain,
iommu_unit->dev[j].dev);
@@ -307,18 +311,21 @@
struct kgsl_iommu *iommu = mmu->priv;
int i, j, ret = 0;
- BUG_ON(mmu->hwpagetable == NULL);
- BUG_ON(mmu->hwpagetable->priv == NULL);
-
- iommu_pt = mmu->hwpagetable->priv;
-
/*
* Loop through all the iommu devcies under all iommu units and
* attach the domain
*/
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ iommu_pt = mmu->defaultpagetable->priv;
for (j = 0; j < iommu_unit->dev_count; j++) {
+ /*
+ * If there is a 2nd default pagetable then priv domain
+ * is attached to this pagetable
+ */
+ if (mmu->priv_bank_table &&
+ (KGSL_IOMMU_CONTEXT_PRIV == j))
+ iommu_pt = mmu->priv_bank_table->priv;
if (!iommu_unit->dev[j].attached) {
ret = iommu_attach_device(iommu_pt->domain,
iommu_unit->dev[j].dev);
@@ -614,17 +621,32 @@
int i = 0;
struct kgsl_iommu *iommu = mmu->priv;
struct kgsl_iommu_pt *iommu_pt;
+ struct kgsl_pagetable *pagetable = NULL;
+ /* If chip is not 8960 then we use the 2nd context bank for pagetable
+ * switching on the 3D side for which a separate table is allocated */
+ if (!cpu_is_msm8960()) {
+ mmu->priv_bank_table =
+ kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
+ if (mmu->priv_bank_table == NULL) {
+ status = -ENOMEM;
+ goto err;
+ }
+ iommu_pt = mmu->priv_bank_table->priv;
+ iommu_pt->asid = 1;
+ }
mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
/* Return error if the default pagetable doesn't exist */
if (mmu->defaultpagetable == NULL) {
status = -ENOMEM;
goto err;
}
+ pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
+ mmu->defaultpagetable;
/* Map the IOMMU regsiters to only defaultpagetable */
for (i = 0; i < iommu->unit_count; i++) {
iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
- status = kgsl_mmu_map(mmu->defaultpagetable,
+ status = kgsl_mmu_map(pagetable,
&(iommu->iommu_units[i].reg_map),
GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
if (status) {
@@ -644,10 +666,14 @@
return status;
err:
for (i--; i >= 0; i--) {
- kgsl_mmu_unmap(mmu->defaultpagetable,
+ kgsl_mmu_unmap(pagetable,
&(iommu->iommu_units[i].reg_map));
iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
}
+ if (mmu->priv_bank_table) {
+ kgsl_mmu_putpagetable(mmu->priv_bank_table);
+ mmu->priv_bank_table = NULL;
+ }
if (mmu->defaultpagetable) {
kgsl_mmu_putpagetable(mmu->defaultpagetable);
mmu->defaultpagetable = NULL;
@@ -669,9 +695,9 @@
if (status)
return -ENOMEM;
}
- /* We use the GPU MMU to control access to IOMMU registers on a225,
- * hence we still keep the MMU active on a225 */
- if (adreno_is_a225(ADRENO_DEVICE(mmu->device))) {
+ /* We use the GPU MMU to control access to IOMMU registers on 8960 with
+ * a225, hence we still keep the MMU active on 8960 */
+ if (cpu_is_msm8960()) {
struct kgsl_mh *mh = &(mmu->device->mh);
kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
@@ -707,6 +733,12 @@
*/
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ /* Make sure that the ASID of the priv bank is set to 1.
+ * When we a different pagetable for the priv bank then the
+ * iommu driver sets the ASID to 0 instead of 1 */
+ KGSL_IOMMU_SET_IOMMU_REG(iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_PRIV,
+ CONTEXTIDR, 1);
for (j = 0; j < iommu_unit->dev_count; j++)
iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
KGSL_IOMMU_GET_IOMMU_REG(
@@ -816,14 +848,19 @@
struct kgsl_iommu *iommu = mmu->priv;
int i;
for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
+ mmu->priv_bank_table : mmu->defaultpagetable);
if (iommu->iommu_units[i].reg_map.gpuaddr)
- kgsl_mmu_unmap(mmu->defaultpagetable,
+ kgsl_mmu_unmap(pagetable,
&(iommu->iommu_units[i].reg_map));
if (iommu->iommu_units[i].reg_map.hostptr)
iounmap(iommu->iommu_units[i].reg_map.hostptr);
kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
iommu->iommu_units[i].reg_map.sglen);
}
+
+ if (mmu->priv_bank_table)
+ kgsl_mmu_putpagetable(mmu->priv_bank_table);
if (mmu->defaultpagetable)
kgsl_mmu_putpagetable(mmu->defaultpagetable);
kfree(iommu->asids);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 5216b34..dfaadba 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -39,7 +39,8 @@
/* For IOMMU only unmap the global structures to global pt */
if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) &&
(KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
- (KGSL_MMU_GLOBAL_PT != pt->name))
+ (KGSL_MMU_GLOBAL_PT != pt->name) &&
+ (KGSL_MMU_PRIV_BANK_TABLE_NAME != pt->name))
return 0;
for (i = 0; i < KGSL_DEVICE_MAX; i++) {
struct kgsl_device *device = kgsl_driver.devp[i];
@@ -58,7 +59,8 @@
/* For IOMMU only map the global structures to global pt */
if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) &&
(KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
- (KGSL_MMU_GLOBAL_PT != pt->name))
+ (KGSL_MMU_GLOBAL_PT != pt->name) &&
+ (KGSL_MMU_PRIV_BANK_TABLE_NAME != pt->name))
return 0;
for (i = 0; i < KGSL_DEVICE_MAX; i++) {
struct kgsl_device *device = kgsl_driver.devp[i];
@@ -453,9 +455,9 @@
* just once from this pool of the defaultpagetable
*/
if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) &&
- (KGSL_MMU_GLOBAL_PT == name)) {
- pagetable->kgsl_pool = gen_pool_create(KGSL_MMU_ALIGN_SHIFT,
- -1);
+ ((KGSL_MMU_GLOBAL_PT == name) ||
+ (KGSL_MMU_PRIV_BANK_TABLE_NAME == name))) {
+ pagetable->kgsl_pool = gen_pool_create(PAGE_SHIFT, -1);
if (pagetable->kgsl_pool == NULL) {
KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
KGSL_MMU_ALIGN_SHIFT);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 2db327b..4c0c015 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -29,6 +29,7 @@
as an identifier */
#define KGSL_MMU_GLOBAL_PT 0
+#define KGSL_MMU_PRIV_BANK_TABLE_NAME 0xFFFFFFFF
struct kgsl_device;
@@ -165,6 +166,8 @@
struct kgsl_memdesc setstate_memory;
/* current page table object being used by device mmu */
struct kgsl_pagetable *defaultpagetable;
+ /* pagetable object used for priv bank of IOMMU */
+ struct kgsl_pagetable *priv_bank_table;
struct kgsl_pagetable *hwpagetable;
const struct kgsl_mmu_ops *mmu_ops;
void *priv;
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index daf21b8..78fc3ec 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -1769,7 +1769,7 @@
kref_put(&send_ioctx->kref, srpt_put_send_ioctx_kref);
goto send_sense;
}
- ret = transport_generic_allocate_tasks(cmd, srp_cmd->cdb);
+ ret = target_setup_cmd_from_cdb(cmd, srp_cmd->cdb);
if (ret < 0) {
kref_put(&send_ioctx->kref, srpt_put_send_ioctx_kref);
if (cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) {
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index 2ae9f28..6e62e60 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -25,7 +25,7 @@
#include <linux/scatterlist.h>
#include <linux/of.h>
#include <linux/of_device.h>
-
+#include <linux/regulator/consumer.h>
#include <asm/sizes.h>
#include <mach/iommu_hw-v2.h>
@@ -383,10 +383,16 @@
goto fail;
}
- ret = __enable_clocks(iommu_drvdata);
+ ret = regulator_enable(iommu_drvdata->gdsc);
if (ret)
goto fail;
+ ret = __enable_clocks(iommu_drvdata);
+ if (ret) {
+ regulator_disable(iommu_drvdata->gdsc);
+ goto fail;
+ }
+
if (!msm_iommu_ctx_attached(dev->parent))
__program_iommu(iommu_drvdata->base);
@@ -431,6 +437,8 @@
__reset_context(iommu_drvdata->base, ctx_drvdata->num);
__disable_clocks(iommu_drvdata);
+ regulator_disable(iommu_drvdata->gdsc);
+
list_del_init(&ctx_drvdata->attached_elm);
ctx_drvdata->attached_domain = NULL;
diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index d6858de..87e1a46 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.c
@@ -75,6 +75,10 @@
if (!drvdata->base)
return -ENOMEM;
+ drvdata->gdsc = devm_regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(drvdata->gdsc))
+ return -EINVAL;
+
drvdata->pclk = clk_get(&pdev->dev, "iface_clk");
if (IS_ERR(drvdata->pclk))
return PTR_ERR(drvdata->pclk);
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 971cf10..6085871 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1214,7 +1214,7 @@
unsigned char adie_type_bahma;
int retval = 0;
unsigned int rdsMask = 0;
- unsigned char value;
+ unsigned char value = 0;
adie_type_bahma = is_bahama();
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index 50399de..774a46d 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -82,7 +82,7 @@
i2c_byte1 = write_arr[i].reg_addr;
i2c_byte2 = value;
if (size != (i+1)) {
- i2c_byte2 = (i2c_byte2 & 0xFF00) >> 8;
+ i2c_byte2 = value & 0xFF;
CDBG("%s: byte1:0x%x, byte2:0x%x\n",
__func__, i2c_byte1, i2c_byte2);
rc = msm_camera_i2c_write(
@@ -97,7 +97,7 @@
i++;
i2c_byte1 = write_arr[i].reg_addr;
- i2c_byte2 = value & 0xFF;
+ i2c_byte2 = (value & 0xFF00) >> 8;
}
} else {
i2c_byte1 = (value & 0xFF00) >> 8;
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 834c9b0..9b42f9b 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -136,6 +136,15 @@
image_mode = -1;
break;
}
+ } else if (vfe_msg == VFE_MSG_OUTPUT_TERTIARY1) {
+ switch (pmctl->vfe_output_mode) {
+ case VFE_OUTPUTS_RDI0:
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+ break;
+ default:
+ image_mode = -1;
+ break;
+ }
} else
image_mode = -1;
@@ -331,6 +340,9 @@
case MSG_ID_OUTPUT_SECONDARY:
msgid = VFE_MSG_OUTPUT_SECONDARY;
break;
+ case MSG_ID_OUTPUT_TERTIARY1:
+ msgid = VFE_MSG_OUTPUT_TERTIARY1;
+ break;
default:
pr_err("%s: Invalid VFE output id: %d\n",
__func__, isp_output->output_id);
@@ -673,6 +685,7 @@
case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC:
case CMD_AXI_START:
case CMD_AXI_STOP:
+ case CMD_AXI_CFG_TERT1:
/* Dont need to pass buffer information.
* subdev will get the buffer from media
* controller free queue.
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 9382292..acff492 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -432,8 +432,15 @@
axi_ctrl->share_ctrl->outpath.out2.ch1 =
0x0000FFFF & (*ch_info++ >> 16);
axi_ctrl->share_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+ axi_ctrl->share_ctrl->outpath.out2.image_mode =
+ 0x0000FFFF & (*ch_info++ >> 16);
+
switch (mode) {
+ case OUTPUT_TERT1:
+ axi_ctrl->share_ctrl->outpath.output_mode =
+ VFE32_OUTPUT_MODE_TERTIARY1;
+ break;
case OUTPUT_PRIM:
axi_ctrl->share_ctrl->outpath.output_mode =
VFE32_OUTPUT_MODE_PRIMARY;
@@ -714,7 +721,7 @@
static void vfe32_start_common(struct vfe32_ctrl_type *vfe32_ctrl)
{
- uint32_t irq_mask = 0x00E00021;
+ uint32_t irq_mask = 0x00E00021, irq_mask1;
vfe32_ctrl->start_ack_pending = TRUE;
CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
vfe32_ctrl->share_ctrl->operation_mode,
@@ -723,19 +730,31 @@
irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK;
else
irq_mask |= 0x000FE000;
-
+ irq_mask |=
+ msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
msm_camera_io_w(irq_mask,
vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+ if (vfe32_ctrl->share_ctrl->operation_mode == VFE_OUTPUTS_RDI0) {
+ irq_mask1 =
+ msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_1);
+ irq_mask1 |= VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK;
+ msm_camera_io_w(irq_mask1, vfe32_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_1);
+ msm_camera_io_w_mb(2, vfe32_ctrl->share_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ } else {
+ msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
+ VFE_CAMIF_COMMAND);
+ }
/* Ensure the write order while writing
to the command register using the barrier */
- msm_camera_io_w_mb(1,
- vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- msm_camera_io_w_mb(1,
- vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
-
atomic_set(&vfe32_ctrl->share_ctrl->vstate, 1);
}
@@ -989,7 +1008,8 @@
struct msm_cam_media_controller *pmctl,
struct vfe32_ctrl_type *vfe32_ctrl)
{
- uint32_t irq_comp_mask = 0;
+ uint32_t irq_comp_mask = 0, irq_mask = 0;
+
irq_comp_mask =
msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
VFE_IRQ_COMP_MASK);
@@ -1018,6 +1038,16 @@
0x1 << (vfe32_ctrl->share_ctrl->outpath.out1.ch1 + 8) |
0x1 << (vfe32_ctrl->share_ctrl->outpath.out1.ch2 + 8));
}
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_TERTIARY1) {
+ irq_mask = msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ irq_mask |= (0x1 << (vfe32_ctrl->share_ctrl->outpath.out2.ch0 +
+ VFE_WM_OFFSET));
+ msm_camera_io_w(irq_mask, vfe32_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ }
+
msm_camera_io_w(irq_comp_mask,
vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
@@ -1235,6 +1265,8 @@
ch = &share_ctrl->outpath.out0;
else if (path == VFE_MSG_OUTPUT_SECONDARY)
ch = &share_ctrl->outpath.out1;
+ else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+ ch = &share_ctrl->outpath.out2;
else
pr_err("%s: Invalid path %d\n", __func__,
path);
@@ -1251,8 +1283,10 @@
if (path == VFE_MSG_OUTPUT_PRIMARY)
image_mode = axi_ctrl->share_ctrl->outpath.out0.image_mode;
- else
+ else if (path == VFE_MSG_OUTPUT_SECONDARY)
image_mode = axi_ctrl->share_ctrl->outpath.out1.image_mode;
+ else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+ image_mode = axi_ctrl->share_ctrl->outpath.out2.image_mode;
vfe32_subdev_notify(id, path, image_mode,
&axi_ctrl->subdev, axi_ctrl->share_ctrl);
@@ -1269,8 +1303,10 @@
uint32_t image_mode = 0;
if (path == VFE_MSG_OUTPUT_PRIMARY)
image_mode = vfe32_ctrl->share_ctrl->outpath.out0.image_mode;
- else
+ else if (path == VFE_MSG_OUTPUT_SECONDARY)
image_mode = vfe32_ctrl->share_ctrl->outpath.out1.image_mode;
+ else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+ image_mode = vfe32_ctrl->share_ctrl->outpath.out2.image_mode;
vfe32_subdev_notify(id, path, image_mode,
&vfe32_ctrl->subdev, vfe32_ctrl->share_ctrl);
@@ -1286,8 +1322,9 @@
vfe32_ctrl->share_ctrl->vfebase, outch->ch0,
outch->pong.ch_paddr[0]);
- if (vfe32_ctrl->share_ctrl->operation_mode !=
- VFE_OUTPUTS_RAW) {
+ if ((vfe32_ctrl->share_ctrl->operation_mode !=
+ VFE_OUTPUTS_RAW) &&
+ (path != VFE_MSG_OUTPUT_TERTIARY1)) {
vfe32_put_ch_ping_addr(
vfe32_ctrl->share_ctrl->vfebase, outch->ch1,
outch->ping.ch_paddr[1]);
@@ -1377,6 +1414,11 @@
rc = vfe32_configure_pingpong_buffers(
VFE_MSG_V32_START, VFE_MSG_OUTPUT_PRIMARY,
vfe32_ctrl);
+ else if (vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_RDI0)
+ rc = vfe32_configure_pingpong_buffers(
+ VFE_MSG_V32_START, VFE_MSG_OUTPUT_TERTIARY1,
+ vfe32_ctrl);
else
/* Configure secondary channel */
rc = vfe32_configure_pingpong_buffers(
@@ -2844,11 +2886,14 @@
CDBG("stop video triggered .\n");
}
+ spin_lock_irqsave(&vfe32_ctrl->start_ack_lock, flags);
if (vfe32_ctrl->start_ack_pending == TRUE) {
+ vfe32_ctrl->start_ack_pending = FALSE;
+ spin_unlock_irqrestore(&vfe32_ctrl->start_ack_lock, flags);
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
- vfe32_ctrl->start_ack_pending = FALSE;
} else {
+ spin_unlock_irqrestore(&vfe32_ctrl->start_ack_lock, flags);
if (vfe32_ctrl->recording_state ==
VFE_STATE_STOP_REQUESTED) {
vfe32_ctrl->recording_state = VFE_STATE_STOPPED;
@@ -2977,6 +3022,23 @@
} /* if snapshot mode. */
}
+static void vfe32_process_rdi0_reg_update_irq(
+ struct vfe32_ctrl_type *vfe32_ctrl)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&vfe32_ctrl->start_ack_lock, flags);
+ if (vfe32_ctrl->start_ack_pending == TRUE) {
+ vfe32_ctrl->start_ack_pending = FALSE;
+ spin_unlock_irqrestore(
+ &vfe32_ctrl->start_ack_lock, flags);
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
+ } else {
+ spin_unlock_irqrestore(
+ &vfe32_ctrl->start_ack_lock, flags);
+ }
+}
+
static void vfe32_set_default_reg_values(
struct vfe32_ctrl_type *vfe32_ctrl)
{
@@ -3381,6 +3443,48 @@
}
}
+static void vfe32_process_output_path_irq_rdi0(
+ struct axi_ctrl_t *axi_ctrl)
+{
+ uint32_t ping_pong;
+ uint32_t ch0_paddr = 0;
+ /* this must be rdi image output. */
+ struct msm_free_buf *free_buf = NULL;
+ /*RDI0*/
+ if (axi_ctrl->share_ctrl->operation_mode == VFE_OUTPUTS_RDI0) {
+ free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_TERTIARY1, axi_ctrl);
+ if (free_buf) {
+ ping_pong = msm_camera_io_r(axi_ctrl->
+ share_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS);
+
+ /* Y only channel */
+ ch0_paddr = vfe32_get_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out2.ch0);
+
+ pr_debug("%s ch0 = 0x%x\n",
+ __func__, ch0_paddr);
+
+ /* Y channel */
+ vfe32_put_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out2.ch0,
+ free_buf->ch_paddr[0]);
+
+ vfe_send_outmsg(axi_ctrl,
+ MSG_ID_OUTPUT_TERTIARY1, ch0_paddr,
+ 0, 0,
+ axi_ctrl->share_ctrl->outpath.out2.image_mode);
+
+ } else {
+ axi_ctrl->share_ctrl->outpath.out2.frame_drop_cnt++;
+ pr_err("path_irq_2 irq - no free buffer for rdi0!\n");
+ }
+ }
+}
+
static uint32_t vfe32_process_stats_irq_common(
struct vfe32_ctrl_type *vfe32_ctrl,
uint32_t statsNum, uint32_t newAddr)
@@ -3756,6 +3860,10 @@
CDBG("irq regUpdateIrq\n");
vfe32_process_reg_update_irq(vfe32_ctrl);
break;
+ case VFE_IRQ_STATUS1_RDI0_REG_UPDATE:
+ CDBG("irq rdi0 regUpdateIrq\n");
+ vfe32_process_rdi0_reg_update_irq(vfe32_ctrl);
+ break;
case VFE_IMASK_WHILE_STOPPING_1:
CDBG("irq resetAckIrq\n");
vfe32_process_reset_irq(vfe32_ctrl);
@@ -3845,6 +3953,12 @@
(void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
if (qcmd->vfeInterruptStatus1 &
+ VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK)
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS1_RDI0_REG_UPDATE);
+
+ if (qcmd->vfeInterruptStatus1 &
VFE_IMASK_WHILE_STOPPING_1)
v4l2_subdev_notify(&axi_ctrl->subdev,
NOTIFY_VFE_IRQ,
@@ -4284,6 +4398,7 @@
spin_lock_init(&vfe32_ctrl->state_lock);
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);
@@ -4366,6 +4481,11 @@
share_ctrl->outpath.out0.ch2]);
}
break;
+ case VFE_OUTPUTS_RDI0:
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out2.ch0]);
+ break;
default:
if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_SECONDARY) {
@@ -4467,8 +4587,8 @@
}
vfe32_config_axi(axi_ctrl, OUTPUT_PRIM, axio);
kfree(axio);
- }
break;
+ }
case CMD_AXI_CFG_PRIM_ALL_CHNLS: {
uint32_t *axio = NULL;
axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length,
@@ -4486,8 +4606,8 @@
}
vfe32_config_axi(axi_ctrl, OUTPUT_PRIM_ALL_CHNLS, axio);
kfree(axio);
- }
break;
+ }
case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC: {
uint32_t *axio = NULL;
axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length,
@@ -4505,8 +4625,8 @@
}
vfe32_config_axi(axi_ctrl, OUTPUT_PRIM|OUTPUT_SEC, axio);
kfree(axio);
- }
break;
+ }
case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS: {
uint32_t *axio = NULL;
axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length,
@@ -4525,8 +4645,8 @@
vfe32_config_axi(axi_ctrl,
OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio);
kfree(axio);
- }
break;
+ }
case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC: {
uint32_t *axio = NULL;
axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length,
@@ -4545,8 +4665,28 @@
vfe32_config_axi(axi_ctrl,
OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio);
kfree(axio);
- }
break;
+ }
+ case CMD_AXI_CFG_TERT1: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe32_config_axi(axi_ctrl,
+ OUTPUT_TERT1, axio);
+ kfree(axio);
+ break;
+ }
case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC_ALL_CHNLS:
pr_err("%s Invalid/Unsupported AXI configuration %x",
__func__, cfgcmd.cmd_type);
@@ -4585,6 +4725,13 @@
CDBG("Image composite done 1 irq occured.\n");
vfe32_process_output_path_irq_1(axi_ctrl);
}
+
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_TERTIARY1)
+ if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0
+ + VFE_WM_OFFSET)))
+ vfe32_process_output_path_irq_rdi0(axi_ctrl);
+
/* in snapshot mode if done then send
snapshot done message */
if (axi_ctrl->share_ctrl->operation_mode ==
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index d5da432..1746f3f 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -87,6 +87,9 @@
* the luma samples. JPEG 4:2:2 */
#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0
+/* wm bit offset for IRQ MASK and IRQ STATUS register */
+#define VFE_WM_OFFSET 6
+
/* constants for irq registers */
#define VFE_DISABLE_ALL_IRQS 0
/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS. */
@@ -115,6 +118,17 @@
#define VFE_IRQ_STATUS0_ASYNC_TIMER2 0x40000000 /* bit 30 */
#define VFE_IRQ_STATUS0_ASYNC_TIMER3 0x80000000 /* bit 32 */
+#define VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK 0x4000000 /*bit 26*/
+#define VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK 0x8000000 /*bit 27*/
+
+/*TODOs the irq status passed from axi to vfe irq handler does not account
+* for 2 irq status registers. So below macro is added to differentiate between
+* same bit set on both irq status registers. This wil be fixed later by passing
+*entire payload to vfe irq handler and parsing there instead of passing just the
+*status bit*/
+#define VFE_IRQ_STATUS1_RDI0_REG_UPDATE 0x84000000 /*bit 26*/
+#define VFE_IRQ_STATUS1_RDI1_REG_UPDATE 0x88000000 /*bit 27*/
+
/* imask for while waiting for stop ack, driver has already
* requested stop, waiting for reset irq, and async timer irq.
* For irq_status_0, bit 28-32 are for async timer. For
@@ -788,7 +802,7 @@
struct vfe32_output_ch out0; /* preview and thumbnail */
struct vfe32_output_ch out1; /* snapshot */
- struct vfe32_output_ch out2; /* video */
+ struct vfe32_output_ch out2; /* rdi0 */
};
struct vfe32_frame_extra {
@@ -893,6 +907,7 @@
#define VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS BIT(7)
#define VFE32_OUTPUT_MODE_SECONDARY BIT(8)
#define VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS BIT(9)
+#define VFE32_OUTPUT_MODE_TERTIARY1 BIT(10)
struct vfe_stats_control {
uint8_t ackPending;
@@ -946,6 +961,7 @@
uint32_t vfeImaskCompositePacked;
spinlock_t update_ack_lock;
+ spinlock_t start_ack_lock;
spinlock_t state_lock;
spinlock_t io_lock;
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 7697a79..b1e584d 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -255,10 +255,6 @@
struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
-#if defined(CONFIG_OV5647)
- extern int lcd_camera_power_onoff(int on);
-#endif
-
#define VIDIOC_MSM_SENSOR_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 10, void __user *)
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index eab0899..d192563 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -643,8 +643,6 @@
}
s_ctrl = client->dev.platform_data;
- if (s_ctrl->sensordata->pmic_gpio_enable)
- lcd_camera_power_onoff(0);
return rc;
}
@@ -716,11 +714,6 @@
gpio_direction_output(info->sensor_pwd, 1);
gpio_direction_output(info->sensor_reset, 0);
usleep_range(10000, 11000);
- if (info->pmic_gpio_enable) {
- info->pmic_gpio_enable = 0;
- lcd_camera_power_onoff(1);
- }
- usleep_range(10000, 11000);
rc = msm_sensor_power_up(s_ctrl);
if (rc < 0) {
CDBG("%s: msm_sensor_power_up failed\n", __func__);
diff --git a/drivers/media/video/msm/sensors/ov7692_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
index a6af770..6fc1da1 100644
--- a/drivers/media/video/msm/sensors/ov7692_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_v4l2.c
@@ -585,7 +585,8 @@
static struct msm_camera_i2c_reg_conf ov7692_wb_oem[][4] = {
{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
{-1, -1, -1},},/*WHITEBALNACE OFF*/
- {{0x13, 0xf7}, {0x15, 0x00},}, /*WHITEBALNACE AUTO*/
+ {{0x13, 0xf7}, {0x15, 0x00}, {-1, -1, -1},
+ {-1, -1, -1},}, /*WHITEBALNACE AUTO*/
{{0x13, 0xf5}, {0x01, 0x56}, {0x02, 0x50},
{0x15, 0x00},}, /*WHITEBALNACE CUSTOM*/
{{0x13, 0xf5}, {0x01, 0x66}, {0x02, 0x40},
@@ -861,44 +862,6 @@
.video = &ov7692_subdev_video_ops,
};
-int32_t ov7692_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
-{
- int32_t rc = 0;
- struct msm_camera_sensor_info *info = NULL;
-
- info = s_ctrl->sensordata;
- if (info->pmic_gpio_enable) {
- info->sensor_lcd_gpio_onoff(1);
- usleep_range(5000, 5100);
- }
-
- rc = msm_sensor_power_up(s_ctrl);
- if (rc < 0) {
- CDBG("%s: msm_sensor_power_up failed\n", __func__);
- return rc;
- }
-
- return rc;
-}
-
-int32_t ov7692_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
-{
- int32_t rc = 0;
- struct msm_camera_sensor_info *info = NULL;
-
- rc = msm_sensor_power_down(s_ctrl);
- if (rc < 0)
- CDBG("%s: msm_sensor_power_down failed\n", __func__);
-
- info = s_ctrl->sensordata;
- if (info->pmic_gpio_enable) {
- info->pmic_gpio_enable = 0;
- info->sensor_lcd_gpio_onoff(0);
- usleep_range(5000, 5100);
- }
- return rc;
-}
-
static struct msm_sensor_fn_t ov7692_func_tbl = {
.sensor_start_stream = msm_sensor_start_stream,
.sensor_stop_stream = msm_sensor_stop_stream,
@@ -907,8 +870,8 @@
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
.sensor_config = msm_sensor_config,
- .sensor_power_up = ov7692_sensor_power_up,
- .sensor_power_down = ov7692_sensor_power_down,
+ .sensor_power_up = msm_sensor_power_up,
+ .sensor_power_down = msm_sensor_power_down,
.sensor_get_csi_params = msm_sensor_get_csi_params,
};
diff --git a/drivers/media/video/msm/sensors/ov8825_v4l2.c b/drivers/media/video/msm/sensors/ov8825_v4l2.c
index bb846e9..9f09208 100644
--- a/drivers/media/video/msm/sensors/ov8825_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov8825_v4l2.c
@@ -808,33 +808,12 @@
{ }
};
-int32_t ov8825_sensor_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int32_t rc = 0;
- struct msm_sensor_ctrl_t *s_ctrl;
-
- CDBG("\n in ov8825_sensor_i2c_probe\n");
- rc = msm_sensor_i2c_probe(client, id);
- if (client->dev.platform_data == NULL) {
- pr_err("%s: NULL sensor data\n", __func__);
- return -EFAULT;
- }
- s_ctrl = client->dev.platform_data;
- if (s_ctrl->sensordata->pmic_gpio_enable)
- lcd_camera_power_onoff(0);
- return rc;
-}
-
int32_t ov8825_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc = 0;
struct msm_camera_sensor_info *info = NULL;
+
info = s_ctrl->sensordata;
- if (info->pmic_gpio_enable) {
- info->pmic_gpio_enable = 0;
- lcd_camera_power_onoff(1);
- }
gpio_direction_output(info->sensor_pwd, 0);
gpio_direction_output(info->sensor_reset, 0);
usleep_range(10000, 11000);
@@ -853,7 +832,7 @@
static struct i2c_driver ov8825_i2c_driver = {
.id_table = ov8825_i2c_id,
- .probe = ov8825_sensor_i2c_probe,
+ .probe = msm_sensor_i2c_probe,
.driver = {
.name = SENSOR_NAME,
},
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 25b5c5c..bdace3c 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -69,6 +69,8 @@
struct ion_handle *hndl;
size_t len;
int rc = 0;
+ if (size == 0)
+ goto skip_mem_alloc;
flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
hndl = ion_alloc(client->clnt, size, align, flags);
if (IS_ERR_OR_NULL(hndl)) {
@@ -96,6 +98,7 @@
fail_map:
ion_free(client->clnt, hndl);
fail_shared_mem_alloc:
+skip_mem_alloc:
return rc;
}
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index ec93628..63f23eb 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -477,7 +477,14 @@
rc = vidc_hal_session_set_property((void *)inst->session,
HAL_PARAM_FRAME_SIZE, &frame_sz);
if (rc) {
- pr_err("Failed to set hal property for framesize\n");
+ pr_err("Failed to set framesize for Output port\n");
+ break;
+ }
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ if (rc) {
+ pr_err("Failed to set framesize for Capture port\n");
break;
}
rc = msm_comm_try_get_bufreqs(inst);
@@ -743,6 +750,8 @@
venc_profile_level.profile = control.value;
profile_level.level = venc_profile_level.level;
pdata = &profile_level;
+ pr_debug("\nprofile: %d\n",
+ profile_level.profile);
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
property_id =
@@ -804,6 +813,8 @@
venc_profile_level.level = control.value;
profile_level.profile = venc_profile_level.profile;
pdata = &profile_level;
+ pr_debug("\nLevel: %d\n",
+ profile_level.level);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
property_id =
@@ -895,7 +906,7 @@
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
property_id =
HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
- h264_db_control.slicebeta_offset = control.value;
+ h264_db_control.slice_beta_offset = control.value;
pdata = &h264_db_control;
default:
break;
@@ -1164,7 +1175,7 @@
}
rc = vb2_dqbuf(q, b, true);
if (rc)
- pr_err("Failed to qbuf, %d\n", rc);
+ pr_err("Failed to dqbuf, %d\n", rc);
return rc;
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 9b617aa..ba5fdc4 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -813,7 +813,7 @@
if (rc || state == inst->state)
break;
default:
- pr_err("State not recognized\n");
+ pr_err("State not recognized: %d\n", flipped_state);
rc = -EINVAL;
break;
}
@@ -855,6 +855,7 @@
frame_data.alloc_len = vb->v4l2_planes[0].length;
frame_data.filled_len = vb->v4l2_planes[0].bytesused;
frame_data.device_addr = vb->v4l2_planes[0].m.userptr;
+ frame_data.timestamp = vb->v4l2_buf.timestamp.tv_usec;
frame_data.clnt_data = (u32)vb;
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
frame_data.buffer_type = HAL_BUFFER_INPUT;
@@ -871,10 +872,8 @@
frame_data.filled_len = 0;
frame_data.buffer_type = HAL_BUFFER_OUTPUT;
frame_data.extradata_addr = 0;
- pr_debug("Sending ftb to hal...: Alloc: %d :filled: %d"
- " extradata_addr: %d\n", frame_data.alloc_len,
- frame_data.filled_len,
- frame_data.extradata_addr);
+ pr_debug("Sending ftb to hal..: Alloc: %d :filled: %d\n",
+ frame_data.alloc_len, frame_data.filled_len);
rc = vidc_hal_session_ftb((void *) inst->session,
&frame_data);
} else {
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 13a319d9..583b5a9 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -23,7 +23,7 @@
#define REG_ADDR_OFFSET_BITMASK 0x000FFFFF
/*Workaround for virtio */
-#define HFI_VIRTIO_FW_BIAS 0x34f00000
+#define HFI_VIRTIO_FW_BIAS 0x14f00000
struct hal_device_data hal_ctxt;
@@ -40,7 +40,7 @@
sys_init = (struct hfi_cmd_sys_session_init_packet *)packet;
sess = (struct hal_session *) sys_init->session_id;
- switch (sys_init->packet) {
+ switch (sys_init->packet_type) {
case HFI_CMD_SESSION_EMPTY_BUFFER:
if (sess->is_decoder) {
struct hfi_cmd_session_empty_buffer_compressed_packet
@@ -73,7 +73,7 @@
struct hfi_buffer_info *buff;
buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
buff->buffer_addr -= HFI_VIRTIO_FW_BIAS;
- buff->extradata_addr -= HFI_VIRTIO_FW_BIAS;
+ buff->extra_data_addr -= HFI_VIRTIO_FW_BIAS;
} else {
for (i = 0; i < pkt->num_buffers; i++)
pkt->rg_buffer_info[i] -= HFI_VIRTIO_FW_BIAS;
@@ -89,7 +89,7 @@
struct hfi_buffer_info *buff;
buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
buff->buffer_addr -= HFI_VIRTIO_FW_BIAS;
- buff->extradata_addr -= HFI_VIRTIO_FW_BIAS;
+ buff->extra_data_addr -= HFI_VIRTIO_FW_BIAS;
} else {
for (i = 0; i < pkt->num_buffers; i++)
pkt->rg_buffer_info[i] -= HFI_VIRTIO_FW_BIAS;
@@ -640,7 +640,8 @@
goto err_no_dev;
}
pkt.size = sizeof(struct hfi_cmd_sys_init_packet);
- pkt.packet = HFI_CMD_SYS_INIT;
+ pkt.packet_type = HFI_CMD_SYS_INIT;
+ pkt.arch_type = HFI_ARCH_OX_OFFSET;
if (vidc_hal_iface_cmdq_write(dev, &pkt)) {
rc = -ENOTEMPTY;
goto err_write_fail;
@@ -664,8 +665,6 @@
}
write_register(dev->hal_data->register_base_addr,
VIDC_CPU_CS_SCIACMDARG3, 0, 0);
- disable_irq_nosync(dev->hal_data->irq);
- vidc_hal_interface_queues_release(dev);
HAL_MSG_INFO("\nHAL exited\n");
return 0;
}
@@ -742,8 +741,8 @@
switch (resource_hdr->resource_id) {
case VIDC_RESOURCE_OCMEM:
{
- struct hfi_resource_ocmem_type *hfioc_mem =
- (struct hfi_resource_ocmem_type *)
+ struct hfi_resource_ocmem *hfioc_mem =
+ (struct hfi_resource_ocmem *)
&pkt->rg_resource_data[0];
struct vidc_mem_addr *vidc_oc_mem =
(struct vidc_mem_addr *) resource_value;
@@ -751,7 +750,7 @@
pkt->resource_type = HFI_RESOURCE_OCMEM;
hfioc_mem->size = (u32) vidc_oc_mem->mem_size;
hfioc_mem->mem = (u8 *) vidc_oc_mem->align_device_addr;
- pkt->size += sizeof(struct hfi_resource_ocmem_type);
+ pkt->size += sizeof(struct hfi_resource_ocmem);
if (vidc_hal_iface_cmdq_write(dev, pkt))
rc = -ENOTEMPTY;
break;
@@ -807,7 +806,41 @@
rc = -ENOTEMPTY;
return rc;
}
-
+static u32 get_hfi_buffer(int hal_buffer)
+{
+ u32 buffer;
+ switch (hal_buffer) {
+ case HAL_BUFFER_INPUT:
+ buffer = HFI_BUFFER_INPUT;
+ break;
+ case HAL_BUFFER_OUTPUT:
+ buffer = HFI_BUFFER_OUTPUT;
+ break;
+ case HAL_BUFFER_OUTPUT2:
+ buffer = HFI_BUFFER_OUTPUT;
+ break;
+ case HAL_BUFFER_EXTRADATA_INPUT:
+ buffer = HFI_BUFFER_EXTRADATA_INPUT;
+ break;
+ case HAL_BUFFER_EXTRADATA_OUTPUT:
+ buffer = HFI_BUFFER_EXTRADATA_OUTPUT;
+ break;
+ case HAL_BUFFER_EXTRADATA_OUTPUT2:
+ buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
+ break;
+ case HAL_BUFFER_INTERNAL_SCRATCH:
+ buffer = HFI_BUFFER_INTERNAL_SCRATCH;
+ break;
+ case HAL_BUFFER_INTERNAL_PERSIST:
+ buffer = HFI_BUFFER_INTERNAL_PERSIST;
+ break;
+ default:
+ HAL_MSG_ERROR("Invalid buffer type : 0x%x\n", hal_buffer);
+ buffer = 0;
+ break;
+ }
+ return buffer;
+}
int vidc_hal_session_set_property(void *sess,
enum hal_property ptype, void *pdata)
{
@@ -832,24 +865,37 @@
switch (ptype) {
case HAL_CONFIG_FRAME_RATE:
{
- struct hfi_frame_rate *hfi_fps;
+ struct hfi_frame_rate *hfi;
+ u32 buffer;
+ struct hal_frame_rate *prop =
+ (struct hal_frame_rate *) pdata;
pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_FRAME_RATE;
- hfi_fps = (struct hfi_frame_rate *) &pkt->rg_property_data[1];
- memcpy(hfi_fps, (struct hfi_frame_rate *)
- pdata, sizeof(struct hfi_frame_rate));
+ hfi = (struct hfi_frame_rate *) &pkt->rg_property_data[1];
+ buffer = get_hfi_buffer(prop->buffer_type);
+ if (buffer)
+ hfi->buffer_type = buffer;
+ else
+ return -EINVAL;
+ hfi->frame_rate = prop->frame_rate;
pkt->size += sizeof(u32) + sizeof(struct hfi_frame_rate);
break;
}
case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
{
- struct hfi_uncompressed_format_select *hfi_buf_fmt;
+ u32 buffer;
+ struct hfi_uncompressed_format_select *hfi;
+ struct hal_uncompressed_format_select *prop =
+ (struct hal_uncompressed_format_select *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT;
- hfi_buf_fmt =
- (struct hfi_uncompressed_format_select *)
- &pkt->rg_property_data[1];
- memcpy(hfi_buf_fmt, (struct hfi_uncompressed_format_select *)
- pdata, sizeof(struct hfi_uncompressed_format_select));
+ hfi = (struct hfi_uncompressed_format_select *)
+ &pkt->rg_property_data[1];
+ buffer = get_hfi_buffer(prop->buffer_type);
+ if (buffer)
+ hfi->buffer_type = buffer;
+ else
+ return -EINVAL;
+ hfi->format = prop->format;
pkt->size += sizeof(u32) + sizeof(struct
hfi_uncompressed_format_select);
break;
@@ -862,11 +908,18 @@
break;
case HAL_PARAM_FRAME_SIZE:
{
- struct hfi_frame_size *hfi_rect;
+ u32 buffer;
+ struct hfi_frame_size *hfi;
+ struct hal_frame_size *prop = (struct hal_frame_size *) pdata;
pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_FRAME_SIZE;
- hfi_rect = (struct hfi_frame_size *) &pkt->rg_property_data[1];
- memcpy(hfi_rect, (struct hfi_frame_size *) pdata,
- sizeof(struct hfi_frame_size));
+ hfi = (struct hfi_frame_size *) &pkt->rg_property_data[1];
+ buffer = get_hfi_buffer(prop->buffer_type);
+ if (buffer)
+ hfi->buffer_type = buffer;
+ else
+ return -EINVAL;
+ hfi->height = prop->height;
+ hfi->width = prop->width;
pkt->size += sizeof(u32) + sizeof(struct hfi_frame_size);
break;
}
@@ -875,38 +928,85 @@
struct hfi_enable *hfi;
pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_REALTIME;
hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_enable *) pdata,
- sizeof(struct hfi_enable));
- pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_BUFFER_COUNT_ACTUAL:
{
+ u32 buffer;
struct hfi_buffer_count_actual *hfi;
+ struct hal_buffer_count_actual *prop =
+ (struct hal_buffer_count_actual *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL;
hfi = (struct hfi_buffer_count_actual *)
&pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_buffer_count_actual *) pdata,
- sizeof(struct hfi_buffer_count_actual));
+ hfi->buffer_count_actual = prop->buffer_count_actual;
+ buffer = get_hfi_buffer(prop->buffer_type);
+ if (buffer)
+ hfi->buffer_type = buffer;
+ else
+ return -EINVAL;
pkt->size += sizeof(u32) + sizeof(struct
hfi_buffer_count_actual);
break;
}
case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
{
+ struct hal_nal_stream_format_supported *prop =
+ (struct hal_nal_stream_format_supported *)pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT;
- pkt->rg_property_data[1] = (enum HFI_NAL_STREAM_FORMAT)pdata;
- pkt->size += sizeof(u32) + sizeof(enum HFI_NAL_STREAM_FORMAT);
+ HAL_MSG_ERROR("\ndata is :%d",
+ prop->nal_stream_format_supported);
+ switch (prop->nal_stream_format_supported) {
+ case HAL_NAL_FORMAT_STARTCODES:
+ pkt->rg_property_data[1] =
+ HFI_NAL_FORMAT_STARTCODES;
+ break;
+ case HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER:
+ pkt->rg_property_data[1] =
+ HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER;
+ break;
+ case HAL_NAL_FORMAT_ONE_BYTE_LENGTH:
+ pkt->rg_property_data[1] =
+ HFI_NAL_FORMAT_ONE_BYTE_LENGTH;
+ break;
+ case HAL_NAL_FORMAT_TWO_BYTE_LENGTH:
+ pkt->rg_property_data[1] =
+ HFI_NAL_FORMAT_TWO_BYTE_LENGTH;
+ break;
+ case HAL_NAL_FORMAT_FOUR_BYTE_LENGTH:
+ pkt->rg_property_data[1] =
+ HFI_NAL_FORMAT_FOUR_BYTE_LENGTH;
+ break;
+ default:
+ HAL_MSG_ERROR("Invalid nal format: 0x%x",
+ prop->nal_stream_format_supported);
+ break;
+ }
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_VDEC_OUTPUT_ORDER:
{
+ int *data = (int *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER;
- pkt->rg_property_data[1] = (enum HFI_OUTPUT_ORDER)pdata;
- pkt->size += sizeof(u32) + sizeof(enum HFI_OUTPUT_ORDER);
+ switch (*data) {
+ case HAL_OUTPUT_ORDER_DECODE:
+ pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DISPLAY;
+ break;
+ case HAL_OUTPUT_ORDER_DISPLAY:
+ pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DECODE;
+ break;
+ default:
+ HAL_MSG_ERROR("invalid output order: 0x%x",
+ *data);
+ break;
+ }
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_VDEC_PICTURE_TYPE_DECODE:
@@ -916,7 +1016,7 @@
HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE;
hfi = (struct hfi_enable_picture *) &pkt->rg_property_data[1];
hfi->picture_type = (u32) pdata;
- pkt->size += sizeof(u32) + sizeof(struct hfi_enable_picture);
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO:
@@ -925,9 +1025,8 @@
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_enable *) pdata,
- sizeof(struct hfi_enable));
- pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
@@ -936,41 +1035,64 @@
pkt->rg_property_data[0] =
HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_enable *) pdata,
- sizeof(struct hfi_enable));
- pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_VDEC_MULTI_STREAM:
{
+ u32 buffer;
struct hfi_multi_stream *hfi;
+ struct hal_multi_stream *prop =
+ (struct hal_multi_stream *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
hfi = (struct hfi_multi_stream *) &pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_multi_stream *)pdata,
- sizeof(struct hfi_multi_stream));
+ buffer = get_hfi_buffer(prop->buffer_type);
+ if (buffer)
+ hfi->buffer_type = buffer;
+ else
+ return -EINVAL;
+ hfi->enable = prop->enable;
+ hfi->width = prop->width;
+ hfi->height = prop->height;
pkt->size += sizeof(u32) + sizeof(struct hfi_multi_stream);
break;
}
case HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT:
{
- struct hfi_display_picture_buffer_count *hfi_disp_buf;
+ struct hfi_display_picture_buffer_count *hfi;
+ struct hal_display_picture_buffer_count *prop =
+ (struct hal_display_picture_buffer_count *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT;
- hfi_disp_buf = (struct hfi_display_picture_buffer_count *)
+ hfi = (struct hfi_display_picture_buffer_count *)
&pkt->rg_property_data[1];
- memcpy(hfi_disp_buf,
- (struct hfi_display_picture_buffer_count *)pdata,
- sizeof(struct hfi_display_picture_buffer_count));
+ hfi->count = prop->count;
+ hfi->enable = prop->enable;
pkt->size += sizeof(u32) +
sizeof(struct hfi_display_picture_buffer_count);
break;
}
case HAL_PARAM_DIVX_FORMAT:
{
+ int *data = pdata;
pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_DIVX_FORMAT;
- pkt->rg_property_data[1] = (enum HFI_DIVX_FORMAT)pdata;
- pkt->size += sizeof(u32) + sizeof(enum HFI_DIVX_FORMAT);
+ switch (*data) {
+ case HAL_DIVX_FORMAT_4:
+ pkt->rg_property_data[1] = HFI_DIVX_FORMAT_4;
+ break;
+ case HAL_DIVX_FORMAT_5:
+ pkt->rg_property_data[1] = HFI_DIVX_FORMAT_5;
+ break;
+ case HAL_DIVX_FORMAT_6:
+ pkt->rg_property_data[1] = HFI_DIVX_FORMAT_6;
+ break;
+ default:
+ HAL_MSG_ERROR("Invalid divx format: 0x%x", *data);
+ break;
+ }
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING:
@@ -979,25 +1101,23 @@
pkt->rg_property_data[0] =
HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_enable *) pdata,
- sizeof(struct hfi_enable));
- pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER:
{
- struct hfi_enable *enable;
+ struct hfi_enable *hfi;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
- enable = (struct hfi_enable *) &pkt->rg_property_data[1];
- memcpy(enable, (struct hfi_enable *) pdata,
- sizeof(struct hfi_enable));
- pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_CONFIG_VENC_REQUEST_IFRAME:
pkt->rg_property_data[0] =
- HFI_PROPERTY_CONFIG_VENC_REQUEST_IFRAME;
+ HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
break;
case HAL_PARAM_VENC_MPEG4_SHORT_HEADER:
break;
@@ -1009,31 +1129,64 @@
pkt->rg_property_data[0] =
HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1];
- hfi->bit_rate = ((struct hfi_bitrate *)pdata)->bit_rate;
- pkt->size += sizeof(u32) + sizeof(struct hfi_bitrate);
+ hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate;
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_PROFILE_LEVEL_CURRENT:
{
- struct hfi_profile_level *hfi_profile_level;
+ struct hfi_profile_level *hfi;
+ struct hal_profile_level *prop =
+ (struct hal_profile_level *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
- hfi_profile_level = (struct hfi_profile_level *)
- &pkt->rg_property_data[1];
- memcpy(hfi_profile_level, (struct hfi_profile_level *) pdata,
- sizeof(struct hfi_profile_level));
+ hfi = (struct hfi_profile_level *)
+ &pkt->rg_property_data[1];
+ hfi->level = (u32) prop->level;
+ hfi->profile = prop->profile;
+ if (!hfi->profile)
+ hfi->profile = HFI_H264_PROFILE_HIGH;
+ if (!hfi->level)
+ hfi->level = 1;
pkt->size += sizeof(u32) + sizeof(struct hfi_profile_level);
break;
}
case HAL_PARAM_VENC_H264_ENTROPY_CONTROL:
{
struct hfi_h264_entropy_control *hfi;
+ struct hal_h264_entropy_control *prop =
+ (struct hal_h264_entropy_control *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL;
hfi = (struct hfi_h264_entropy_control *)
&pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_h264_entropy_control *) pdata,
- sizeof(struct hfi_h264_entropy_control));
+ switch (prop->entropy_mode) {
+ case HAL_H264_ENTROPY_CAVLC:
+ hfi->cabac_model = HFI_H264_ENTROPY_CAVLC;
+ break;
+ case HAL_H264_ENTROPY_CABAC:
+ hfi->cabac_model = HFI_H264_ENTROPY_CABAC;
+ switch (prop->cabac_model) {
+ case HAL_H264_CABAC_MODEL_0:
+ hfi->cabac_model = HFI_H264_CABAC_MODEL_0;
+ break;
+ case HAL_H264_CABAC_MODEL_1:
+ hfi->cabac_model = HFI_H264_CABAC_MODEL_1;
+ break;
+ case HAL_H264_CABAC_MODEL_2:
+ hfi->cabac_model = HFI_H264_CABAC_MODEL_2;
+ break;
+ default:
+ HAL_MSG_ERROR("Invalid cabac model 0x%x",
+ prop->entropy_mode);
+ break;
+ }
+ break;
+ default:
+ HAL_MSG_ERROR("Invalid entropy selected: 0x%x",
+ prop->cabac_model);
+ break;
+ }
pkt->size += sizeof(u32) + sizeof(
struct hfi_h264_entropy_control);
break;
@@ -1042,8 +1195,28 @@
{
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
- pkt->rg_property_data[1] = (enum HFI_RATE_CONTROL)pdata;
- pkt->size += sizeof(u32) + sizeof(enum HFI_RATE_CONTROL);
+ switch ((enum hal_rate_control)pdata) {
+ case HAL_RATE_CONTROL_OFF:
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF;
+ break;
+ case HAL_RATE_CONTROL_CBR_CFR:
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_CFR;
+ break;
+ case HAL_RATE_CONTROL_CBR_VFR:
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_VFR;
+ break;
+ case HAL_RATE_CONTROL_VBR_CFR:
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_CFR;
+ break;
+ case HAL_RATE_CONTROL_VBR_VFR:
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_VFR;
+ break;
+ default:
+ HAL_MSG_ERROR("Invalid Rate control setting: 0x%x",
+ (int) pdata);
+ break;
+ }
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION:
@@ -1056,8 +1229,7 @@
hfi->time_increment_resolution =
((struct hal_mpeg4_time_resolution *)pdata)->
time_increment_resolution;
- pkt->size += sizeof(u32) + sizeof(
- struct hfi_mpeg4_time_resolution);
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION:
@@ -1066,20 +1238,36 @@
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION;
hfi = (struct hfi_mpeg4_header_extension *)
- &pkt->rg_property_data[1];
+ &pkt->rg_property_data[1];
hfi->header_extension = (u32) pdata;
- pkt->size += sizeof(u32) +
- sizeof(struct hfi_mpeg4_header_extension);
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_VENC_H264_DEBLOCK_CONTROL:
{
struct hfi_h264_db_control *hfi;
+ struct hal_h264_db_control *prop =
+ (struct hal_h264_db_control *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL;
hfi = (struct hfi_h264_db_control *) &pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_h264_db_control *) pdata,
- sizeof(struct hfi_h264_db_control));
+ switch (prop->mode) {
+ case HAL_H264_DB_MODE_DISABLE:
+ hfi->mode = HFI_H264_DB_MODE_DISABLE;
+ break;
+ case HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY:
+ hfi->mode = HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
+ break;
+ case HAL_H264_DB_MODE_ALL_BOUNDARY:
+ hfi->mode = HFI_H264_DB_MODE_ALL_BOUNDARY;
+ break;
+ default:
+ HAL_MSG_ERROR("Invalid deblocking mode: 0x%x",
+ prop->mode);
+ break;
+ }
+ hfi->slice_alpha_offset = prop->slice_alpha_offset;
+ hfi->slice_beta_offset = prop->slice_beta_offset;
pkt->size += sizeof(u32) +
sizeof(struct hfi_h264_db_control);
break;
@@ -1090,11 +1278,10 @@
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF;
hfi = (struct hfi_temporal_spatial_tradeoff *)
- &pkt->rg_property_data[1];
+ &pkt->rg_property_data[1];
hfi->ts_factor = ((struct hfi_temporal_spatial_tradeoff *)
pdata)->ts_factor;
- pkt->size += sizeof(u32) +
- sizeof(struct hfi_temporal_spatial_tradeoff);
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_PARAM_VENC_SESSION_QP:
@@ -1125,7 +1312,7 @@
pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD;
hfi = (struct hfi_idr_period *) &pkt->rg_property_data[1];
hfi->idr_period = ((struct hfi_idr_period *) pdata)->idr_period;
- pkt->size += sizeof(u32) + sizeof(struct hfi_idr_period);
+ pkt->size += sizeof(u32) * 2;
break;
}
case HAL_CONFIG_VPE_OPERATIONS:
@@ -1133,25 +1320,67 @@
case HAL_PARAM_VENC_INTRA_REFRESH:
{
struct hfi_intra_refresh *hfi;
+ struct hal_intra_refresh *prop =
+ (struct hal_intra_refresh *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH;
hfi = (struct hfi_intra_refresh *) &pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_intra_refresh *) pdata,
- sizeof(struct hfi_intra_refresh));
+ switch (prop->mode) {
+ case HAL_INTRA_REFRESH_NONE:
+ hfi->mode = HFI_INTRA_REFRESH_NONE;
+ break;
+ case HAL_INTRA_REFRESH_ADAPTIVE:
+ hfi->mode = HFI_INTRA_REFRESH_ADAPTIVE;
+ break;
+ case HAL_INTRA_REFRESH_CYCLIC:
+ hfi->mode = HFI_INTRA_REFRESH_CYCLIC;
+ break;
+ case HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE:
+ hfi->mode = HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE;
+ break;
+ case HAL_INTRA_REFRESH_RANDOM:
+ hfi->mode = HFI_INTRA_REFRESH_RANDOM;
+ break;
+ default:
+ HAL_MSG_ERROR("Invalid intra refresh setting: 0x%x",
+ prop->mode);
+ break;
+ }
+ hfi->air_mbs = prop->air_mbs;
+ hfi->air_ref = prop->air_ref;
+ hfi->cir_mbs = prop->cir_mbs;
pkt->size += sizeof(u32) + sizeof(struct hfi_intra_refresh);
break;
}
case HAL_PARAM_VENC_MULTI_SLICE_CONTROL:
{
struct hfi_multi_slice_control *hfi;
+ struct hal_multi_slice_control *prop =
+ (struct hal_multi_slice_control *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL;
hfi = (struct hfi_multi_slice_control *)
- &pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_multi_slice_control *) pdata,
- sizeof(struct hfi_multi_slice_control));
+ &pkt->rg_property_data[1];
+ switch (prop->multi_slice) {
+ case HAL_MULTI_SLICE_OFF:
+ hfi->multi_slice = HFI_MULTI_SLICE_OFF;
+ break;
+ case HAL_MULTI_SLICE_GOB:
+ hfi->multi_slice = HFI_MULTI_SLICE_GOB;
+ break;
+ case HAL_MULTI_SLICE_BY_MB_COUNT:
+ hfi->multi_slice = HFI_MULTI_SLICE_BY_MB_COUNT;
+ break;
+ case HAL_MULTI_SLICE_BY_BYTE_COUNT:
+ hfi->multi_slice = HFI_MULTI_SLICE_BY_BYTE_COUNT;
+ break;
+ default:
+ HAL_MSG_ERROR("Invalid slice settings: 0x%x",
+ prop->multi_slice);
+ break;
+ }
pkt->size += sizeof(u32) + sizeof(struct
- hfi_multi_slice_control);
+ hfi_multi_slice_control);
break;
}
case HAL_CONFIG_VPE_DEINTERLACE:
@@ -1161,8 +1390,8 @@
struct hfi_debug_config *hfi;
pkt->rg_property_data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG;
hfi = (struct hfi_debug_config *) &pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_debug_config *) pdata,
- sizeof(struct hfi_debug_config));
+ hfi->debug_config = ((struct hal_debug_config *)
+ pdata)->debug_config;
pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
sizeof(struct hfi_debug_config);
break;
@@ -1353,7 +1582,7 @@
new_session->device = dev;
list_add_tail(&new_session->list, &dev->sess_head);
pkt.size = sizeof(struct hfi_cmd_sys_session_init_packet);
- pkt.packet = HFI_CMD_SYS_SESSION_INIT;
+ pkt.packet_type = HFI_CMD_SYS_SESSION_INIT;
pkt.session_id = (u32) new_session;
pkt.session_domain = session_type;
pkt.session_codec = codec_type;
@@ -1363,7 +1592,7 @@
}
static int vidc_hal_send_session_cmd(void *session_id,
- enum HFI_COMMAND pkt_type)
+ int pkt_type)
{
struct vidc_hal_session_cmd_pkt pkt;
int rc = 0;
@@ -1400,6 +1629,7 @@
int vidc_hal_session_set_buffers(void *sess,
struct vidc_buffer_addr_info *buffer_info)
{
+ u32 buffer;
struct hfi_cmd_session_set_buffers_packet *pkt;
u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
int rc = 0;
@@ -1430,7 +1660,7 @@
if ((buffer_info->buffer_type == HAL_BUFFER_OUTPUT) ||
(buffer_info->buffer_type == HAL_BUFFER_OUTPUT2)) {
struct hfi_buffer_info *buff;
- pkt->extradata_size = buffer_info->extradata_size;
+ pkt->extra_data_size = buffer_info->extradata_size;
pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
sizeof(u32) + ((buffer_info->num_buffers) *
sizeof(struct hfi_buffer_info));
@@ -1438,25 +1668,23 @@
for (i = 0; i < pkt->num_buffers; i++) {
buff->buffer_addr =
buffer_info->align_device_addr;
- buff->extradata_addr =
+ buff->extra_data_addr =
buffer_info->extradata_addr;
}
} else {
- pkt->extradata_size = 0;
+ pkt->extra_data_size = 0;
pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
((buffer_info->num_buffers - 1) * sizeof(u32));
for (i = 0; i < pkt->num_buffers; i++)
pkt->rg_buffer_info[i] =
buffer_info->align_device_addr;
}
-
- if (buffer_info->buffer_type == HAL_BUFFER_INTERNAL_SCRATCH)
- pkt->buffer_type = HFI_BUFFER_INTERNAL_SCRATCH;
- else if (buffer_info->buffer_type == HAL_BUFFER_INTERNAL_PERSIST)
- pkt->buffer_type = HFI_BUFFER_INTERNAL_PERSIST;
+ buffer = get_hfi_buffer(buffer_info->buffer_type);
+ if (buffer)
+ pkt->buffer_type = buffer;
else
- pkt->buffer_type = (enum HFI_BUFFER) buffer_info->buffer_type;
-
+ return -EINVAL;
+ HAL_MSG_INFO("set buffers: 0x%x", buffer_info->buffer_type);
if (vidc_hal_iface_cmdq_write(session->device, pkt))
rc = -ENOTEMPTY;
return rc;
@@ -1465,6 +1693,7 @@
int vidc_hal_session_release_buffers(void *sess,
struct vidc_buffer_addr_info *buffer_info)
{
+ u32 buffer;
struct hfi_cmd_session_release_buffer_packet *pkt;
u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
int rc = 0;
@@ -1486,7 +1715,6 @@
((buffer_info->num_buffers - 1) * sizeof(u32));
pkt->packet_type = HFI_CMD_SESSION_RELEASE_BUFFERS;
pkt->session_id = (u32) session;
- pkt->buffer_type = (enum HFI_BUFFER) buffer_info->buffer_type;
pkt->buffer_size = buffer_info->buffer_size;
pkt->num_buffers = buffer_info->num_buffers;
@@ -1497,10 +1725,10 @@
for (i = 0; i < pkt->num_buffers; i++) {
buff->buffer_addr =
buffer_info->align_device_addr;
- buff->extradata_addr =
+ buff->extra_data_addr =
buffer_info->extradata_addr;
}
- pkt->extradata_size = buffer_info->extradata_size;
+ pkt->extra_data_size = buffer_info->extradata_size;
pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
sizeof(u32) + ((buffer_info->num_buffers) *
sizeof(struct hfi_buffer_info));
@@ -1508,11 +1736,16 @@
for (i = 0; i < pkt->num_buffers; i++)
pkt->rg_buffer_info[i] =
buffer_info->align_device_addr;
- pkt->extradata_size = 0;
+ pkt->extra_data_size = 0;
pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
((buffer_info->num_buffers - 1) * sizeof(u32));
}
-
+ buffer = get_hfi_buffer(buffer_info->buffer_type);
+ if (buffer)
+ pkt->buffer_type = buffer;
+ else
+ return -EINVAL;
+ HAL_MSG_INFO("Release buffers: 0x%x", buffer_info->buffer_type);
if (vidc_hal_iface_cmdq_write(session->device, pkt))
rc = -ENOTEMPTY;
return rc;
@@ -1572,8 +1805,8 @@
struct hfi_cmd_session_empty_buffer_compressed_packet);
pkt.packet_type = HFI_CMD_SESSION_EMPTY_BUFFER;
pkt.session_id = (u32) session;
- pkt.timestamp_hi = (int) (((u64)input_frame->timestamp) >> 32);
- pkt.timestamp_lo = (int) input_frame->timestamp;
+ pkt.time_stamp_hi = (int) (((u64)input_frame->timestamp) >> 32);
+ pkt.time_stamp_lo = (int) input_frame->timestamp;
pkt.flags = input_frame->flags;
pkt.mark_target = input_frame->mark_target;
pkt.mark_data = input_frame->mark_data;
@@ -1590,11 +1823,11 @@
pkt;
pkt.size = sizeof(struct
hfi_cmd_session_empty_buffer_uncompressed_plane0_packet);
- pkt.packet = HFI_CMD_SESSION_EMPTY_BUFFER;
+ pkt.packet_type = HFI_CMD_SESSION_EMPTY_BUFFER;
pkt.session_id = (u32) session;
pkt.view_id = 0;
- pkt.timestamp_hi = (u32) (((u64)input_frame->timestamp) >> 32);
- pkt.timestamp_lo = (u32) input_frame->timestamp;
+ pkt.time_stamp_hi = (u32) (((u64)input_frame->timestamp) >> 32);
+ pkt.time_stamp_lo = (u32) input_frame->timestamp;
pkt.flags = input_frame->flags;
pkt.mark_target = input_frame->mark_target;
pkt.mark_data = input_frame->mark_data;
@@ -1734,8 +1967,23 @@
pkt.size = sizeof(struct hfi_cmd_session_flush_packet);
pkt.packet_type = HFI_CMD_SESSION_FLUSH;
pkt.session_id = (u32) session;
- pkt.flush_type = flush_mode;
-
+ switch (flush_mode) {
+ case HAL_FLUSH_INPUT:
+ pkt.flush_type = HFI_FLUSH_INPUT;
+ break;
+ case HAL_FLUSH_OUTPUT:
+ pkt.flush_type = HFI_FLUSH_OUTPUT;
+ break;
+ case HAL_FLUSH_OUTPUT2:
+ pkt.flush_type = HFI_FLUSH_OUTPUT2;
+ break;
+ case HAL_FLUSH_ALL:
+ pkt.flush_type = HFI_FLUSH_ALL;
+ break;
+ default:
+ HAL_MSG_ERROR("Invalid flush mode: 0x%x\n", flush_mode);
+ break;
+ }
if (vidc_hal_iface_cmdq_write(session->device, &pkt))
rc = -ENOTEMPTY;
return rc;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.h b/drivers/media/video/msm_vidc/vidc_hal.h
index 15441f4..a36d7f3 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.h
+++ b/drivers/media/video/msm_vidc/vidc_hal.h
@@ -11,27 +11,28 @@
*
*/
-#ifndef __VIDC_HAL_H__
-#define __VIDC_HAL_H__
+#ifndef __H_VIDC_HAL_H__
+#define __H_VIDC_HAL_H__
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include "vidc_hal_api.h"
#include "msm_smem.h"
+#include "vidc_hal_helper.h"
#ifdef HAL_MSG_LOG
-#define HAL_MSG_LOW(x...) pr_debug(KERN_INFO x)
-#define HAL_MSG_MEDIUM(x...) pr_debug(KERN_INFO x)
-#define HAL_MSG_HIGH(x...) pr_debug(KERN_INFO x)
+#define HAL_MSG_LOW(x...) pr_info(KERN_INFO x)
+#define HAL_MSG_MEDIUM(x...) pr_info(KERN_INFO x)
+#define HAL_MSG_HIGH(x...) pr_info(KERN_INFO x)
#else
#define HAL_MSG_LOW(x...)
#define HAL_MSG_MEDIUM(x...)
#define HAL_MSG_HIGH(x...)
#endif
-#define HAL_MSG_ERROR(x...) pr_err(KERN_INFO x)
-#define HAL_MSG_FATAL(x...) pr_err(KERN_INFO x)
-#define HAL_MSG_INFO(x...) pr_info(KERN_INFO x)
+#define HAL_MSG_ERROR(x...) pr_err(KERN_INFO x)
+#define HAL_MSG_FATAL(x...) pr_err(KERN_INFO x)
+#define HAL_MSG_INFO(x...) pr_info(KERN_INFO x)
#define HFI_MASK_QHDR_TX_TYPE 0xFF000000
#define HFI_MASK_QHDR_RX_TYPE 0x00FF0000
@@ -87,7 +88,7 @@
#define VIDC_IFACEQ_TABLE_SIZE (sizeof(struct hfi_queue_table_header) \
+ sizeof(struct hfi_queue_header) * VIDC_IFACEQ_NUMQ)
-#define VIDC_IFACEQ_QUEUE_SIZE (VIDC_IFACEQ_MAX_PKT_SIZE * \
+#define VIDC_IFACEQ_QUEUE_SIZE (VIDC_IFACEQ_MAX_PKT_SIZE * \
VIDC_IFACEQ_MAX_BUF_COUNT * VIDC_IFACE_MAX_PARALLEL_CLNTS)
#define VIDC_IFACEQ_GET_QHDR_START_ADDR(ptr, i) \
@@ -107,409 +108,162 @@
VIDC_HWREG_HVI_SOFTINTEN = 0xA,
};
-enum HFI_EVENT {
- HFI_EVENT_SYS_ERROR,
- HFI_EVENT_SESSION_ERROR,
- HFI_EVENT_SESSION_SEQUENCE_CHANGED,
- HFI_EVENT_SESSION_PROPERTY_CHANGED,
- HFI_UNUSED_EVENT = 0x10000000,
-};
+#define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3)
+#define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4)
-enum HFI_EVENT_DATA_SEQUENCE_CHANGED {
- HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES,
- HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES,
- HFI_UNUSED_SEQCHG = 0x10000000,
-};
+#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES \
+ (HFI_OX_BASE + 0x1)
+#define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES \
+ (HFI_OX_BASE + 0x2)
-#define HFI_BUFFERFLAG_EOS 0x00000001
-#define HFI_BUFFERFLAG_STARTTIME 0x00000002
-#define HFI_BUFFERFLAG_DECODEONLY 0x00000004
-#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008
-#define HFI_BUFFERFLAG_ENDOFFRAME 0x00000010
-#define HFI_BUFFERFLAG_SYNCFRAME 0x00000020
-#define HFI_BUFFERFLAG_EXTRADATA 0x00000040
-#define HFI_BUFFERFLAG_CODECCONFIG 0x00000080
-#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
-#define HFI_BUFFERFLAG_READONLY 0x00000200
-#define HFI_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
+#define HFI_BUFFERFLAG_EOS 0x00000001
+#define HFI_BUFFERFLAG_STARTTIME 0x00000002
+#define HFI_BUFFERFLAG_DECODEONLY 0x00000004
+#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008
+#define HFI_BUFFERFLAG_ENDOFFRAME 0x00000010
+#define HFI_BUFFERFLAG_SYNCFRAME 0x00000020
+#define HFI_BUFFERFLAG_EXTRADATA 0x00000040
+#define HFI_BUFFERFLAG_CODECCONFIG 0x00000080
+#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
+#define HFI_BUFFERFLAG_READONLY 0x00000200
+#define HFI_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
-enum HFI_ERROR {
- HFI_ERR_NONE = 0,
- HFI_ERR_SYS_UNKNOWN = 0x80000001,
- HFI_ERR_SYS_FATAL = 0x80000002,
- HFI_ERR_SYS_INVALID_PARAMETER = 0x80000003,
- HFI_ERR_SYS_VERSION_MISMATCH = 0x80000004,
- HFI_ERR_SYS_INSUFFICIENT_RESOURCES = 0x80000005,
- HFI_ERR_SYS_MAX_SESSIONS_REACHED = 0x80000006,
- HFI_ERR_SYS_UNSUPPORTED_CODEC = 0x80000007,
- HFI_ERR_SYS_SESSION_IN_USE = 0x80000008,
- HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE = 0x80000009,
- HFI_ERR_SYS_UNSUPPORTED_DOMAIN = 0x8000000A,
- HFI_ERR_SESSION_START_UNUSED = 0x80001000,
- HFI_ERR_SESSION_UNKNOWN = 0x80001001,
- HFI_ERR_SESSION_FATAL = 0x80001002,
- HFI_ERR_SESSION_INVALID_PARAMETER = 0x80001003,
- HFI_ERR_SESSION_BAD_POINTER = 0x80001004,
- HFI_ERR_SESSION_INVALID_SESSION_ID = 0x80001005,
- HFI_ERR_SESSION_INVALID_STREAM_ID = 0x80001006,
- HFI_ERR_SESSION_INCORRECT_STATE_OPERATION = 0x80001007,
- HFI_ERR_SESSION_UNSUPPORTED_PROPERTY = 0x80001008,
- HFI_ERR_SESSION_UNSUPPORTED_SETTING = 0x80001009,
- HFI_ERR_SESSION_INSUFFICIENT_RESOURCES = 0x8000100A,
- HFI_ERR_SESSION_STREAM_CORRUPT = 0x8000100B,
- HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED = 0x8000100C,
- HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED = 0x8000100D,
- HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING = 0x8000100E,
- HFI_ERR_SESSION_SAME_STATE_OPERATION = 0x8000100F,
- HFI_UNUSED_ERR = 0x10000000,
-};
+#define HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING \
+ (HFI_OX_BASE + 0x1001)
+#define HFI_ERR_SESSION_SAME_STATE_OPERATION \
+ (HFI_OX_BASE + 0x1002)
+#define HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED \
+ (HFI_OX_BASE + 0x1003)
-enum HFI_DOMAIN {
- HFI_VIDEO_DOMAIN_VPE,
- HFI_VIDEO_DOMAIN_ENCODER,
- HFI_VIDEO_DOMAIN_DECODER,
- HFI_UNUSED_DOMAIN = 0x10000000,
-};
+#define HFI_BUFFER_INTERNAL_SCRATCH (HFI_OX_BASE + 0x1)
+#define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2)
+#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3)
+#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
-enum HFI_VIDEO_CODEC {
- HFI_VIDEO_CODEC_UNKNOWN = 0x00000000,
- HFI_VIDEO_CODEC_H264 = 0x00000002,
- HFI_VIDEO_CODEC_H263 = 0x00000004,
- HFI_VIDEO_CODEC_MPEG1 = 0x00000008,
- HFI_VIDEO_CODEC_MPEG2 = 0x00000010,
- HFI_VIDEO_CODEC_MPEG4 = 0x00000020,
- HFI_VIDEO_CODEC_DIVX_311 = 0x00000040,
- HFI_VIDEO_CODEC_DIVX = 0x00000080,
- HFI_VIDEO_CODEC_VC1 = 0x00000100,
- HFI_VIDEO_CODEC_SPARK = 0x00000200,
- HFI_VIDEO_CODEC_VP6 = 0x00000400,
- HFI_VIDEO_CODEC_VP7 = 0x00000800,
- HFI_VIDEO_CODEC_VP8 = 0x00001000,
- HFI_UNUSED_CODEC = 0x10000000,
-};
+#define HFI_BUFFER_MODE_STATIC (HFI_OX_BASE + 0x1)
+#define HFI_BUFFER_MODE_RING (HFI_OX_BASE + 0x2)
-enum HFI_H263_PROFILE {
- HFI_H263_PROFILE_BASELINE = 0x00000001,
- HFI_H263_PROFILE_H320CODING = 0x00000002,
- HFI_H263_PROFILE_BACKWARDCOMPATIBLE = 0x00000004,
- HFI_H263_PROFILE_ISWV2 = 0x00000008,
- HFI_H263_PROFILE_ISWV3 = 0x00000010,
- HFI_H263_PROFILE_HIGHCOMPRESSION = 0x00000020,
- HFI_H263_PROFILE_INTERNET = 0x00000040,
- HFI_H263_PROFILE_INTERLACE = 0x00000080,
- HFI_H263_PROFILE_HIGHLATENCY = 0x00000100,
- HFI_UNUSED_H263_PROFILE = 0x10000000,
-};
+#define HFI_FLUSH_INPUT (HFI_OX_BASE + 0x1)
+#define HFI_FLUSH_OUTPUT (HFI_OX_BASE + 0x2)
+#define HFI_FLUSH_OUTPUT2 (HFI_OX_BASE + 0x3)
+#define HFI_FLUSH_ALL (HFI_OX_BASE + 0x4)
-enum HFI_H263_LEVEL {
- HFI_H263_LEVEL_10 = 0x00000001,
- HFI_H263_LEVEL_20 = 0x00000002,
- HFI_H263_LEVEL_30 = 0x00000004,
- HFI_H263_LEVEL_40 = 0x00000008,
- HFI_H263_LEVEL_45 = 0x00000010,
- HFI_H263_LEVEL_50 = 0x00000020,
- HFI_H263_LEVEL_60 = 0x00000040,
- HFI_H263_LEVEL_70 = 0x00000080,
- HFI_UNUSED_H263_LEVEL = 0x10000000,
-};
+#define HFI_EXTRADATA_NONE 0x00000000
+#define HFI_EXTRADATA_MB_QUANTIZATION 0x00000001
+#define HFI_EXTRADATA_INTERLACE_VIDEO 0x00000002
+#define HFI_EXTRADATA_VC1_FRAMEDISP 0x00000003
+#define HFI_EXTRADATA_VC1_SEQDISP 0x00000004
+#define HFI_EXTRADATA_TIMESTAMP 0x00000005
+#define HFI_EXTRADATA_S3D_FRAME_PACKING 0x00000006
+#define HFI_EXTRADATA_MULTISLICE_INFO 0x7F100000
+#define HFI_EXTRADATA_NUM_CONCEALED_MB 0x7F100001
+#define HFI_EXTRADATA_INDEX 0x7F100002
+#define HFI_EXTRADATA_METADATA_FILLER 0x7FE00002
-enum HFI_MPEG2_PROFILE {
- HFI_MPEG2_PROFILE_SIMPLE = 0x00000001,
- HFI_MPEG2_PROFILE_MAIN = 0x00000002,
- HFI_MPEG2_PROFILE_422 = 0x00000004,
- HFI_MPEG2_PROFILE_SNR = 0x00000008,
- HFI_MPEG2_PROFILE_SPATIAL = 0x00000010,
- HFI_MPEG2_PROFILE_HIGH = 0x00000020,
- HFI_UNUSED_MPEG2_PROFILE = 0x10000000,
-};
-
-enum HFI_MPEG2_LEVEL {
- HFI_MPEG2_LEVEL_LL = 0x00000001,
- HFI_MPEG2_LEVEL_ML = 0x00000002,
- HFI_MPEG2_LEVEL_H14 = 0x00000004,
- HFI_MPEG2_LEVEL_HL = 0x00000008,
- HFI_UNUSED_MEPG2_LEVEL = 0x10000000,
-};
-
-enum HFI_MPEG4_PROFILE {
- HFI_MPEG4_PROFILE_SIMPLE = 0x00000001,
- HFI_MPEG4_PROFILE_SIMPLESCALABLE = 0x00000002,
- HFI_MPEG4_PROFILE_CORE = 0x00000004,
- HFI_MPEG4_PROFILE_MAIN = 0x00000008,
- HFI_MPEG4_PROFILE_NBIT = 0x00000010,
- HFI_MPEG4_PROFILE_SCALABLETEXTURE = 0x00000020,
- HFI_MPEG4_PROFILE_SIMPLEFACE = 0x00000040,
- HFI_MPEG4_PROFILE_SIMPLEFBA = 0x00000080,
- HFI_MPEG4_PROFILE_BASICANIMATED = 0x00000100,
- HFI_MPEG4_PROFILE_HYBRID = 0x00000200,
- HFI_MPEG4_PROFILE_ADVANCEDREALTIME = 0x00000400,
- HFI_MPEG4_PROFILE_CORESCALABLE = 0x00000800,
- HFI_MPEG4_PROFILE_ADVANCEDCODING = 0x00001000,
- HFI_MPEG4_PROFILE_ADVANCEDCORE = 0x00002000,
- HFI_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
- HFI_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00008000,
- HFI_UNUSED_MPEG4_PROFILE = 0x10000000,
-};
-
-enum HFI_MPEG4_LEVEL {
- HFI_MPEG4_LEVEL_0 = 0x00000001,
- HFI_MPEG4_LEVEL_0b = 0x00000002,
- HFI_MPEG4_LEVEL_1 = 0x00000004,
- HFI_MPEG4_LEVEL_2 = 0x00000008,
- HFI_MPEG4_LEVEL_3 = 0x00000010,
- HFI_MPEG4_LEVEL_4 = 0x00000020,
- HFI_MPEG4_LEVEL_4a = 0x00000040,
- HFI_MPEG4_LEVEL_5 = 0x00000080,
- HFI_MPEG4_LEVEL_VENDOR_START_UNUSED = 0x7F000000,
- HFI_MPEG4_LEVEL_6 = 0x7F000001,
- HFI_MPEG4_LEVEL_7 = 0x7F000002,
- HFI_MPEG4_LEVEL_8 = 0x7F000003,
- HFI_MPEG4_LEVEL_9 = 0x7F000004,
- HFI_MPEG4_LEVEL_3b = 0x7F000005,
- HFI_UNUSED_MPEG4_LEVEL = 0x10000000,
-};
-
-enum HFI_H264_PROFILE {
- HFI_H264_PROFILE_BASELINE = 0x00000001,
- HFI_H264_PROFILE_MAIN = 0x00000002,
- HFI_H264_PROFILE_EXTENDED = 0x00000004,
- HFI_H264_PROFILE_HIGH = 0x00000008,
- HFI_H264_PROFILE_HIGH10 = 0x00000010,
- HFI_H264_PROFILE_HIGH422 = 0x00000020,
- HFI_H264_PROFILE_HIGH444 = 0x00000040,
- HFI_H264_PROFILE_STEREO_HIGH = 0x00000080,
- HFI_H264_PROFILE_MV_HIGH = 0x00000100,
- HFI_UNUSED_H264_PROFILE = 0x10000000,
-};
-
-enum HFI_H264_LEVEL {
- HFI_H264_LEVEL_1 = 0x00000001,
- HFI_H264_LEVEL_1b = 0x00000002,
- HFI_H264_LEVEL_11 = 0x00000004,
- HFI_H264_LEVEL_12 = 0x00000008,
- HFI_H264_LEVEL_13 = 0x00000010,
- HFI_H264_LEVEL_2 = 0x00000020,
- HFI_H264_LEVEL_21 = 0x00000040,
- HFI_H264_LEVEL_22 = 0x00000080,
- HFI_H264_LEVEL_3 = 0x00000100,
- HFI_H264_LEVEL_31 = 0x00000200,
- HFI_H264_LEVEL_32 = 0x00000400,
- HFI_H264_LEVEL_4 = 0x00000800,
- HFI_H264_LEVEL_41 = 0x00001000,
- HFI_H264_LEVEL_42 = 0x00002000,
- HFI_H264_LEVEL_5 = 0x00004000,
- HFI_H264_LEVEL_51 = 0x00008000,
- HFI_UNUSED_H264_LEVEL = 0x10000000,
-};
-
-enum HFI_VPX_PROFILE {
- HFI_VPX_PROFILE_SIMPLE = 0x00000001,
- HFI_VPX_PROFILE_ADVANCED = 0x00000002,
- HFI_VPX_PROFILE_VERSION_0 = 0x00000004,
- HFI_VPX_PROFILE_VERSION_1 = 0x00000008,
- HFI_VPX_PROFILE_VERSION_2 = 0x00000010,
- HFI_VPX_PROFILE_VERSION_3 = 0x00000020,
- HFI_VPX_PROFILE_UNUSED = 0x10000000,
-};
-
-enum HFI_VC1_PROFILE {
- HFI_VC1_PROFILE_SIMPLE = 0x00000001,
- HFI_VC1_PROFILE_MAIN = 0x00000002,
- HFI_VC1_PROFILE_ADVANCED = 0x00000004,
- HFI_UNUSED_VC1_PROFILE = 0x10000000,
-};
-
-enum HFI_VC1_LEVEL {
- HFI_VC1_LEVEL_LOW = 0x00000001,
- HFI_VC1_LEVEL_MEDIUM = 0x00000002,
- HFI_VC1_LEVEL_HIGH = 0x00000004,
- HFI_VC1_LEVEL_0 = 0x00000008,
- HFI_VC1_LEVEL_1 = 0x00000010,
- HFI_VC1_LEVEL_2 = 0x00000020,
- HFI_VC1_LEVEL_3 = 0x00000040,
- HFI_VC1_LEVEL_4 = 0x00000080,
- HFI_UNUSED_VC1_LEVEL = 0x10000000,
-};
-
-enum HFI_DIVX_FORMAT {
- HFI_DIVX_FORMAT_4,
- HFI_DIVX_FORMAT_5,
- HFI_DIVX_FORMAT_6,
- HFI_UNUSED_DIVX_FORMAT = 0x10000000,
-};
-
-enum HFI_DIVX_PROFILE {
- HFI_DIVX_PROFILE_QMOBILE = 0x00000001,
- HFI_DIVX_PROFILE_MOBILE = 0x00000002,
- HFI_DIVX_PROFILE_MT = 0x00000004,
- HFI_DIVX_PROFILE_HT = 0x00000008,
- HFI_DIVX_PROFILE_HD = 0x00000010,
- HFI_UNUSED_DIVX_PROFILE = 0x10000000,
-};
-
-enum HFI_BUFFER {
- HFI_BUFFER_INPUT,
- HFI_BUFFER_OUTPUT,
- HFI_BUFFER_OUTPUT2,
- HFI_BUFFER_EXTRADATA_INPUT,
- HFI_BUFFER_EXTRADATA_OUTPUT,
- HFI_BUFFER_EXTRADATA_OUTPUT2,
- HFI_BUFFER_INTERNAL_SCRATCH = 0x7F000001,
- HFI_BUFFER_INTERNAL_PERSIST = 0x7F000002,
- HFI_UNUSED_BUFFER = 0x10000000,
-};
-
-enum HFI_BUFFER_MODE {
- HFI_BUFFER_MODE_STATIC,
- HFI_BUFFER_MODE_RING,
- HFI_UNUSED_BUFFER_MODE = 0x10000000,
-};
-
-enum HFI_FLUSH {
- HFI_FLUSH_INPUT,
- HFI_FLUSH_OUTPUT,
- HFI_FLUSH_OUTPUT2,
- HFI_FLUSH_ALL,
- HFI_UNUSED_FLUSH = 0x10000000,
-};
-
-enum HFI_EXTRADATA {
- HFI_EXTRADATA_NONE = 0x00000000,
- HFI_EXTRADATA_MB_QUANTIZATION = 0x00000001,
- HFI_EXTRADATA_INTERLACE_VIDEO = 0x00000002,
- HFI_EXTRADATA_VC1_FRAMEDISP = 0x00000003,
- HFI_EXTRADATA_VC1_SEQDISP = 0x00000004,
- HFI_EXTRADATA_TIMESTAMP = 0x00000005,
- HFI_EXTRADATA_MULTISLICE_INFO = 0x7F100000,
- HFI_EXTRADATA_NUM_CONCEALED_MB = 0x7F100001,
- HFI_EXTRADATA_INDEX = 0x7F100002,
- HFI_EXTRADATA_METADATA_FILLER = 0x7FE00002,
- HFI_UNUSED_EXTRADATA = 0x10000000,
-};
-
-enum HFI_EXTRADATA_INDEX_TYPE {
- HFI_INDEX_EXTRADATA_INPUT_CROP = 0x0700000E,
- HFI_INDEX_EXTRADATA_DIGITAL_ZOOM = 0x07000010,
- HFI_INDEX_EXTRADATA_ASPECT_RATIO = 0x7F100003,
-};
+#define HFI_INDEX_EXTRADATA_INPUT_CROP 0x0700000E
+#define HFI_INDEX_EXTRADATA_DIGITAL_ZOOM 0x07000010
+#define HFI_INDEX_EXTRADATA_ASPECT_RATIO 0x7F100003
struct hfi_extradata_header {
u32 size;
u32 version;
- u32 port_tndex;
- enum HFI_EXTRADATA type;
+ u32 port_index;
+ u32 type;
u32 data_size;
u8 rg_data[1];
};
-enum HFI_INTERLACE_FORMAT {
- HFI_INTERLACE_FRAME_PROGRESSIVE = 0x01,
- HFI_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST = 0x02,
- HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04,
- HFI_INTERLACE_FRAME_TOPFIELDFIRST = 0x08,
- HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10,
- HFI_UNUSED_INTERLACE = 0x10000000,
-};
+#define HFI_INTERLACE_FRAME_PROGRESSIVE 0x01
+#define HFI_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST 0x02
+#define HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST 0x04
+#define HFI_INTERLACE_FRAME_TOPFIELDFIRST 0x08
+#define HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST 0x10
-enum HFI_PROPERTY {
- HFI_PROPERTY_SYS_UNUSED = 0x08000000,
- HFI_PROPERTY_SYS_IDLE_INDICATOR,
- HFI_PROPERTY_SYS_DEBUG_CONFIG,
- HFI_PROPERTY_SYS_RESOURCE_OCMEM_REQUIREMENT_INFO,
- HFI_PROPERTY_PARAM_UNUSED = 0x04000000,
- HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL,
- HFI_PROPERTY_PARAM_FRAME_SIZE,
- HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT,
- HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED,
- HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO,
- HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO,
- HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED,
- HFI_PROPERTY_PARAM_CHROMA_SITE,
- HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG,
- HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT,
- HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED,
- HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED,
- HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED,
- HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT,
- HFI_PROPERTY_PARAM_MULTI_VIEW_FORMAT,
- HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED,
- HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE,
- HFI_PROPERTY_PARAM_CODEC_SUPPORTED,
- HFI_PROPERTY_PARAM_DIVX_FORMAT,
+#define HFI_PROPERTY_SYS_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000)
+#define HFI_PROPERTY_SYS_IDLE_INDICATOR \
+ (HFI_PROPERTY_SYS_OX_START + 0x001)
- HFI_PROPERTY_CONFIG_UNUSED = 0x02000000,
- HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS,
- HFI_PROPERTY_CONFIG_REALTIME,
- HFI_PROPERTY_CONFIG_PRIORITY,
- HFI_PROPERTY_CONFIG_BATCH_INFO,
- HFI_PROPERTY_CONFIG_FRAME_RATE,
+#define HFI_PROPERTY_PARAM_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x1000)
+#define HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL \
+ (HFI_PROPERTY_PARAM_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO \
+ (HFI_PROPERTY_PARAM_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED \
+ (HFI_PROPERTY_PARAM_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_CHROMA_SITE \
+(HFI_PROPERTY_PARAM_OX_START + 0x004)
+#define HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG \
+ (HFI_PROPERTY_PARAM_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE \
+ (HFI_PROPERTY_PARAM_OX_START + 0x006)
+#define HFI_PROPERTY_PARAM_DIVX_FORMAT \
+ (HFI_PROPERTY_PARAM_OX_START + 0x007)
- HFI_PROPERTY_PARAM_VDEC_UNUSED = 0x01000000,
- HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER,
- HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT,
- HFI_PROPERTY_PARAM_VDEC_MULTI_VIEW_SELECT,
- HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE,
- HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM,
- HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER,
- HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION,
- HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB,
- HFI_PROPERTY_PARAM_VDEC_H264_ENTROPY_SWITCHING,
- HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO,
+#define HFI_PROPERTY_CONFIG_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000)
+#define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x001)
+#define HFI_PROPERTY_CONFIG_REALTIME \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x002)
+#define HFI_PROPERTY_CONFIG_PRIORITY \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x003)
+#define HFI_PROPERTY_CONFIG_BATCH_INFO \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x004)
- HFI_PROPERTY_CONFIG_VDEC_UNUSED = 0x00800000,
- HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
- HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING,
- HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP,
+#define HFI_PROPERTY_PARAM_VDEC_OX_START \
+ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x3000)
+#define HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT\
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_VDEC_MULTI_VIEW_SELECT \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x004)
+#define HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x006)
+#define HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x007)
+#define HFI_PROPERTY_PARAM_VDEC_H264_ENTROPY_SWITCHING \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x008)
+#define HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO\
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x009)
- HFI_PROPERTY_PARAM_VENC_UNUSED = 0x00400000,
- HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE,
- HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL,
- HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL,
- HFI_PROPERTY_PARAM_VENC_RATE_CONTROL,
- HFI_PROPERTY_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF,
- HFI_PROPERTY_PARAM_VENC_SESSION_QP,
- HFI_PROPERTY_PARAM_VENC_MPEG4_AC_PREDICTION,
- HFI_PROPERTY_PARAM_VENC_MPEG4_DATA_PARTITIONING,
- HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION,
- HFI_PROPERTY_PARAM_VENC_MPEG4_SHORT_HEADER,
- HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION,
- HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO,
- HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH,
- HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL,
+#define HFI_PROPERTY_CONFIG_VDEC_OX_START \
+ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000)
+#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER \
+ (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING \
+ (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x002)
+#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP \
+ (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x003)
- HFI_PROPERTY_CONFIG_VENC_UNUSED = 0x00200000,
- HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE,
- HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD,
- HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD,
- HFI_PROPERTY_CONFIG_VENC_REQUEST_IFRAME,
- HFI_PROPERTY_CONFIG_VENC_TIMESTAMP_SCALE,
- HFI_PROPERTY_PARAM_VENC_MPEG4_QPEL,
- HFI_PROPERTY_PARAM_VENC_ADVANCED,
+#define HFI_PROPERTY_PARAM_VENC_OX_START \
+ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x5000)
+#define HFI_PROPERTY_CONFIG_VENC_OX_START \
+ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
- HFI_PROPERTY_PARAM_VPE_UNUSED = 0x00100000,
-
- HFI_PROPERTY_CONFIG_VPE_UNUSED = 0x00080000,
- HFI_PROPERTY_CONFIG_VPE_DEINTERLACE,
- HFI_PROPERTY_CONFIG_VPE_OPERATIONS,
- HFI_PROPERTY_UNUSED = 0x10000000,
-};
+#define HFI_PROPERTY_PARAM_VPE_OX_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000)
+#define HFI_PROPERTY_CONFIG_VPE_OX_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x8000)
struct hfi_batch_info {
u32 input_batch_count;
u32 output_batch_count;
};
-struct hfi_bitrate {
- u32 bit_rate;
-};
-
struct hfi_buffer_count_actual {
- enum HFI_BUFFER buffer;
+ u32 buffer_type;
u32 buffer_count_actual;
};
struct hfi_buffer_requirements {
- enum HFI_BUFFER buffer;
+ u32 buffer_type;
u32 buffer_size;
u32 buffer_region_size;
u32 buffer_hold_count;
@@ -519,35 +273,12 @@
u32 buffer_alignment;
};
-enum HFI_CAPABILITY {
- HFI_CAPABILITY_FRAME_WIDTH,
- HFI_CAPABILITY_FRAME_HEIGHT,
- HFI_CAPABILITY_MBS_PER_FRAME,
- HFI_CAPABILITY_MBS_PER_SECOND,
- HFI_CAPABILITY_FRAMERATE,
- HFI_CAPABILITY_SCALE_X,
- HFI_CAPABILITY_SCALE_Y,
- HFI_CAPABILITY_BITRATE,
- HFI_UNUSED_CAPABILITY = 0x10000000,
-};
-
-struct hfi_capability_supported {
- enum HFI_CAPABILITY eCapabilityType;
- u32 min;
- u32 max;
- u32 step_size;
-};
-
-struct hfi_capability_supported_INFO {
- u32 num_capabilities;
- struct hfi_capability_supported rg_data[1];
-};
-
-enum HFI_CHROMA_SITE {
- HFI_CHROMA_SITE_0,
- HFI_CHROMA_SITE_1,
- HFI_UNUSED_CHROMA = 0x10000000,
-};
+#define HFI_CHROMA_SITE_0 (HFI_OX_BASE + 0x1)
+#define HFI_CHROMA_SITE_1 (HFI_OX_BASE + 0x2)
+#define HFI_CHROMA_SITE_2 (HFI_OX_BASE + 0x3)
+#define HFI_CHROMA_SITE_3 (HFI_OX_BASE + 0x4)
+#define HFI_CHROMA_SITE_4 (HFI_OX_BASE + 0x5)
+#define HFI_CHROMA_SITE_5 (HFI_OX_BASE + 0x6)
struct hfi_data_payload {
u32 size;
@@ -567,86 +298,17 @@
u32 count;
};
-struct hfi_enable {
- int enable;
-};
-
-enum HFI_H264_DB_MODE {
- HFI_H264_DB_MODE_DISABLE,
- HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY,
- HFI_H264_DB_MODE_ALL_BOUNDARY,
- HFI_UNUSED_H264_DB = 0x10000000,
-};
-
-struct hfi_h264_db_control {
- enum HFI_H264_DB_MODE mode;
- int slice_alpha_offset;
- int slice_beta_offset;
-};
-
-enum HFI_H264_ENTROPY {
- HFI_H264_ENTROPY_CAVLC,
- HFI_H264_ENTROPY_CABAC,
- HFI_UNUSED_ENTROPY = 0x10000000,
-};
-
-enum HFI_H264_CABAC_MODEL {
- HFI_H264_CABAC_MODEL_0,
- HFI_H264_CABAC_MODEL_1,
- HFI_H264_CABAC_MODEL_2,
- HFI_UNUSED_CABAC = 0x10000000,
-};
-
-struct hfi_h264_entropy_control {
- enum HFI_H264_ENTROPY entropy_mode;
- enum HFI_H264_CABAC_MODEL cabac_model;
-};
-
struct hfi_extra_data_header_config {
u32 type;
- enum HFI_BUFFER buffer_type;
+ u32 buffer_type;
u32 version;
u32 port_index;
- u32 client_extradata_id;
-};
-
-struct hfi_frame_rate {
- enum HFI_BUFFER buffer_type;
- u32 frame_rate;
+ u32 client_extra_data_id;
};
struct hfi_interlace_format_supported {
- enum HFI_BUFFER buffer;
- enum HFI_INTERLACE_FORMAT format;
-};
-
-enum hfi_intra_refresh_mode {
- HFI_INTRA_REFRESH_NONE,
- HFI_INTRA_REFRESH_CYCLIC,
- HFI_INTRA_REFRESH_ADAPTIVE,
- HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE,
- HFI_INTRA_REFRESH_RANDOM,
- HFI_UNUSED_INTRA = 0x10000000,
-};
-
-struct hfi_intra_refresh {
- enum hfi_intra_refresh_mode mode;
- u32 air_mbs;
- u32 air_ref;
- u32 cir_mbs;
-};
-
-struct hfi_idr_period {
- u32 idr_period;
-};
-
-struct hfi_intra_period {
- u32 pframes;
- u32 bframes;
-};
-
-struct hfi_timestamp_scale {
- u32 time_stamp_scale;
+ u32 buffer_type;
+ u32 format;
};
struct hfi_mb_error_map {
@@ -659,424 +321,110 @@
u32 size;
};
-struct hfi_mpeg4_header_extension {
- u32 header_extension;
-};
-
-struct hfi_mpeg4_time_resolution {
- u32 time_increment_resolution;
-};
-
-enum HFI_MULTI_SLICE {
- HFI_MULTI_SLICE_OFF,
- HFI_MULTI_SLICE_BY_MB_COUNT,
- HFI_MULTI_SLICE_BY_BYTE_COUNT,
- HFI_MULTI_SLICE_GOB,
- HFI_UNUSED_SLICE = 0x10000000,
-};
-
-struct hfi_multi_slice_control {
- enum HFI_MULTI_SLICE multi_slice;
- u32 slice_size;
-};
-
-struct hfi_multi_stream {
- enum HFI_BUFFER buffer;
- u32 enable;
- u32 width;
- u32 height;
-};
-
-struct hfi_multi_view_format {
- u32 views;
- u32 rg_view_order[1];
-};
-
struct hfi_multi_view_select {
u32 view_index;
};
-enum HFI_NAL_STREAM_FORMAT {
- HFI_NAL_FORMAT_STARTCODES = 0x00000001,
- HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER = 0x00000002,
- HFI_NAL_FORMAT_ONE_BYTE_LENGTH = 0x00000004,
- HFI_NAL_FORMAT_TWO_BYTE_LENGTH = 0x00000008,
- HFI_NAL_FORMAT_FOUR_BYTE_LENGTH = 0x00000010,
- HFI_UNUSED_NAL = 0x10000000,
-};
+#define HFI_PRIORITY_LOW 10
+#define HFI_PRIOIRTY_MEDIUM 20
+#define HFI_PRIORITY_HIGH 30
-struct hfi_nal_stream_format_supported {
- u32 nal_stream_format_supported;
-};
+#define HFI_OUTPUT_ORDER_DISPLAY (HFI_OX_BASE + 0x1)
+#define HFI_OUTPUT_ORDER_DECODE (HFI_OX_BASE + 0x2)
-enum HFI_PICTURE {
- HFI_PICTURE_I = 0x01,
- HFI_PICTURE_P = 0x02,
- HFI_PICTURE_B = 0x04,
- HFI_PICTURE_IDR = 0x7F001000,
- HFI_UNUSED_PICT = 0x10000000,
-};
-
-enum HFI_PRIORITY {
- HFI_PRIORITY_LOW = 10,
- HFI_PRIOIRTY_MEDIUM = 20,
- HFI_PRIORITY_HIGH = 30,
- HFI_UNUSED_PRIORITY = 0x10000000,
-};
-
-struct hfi_profile_level {
- u32 profile;
- u32 level;
-};
-
-struct hfi_profile_level_supported {
- u32 profile_count;
- struct hfi_profile_level rg_profile_level[1];
-};
-
-enum HFI_ROTATE {
- HFI_ROTATE_NONE,
- HFI_ROTATE_90,
- HFI_ROTATE_180,
- HFI_ROTATE_270,
- HFI_UNUSED_ROTATE = 0x10000000,
-};
-
-enum HFI_FLIP {
- HFI_FLIP_NONE,
- HFI_FLIP_HORIZONTAL,
- HFI_FLIP_VERTICAL,
- HFI_UNUSED_FLIP = 0x10000000,
-};
-
-struct hfi_operations {
- enum HFI_ROTATE rotate;
- enum HFI_FLIP flip;
-};
-
-enum HFI_OUTPUT_ORDER {
- HFI_OUTPUT_ORDER_DISPLAY,
- HFI_OUTPUT_ORDER_DECODE,
- HFI_UNUSED_OUTPUT = 0x10000000,
-};
-
-struct hfi_quantization {
- u32 qp_i;
- u32 qp_p;
- u32 qp_b;
-};
-
-enum HFI_RATE_CONTROL {
- HFI_RATE_CONTROL_OFF,
- HFI_RATE_CONTROL_VBR_VFR,
- HFI_RATE_CONTROL_VBR_CFR,
- HFI_RATE_CONTROL_CBR_VFR,
- HFI_RATE_CONTROL_CBR_CFR,
- HFI_UNUSED_RC = 0x10000000,
-};
-
-struct hfi_slice_delivery_mode {
- int enable;
-};
-
-struct hfi_temporal_spatial_tradeoff {
- u32 ts_factor;
-};
-
-struct hfi_frame_size {
- enum HFI_BUFFER buffer;
- u32 width;
- u32 height;
-};
-
-enum HFI_UNCOMPRESSED_FORMAT {
- HFI_COLOR_FORMAT_MONOCHROME,
- HFI_COLOR_FORMAT_NV12,
- HFI_COLOR_FORMAT_NV21,
- HFI_COLOR_FORMAT_NV12_4x4TILE,
- HFI_COLOR_FORMAT_NV21_4x4TILE,
- HFI_COLOR_FORMAT_YUYV,
- HFI_COLOR_FORMAT_YVYU,
- HFI_COLOR_FORMAT_UYVY,
- HFI_COLOR_FORMAT_VYUY,
- HFI_COLOR_FORMAT_RGB565,
- HFI_COLOR_FORMAT_BGR565,
- HFI_COLOR_FORMAT_RGB888,
- HFI_COLOR_FORMAT_BGR888,
- HFI_UNUSED_COLOR = 0x10000000,
-};
-
-struct hfi_uncompressed_format_select {
- enum HFI_BUFFER buffer;
- enum HFI_UNCOMPRESSED_FORMAT format;
-};
-
-struct hfi_uncompressed_format_supported {
- enum HFI_BUFFER buffer;
- u32 format_entries;
- u32 rg_format_info[1];
-};
-
-struct hfi_uncompressed_plane_actual {
- int actual_stride;
- u32 actual_plane_buffer_height;
-};
-
-struct hfi_uncompressed_plane_actual_info {
- enum HFI_BUFFER buffer;
- u32 num_planes;
- struct hfi_uncompressed_plane_actual rg_plane_format[1];
-};
-
-struct hfi_uncompressed_plane_constraints {
- u32 stride_multiples;
- u32 max_stride;
- u32 min_plane_buffer_height_multiple;
- u32 buffer_alignment;
-};
-
-struct hfi_uncompressed_plane_info {
- enum HFI_UNCOMPRESSED_FORMAT format;
- u32 num_planes;
- struct hfi_uncompressed_plane_constraints rg_plane_format[1];
-};
+#define HFI_RATE_CONTROL_OFF (HFI_OX_BASE + 0x1)
+#define HFI_RATE_CONTROL_VBR_VFR (HFI_OX_BASE + 0x2)
+#define HFI_RATE_CONTROL_VBR_CFR (HFI_OX_BASE + 0x3)
+#define HFI_RATE_CONTROL_CBR_VFR (HFI_OX_BASE + 0x4)
+#define HFI_RATE_CONTROL_CBR_CFR (HFI_OX_BASE + 0x5)
struct hfi_uncompressed_plane_actual_constraints_info {
- enum HFI_BUFFER buffer;
+ u32 buffer_type;
u32 num_planes;
struct hfi_uncompressed_plane_constraints rg_plane_format[1];
};
-struct hfi_codec_supported {
- u32 decoder_codec_supported;
- u32 encoder_codec_supported;
-};
+#define HFI_CMD_SYS_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000)
+#define HFI_CMD_SYS_SESSION_ABORT (HFI_CMD_SYS_OX_START + 0x001)
+#define HFI_CMD_SYS_PING (HFI_CMD_SYS_OX_START + 0x002)
-enum HFI_DEBUG_MSG {
- HFI_DEBUG_MSG_LOW = 0x00000001,
- HFI_DEBUG_MSG_MEDIUM = 0x00000002,
- HFI_DEBUG_MSG_HIGH = 0x00000004,
- HFI_DEBUG_MSG_ERROR = 0x00000008,
- HFI_DEBUG_MSG_FATAL = 0x00000010,
- HFI_UNUSED_DEBUG_MSG = 0x10000000,
-};
+#define HFI_CMD_SESSION_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x1000)
+#define HFI_CMD_SESSION_LOAD_RESOURCES (HFI_CMD_SESSION_OX_START + 0x001)
+#define HFI_CMD_SESSION_START (HFI_CMD_SESSION_OX_START + 0x002)
+#define HFI_CMD_SESSION_STOP (HFI_CMD_SESSION_OX_START + 0x003)
+#define HFI_CMD_SESSION_EMPTY_BUFFER (HFI_CMD_SESSION_OX_START + 0x004)
+#define HFI_CMD_SESSION_FILL_BUFFER (HFI_CMD_SESSION_OX_START + 0x005)
+#define HFI_CMD_SESSION_SUSPEND (HFI_CMD_SESSION_OX_START + 0x006)
+#define HFI_CMD_SESSION_RESUME (HFI_CMD_SESSION_OX_START + 0x007)
+#define HFI_CMD_SESSION_FLUSH (HFI_CMD_SESSION_OX_START + 0x008)
+#define HFI_CMD_SESSION_GET_PROPERTY (HFI_CMD_SESSION_OX_START + 0x009)
+#define HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER \
+ (HFI_CMD_SESSION_OX_START + 0x00A)
+#define HFI_CMD_SESSION_RELEASE_BUFFERS \
+ (HFI_CMD_SESSION_OX_START + 0x00B)
+#define HFI_CMD_SESSION_RELEASE_RESOURCES \
+ (HFI_CMD_SESSION_OX_START + 0x00C)
-struct hfi_debug_config {
- u32 debug_config;
-};
+#define HFI_MSG_SYS_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000)
+#define HFI_MSG_SYS_IDLE (HFI_MSG_SYS_OX_START + 0x1)
+#define HFI_MSG_SYS_PING_ACK (HFI_MSG_SYS_OX_START + 0x2)
+#define HFI_MSG_SYS_PROPERTY_INFO (HFI_MSG_SYS_OX_START + 0x3)
+#define HFI_MSG_SYS_SESSION_ABORT_DONE (HFI_MSG_SYS_OX_START + 0x4)
-struct hfi_properties_supported {
- u32 num_properties;
- u32 rg_properties[1];
-};
-
-enum HFI_RESOURCE {
- HFI_RESOURCE_OCMEM = 0x00000001,
- HFI_UNUSED_RESOURCE = 0x10000000,
-};
-
-struct hfi_resource_ocmem_type {
- u32 size;
- u8 *mem;
-};
-
-struct hfi_resource_ocmem_requirement {
- enum HFI_DOMAIN session_domain;
- u32 width;
- u32 height;
- u32 size;
-};
-
-struct hfi_resource_ocmem_requirement_info {
- u32 num_entries;
- struct hfi_resource_ocmem_requirement rg_requirements[1];
-};
-
-struct hfi_venc_config_advanced {
- u8 pipe2d;
- u8 hw_mode;
- u8 low_delay_enforce;
- int h264_constrain_intra_pred;
- int h264_transform_8x8_flag;
- int mpeg4_qpel_enable;
- int multi_refP_en;
- int qmatrix_en;
- u8 vpp_info_packet_mode;
- u8 ref_tile_mode;
- u8 bitstream_flush_mode;
- u32 ds_display_frame_width;
- u32 ds_display_frame_height;
- u32 perf_tune_param_ptr;
-};
-
-enum HFI_COMMAND {
- HFI_CMD_SYS_UNUSED = 0x01000000,
- HFI_CMD_SYS_INIT,
- HFI_CMD_SYS_SESSION_INIT,
- HFI_CMD_SYS_SESSION_END,
- HFI_CMD_SYS_SESSION_ABORT,
- HFI_CMD_SYS_SET_RESOURCE,
- HFI_CMD_SYS_RELEASE_RESOURCE,
- HFI_CMD_SYS_PING,
- HFI_CMD_SYS_PC_PREP,
- HFI_CMD_SYS_SET_PROPERTY,
- HFI_CMD_SYS_GET_PROPERTY,
-
- HFI_CMD_SESSION_UNUSED = 0x02000000,
- HFI_CMD_SESSION_LOAD_RESOURCES,
- HFI_CMD_SESSION_START,
- HFI_CMD_SESSION_STOP,
- HFI_CMD_SESSION_EMPTY_BUFFER,
- HFI_CMD_SESSION_FILL_BUFFER,
- HFI_CMD_SESSION_FLUSH,
- HFI_CMD_SESSION_SUSPEND,
- HFI_CMD_SESSION_RESUME,
- HFI_CMD_SESSION_SET_PROPERTY,
- HFI_CMD_SESSION_GET_PROPERTY,
- HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER,
- HFI_CMD_SESSION_GET_SEQUENCE_HEADER,
- HFI_CMD_SESSION_SET_BUFFERS,
- HFI_CMD_SESSION_RELEASE_BUFFERS,
- HFI_CMD_SESSION_RELEASE_RESOURCES,
-
- HFI_CMD_UNUSED = 0x10000000,
-};
-
-enum HFI_MESSAGE {
- HFI_MSG_SYS_UNUSED = 0x01000000,
- HFI_MSG_SYS_IDLE,
- HFI_MSG_SYS_PC_PREP_DONE,
- HFI_MSG_SYS_RELEASE_RESOURCE,
- HFI_MSG_SYS_PING_ACK,
- HFI_MSG_SYS_DEBUG,
- HFI_MSG_SYS_INIT_DONE,
- HFI_MSG_SYS_PROPERTY_INFO,
- HFI_MSG_SESSION_UNUSED = 0x02000000,
- HFI_MSG_EVENT_NOTIFY,
- HFI_MSG_SYS_SESSION_INIT_DONE,
- HFI_MSG_SYS_SESSION_END_DONE,
- HFI_MSG_SYS_SESSION_ABORT_DONE,
- HFI_MSG_SESSION_LOAD_RESOURCES_DONE,
- HFI_MSG_SESSION_START_DONE,
- HFI_MSG_SESSION_STOP_DONE,
- HFI_MSG_SESSION_SUSPEND_DONE,
- HFI_MSG_SESSION_RESUME_DONE,
- HFI_MSG_SESSION_EMPTY_BUFFER_DONE,
- HFI_MSG_SESSION_FILL_BUFFER_DONE,
- HFI_MSG_SESSION_FLUSH_DONE,
- HFI_MSG_SESSION_PROPERTY_INFO,
- HFI_MSG_SESSION_RELEASE_RESOURCES_DONE,
- HFI_MSG_SESSION_PARSE_SEQUENCE_HEADER_DONE,
- HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE,
- HFI_MSG_UNUSED = 0x10000000,
-};
-
-struct vidc_hal_msg_pkt_hdr {
- u32 size;
- enum HFI_MESSAGE packet;
-};
-
-struct vidc_hal_session_cmd_pkt {
- u32 size;
- enum HFI_COMMAND packet_type;
- u32 session_id;
-};
-
-enum HFI_STATUS {
- HFI_FAIL = 0,
- HFI_SUCCESS,
- HFI_UNUSED_STATUS = 0x10000000,
-};
-
-struct hfi_cmd_sys_init_packet {
- u32 size;
- enum HFI_COMMAND packet;
-};
-
-struct hfi_cmd_sys_session_init_packet {
- u32 size;
- enum HFI_COMMAND packet;
- u32 session_id;
- enum HFI_DOMAIN session_domain;
- enum HFI_VIDEO_CODEC session_codec;
-};
-
-struct hfi_cmd_sys_session_end_packet {
- u32 size;
- enum HFI_COMMAND packet_type;
- u32 session_id;
-};
+#define HFI_MSG_SESSION_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x1000)
+#define HFI_MSG_SESSION_LOAD_RESOURCES_DONE (HFI_MSG_SESSION_OX_START + 0x1)
+#define HFI_MSG_SESSION_START_DONE (HFI_MSG_SESSION_OX_START + 0x2)
+#define HFI_MSG_SESSION_STOP_DONE (HFI_MSG_SESSION_OX_START + 0x3)
+#define HFI_MSG_SESSION_SUSPEND_DONE (HFI_MSG_SESSION_OX_START + 0x4)
+#define HFI_MSG_SESSION_RESUME_DONE (HFI_MSG_SESSION_OX_START + 0x5)
+#define HFI_MSG_SESSION_FLUSH_DONE (HFI_MSG_SESSION_OX_START + 0x6)
+#define HFI_MSG_SESSION_EMPTY_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x7)
+#define HFI_MSG_SESSION_FILL_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x8)
+#define HFI_MSG_SESSION_PROPERTY_INFO (HFI_MSG_SESSION_OX_START + 0x9)
+#define HFI_MSG_SESSION_RELEASE_RESOURCES_DONE (HFI_MSG_SESSION_OX_START + 0xA)
+#define HFI_MSG_SESSION_PARSE_SEQUENCE_HEADER_DONE \
+ (HFI_MSG_SESSION_OX_START + 0xB)
struct hfi_cmd_sys_session_abort_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
};
-struct hfi_cmd_sys_pc_prep_packet {
- u32 size;
- enum HFI_COMMAND packet_type;
-};
-
-struct hfi_cmd_sys_set_resource_packet {
- u32 size;
- enum HFI_COMMAND packet_type;
- u32 resource_handle;
- enum HFI_RESOURCE resource_type;
- u32 rg_resource_data[1];
-};
-
-struct hfi_cmd_sys_release_resource_packet {
- u32 size;
- enum HFI_COMMAND packet_type;
- enum HFI_RESOURCE resource_type;
- u32 resource_handle;
-};
-
struct hfi_cmd_sys_ping_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 client_data;
};
-struct hfi_cmd_sys_set_property_packet {
- u32 size;
- enum HFI_COMMAND packet_type;
- u32 num_properties;
- u32 rg_property_data[1];
-};
-
-struct hfi_cmd_sys_get_property_packet {
- u32 size;
- enum HFI_COMMAND packet_type;
- u32 num_properties;
- enum HFI_PROPERTY rg_property_data[1];
-};
-
struct hfi_cmd_session_load_resources_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
};
struct hfi_cmd_session_start_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
};
struct hfi_cmd_session_stop_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
};
struct hfi_cmd_session_empty_buffer_compressed_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
- u32 timestamp_hi;
- u32 timestamp_lo;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
u32 flags;
u32 mark_target;
u32 mark_data;
@@ -1085,15 +433,16 @@
u32 filled_len;
u32 input_tag;
u8 *packet_buffer;
+ u8 *extra_data_buffer;
};
struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet {
u32 size;
- enum HFI_COMMAND packet;
+ u32 packet_type;
u32 session_id;
u32 view_id;
- u32 timestamp_hi;
- u32 timestamp_lo;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
u32 flags;
u32 mark_target;
u32 mark_data;
@@ -1102,6 +451,7 @@
u32 offset;
u32 input_tag;
u8 *packet_buffer;
+ u8 *extra_data_buffer;
};
struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet {
@@ -1122,234 +472,153 @@
struct hfi_cmd_session_fill_buffer_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
u32 stream_id;
+ u32 output_tag;
u8 *packet_buffer;
u8 *extra_data_buffer;
};
struct hfi_cmd_session_flush_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_FLUSH flush_type;
+ u32 flush_type;
};
struct hfi_cmd_session_suspend_packet {
u32 size;
- enum HFI_COMMAND packet;
+ u32 packet_type;
u32 session_id;
};
struct hfi_cmd_session_resume_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
};
-struct hfi_cmd_session_set_property_packet {
- u32 size;
- enum HFI_COMMAND packet_type;
- u32 session_id;
- u32 num_properties;
- u32 rg_property_data[0];
-};
-
struct hfi_cmd_session_get_property_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
u32 num_properties;
- enum HFI_PROPERTY rg_property_data[1];
-};
-
-struct hfi_buffer_info {
- u32 buffer_addr;
- u32 extradata_addr;
-};
-
-struct hfi_cmd_session_set_buffers_packet {
- u32 size;
- enum HFI_COMMAND packet_type;
- u32 session_id;
- enum HFI_BUFFER buffer_type;
- enum HFI_BUFFER_MODE buffer_mode;
- u32 buffer_size;
- u32 extradata_size;
- u32 min_buffer_size;
- u32 num_buffers;
- u32 rg_buffer_info[1];
+ u32 rg_property_data[1];
};
struct hfi_cmd_session_release_buffer_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_BUFFER buffer_type;
+ u32 buffer_type;
u32 buffer_size;
- u32 extradata_size;
+ u32 extra_data_size;
u32 num_buffers;
u32 rg_buffer_info[1];
};
struct hfi_cmd_session_release_resources_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
};
struct hfi_cmd_session_parse_sequence_header_packet {
u32 size;
- enum HFI_COMMAND packet_type;
+ u32 packet_type;
u32 session_id;
u32 header_len;
u8 *packet_buffer;
};
-struct hfi_cmd_session_get_sequence_header_packet {
- u32 size;
- enum HFI_COMMAND packet_type;
- u32 session_id;
- u32 buffer_len;
- u8 *packet_buffer;
-};
-
-struct hfi_msg_event_notify_packet {
- u32 size;
- enum HFI_MESSAGE packet_type;
- u32 session_id;
- enum HFI_EVENT event_id;
- u32 event_data1;
- u32 event_data2;
- u32 rg_ext_event_data[1];
-};
-
-struct hfi_msg_sys_init_done_packet {
- u32 size;
- enum HFI_MESSAGE packet_type;
- enum HFI_ERROR error_type;
- u32 num_properties;
- u32 rg_property_data[1];
-};
-
-struct hfi_msg_sys_session_init_done_packet {
- u32 size;
- enum HFI_MESSAGE packet_type;
- u32 session_id;
- enum HFI_ERROR error_type;
- u32 num_properties;
- u32 rg_property_data[1];
-};
-
-struct hfi_msg_sys_session_end_done_packet {
- u32 size;
- enum HFI_MESSAGE packet_type;
- u32 session_id;
- enum HFI_ERROR error_type;
-};
-
struct hfi_msg_sys_session_abort_done_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_ERROR error_type;
+ u32 error_type;
};
struct hfi_msg_sys_idle_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
-};
-
-struct hfi_msg_sys_pc_prep_done_packet {
- u32 size;
- enum HFI_MESSAGE packet_type;
- enum HFI_ERROR error_type;
-};
-
-struct hfi_msg_sys_release_resource_done_packet {
- u32 size;
- enum HFI_MESSAGE packet_type;
- u32 resource_handle;
- enum HFI_ERROR error_type;
+ u32 packet_type;
};
struct hfi_msg_sys_ping_ack_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 client_data;
};
-struct hfi_msg_sys_debug_packet {
- u32 size;
- enum HFI_MESSAGE packet_type;
- enum HFI_DEBUG_MSG msg_type;
- u32 msg_size;
- u32 timestamp_hi;
- u32 timestamp_lo;
- u8 rg_msg_data[1];
-};
-
struct hfi_msg_sys_property_info_packet {
- u32 nsize;
- enum HFI_MESSAGE packet_type;
+ u32 size;
+ u32 packet_type;
u32 num_properties;
u32 rg_property_data[1];
};
struct hfi_msg_session_load_resources_done_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_ERROR error_type;
+ u32 error_type;
};
struct hfi_msg_session_start_done_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_ERROR error_type;
+ u32 error_type;
};
struct hfi_msg_session_stop_done_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_ERROR error_type;
+ u32 error_type;
};
struct hfi_msg_session_suspend_done_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_ERROR error_type;
+ u32 error_type;
};
struct hfi_msg_session_resume_done_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_ERROR error_type;
+ u32 error_type;
+};
+
+struct hfi_msg_session_flush_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 flush_type;
};
struct hfi_msg_session_empty_buffer_done_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_ERROR error_type;
+ u32 error_type;
u32 offset;
u32 filled_len;
u32 input_tag;
u8 *packet_buffer;
+ u8 *extra_data_buffer;
};
struct hfi_msg_session_fill_buffer_done_compressed_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
- u32 timestamp_hi;
- u32 timestamp_lo;
- enum HFI_ERROR error_type;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 error_type;
u32 flags;
u32 mark_target;
u32 mark_data;
@@ -1358,34 +627,36 @@
u32 alloc_len;
u32 filled_len;
u32 input_tag;
- enum HFI_PICTURE picture_type;
+ u32 output_tag;
+ u32 picture_type;
u8 *packet_buffer;
u8 *extra_data_buffer;
};
struct hfi_msg_session_fbd_uncompressed_plane0_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
u32 stream_id;
u32 view_id;
- enum HFI_ERROR error_type;
- u32 timestamp_hi;
- u32 timestamp_lo;
+ u32 error_type;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
u32 flags;
u32 mark_target;
u32 mark_data;
u32 stats;
u32 alloc_len;
u32 filled_len;
- u32 oofset;
+ u32 offset;
u32 frame_width;
u32 frame_height;
- u32 start_xCoord;
- u32 start_yCoord;
+ u32 start_x_coord;
+ u32 start_y_coord;
u32 input_tag;
- u32 input_tag1;
- enum HFI_PICTURE picture_type;
+ u32 input_tag2;
+ u32 output_tag;
+ u32 picture_type;
u8 *packet_buffer;
u8 *extra_data_buffer;
};
@@ -1395,7 +666,7 @@
u32 alloc_len;
u32 filled_len;
u32 offset;
- u8 *packet_buffer;
+ u8 *packet_buffer2;
};
struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet {
@@ -1403,38 +674,21 @@
u32 alloc_len;
u32 filled_len;
u32 offset;
- u8 *packet_buffer;
-};
-
-struct hfi_msg_session_flush_done_packet {
- u32 size;
- enum HFI_MESSAGE packet_type;
- u32 session_id;
- enum HFI_ERROR error_type;
- enum HFI_FLUSH flush_type;
+ u8 *packet_buffer3;
};
struct hfi_msg_session_parse_sequence_header_done_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_ERROR error_type;
+ u32 error_type;
u32 num_properties;
u32 rg_property_data[1];
};
-struct hfi_msg_session_get_sequence_header_done_packet {
- u32 size;
- enum HFI_MESSAGE packet_type;
- u32 session_id;
- enum HFI_ERROR error_type;
- u32 header_len;
- u8 *sequence_header;
-};
-
struct hfi_msg_session_property_info_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
u32 num_properties;
u32 rg_property_data[1];
@@ -1442,9 +696,9 @@
struct hfi_msg_session_release_resources_done_packet {
u32 size;
- enum HFI_MESSAGE packet_type;
+ u32 packet_type;
u32 session_id;
- enum HFI_ERROR error_type;
+ u32 error_type;
};
struct hfi_extradata_mb_quantization_payload {
@@ -1453,7 +707,7 @@
struct hfi_extradata_vc1_pswnd {
u32 ps_wnd_h_offset;
- u32 ps_wndv_offset;
+ u32 ps_wnd_v_offset;
u32 ps_wnd_width;
u32 ps_wnd_height;
};
@@ -1481,12 +735,8 @@
};
struct hfi_extradata_timestamp_payload {
- u32 timestamp_low;
- u32 timestamp_high;
-};
-
-struct hfi_extradata_interlace_video_payload {
- enum HFI_INTERLACE_FORMAT format;
+ u32 time_stamp_low;
+ u32 time_stamp_high;
};
enum HFI_S3D_FP_LAYOUT {
@@ -1496,14 +746,14 @@
HFI_S3D_FP_LAYOUT_INTRLV_ROW,
HFI_S3D_FP_LAYOUT_SIDEBYSIDE,
HFI_S3D_FP_LAYOUT_TOPBOTTOM,
- HFI_S3D_FP_LAYOUT_UNUSED = 0x10000000,
+ HFI_S3D_FP_LAYOUT_UNUSED = 0x10000000
};
enum HFI_S3D_FP_VIEW_ORDER {
HFI_S3D_FP_LEFTVIEW_FIRST,
HFI_S3D_FP_RIGHTVIEW_FIRST,
HFI_S3D_FP_UNKNOWN,
- HFI_S3D_FP_VIEWORDER_UNUSED = 0x10000000,
+ HFI_S3D_FP_VIEWORDER_UNUSED = 0x10000000
};
enum HFI_S3D_FP_FLIP {
@@ -1512,18 +762,22 @@
HFI_S3D_FP_FLIP_LEFT_VERT,
HFI_S3D_FP_FLIP_RIGHT_HORIZ,
HFI_S3D_FP_FLIP_RIGHT_VERT,
- HFI_S3D_FP_FLIP_UNUSED = 0x10000000,
+ HFI_S3D_FP_FLIP_UNUSED = 0x10000000
};
struct hfi_extradata_s3d_frame_packing_payload {
- enum HFI_S3D_FP_LAYOUT eLayout;
- enum HFI_S3D_FP_VIEW_ORDER eOrder;
- enum HFI_S3D_FP_FLIP eFlip;
- int bQuinCunx;
- u32 nLeftViewLumaSiteX;
- u32 nLeftViewLumaSiteY;
- u32 nRightViewLumaSiteX;
- u32 nRightViewLumaSiteY;
+ enum HFI_S3D_FP_LAYOUT layout;
+ enum HFI_S3D_FP_VIEW_ORDER order;
+ enum HFI_S3D_FP_FLIP flip;
+ int quin_cunx;
+ u32 left_view_luma_site_x;
+ u32 left_view_luma_site_y;
+ u32 right_view_luma_site_x;
+ u32 right_view_luma_site_y;
+};
+
+struct hfi_extradata_interlace_video_payload {
+ u32 format;
};
struct hfi_extradata_num_concealed_mb_payload {
@@ -1615,4 +869,4 @@
/* Interrupt Processing:*/
void vidc_hal_response_handler(struct hal_device *device);
-#endif /*__VIDC_HAL_H__ */
+#endif
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 036091b..b3ea92a 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -40,6 +40,12 @@
#define HAL_BUFFERFLAG_READONLY 0x00000200
#define HAL_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
+#define HAL_DEBUG_MSG_LOW 0x00000001
+#define HAL_DEBUG_MSG_MEDIUM 0x00000002
+#define HAL_DEBUG_MSG_HIGH 0x00000004
+#define HAL_DEBUG_MSG_ERROR 0x00000008
+#define HAL_DEBUG_MSG_FATAL 0x00000010
+
enum vidc_status {
VIDC_ERR_NONE = 0x0,
VIDC_ERR_FAIL = 0x80000000,
@@ -242,11 +248,12 @@
enum hal_h264_profile {
HAL_H264_PROFILE_BASELINE = 0x00000001,
HAL_H264_PROFILE_MAIN = 0x00000002,
- HAL_H264_PROFILE_EXTENDED = 0x00000004,
- HAL_H264_PROFILE_HIGH = 0x00000008,
+ HAL_H264_PROFILE_HIGH = 0x00000004,
+ HAL_H264_PROFILE_EXTENDED = 0x00000008,
HAL_H264_PROFILE_HIGH10 = 0x00000010,
HAL_H264_PROFILE_HIGH422 = 0x00000020,
HAL_H264_PROFILE_HIGH444 = 0x00000040,
+ HAL_H264_PROFILE_CONSTRAINED_HIGH = 0x00000080,
HAL_UNUSED_H264_PROFILE = 0x10000000,
};
@@ -541,7 +548,7 @@
struct hal_h264_db_control {
enum hal_h264_db_mode mode;
int slice_alpha_offset;
- int slicebeta_offset;
+ int slice_beta_offset;
};
struct hal_temporal_spatial_tradeoff {
diff --git a/drivers/media/video/msm_vidc/vidc_hal_helper.h b/drivers/media/video/msm_vidc/vidc_hal_helper.h
new file mode 100644
index 0000000..d4e2619
--- /dev/null
+++ b/drivers/media/video/msm_vidc/vidc_hal_helper.h
@@ -0,0 +1,832 @@
+/* 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 __H_VIDC_HAL_HELPER_H__
+#define __H_VIDC_HAL_HELPER_H__
+
+#define HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
+ { stride = (frame_width + stride_multiple - 1) & \
+ (0xffffffff - (stride_multiple - 1))}
+
+#define HFI_NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height,\
+ min_buf_height_multiple) \
+ { buf_height = (frame_height + min_buf_height_multiple - 1) & \
+ (0xffffffff - (min_buf_height_multiple - 1)) }
+
+#define HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
+ { stride = ((((frame_width + 1) >> 1) + stride_multiple - 1) & \
+ (0xffffffff - (stride_multiple - 1))) << 1 }
+
+#define HFI_NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height,\
+ min_buf_height_multiple) \
+ { buf_height = ((((frame_height + 1) >> 1) + \
+ min_buf_height_multiple - 1) & (0xffffffff - \
+ (min_buf_height_multiple - 1))) }
+
+#define HFI_NV12_IL_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride, \
+ y_buf_height, uv_buf_size, uv_stride, uv_buf_height, uv_alignment) \
+ { y_buf_size = (y_stride * y_buf_height); \
+ uv_buf_size = (uv_stride * uv_buf_height) + uv_alignment; \
+ buf_size = y_buf_size + uv_buf_size }
+
+#define HFI_YUYV_CALC_STRIDE(stride, frame_width, stride_multiple) \
+ { stride = ((frame_width << 1) + stride_multiple - 1) & \
+ (0xffffffff - (stride_multiple - 1)) }
+
+#define HFI_YUYV_CALC_BUFHEIGHT(buf_height, frame_height,\
+ min_buf_height_multiple) \
+ { buf_height = ((frame_height + min_buf_height_multiple - 1) & \
+ (0xffffffff - (min_buf_height_multiple - 1))) }
+
+#define HFI_YUYV_CALC_BUF_SIZE(buf_size, stride, buf_height) \
+ { buf_size = stride * buf_height }
+
+#define HFI_RGB888_CALC_STRIDE(stride, frame_width, stride_multiple) \
+ { stride = ((frame_width * 3) + stride_multiple - 1) & \
+ (0xffffffff - (stride_multiple - 1)) }
+
+#define HFI_RGB888_CALC_BUFHEIGHT(buf_height, frame_height,\
+ min_buf_height_multiple) \
+ { buf_height = ((frame_height + min_buf_height_multiple - 1) & \
+ (0xffffffff - (min_buf_height_multiple - 1))) }
+
+#define HFI_RGB888_CALC_BUF_SIZE(buf_size, stride, buf_height) \
+ { buf_size = (stride * buf_height) }
+
+#define HFI_COMMON_BASE (0)
+#define HFI_OX_BASE (0x01000000)
+
+#define HFI_VIDEO_DOMAIN_ENCODER (HFI_COMMON_BASE + 0x1)
+#define HFI_VIDEO_DOMAIN_DECODER (HFI_COMMON_BASE + 0x2)
+#define HFI_VIDEO_DOMAIN_VPE (HFI_COMMON_BASE + 0x3)
+#define HFI_VIDEO_DOMAIN_MBI (HFI_COMMON_BASE + 0x4)
+
+#define HFI_DOMAIN_BASE_COMMON (HFI_COMMON_BASE + 0)
+#define HFI_DOMAIN_BASE_VDEC (HFI_COMMON_BASE + 0x01000000)
+#define HFI_DOMAIN_BASE_VENC (HFI_COMMON_BASE + 0x02000000)
+#define HFI_DOMAIN_BASE_VPE (HFI_COMMON_BASE + 0x03000000)
+
+#define HFI_VIDEO_ARCH_OX (HFI_COMMON_BASE + 0x1)
+
+#define HFI_ARCH_COMMON_OFFSET (0)
+#define HFI_ARCH_OX_OFFSET (0x00200000)
+
+#define HFI_ERR_NONE HFI_COMMON_BASE
+#define HFI_ERR_SYS_FATAL (HFI_COMMON_BASE + 0x1)
+#define HFI_ERR_SYS_INVALID_PARAMETER (HFI_COMMON_BASE + 0x2)
+#define HFI_ERR_SYS_VERSION_MISMATCH (HFI_COMMON_BASE + 0x3)
+#define HFI_ERR_SYS_INSUFFICIENT_RESOURCES (HFI_COMMON_BASE + 0x4)
+#define HFI_ERR_SYS_MAX_SESSIONS_REACHED (HFI_COMMON_BASE + 0x5)
+#define HFI_ERR_SYS_UNSUPPORTED_CODEC (HFI_COMMON_BASE + 0x6)
+#define HFI_ERR_SYS_SESSION_IN_USE (HFI_COMMON_BASE + 0x7)
+#define HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE (HFI_COMMON_BASE + 0x8)
+#define HFI_ERR_SYS_UNSUPPORTED_DOMAIN (HFI_COMMON_BASE + 0x9)
+
+#define HFI_ERR_SESSION_FATAL (HFI_COMMON_BASE + 0x1001)
+#define HFI_ERR_SESSION_INVALID_PARAMETER (HFI_COMMON_BASE + 0x1002)
+#define HFI_ERR_SESSION_BAD_POINTER (HFI_COMMON_BASE + 0x1003)
+#define HFI_ERR_SESSION_INVALID_SESSION_ID (HFI_COMMON_BASE + 0x1004)
+#define HFI_ERR_SESSION_INVALID_STREAM_ID (HFI_COMMON_BASE + 0x1005)
+#define HFI_ERR_SESSION_INCORRECT_STATE_OPERATION \
+ (HFI_COMMON_BASE + 0x1006)
+#define HFI_ERR_SESSION_UNSUPPORTED_PROPERTY (HFI_COMMON_BASE + 0x1007)
+
+#define HFI_ERR_SESSION_UNSUPPORTED_SETTING (HFI_COMMON_BASE + 0x1008)
+
+#define HFI_ERR_SESSION_INSUFFICIENT_RESOURCES (HFI_COMMON_BASE + 0x1009)
+
+#define HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED \
+ (HFI_COMMON_BASE + 0x100A)
+
+#define HFI_ERR_SESSION_STREAM_CORRUPT (HFI_COMMON_BASE + 0x100B)
+#define HFI_ERR_SESSION_ENC_OVERFLOW (HFI_COMMON_BASE + 0x100C)
+
+#define HFI_EVENT_SYS_ERROR (HFI_COMMON_BASE + 0x1)
+#define HFI_EVENT_SESSION_ERROR (HFI_COMMON_BASE + 0x2)
+
+#define HFI_VIDEO_CODEC_H264 0x00000002
+#define HFI_VIDEO_CODEC_H263 0x00000004
+#define HFI_VIDEO_CODEC_MPEG1 0x00000008
+#define HFI_VIDEO_CODEC_MPEG2 0x00000010
+#define HFI_VIDEO_CODEC_MPEG4 0x00000020
+#define HFI_VIDEO_CODEC_DIVX_311 0x00000040
+#define HFI_VIDEO_CODEC_DIVX 0x00000080
+#define HFI_VIDEO_CODEC_VC1 0x00000100
+#define HFI_VIDEO_CODEC_SPARK 0x00000200
+#define HFI_VIDEO_CODEC_VP8 0x00001000
+
+#define HFI_H264_PROFILE_BASELINE 0x00000001
+#define HFI_H264_PROFILE_MAIN 0x00000002
+#define HFI_H264_PROFILE_HIGH 0x00000004
+#define HFI_H264_PROFILE_STEREO_HIGH 0x00000008
+#define HFI_H264_PROFILE_MULTIVIEW_HIGH 0x00000010
+#define HFI_H264_PROFILE_CONSTRAINED_HIGH 0x00000020
+
+#define HFI_H264_LEVEL_1 0x00000001
+#define HFI_H264_LEVEL_1b 0x00000002
+#define HFI_H264_LEVEL_11 0x00000004
+#define HFI_H264_LEVEL_12 0x00000008
+#define HFI_H264_LEVEL_13 0x00000010
+#define HFI_H264_LEVEL_2 0x00000020
+#define HFI_H264_LEVEL_21 0x00000040
+#define HFI_H264_LEVEL_22 0x00000080
+#define HFI_H264_LEVEL_3 0x00000100
+#define HFI_H264_LEVEL_31 0x00000200
+#define HFI_H264_LEVEL_32 0x00000400
+#define HFI_H264_LEVEL_4 0x00000800
+#define HFI_H264_LEVEL_41 0x00001000
+#define HFI_H264_LEVEL_42 0x00002000
+#define HFI_H264_LEVEL_5 0x00004000
+#define HFI_H264_LEVEL_51 0x00008000
+
+#define HFI_H263_PROFILE_BASELINE 0x00000001
+
+#define HFI_H263_LEVEL_10 0x00000001
+#define HFI_H263_LEVEL_20 0x00000002
+#define HFI_H263_LEVEL_30 0x00000004
+#define HFI_H263_LEVEL_40 0x00000008
+#define HFI_H263_LEVEL_45 0x00000010
+#define HFI_H263_LEVEL_50 0x00000020
+#define HFI_H263_LEVEL_60 0x00000040
+#define HFI_H263_LEVEL_70 0x00000080
+
+#define HFI_MPEG2_PROFILE_SIMPLE 0x00000001
+#define HFI_MPEG2_PROFILE_MAIN 0x00000002
+#define HFI_MPEG2_PROFILE_422 0x00000004
+#define HFI_MPEG2_PROFILE_SNR 0x00000008
+#define HFI_MPEG2_PROFILE_SPATIAL 0x00000010
+#define HFI_MPEG2_PROFILE_HIGH 0x00000020
+
+#define HFI_MPEG2_LEVEL_LL 0x00000001
+#define HFI_MPEG2_LEVEL_ML 0x00000002
+#define HFI_MPEG2_LEVEL_H14 0x00000004
+#define HFI_MPEG2_LEVEL_HL 0x00000008
+
+#define HFI_MPEG4_PROFILE_SIMPLE 0x00000001
+#define HFI_MPEG4_PROFILE_ADVANCEDSIMPLE 0x00000002
+
+#define HFI_MPEG4_LEVEL_0 0x00000001
+#define HFI_MPEG4_LEVEL_0b 0x00000002
+#define HFI_MPEG4_LEVEL_1 0x00000004
+#define HFI_MPEG4_LEVEL_2 0x00000008
+#define HFI_MPEG4_LEVEL_3 0x00000010
+#define HFI_MPEG4_LEVEL_4 0x00000020
+#define HFI_MPEG4_LEVEL_4a 0x00000040
+#define HFI_MPEG4_LEVEL_5 0x00000080
+#define HFI_MPEG4_LEVEL_6 0x00000100
+#define HFI_MPEG4_LEVEL_7 0x00000200
+#define HFI_MPEG4_LEVEL_8 0x00000400
+#define HFI_MPEG4_LEVEL_9 0x00000800
+#define HFI_MPEG4_LEVEL_3b 0x00001000
+
+#define HFI_VC1_PROFILE_SIMPLE 0x00000001
+#define HFI_VC1_PROFILE_MAIN 0x00000002
+#define HFI_VC1_PROFILE_ADVANCED 0x00000004
+
+#define HFI_VC1_LEVEL_LOW 0x00000001
+#define HFI_VC1_LEVEL_MEDIUM 0x00000002
+#define HFI_VC1_LEVEL_HIGH 0x00000004
+#define HFI_VC1_LEVEL_0 0x00000008
+#define HFI_VC1_LEVEL_1 0x00000010
+#define HFI_VC1_LEVEL_2 0x00000020
+#define HFI_VC1_LEVEL_3 0x00000040
+#define HFI_VC1_LEVEL_4 0x00000080
+
+#define HFI_VPX_PROFILE_SIMPLE 0x00000001
+#define HFI_VPX_PROFILE_ADVANCED 0x00000002
+#define HFI_VPX_PROFILE_VERSION_0 0x00000004
+#define HFI_VPX_PROFILE_VERSION_1 0x00000008
+#define HFI_VPX_PROFILE_VERSION_2 0x00000010
+#define HFI_VPX_PROFILE_VERSION_3 0x00000020
+
+#define HFI_DIVX_FORMAT_4 (HFI_COMMON_BASE + 0x1)
+#define HFI_DIVX_FORMAT_5 (HFI_COMMON_BASE + 0x2)
+#define HFI_DIVX_FORMAT_6 (HFI_COMMON_BASE + 0x3)
+
+#define HFI_DIVX_PROFILE_QMOBILE 0x00000001
+#define HFI_DIVX_PROFILE_MOBILE 0x00000002
+#define HFI_DIVX_PROFILE_MT 0x00000004
+#define HFI_DIVX_PROFILE_HT 0x00000008
+#define HFI_DIVX_PROFILE_HD 0x00000010
+
+#define HFI_BUFFER_INPUT (HFI_COMMON_BASE + 0x1)
+#define HFI_BUFFER_OUTPUT (HFI_COMMON_BASE + 0x2)
+#define HFI_BUFFER_OUTPUT2 (HFI_COMMON_BASE + 0x3)
+#define HFI_BUFFER_INTERNAL_PERSIST (HFI_COMMON_BASE + 0x4)
+
+struct hfi_buffer_info {
+ u32 buffer_addr;
+ u32 extra_data_addr;
+};
+
+#define HFI_PROPERTY_SYS_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000)
+#define HFI_PROPERTY_SYS_DEBUG_CONFIG \
+ (HFI_PROPERTY_SYS_COMMON_START + 0x001)
+#define HFI_PROPERTY_SYS_RESOURCE_OCMEM_REQUIREMENT_INFO \
+(HFI_PROPERTY_SYS_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x1000)
+#define HFI_PROPERTY_PARAM_FRAME_SIZE \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x003)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x004)
+#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x005)
+#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x006)
+#define HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x007)
+#define HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x008)
+#define HFI_PROPERTY_PARAM_CODEC_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x009)
+#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00A)
+#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00B)
+#define HFI_PROPERTY_PARAM_MULTI_VIEW_FORMAT \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00C)
+
+#define HFI_PROPERTY_CONFIG_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000)
+#define HFI_PROPERTY_CONFIG_FRAME_RATE \
+ (HFI_PROPERTY_CONFIG_COMMON_START + 0x001)
+
+#define HFI_PROPERTY_PARAM_VDEC_COMMON_START \
+ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x3000)
+#define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM \
+ (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x001)
+
+#define HFI_PROPERTY_CONFIG_VDEC_COMMON_START \
+ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x4000)
+
+#define HFI_PROPERTY_PARAM_VENC_COMMON_START \
+ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x5000)
+#define HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x003)
+#define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x004)
+#define HFI_PROPERTY_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x005)
+#define HFI_PROPERTY_PARAM_VENC_QUALITY_VS_SPEED \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x010)
+#define HFI_PROPERTY_PARAM_VENC_SESSION_QP \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x006)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_AC_PREDICTION \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x007)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_DATA_PARTITIONING \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x008)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x009)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_SHORT_HEADER \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00A)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00B)
+#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00C)
+#define HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00D)
+#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00E)
+#define HFI_PROPERTY_PARAM_VENC_VBVBUFFER_SIZE \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00F)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_QPEL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x011)
+#define HFI_PROPERTY_PARAM_VENC_ADVANCED \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x012)
+#define HFI_PROPERTY_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x013)
+#define HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x014)
+
+#define HFI_PROPERTY_CONFIG_VENC_COMMON_START \
+ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000)
+#define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x002)
+#define HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x003)
+#define HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x004)
+#define HFI_PROPERTY_CONFIG_VENC_TIMESTAMP_SCALE \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x005)
+#define HFI_PROPERTY_CONFIG_VENC_FRAME_QP \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x006)
+#define HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x007)
+
+#define HFI_PROPERTY_PARAM_VPE_COMMON_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
+
+#define HFI_PROPERTY_CONFIG_VPE_COMMON_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000)
+#define HFI_PROPERTY_CONFIG_VPE_DEINTERLACE \
+ (HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VPE_OPERATIONS \
+ (HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x002)
+
+struct hfi_bitrate {
+ u32 bit_rate;
+};
+
+#define HFI_CAPABILITY_FRAME_WIDTH (HFI_COMMON_BASE + 0x1)
+#define HFI_CAPABILITY_FRAME_HEIGHT (HFI_COMMON_BASE + 0x2)
+#define HFI_CAPABILITY_MBS_PER_FRAME (HFI_COMMON_BASE + 0x3)
+#define HFI_CAPABILITY_MBS_PER_SECOND (HFI_COMMON_BASE + 0x4)
+#define HFI_CAPABILITY_FRAMERATE (HFI_COMMON_BASE + 0x5)
+#define HFI_CAPABILITY_SCALE_X (HFI_COMMON_BASE + 0x6)
+#define HFI_CAPABILITY_SCALE_Y (HFI_COMMON_BASE + 0x7)
+#define HFI_CAPABILITY_BITRATE (HFI_COMMON_BASE + 0x8)
+
+struct hfi_capability_supported {
+ u32 capability_type;
+ u32 min;
+ u32 max;
+ u32 step_size;
+};
+
+struct hfi_capability_supported_info {
+ u32 num_capabilities;
+ struct hfi_capability_supported rg_data[1];
+};
+
+#define HFI_DEBUG_MSG_LOW 0x00000001
+#define HFI_DEBUG_MSG_MEDIUM 0x00000002
+#define HFI_DEBUG_MSG_HIGH 0x00000004
+#define HFI_DEBUG_MSG_ERROR 0x00000008
+#define HFI_DEBUG_MSG_FATAL 0x00000010
+
+struct hfi_debug_config {
+ u32 debug_config;
+};
+
+struct hfi_enable {
+ int enable;
+};
+
+#define HFI_H264_DB_MODE_DISABLE (HFI_COMMON_BASE + 0x1)
+#define HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY (HFI_COMMON_BASE + 0x2)
+#define HFI_H264_DB_MODE_ALL_BOUNDARY (HFI_COMMON_BASE + 0x3)
+
+struct hfi_h264_db_control {
+ u32 mode;
+ int slice_alpha_offset;
+ int slice_beta_offset;
+};
+
+#define HFI_H264_ENTROPY_CAVLC (HFI_COMMON_BASE + 0x1)
+#define HFI_H264_ENTROPY_CABAC (HFI_COMMON_BASE + 0x2)
+
+#define HFI_H264_CABAC_MODEL_0 (HFI_COMMON_BASE + 0x1)
+#define HFI_H264_CABAC_MODEL_1 (HFI_COMMON_BASE + 0x2)
+#define HFI_H264_CABAC_MODEL_2 (HFI_COMMON_BASE + 0x3)
+
+struct hfi_h264_entropy_control {
+ u32 entropy_mode;
+ u32 cabac_model;
+};
+
+struct hfi_frame_rate {
+ u32 buffer_type;
+ u32 frame_rate;
+};
+
+#define HFI_INTRA_REFRESH_NONE (HFI_COMMON_BASE + 0x1)
+#define HFI_INTRA_REFRESH_CYCLIC (HFI_COMMON_BASE + 0x2)
+#define HFI_INTRA_REFRESH_ADAPTIVE (HFI_COMMON_BASE + 0x3)
+#define HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE (HFI_COMMON_BASE + 0x4)
+#define HFI_INTRA_REFRESH_RANDOM (HFI_COMMON_BASE + 0x5)
+
+struct hfi_intra_refresh {
+ u32 mode;
+ u32 air_mbs;
+ u32 air_ref;
+ u32 cir_mbs;
+};
+
+struct hfi_idr_period {
+ u32 idr_period;
+};
+
+struct hfi_intra_period {
+ u32 pframes;
+ u32 bframes;
+};
+
+struct hfi_timestamp_scale {
+ u32 time_stamp_scale;
+};
+
+struct hfi_mpeg4_header_extension {
+ u32 header_extension;
+};
+
+struct hfi_mpeg4_time_resolution {
+ u32 time_increment_resolution;
+};
+
+struct hfi_multi_stream {
+ u32 buffer_type;
+ u32 enable;
+ u32 width;
+ u32 height;
+};
+
+struct hfi_multi_view_format {
+ u32 views;
+ u32 rg_view_order[1];
+};
+
+#define HFI_MULTI_SLICE_OFF (HFI_COMMON_BASE + 0x1)
+#define HFI_MULTI_SLICE_BY_MB_COUNT (HFI_COMMON_BASE + 0x2)
+#define HFI_MULTI_SLICE_BY_BYTE_COUNT (HFI_COMMON_BASE + 0x3)
+#define HFI_MULTI_SLICE_GOB (HFI_COMMON_BASE + 0x4)
+
+struct hfi_multi_slice_control {
+ u32 multi_slice;
+ u32 slice_size;
+};
+
+#define HFI_NAL_FORMAT_STARTCODES 0x00000001
+#define HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER 0x00000002
+#define HFI_NAL_FORMAT_ONE_BYTE_LENGTH 0x00000004
+#define HFI_NAL_FORMAT_TWO_BYTE_LENGTH 0x00000008
+#define HFI_NAL_FORMAT_FOUR_BYTE_LENGTH 0x00000010
+
+struct hfi_nal_stream_format_supported {
+ u32 nal_stream_format_supported;
+};
+
+#define HFI_PICTURE_TYPE_I 0x01
+#define HFI_PICTURE_TYPE_P 0x02
+#define HFI_PICTURE_TYPE_B 0x04
+#define HFI_PICTURE_TYPE_IDR 0x08
+
+struct hfi_profile_level {
+ u32 profile;
+ u32 level;
+};
+
+struct hfi_profile_level_supported {
+ u32 profile_count;
+ struct hfi_profile_level rg_profile_level[1];
+};
+
+struct hfi_quantization {
+ u32 qp_i;
+ u32 qp_p;
+ u32 qp_b;
+ u32 layer_id;
+};
+
+struct hfi_temporal_spatial_tradeoff {
+ u32 ts_factor;
+};
+
+struct hfi_frame_size {
+ u32 buffer_type;
+ u32 width;
+ u32 height;
+};
+
+#define HFI_COLOR_FORMAT_MONOCHROME (HFI_COMMON_BASE + 0x1)
+#define HFI_COLOR_FORMAT_NV12 (HFI_COMMON_BASE + 0x2)
+#define HFI_COLOR_FORMAT_NV21 (HFI_COMMON_BASE + 0x3)
+#define HFI_COLOR_FORMAT_NV12_4x4TILE (HFI_COMMON_BASE + 0x4)
+#define HFI_COLOR_FORMAT_NV21_4x4TILE (HFI_COMMON_BASE + 0x5)
+#define HFI_COLOR_FORMAT_YUYV (HFI_COMMON_BASE + 0x6)
+#define HFI_COLOR_FORMAT_YVYU (HFI_COMMON_BASE + 0x7)
+#define HFI_COLOR_FORMAT_UYVY (HFI_COMMON_BASE + 0x8)
+#define HFI_COLOR_FORMAT_VYUY (HFI_COMMON_BASE + 0x9)
+#define HFI_COLOR_FORMAT_RGB565 (HFI_COMMON_BASE + 0xA)
+#define HFI_COLOR_FORMAT_BGR565 (HFI_COMMON_BASE + 0xB)
+#define HFI_COLOR_FORMAT_RGB888 (HFI_COMMON_BASE + 0xC)
+#define HFI_COLOR_FORMAT_BGR888 (HFI_COMMON_BASE + 0xD)
+
+struct hfi_uncompressed_format_select {
+ u32 buffer_type;
+ u32 format;
+};
+
+struct hfi_uncompressed_format_supported {
+ u32 buffer_type;
+ u32 format_entries;
+ u32 rg_format_info[1];
+};
+
+struct hfi_uncompressed_plane_actual {
+ int actual_stride;
+ u32 actual_plane_buffer_height;
+};
+
+struct hfi_uncompressed_plane_actual_info {
+ u32 buffer_type;
+ u32 num_planes;
+ struct hfi_uncompressed_plane_actual rg_plane_format[1];
+};
+
+struct hfi_uncompressed_plane_constraints {
+ u32 stride_multiples;
+ u32 max_stride;
+ u32 min_plane_buffer_height_multiple;
+ u32 buffer_alignment;
+};
+
+struct hfi_uncompressed_plane_info {
+ u32 format;
+ u32 num_planes;
+ struct hfi_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+struct hfi_codec_supported {
+ u32 decoder_codec_supported;
+ u32 encoder_codec_supported;
+};
+
+struct hfi_properties_supported {
+ u32 num_properties;
+ u32 rg_properties[1];
+};
+
+#define HFI_ROTATE_NONE (HFI_COMMON_BASE + 0x1)
+#define HFI_ROTATE_90 (HFI_COMMON_BASE + 0x2)
+#define HFI_ROTATE_180 (HFI_COMMON_BASE + 0x3)
+#define HFI_ROTATE_270 (HFI_COMMON_BASE + 0x4)
+
+#define HFI_FLIP_NONE (HFI_COMMON_BASE + 0x1)
+#define HFI_FLIP_HORIZONTAL (HFI_COMMON_BASE + 0x2)
+#define HFI_FLIP_VERTICAL (HFI_COMMON_BASE + 0x3)
+
+struct hfi_operations {
+ u32 rotate;
+ u32 flip;
+};
+
+#define HFI_RESOURCE_OCMEM 0x00000001
+
+struct hfi_resource_ocmem {
+ u32 size;
+ u8 *mem;
+};
+
+struct hfi_resource_ocmem_requirement {
+ u32 session_domain;
+ u32 width;
+ u32 height;
+ u32 size;
+};
+
+struct hfi_resource_ocmem_requirement_info {
+ u32 num_entries;
+ struct hfi_resource_ocmem_requirement rg_requirements[1];
+};
+
+struct hfi_venc_config_advanced {
+ u8 pipe2d;
+ u8 hw_mode;
+ u8 low_delay_enforce;
+ int h264_constrain_intra_pred;
+ int h264_transform_8x8_flag;
+ int mpeg4_qpel_enable;
+ int multi_refp_en;
+ int qmatrix_en;
+ u8 vpp_info_packet_mode;
+ u8 ref_tile_mode;
+ u8 bitstream_flush_mode;
+ u32 ds_display_frame_width;
+ u32 ds_display_frame_height;
+ u32 perf_tune_param_ptr;
+ u32 input_x_offset;
+ u32 input_y_offset;
+ u32 input_roi_width;
+ u32 input_roi_height;
+ u32 vsp_fifo_dma_sel;
+ u32 h264_num_ref_frames;
+};
+
+#define HFI_CMD_SYS_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000)
+#define HFI_CMD_SYS_INIT (HFI_CMD_SYS_COMMON_START + 0x001)
+#define HFI_CMD_SYS_PC_PREP (HFI_CMD_SYS_COMMON_START + 0x002)
+#define HFI_CMD_SYS_SET_RESOURCE (HFI_CMD_SYS_COMMON_START + 0x003)
+#define HFI_CMD_SYS_RELEASE_RESOURCE (HFI_CMD_SYS_COMMON_START + 0x004)
+#define HFI_CMD_SYS_SET_PROPERTY (HFI_CMD_SYS_COMMON_START + 0x005)
+#define HFI_CMD_SYS_GET_PROPERTY (HFI_CMD_SYS_COMMON_START + 0x006)
+#define HFI_CMD_SYS_SESSION_INIT (HFI_CMD_SYS_COMMON_START + 0x007)
+#define HFI_CMD_SYS_SESSION_END (HFI_CMD_SYS_COMMON_START + 0x008)
+#define HFI_CMD_SYS_SET_BUFFERS (HFI_CMD_SYS_COMMON_START + 0x009)
+
+#define HFI_CMD_SESSION_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x1000)
+#define HFI_CMD_SESSION_SET_PROPERTY \
+ (HFI_CMD_SESSION_COMMON_START + 0x001)
+#define HFI_CMD_SESSION_SET_BUFFERS \
+ (HFI_CMD_SESSION_COMMON_START + 0x002)
+#define HFI_CMD_SESSION_GET_SEQUENCE_HEADER \
+ (HFI_CMD_SESSION_COMMON_START + 0x003)
+
+#define HFI_MSG_SYS_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000)
+#define HFI_MSG_SYS_INIT_DONE (HFI_MSG_SYS_COMMON_START + 0x1)
+#define HFI_MSG_SYS_PC_PREP_DONE (HFI_MSG_SYS_COMMON_START + 0x2)
+#define HFI_MSG_SYS_RELEASE_RESOURCE (HFI_MSG_SYS_COMMON_START + 0x3)
+#define HFI_MSG_SYS_DEBUG (HFI_MSG_SYS_COMMON_START + 0x4)
+#define HFI_MSG_SYS_SESSION_INIT_DONE (HFI_MSG_SYS_COMMON_START + 0x6)
+#define HFI_MSG_SYS_SESSION_END_DONE (HFI_MSG_SYS_COMMON_START + 0x7)
+
+#define HFI_MSG_SESSION_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x1000)
+#define HFI_MSG_EVENT_NOTIFY (HFI_MSG_SESSION_COMMON_START + 0x1)
+#define HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE \
+ (HFI_MSG_SESSION_COMMON_START + 0x2)
+
+struct vidc_hal_msg_pkt_hdr {
+ u32 size;
+ u32 packet;
+};
+
+struct vidc_hal_session_cmd_pkt {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_sys_init_packet {
+ u32 size;
+ u32 packet_type;
+ u32 arch_type;
+};
+
+struct hfi_cmd_sys_pc_prep_packet {
+ u32 size;
+ u32 packet_type;
+};
+
+struct hfi_cmd_sys_set_resource_packet {
+ u32 size;
+ u32 packet_type;
+ u32 resource_handle;
+ u32 resource_type;
+ u32 rg_resource_data[1];
+};
+
+struct hfi_cmd_sys_release_resource_packet {
+ u32 size;
+ u32 packet_type;
+ u32 resource_type;
+ u32 resource_handle;
+};
+
+struct hfi_cmd_sys_set_property_packet {
+ u32 size;
+ u32 packet_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_cmd_sys_get_property_packet {
+ u32 size;
+ u32 packet_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_cmd_sys_session_init_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 session_domain;
+ u32 session_codec;
+};
+
+struct hfi_cmd_sys_session_end_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_sys_set_buffers_packet {
+ u32 size;
+ u32 packet_type;
+ u32 buffer_type;
+ u32 buffer_size;
+ u32 num_buffers;
+ u32 rg_buffer_addr[1];
+};
+
+struct hfi_cmd_session_set_property_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 num_properties;
+ u32 rg_property_data[0];
+};
+
+struct hfi_cmd_session_set_buffers_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 buffer_type;
+ u32 buffer_mode;
+ u32 buffer_size;
+ u32 extra_data_size;
+ u32 min_buffer_size;
+ u32 num_buffers;
+ u32 rg_buffer_info[1];
+};
+
+struct hfi_cmd_session_get_sequence_header_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 buffer_len;
+ u8 *packet_buffer;
+};
+
+struct hfi_msg_event_notify_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 event_id;
+ u32 event_data1;
+ u32 event_data2;
+ u32 rg_ext_event_data[1];
+};
+
+struct hfi_msg_sys_init_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 error_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_sys_pc_prep_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 error_type;
+};
+
+struct hfi_msg_sys_release_resource_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 resource_handle;
+ u32 error_type;
+};
+
+struct hfi_msg_sys_session_init_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_sys_session_end_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_get_sequence_header_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 header_len;
+ u8 *sequence_header;
+};
+
+struct hfi_msg_sys_debug_packet {
+ u32 size;
+ u32 packet_type;
+ u32 msg_type;
+ u32 msg_size;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u8 rg_msg_data[1];
+};
+
+#endif
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 02b9699..b604d0a 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -15,7 +15,7 @@
#include <linux/list.h>
#include "vidc_hal.h"
-static enum vidc_status vidc_map_hal_err_status(enum HFI_ERROR hfi_err)
+static enum vidc_status vidc_map_hal_err_status(int hfi_err)
{
enum vidc_status vidc_err;
switch (hfi_err) {
@@ -64,8 +64,6 @@
case HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED:
vidc_err = VIDC_ERR_IFRAME_EXPECTED;
break;
- case HFI_ERR_SYS_UNKNOWN:
- case HFI_ERR_SESSION_UNKNOWN:
case HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING:
default:
vidc_err = VIDC_ERR_FAIL;
@@ -82,7 +80,7 @@
int num_properties_changed;
struct hfi_frame_size frame_sz;
u8 *data_ptr;
- enum HFI_PROPERTY prop_id;
+ int prop_id;
HAL_MSG_LOW("RECEIVED:EVENT_NOTIFY");
if (sizeof(struct hfi_msg_event_notify_packet)
> pkt->size) {
@@ -103,12 +101,11 @@
if (num_properties_changed) {
data_ptr = (u8 *) &pkt->rg_ext_event_data[0];
do {
- prop_id = (enum HFI_PROPERTY) *((u32 *)data_ptr);
+ prop_id = (int) *((u32 *)data_ptr);
switch (prop_id) {
case HFI_PROPERTY_PARAM_FRAME_SIZE:
- frame_sz.buffer =
- (enum HFI_BUFFER)
- *((((u32 *)data_ptr)+1));
+ frame_sz.buffer_type =
+ (int) *((((u32 *)data_ptr)+1));
frame_sz.width =
event_notify.width =
*((((u32 *)data_ptr)+2));
@@ -165,7 +162,7 @@
struct vidc_hal_sys_init_done sys_init_done;
u32 rem_bytes, bytes_read = 0, num_properties;
u8 *data_ptr;
- enum HFI_PROPERTY prop_id;
+ int prop_id;
enum vidc_status status = VIDC_ERR_NONE;
HAL_MSG_LOW("RECEIVED:SYS_INIT_DONE");
@@ -202,7 +199,7 @@
num_properties = pkt->num_properties;
while ((num_properties != 0) && (rem_bytes >= sizeof(u32))) {
- prop_id = (enum HFI_PROPERTY) *((u32 *)data_ptr);
+ prop_id = *((u32 *)data_ptr);
data_ptr = data_ptr + 4;
switch (prop_id) {
@@ -282,8 +279,8 @@
rc = VIDC_ERR_FAIL;
}
HAL_MSG_LOW("got buffer requirements for: %d",
- hfi_buf_req->buffer);
- switch (hfi_buf_req->buffer) {
+ hfi_buf_req->buffer_type);
+ switch (hfi_buf_req->buffer_type) {
case HFI_BUFFER_INPUT:
memcpy(&buffreq->buffer[0], hfi_buf_req,
sizeof(struct hfi_buffer_requirements));
@@ -330,8 +327,8 @@
HAL_BUFFER_INTERNAL_PERSIST;
break;
default:
- HAL_MSG_ERROR("hal_process_sess_get_prop_buf_req:"
- "bad_buffer_type: %d", hfi_buf_req->buffer);
+ HAL_MSG_ERROR("%s: bad_buffer_type: %d",
+ __func__, hfi_buf_req->buffer_type);
break;
}
req_bytes -= sizeof(struct hfi_buffer_requirements);
@@ -525,8 +522,8 @@
data_done.size = sizeof(struct msm_vidc_cb_data_done);
data_done.clnt_data = (void *) pkt->input_tag;
- data_done.output_done.timestamp_hi = pkt->timestamp_hi;
- data_done.output_done.timestamp_lo = pkt->timestamp_lo;
+ data_done.output_done.timestamp_hi = pkt->time_stamp_hi;
+ data_done.output_done.timestamp_lo = pkt->time_stamp_lo;
data_done.output_done.flags1 = pkt->flags;
data_done.output_done.mark_target = pkt->mark_target;
data_done.output_done.mark_data = pkt->mark_data;
@@ -559,20 +556,20 @@
data_done.output_done.stream_id = pkt->stream_id;
data_done.output_done.view_id = pkt->view_id;
- data_done.output_done.timestamp_hi = pkt->timestamp_hi;
- data_done.output_done.timestamp_lo = pkt->timestamp_lo;
+ data_done.output_done.timestamp_hi = pkt->time_stamp_hi;
+ data_done.output_done.timestamp_lo = pkt->time_stamp_lo;
data_done.output_done.flags1 = pkt->flags;
data_done.output_done.mark_target = pkt->mark_target;
data_done.output_done.mark_data = pkt->mark_data;
data_done.output_done.stats = pkt->stats;
data_done.output_done.alloc_len1 = pkt->alloc_len;
data_done.output_done.filled_len1 = pkt->filled_len;
- data_done.output_done.offset1 = pkt->oofset;
+ data_done.output_done.offset1 = pkt->offset;
data_done.output_done.frame_width = pkt->frame_width;
data_done.output_done.frame_height = pkt->frame_height;
- data_done.output_done.start_xCoord = pkt->start_xCoord;
- data_done.output_done.start_yCoord = pkt->start_yCoord;
- data_done.output_done.input_tag1 = pkt->input_tag1;
+ data_done.output_done.start_xCoord = pkt->start_x_coord;
+ data_done.output_done.start_yCoord = pkt->start_y_coord;
+ data_done.output_done.input_tag1 = pkt->input_tag;
data_done.output_done.picture_type = pkt->picture_type;
data_done.output_done.packet_buffer1 = pkt->packet_buffer;
data_done.output_done.extra_data_buffer =
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index bbb2509..021dcf1 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -31,7 +31,8 @@
#define WCD9XXX_SLIM_RW_MAX_TRIES 3
#define MAX_WCD9XXX_DEVICE 4
-#define WCD9XXX_I2C_MODE 0x03
+#define TABLA_I2C_MODE 0x03
+#define SITAR_I2C_MODE 0x01
struct wcd9xxx_i2c {
struct i2c_client *client;
@@ -351,15 +352,15 @@
* care of now only tabla.
*/
pr_debug("%s : Read codec version using I2C\n", __func__);
- if (TABLA_IS_1_X(wcd9xxx->version)) {
+ if (!strncmp(wcd9xxx_modules[0].client->name, "sitar", 5)) {
+ wcd9xxx_dev = sitar_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
+ } else if (TABLA_IS_1_X(wcd9xxx->version)) {
wcd9xxx_dev = tabla1x_devs;
wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
} else if (TABLA_IS_2_0(wcd9xxx->version)) {
wcd9xxx_dev = tabla_devs;
wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
- } else {
- wcd9xxx_dev = sitar_devs;
- wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
}
}
@@ -712,8 +713,10 @@
struct wcd9xxx_pdata *pdata = client->dev.platform_data;
int val = 0;
int ret = 0;
+ int i2c_mode = 0;
static int device_id;
+ pr_info("%s\n", __func__);
if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
pr_info("tabla card is already detected in slimbus mode\n");
return -ENODEV;
@@ -765,10 +768,13 @@
/*read the tabla status before initializing the device type*/
ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
- if ((ret < 0) || (val != WCD9XXX_I2C_MODE)) {
- pr_err("failed to read the wcd9xxx status\n");
- goto err_device_init;
- }
+ if (!strncmp(wcd9xxx_modules[0].client->name, "sitar", 5))
+ i2c_mode = SITAR_I2C_MODE;
+ else if (!strncmp(wcd9xxx_modules[0].client->name, "tabla", 5))
+ i2c_mode = TABLA_I2C_MODE;
+
+ if ((ret < 0) || (val != i2c_mode))
+ pr_err("failed to read the wcd9xxx status ret = %d\n", ret);
ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
if (ret) {
@@ -1107,16 +1113,25 @@
.suspend = wcd9xxx_slim_suspend,
};
-#define TABLA_I2C_TOP_LEVEL 0
-#define TABLA_I2C_ANALOG 1
-#define TABLA_I2C_DIGITAL_1 2
-#define TABLA_I2C_DIGITAL_2 3
+#define WCD9XXX_I2C_TOP_LEVEL 0
+#define WCD9XXX_I2C_ANALOG 1
+#define WCD9XXX_I2C_DIGITAL_1 2
+#define WCD9XXX_I2C_DIGITAL_2 3
static struct i2c_device_id tabla_id_table[] = {
- {"tabla top level", TABLA_I2C_TOP_LEVEL},
- {"tabla analog", TABLA_I2C_TOP_LEVEL},
- {"tabla digital1", TABLA_I2C_TOP_LEVEL},
- {"tabla digital2", TABLA_I2C_TOP_LEVEL},
+ {"tabla top level", WCD9XXX_I2C_TOP_LEVEL},
+ {"tabla analog", WCD9XXX_I2C_ANALOG},
+ {"tabla digital1", WCD9XXX_I2C_DIGITAL_1},
+ {"tabla digital2", WCD9XXX_I2C_DIGITAL_2},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tabla_id_table);
+
+static struct i2c_device_id sitar_id_table[] = {
+ {"sitar top level", WCD9XXX_I2C_TOP_LEVEL},
+ {"sitar analog", WCD9XXX_I2C_ANALOG},
+ {"sitar digital1", WCD9XXX_I2C_DIGITAL_1},
+ {"sitar digital2", WCD9XXX_I2C_DIGITAL_2},
{}
};
MODULE_DEVICE_TABLE(i2c, tabla_id_table);
@@ -1133,9 +1148,21 @@
.suspend = wcd9xxx_i2c_suspend,
};
+static struct i2c_driver sitar_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "sitar-i2c-core",
+ },
+ .id_table = sitar_id_table,
+ .probe = wcd9xxx_i2c_probe,
+ .remove = __devexit_p(wcd9xxx_i2c_remove),
+ .resume = wcd9xxx_i2c_resume,
+ .suspend = wcd9xxx_i2c_suspend,
+};
+
static int __init wcd9xxx_init(void)
{
- int ret1, ret2, ret3, ret4, ret5;
+ int ret1, ret2, ret3, ret4, ret5, ret6;
ret1 = slim_driver_register(&tabla_slim_driver);
if (ret1 != 0)
@@ -1157,7 +1184,11 @@
if (ret5 != 0)
pr_err("Failed to register sitar SB driver: %d\n", ret5);
- return (ret1 && ret2 && ret3 && ret4 && ret5) ? -1 : 0;
+ ret6 = i2c_add_driver(&sitar_i2c_driver);
+ if (ret6 != 0)
+ pr_err("failed to add the I2C driver\n");
+
+ return (ret1 && ret2 && ret3 && ret4 && ret5 && ret6) ? -1 : 0;
}
module_init(wcd9xxx_init);
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index 555dfdd..6c3e787 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -20,6 +20,7 @@
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
#include <linux/i2c/isa1200.h>
#include "../staging/android/timed_output.h"
@@ -48,6 +49,7 @@
struct regulator **regs;
bool clk_on;
u8 hctrl0_val;
+ struct clk *pwm_clk;
};
static int isa1200_read_reg(struct i2c_client *client, int reg)
@@ -107,13 +109,23 @@
goto chip_dwn;
}
} else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
- /* vote for clock */
- if (haptic->pdata->clk_enable && !haptic->clk_on) {
+ /* check for board specific clk callback */
+ if (haptic->pdata->clk_enable) {
rc = haptic->pdata->clk_enable(true);
if (rc < 0) {
+ pr_err("%s: clk enable cb failed\n",
+ __func__);
+ goto chip_dwn;
+ }
+ }
+
+ /* vote for clock */
+ if (haptic->pdata->need_pwm_clk && !haptic->clk_on) {
+ rc = clk_enable(haptic->pwm_clk);
+ if (rc < 0) {
pr_err("%s: clk enable failed\n",
__func__);
- goto chip_dwn;
+ goto dis_clk_cb;
}
haptic->clk_on = true;
}
@@ -150,29 +162,35 @@
pr_err("%s: stop vibartion fail\n", __func__);
/* de-vote clock */
- if (haptic->pdata->clk_enable && haptic->clk_on) {
- rc = haptic->pdata->clk_enable(false);
- if (rc < 0) {
- pr_err("%s: clk disable failed\n",
- __func__);
- return;
- }
+ if (haptic->pdata->need_pwm_clk && haptic->clk_on) {
+ clk_disable(haptic->pwm_clk);
haptic->clk_on = false;
}
+ /* check for board specific clk callback */
+ if (haptic->pdata->clk_enable) {
+ rc = haptic->pdata->clk_enable(false);
+ if (rc < 0)
+ pr_err("%s: clk disable cb failed\n",
+ __func__);
+ }
}
}
return;
dis_clk:
- if (haptic->pdata->clk_enable && haptic->clk_on) {
- rc = haptic->pdata->clk_enable(false);
- if (rc < 0) {
- pr_err("%s: clk disable failed\n", __func__);
- return;
- }
+ if (haptic->pdata->need_pwm_clk && haptic->clk_on) {
+ clk_disable(haptic->pwm_clk);
haptic->clk_on = false;
}
+
+dis_clk_cb:
+ if (haptic->pdata->clk_enable) {
+ rc = haptic->pdata->clk_enable(false);
+ if (rc < 0)
+ pr_err("%s: clk disable cb failed\n", __func__);
+ }
+
chip_dwn:
if (haptic->is_len_gpio_valid == true)
gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
@@ -545,6 +563,13 @@
ret = PTR_ERR(haptic->pwm);
goto reset_hctrl0;
}
+ } else if (haptic->pdata->need_pwm_clk) {
+ haptic->pwm_clk = clk_get(&client->dev, "pwm_clk");
+ if (IS_ERR(haptic->pwm_clk)) {
+ dev_err(&client->dev, "pwm_clk get failed\n");
+ ret = PTR_ERR(haptic->pwm_clk);
+ goto reset_hctrl0;
+ }
}
printk(KERN_INFO "%s: %s registered\n", __func__, id->name);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e9ccbc7..4534cd8 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -378,8 +378,7 @@
host->curr.got_dataend = 0;
host->curr.wait_for_auto_prog_done = false;
host->curr.got_auto_prog_done = false;
- writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
- (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
+ writel_relaxed(0, host->base + MMCIDATACTRL);
msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
}
@@ -3062,7 +3061,7 @@
msleep(300);
status = gpio_get_value_cansleep(
host->plat->wpswitch_gpio);
- status ^= !host->plat->wpswitch_polarity;
+ status ^= !host->plat->is_wpswitch_active_low;
}
gpio_free(host->plat->wpswitch_gpio);
}
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 8b1d5e6..e569132 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1016,13 +1016,8 @@
send_check_condition = 1;
goto attach_cmd;
}
- /*
- * The Initiator Node has access to the LUN (the addressing method
- * is handled inside of iscsit_get_lun_for_cmd()). Now it's time to
- * allocate 1->N transport tasks (depending on sector count and
- * maximum request size the physical HBA(s) can handle.
- */
- transport_ret = transport_generic_allocate_tasks(&cmd->se_cmd, hdr->cdb);
+
+ transport_ret = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb);
if (transport_ret == -ENOMEM) {
return iscsit_add_reject_from_cmd(
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index a9b4eee..38dfac2 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -213,7 +213,7 @@
* associated read buffers, go ahead and do that here for type
* SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently
* guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
- * by target core in transport_generic_allocate_tasks() ->
+ * by target core in target_setup_cmd_from_cdb() ->
* transport_generic_cmd_sequencer().
*/
if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
@@ -227,7 +227,7 @@
}
}
- ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd);
+ ret = target_setup_cmd_from_cdb(se_cmd, sc->cmnd);
if (ret == -ENOMEM) {
transport_send_check_condition_and_sense(se_cmd,
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 443704f..843ad54 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1550,11 +1550,11 @@
return 0;
}
-/* transport_generic_allocate_tasks():
+/* target_setup_cmd_from_cdb():
*
* Called from fabric RX Thread.
*/
-int transport_generic_allocate_tasks(
+int target_setup_cmd_from_cdb(
struct se_cmd *cmd,
unsigned char *cdb)
{
@@ -1620,7 +1620,7 @@
spin_unlock(&cmd->se_lun->lun_sep_lock);
return 0;
}
-EXPORT_SYMBOL(transport_generic_allocate_tasks);
+EXPORT_SYMBOL(target_setup_cmd_from_cdb);
/*
* Used by fabric module frontends to queue tasks directly.
@@ -1701,6 +1701,8 @@
*/
transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess,
data_length, data_dir, task_attr, sense);
+ if (flags & TARGET_SCF_UNKNOWN_SIZE)
+ se_cmd->unknown_data_length = 1;
/*
* Obtain struct se_cmd->cmd_kref reference and add new cmd to
* se_sess->sess_cmd_list. A second kref_get here is necessary
@@ -1726,7 +1728,7 @@
* Sanitize CDBs via transport_generic_cmd_sequencer() and
* allocate the necessary tasks to complete the received CDB+data
*/
- rc = transport_generic_allocate_tasks(se_cmd, cdb);
+ rc = target_setup_cmd_from_cdb(se_cmd, cdb);
if (rc != 0) {
transport_generic_request_failure(se_cmd);
return;
@@ -2581,7 +2583,7 @@
* Generic Command Sequencer that should work for most DAS transport
* drivers.
*
- * Called from transport_generic_allocate_tasks() in the $FABRIC_MOD
+ * Called from target_setup_cmd_from_cdb() in the $FABRIC_MOD
* RX Thread.
*
* FIXME: Need to support other SCSI OPCODES where as well.
@@ -3142,6 +3144,9 @@
goto out_unsupported_cdb;
}
+ if (cmd->unknown_data_length)
+ cmd->data_length = size;
+
if (size != cmd->data_length) {
pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
" %u does not match SCSI CDB Length: %u for SAM Opcode:"
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index fbe0dd7..d99a02a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -66,6 +66,7 @@
config THERMAL_MONITOR
bool "Monitor thermal state and limit CPU Frequency"
depends on THERMAL_TSENS8960
+ depends on CPU_FREQ_MSM
default n
help
This enables thermal monitoring capability in the kernel in the
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index e0d8d14..a8d3720 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -14,60 +14,51 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/cpufreq.h>
#include <linux/mutex.h>
#include <linux/msm_tsens.h>
#include <linux/workqueue.h>
#include <linux/cpu.h>
-
-#define DEF_TEMP_SENSOR 0
-#define DEF_THERMAL_CHECK_MS 1000
-#define DEF_ALLOWED_MAX_HIGH 60
-#define DEF_ALLOWED_MAX_FREQ 918000
+#include <linux/cpufreq.h>
+#include <linux/msm_tsens.h>
+#include <linux/msm_thermal.h>
+#include <mach/cpufreq.h>
static int enabled;
-static int allowed_max_high = DEF_ALLOWED_MAX_HIGH;
-static int allowed_max_low = (DEF_ALLOWED_MAX_HIGH - 10);
-static int allowed_max_freq = DEF_ALLOWED_MAX_FREQ;
-static int check_interval_ms = DEF_THERMAL_CHECK_MS;
-
-module_param(allowed_max_high, int, 0);
-module_param(allowed_max_freq, int, 0);
-module_param(check_interval_ms, int, 0);
-
+static struct msm_thermal_data msm_thermal_info;
+static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
static struct delayed_work check_temp_work;
-static int update_cpu_max_freq(struct cpufreq_policy *cpu_policy,
- int cpu, int max_freq)
+static int update_cpu_max_freq(int cpu, uint32_t max_freq)
{
int ret = 0;
- if (!cpu_policy)
- return -EINVAL;
-
- cpufreq_verify_within_limits(cpu_policy,
- cpu_policy->min, max_freq);
- cpu_policy->user_policy.max = max_freq;
+ ret = msm_cpufreq_set_freq_limits(cpu, MSM_CPUFREQ_NO_LIMIT, max_freq);
+ if (ret)
+ return ret;
ret = cpufreq_update_policy(cpu);
- if (!ret)
- pr_info("msm_thermal: Limiting core%d max frequency to %d\n",
- cpu, max_freq);
+ if (ret)
+ return ret;
+
+ limited_max_freq = max_freq;
+ if (max_freq != MSM_CPUFREQ_NO_LIMIT)
+ pr_info("msm_thermal: Limiting cpu%d max frequency to %d\n",
+ cpu, max_freq);
+ else
+ pr_info("msm_thermal: Max frequency reset for cpu%d\n", cpu);
return ret;
}
static void check_temp(struct work_struct *work)
{
- struct cpufreq_policy *cpu_policy = NULL;
struct tsens_device tsens_dev;
unsigned long temp = 0;
- unsigned int max_freq = 0;
- int update_policy = 0;
+ uint32_t max_freq = limited_max_freq;
int cpu = 0;
int ret = 0;
- tsens_dev.sensor_num = DEF_TEMP_SENSOR;
+ tsens_dev.sensor_num = msm_thermal_info.sensor_id;
ret = tsens_get_temp(&tsens_dev, &temp);
if (ret) {
pr_debug("msm_thermal: Unable to read TSENS sensor %d\n",
@@ -75,61 +66,42 @@
goto reschedule;
}
+ if (temp >= msm_thermal_info.limit_temp)
+ max_freq = msm_thermal_info.limit_freq;
+ else if (temp <
+ msm_thermal_info.limit_temp - msm_thermal_info.temp_hysteresis)
+ max_freq = MSM_CPUFREQ_NO_LIMIT;
+
+ if (max_freq == limited_max_freq)
+ goto reschedule;
+
+ /* Update new limits */
for_each_possible_cpu(cpu) {
- update_policy = 0;
- cpu_policy = cpufreq_cpu_get(cpu);
- if (!cpu_policy) {
- pr_debug("msm_thermal: NULL policy on cpu %d\n", cpu);
- continue;
- }
- if (temp >= allowed_max_high) {
- if (cpu_policy->max > allowed_max_freq) {
- update_policy = 1;
- max_freq = allowed_max_freq;
- } else {
- pr_debug("msm_thermal: policy max for cpu %d "
- "already < allowed_max_freq\n", cpu);
- }
- } else if (temp < allowed_max_low) {
- if (cpu_policy->max < cpu_policy->cpuinfo.max_freq) {
- max_freq = cpu_policy->cpuinfo.max_freq;
- update_policy = 1;
- } else {
- pr_debug("msm_thermal: policy max for cpu %d "
- "already at max allowed\n", cpu);
- }
- }
-
- if (update_policy)
- update_cpu_max_freq(cpu_policy, cpu, max_freq);
-
- cpufreq_cpu_put(cpu_policy);
+ ret = update_cpu_max_freq(cpu, max_freq);
+ if (ret)
+ pr_debug("Unable to limit cpu%d max freq to %d\n",
+ cpu, max_freq);
}
reschedule:
if (enabled)
schedule_delayed_work(&check_temp_work,
- msecs_to_jiffies(check_interval_ms));
+ msecs_to_jiffies(msm_thermal_info.poll_ms));
}
static void disable_msm_thermal(void)
{
int cpu = 0;
- struct cpufreq_policy *cpu_policy = NULL;
/* make sure check_temp is no longer running */
cancel_delayed_work(&check_temp_work);
flush_scheduled_work();
+ if (limited_max_freq == MSM_CPUFREQ_NO_LIMIT)
+ return;
+
for_each_possible_cpu(cpu) {
- cpu_policy = cpufreq_cpu_get(cpu);
- if (cpu_policy) {
- if (cpu_policy->max < cpu_policy->cpuinfo.max_freq)
- update_cpu_max_freq(cpu_policy, cpu,
- cpu_policy->
- cpuinfo.max_freq);
- cpufreq_cpu_put(cpu_policy);
- }
+ update_cpu_max_freq(cpu, MSM_CPUFREQ_NO_LIMIT);
}
}
@@ -156,16 +128,17 @@
module_param_cb(enabled, &module_ops, &enabled, 0644);
MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
-static int __init msm_thermal_init(void)
+int __init msm_thermal_init(struct msm_thermal_data *pdata)
{
int ret = 0;
+ BUG_ON(!pdata);
+ BUG_ON(pdata->sensor_id >= TSENS_MAX_SENSORS);
+ memcpy(&msm_thermal_info, pdata, sizeof(struct msm_thermal_data));
+
enabled = 1;
INIT_DELAYED_WORK(&check_temp_work, check_temp);
-
schedule_delayed_work(&check_temp_work, 0);
return ret;
}
-fs_initcall(msm_thermal_init);
-
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 21b9669..083ed19 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -95,6 +95,8 @@
struct msm_hs_tx {
unsigned int tx_ready_int_en; /* ok to dma more tx */
unsigned int dma_in_flight; /* tx dma in progress */
+ enum flush_reason flush;
+ wait_queue_head_t wait;
struct msm_dmov_cmd xfer;
dmov_box *command_ptr;
u32 *command_ptr_ptr;
@@ -895,7 +897,7 @@
dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
sizeof(u32), DMA_TO_DEVICE);
-
+ msm_uport->tx.flush = FLUSH_NONE;
msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
}
@@ -1115,9 +1117,13 @@
{
struct msm_hs_port *msm_uport;
- WARN_ON(result != 0x80000002); /* DMA did not finish properly */
-
msm_uport = container_of(cmd_ptr, struct msm_hs_port, tx.xfer);
+ if (msm_uport->tx.flush == FLUSH_STOP)
+ /* DMA FLUSH unsuccesfful */
+ WARN_ON(!(result & DMOV_RSLT_FLUSH));
+ else
+ /* DMA did not finish properly */
+ WARN_ON(!(result & DMOV_RSLT_DONE));
tasklet_schedule(&msm_uport->tx.tlet);
}
@@ -1129,6 +1135,12 @@
tlet_ptr, struct msm_hs_port, tx.tlet);
spin_lock_irqsave(&(msm_uport->uport.lock), flags);
+ if (msm_uport->tx.flush == FLUSH_STOP) {
+ msm_uport->tx.flush = FLUSH_SHUTDOWN;
+ wake_up(&msm_uport->tx.wait);
+ spin_unlock_irqrestore(&(msm_uport->uport.lock), flags);
+ return;
+ }
msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
msm_hs_write(&(msm_uport->uport), UARTDM_IMR_ADDR, msm_uport->imr_reg);
@@ -1770,6 +1782,7 @@
tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
init_waitqueue_head(&rx->wait);
+ init_waitqueue_head(&tx->wait);
wake_lock_init(&rx->wake_lock, WAKE_LOCK_SUSPEND, "msm_serial_hs_rx");
wake_lock_init(&msm_uport->dma_wake_lock, WAKE_LOCK_SUSPEND,
"msm_serial_hs_dma");
@@ -2043,19 +2056,41 @@
*/
static void msm_hs_shutdown(struct uart_port *uport)
{
+ int ret;
+ unsigned int data;
+ unsigned long flags;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
- BUG_ON(msm_uport->rx.flush < FLUSH_STOP);
+ if (msm_uport->tx.dma_in_flight) {
+ spin_lock_irqsave(&uport->lock, flags);
+ /* disable UART TX interface to DM */
+ data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+ data &= ~UARTDM_TX_DM_EN_BMSK;
+ msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+ /* turn OFF UART Transmitter */
+ msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
+ /* reset UART TX */
+ msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
+ /* reset UART TX Error */
+ msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX_ERROR);
+ msm_uport->tx.flush = FLUSH_STOP;
+ spin_unlock_irqrestore(&uport->lock, flags);
+ /* discard flush */
+ msm_dmov_flush(msm_uport->dma_tx_channel, 0);
+ ret = wait_event_timeout(msm_uport->tx.wait,
+ msm_uport->tx.flush == FLUSH_SHUTDOWN, 100);
+ if (!ret)
+ pr_err("%s():HSUART TX Stalls.\n", __func__);
+ }
tasklet_kill(&msm_uport->tx.tlet);
+ BUG_ON(msm_uport->rx.flush < FLUSH_STOP);
wait_event(msm_uport->rx.wait, msm_uport->rx.flush == FLUSH_SHUTDOWN);
tasklet_kill(&msm_uport->rx.tlet);
cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work);
-
flush_workqueue(msm_uport->hsuart_wq);
pm_runtime_disable(uport->dev);
pm_runtime_set_suspended(uport->dev);
- mutex_lock(&msm_uport->clk_mutex);
/* Disable the transmitter */
msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
/* Disable the receiver */
@@ -2068,7 +2103,6 @@
* Hence mb() requires here.
*/
mb();
-
if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
/* to balance clk_state */
clk_disable_unprepare(msm_uport->clk);
@@ -2076,8 +2110,8 @@
clk_disable_unprepare(msm_uport->pclk);
wake_unlock(&msm_uport->dma_wake_lock);
}
- msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
+ msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
dma_unmap_single(uport->dev, msm_uport->tx.dma_base,
UART_XMIT_SIZE, DMA_TO_DEVICE);
@@ -2088,7 +2122,6 @@
free_irq(uport->irq, msm_uport);
if (use_low_power_wakeup(msm_uport))
free_irq(msm_uport->wakeup.irq, msm_uport);
- mutex_unlock(&msm_uport->clk_mutex);
mutex_destroy(&msm_uport->clk_mutex);
}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5dceb41..d97d548 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2808,6 +2808,7 @@
int usb_remote_wakeup(struct usb_device *udev)
{
int status = 0;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
if (udev->state == USB_STATE_SUSPENDED) {
dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
@@ -2816,7 +2817,11 @@
/* Let the drivers do their thing, then... */
usb_autosuspend_device(udev);
}
+ } else {
+ dev_dbg(&udev->dev, "usb not suspended\n");
+ clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
}
+
return status;
}
@@ -3152,7 +3157,9 @@
* value.
*/
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
- if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
+ if (USE_NEW_SCHEME(retry_counter) &&
+ !(hcd->driver->flags & HCD_USB3) &&
+ !(hcd->driver->flags & HCD_OLD_ENUM)) {
struct usb_device_descriptor *buf;
int r = 0;
@@ -3252,7 +3259,9 @@
* - read ep0 maxpacket even for high and low speed,
*/
msleep(10);
- if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
+ if (USE_NEW_SCHEME(retry_counter) &&
+ !(hcd->driver->flags & HCD_USB3) &&
+ !(hcd->driver->flags & HCD_OLD_ENUM))
break;
}
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 742beef..882eb97 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,6 +1,6 @@
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
- depends on (USB && USB_GADGET)
+ depends on (USB || USB_GADGET)
select USB_OTG_UTILS
select USB_GADGET_DUALSPEED
select USB_XHCI_PLATFORM
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 3227508..0b46082 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -1,11 +1,13 @@
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
+ccflags-y += -Idrivers/usb/host
obj-$(CONFIG_USB_DWC3) += dwc3.o
dwc3-y := core.o
dwc3-y += host.o
dwc3-y += gadget.o ep0.o
+dwc3-y += dwc3_otg.o
ifneq ($(CONFIG_DEBUG_FS),)
dwc3-y += debugfs.o
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 99b58d8..1fbfdd8 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -372,6 +372,32 @@
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ /*
+ * Currently, the default and the recommended value for GUSB3PIPECTL
+ * [21:19] in the RTL is 3'b100 or 32 consecutive errors. Based on
+ * analysis and experiments in the lab, it is found that there is a
+ * relatively low probability of getting 32 consecutive word errors
+ * in the presence of random recovered noise (during electrical idle).
+ * This can delay the entry to a low power state such that for
+ * applications where the link stays in a non-U0 state for a short
+ * duration (< 1 microsecond), the local PHY does not enter the low
+ * power state prior to receiving a potential LFPS wakeup. This causes
+ * the PHY CDR (Clock and Data Recovery) operation to be unstable for
+ * some Synopsys PHYs.
+ *
+ * The proposal now is to change the default and the recommended value
+ * for GUSB3PIPECTL[21:19] in the RTL from 3'b100 to a minimum of
+ * 3'b001. Perform the same in software for controllers prior to 2.30a
+ * revision.
+ */
+
+ if (dwc->revision < DWC3_REVISION_230A) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg &= ~DWC3_GUSB3PIPECTL_DELAY_P1P2P3;
+ reg |= 1 << __ffs(DWC3_GUSB3PIPECTL_DELAY_P1P2P3);
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+ }
+
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
if (ret) {
dev_err(dwc->dev, "failed to allocate event buffers\n");
@@ -410,7 +436,6 @@
struct device *dev = &pdev->dev;
int ret = -ENOMEM;
- int irq;
void __iomem *regs;
void *mem;
@@ -425,16 +450,30 @@
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
- dev_err(dev, "missing resource\n");
+ dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
+ dwc->xhci_resources[1] = *res;
- dwc->res = res;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing memory resource\n");
+ return -ENODEV;
+ }
+ dwc->xhci_resources[0] = *res;
+ dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+ DWC3_XHCI_REGS_END;
- res = devm_request_mem_region(dev, res->start, resource_size(res),
+ /*
+ * Request memory region but exclude xHCI regs,
+ * since it will be requested by the xhci-plat driver.
+ */
+ res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
+ resource_size(res) - DWC3_GLOBALS_REGS_START,
dev_name(dev));
+
if (!res) {
dev_err(dev, "can't request mem region\n");
return -ENOMEM;
@@ -446,19 +485,12 @@
return -ENOMEM;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(dev, "missing IRQ\n");
- return -ENODEV;
- }
-
spin_lock_init(&dwc->lock);
platform_set_drvdata(pdev, dwc);
dwc->regs = regs;
dwc->regs_size = resource_size(res);
dwc->dev = dev;
- dwc->irq = irq;
if (!strncmp("super", maximum_speed, 5))
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
@@ -505,15 +537,24 @@
break;
case DWC3_MODE_DRD:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+ ret = dwc3_otg_init(dwc);
+ if (ret) {
+ dev_err(dev, "failed to initialize otg\n");
+ goto err1;
+ }
+
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
+ dwc3_otg_exit(dwc);
goto err1;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
+ dwc3_host_exit(dwc);
+ dwc3_otg_exit(dwc);
goto err1;
}
break;
@@ -542,8 +583,9 @@
dwc3_host_exit(dwc);
break;
case DWC3_MODE_DRD:
- dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
+ dwc3_host_exit(dwc);
+ dwc3_otg_exit(dwc);
break;
default:
/* do nothing */
@@ -576,8 +618,9 @@
dwc3_host_exit(dwc);
break;
case DWC3_MODE_DRD:
- dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
+ dwc3_host_exit(dwc);
+ dwc3_otg_exit(dwc);
break;
default:
/* do nothing */
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 6c7945b..98adff7 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -50,10 +50,13 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include "dwc3_otg.h"
+
/* Global constants */
#define DWC3_ENDPOINTS_NUM 32
+#define DWC3_XHCI_RESOURCES_NUM 2
-#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
+#define DWC3_EVENT_BUFFERS_SIZE (2 * PAGE_SIZE)
#define DWC3_EVENT_TYPE_MASK 0xfe
#define DWC3_EVENT_TYPE_DEV 0
@@ -70,11 +73,22 @@
#define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9
#define DWC3_DEVICE_EVENT_CMD_CMPL 10
#define DWC3_DEVICE_EVENT_OVERFLOW 11
+#define DWC3_DEVICE_EVENT_VENDOR_DEV_TEST_LMP 12
#define DWC3_GEVNTCOUNT_MASK 0xfffc
#define DWC3_GSNPSID_MASK 0xffff0000
#define DWC3_GSNPSREV_MASK 0xffff
+/* DWC3 registers memory space boundries */
+#define DWC3_XHCI_REGS_START 0x0
+#define DWC3_XHCI_REGS_END 0x7fff
+#define DWC3_GLOBALS_REGS_START 0xc100
+#define DWC3_GLOBALS_REGS_END 0xc6ff
+#define DWC3_DEVICE_REGS_START 0xc700
+#define DWC3_DEVICE_REGS_END 0xcbff
+#define DWC3_OTG_REGS_START 0xcc00
+#define DWC3_OTG_REGS_END 0xccff
+
/* Global Registers */
#define DWC3_GSBUSCFG0 0xc100
#define DWC3_GSBUSCFG1 0xc104
@@ -139,8 +153,9 @@
/* OTG Registers */
#define DWC3_OCFG 0xcc00
#define DWC3_OCTL 0xcc04
-#define DWC3_OEVTEN 0xcc08
-#define DWC3_OSTS 0xcc0C
+#define DWC3_OEVT 0xcc08
+#define DWC3_OEVTEN 0xcc0c
+#define DWC3_OSTS 0xcc10
/* Bit fields */
@@ -172,6 +187,7 @@
/* Global USB3 PIPE Control Register */
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+#define DWC3_GUSB3PIPECTL_DELAY_P1P2P3 (7 << 19)
/* Global TX Fifo Size Register */
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
@@ -182,6 +198,9 @@
#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
+/* Global HWPARAMS6 Register */
+#define DWC3_GHWPARAMS6_SRP_SUPPORT (1 << 10)
+
/* Device Configuration Register */
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@@ -300,6 +319,37 @@
#define DWC3_DEPCMD_TYPE_BULK 2
#define DWC3_DEPCMD_TYPE_INTR 3
+/* OTG Events Register */
+#define DWC3_OEVT_DEVICEMODE (1 << 31)
+#define DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT (1 << 24)
+#define DWC3_OEVTEN_OTGADEVBHOSTENDEVNT (1 << 20)
+#define DWC3_OEVTEN_OTGADEVHOSTEVNT (1 << 19)
+#define DWC3_OEVTEN_OTGADEVHNPCHNGEVNT (1 << 18)
+#define DWC3_OEVTEN_OTGADEVSRPDETEVNT (1 << 17)
+#define DWC3_OEVTEN_OTGADEVSESSENDDETEVNT (1 << 16)
+#define DWC3_OEVTEN_OTGBDEVBHOSTENDEVNT (1 << 11)
+#define DWC3_OEVTEN_OTGBDEVHNPCHNGEVNT (1 << 10)
+#define DWC3_OEVTEN_OTGBDEVSESSVLDDETEVNT (1 << 9)
+#define DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT (1 << 8)
+
+/* OTG OSTS register */
+#define DWC3_OTG_OSTS_OTGSTATE_SHIFT (8)
+#define DWC3_OTG_OSTS_OTGSTATE (0xF << DWC3_OTG_OSTS_OTGSTATE_SHIFT)
+#define DWC3_OTG_OSTS_PERIPHERALSTATE (1 << 4)
+#define DWC3_OTG_OSTS_XHCIPRTPOWER (1 << 3)
+#define DWC3_OTG_OSTS_BSESVALID (1 << 2)
+#define DWC3_OTG_OSTS_VBUSVALID (1 << 1)
+#define DWC3_OTG_OSTS_CONIDSTS (1 << 0)
+
+/* OTG OSTS register */
+#define DWC3_OTG_OCTL_PERIMODE (1 << 6)
+#define DWC3_OTG_OCTL_PRTPWRCTL (1 << 5)
+#define DWC3_OTG_OCTL_HNPREQ (1 << 4)
+#define DWC3_OTG_OCTL_SESREQ (1 << 3)
+#define DWC3_OTG_OCTL_TERMSELDLPULSE (1 << 2)
+#define DWC3_OTG_OCTL_DEVSETHNPEN (1 << 1)
+#define DWC3_OTG_OCTL_HSTSETHNPEN (1 << 0)
+
/* Structures */
struct dwc3_trb;
@@ -582,8 +632,9 @@
spinlock_t lock;
struct device *dev;
+ struct dwc3_otg *dotg;
struct platform_device *xhci;
- struct resource *res;
+ struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
struct dwc3_event_buffer **ev_buffs;
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
@@ -594,8 +645,6 @@
void __iomem *regs;
size_t regs_size;
- int irq;
-
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
@@ -609,6 +658,7 @@
#define DWC3_REVISION_185A 0x5533185a
#define DWC3_REVISION_188A 0x5533188a
#define DWC3_REVISION_190A 0x5533190a
+#define DWC3_REVISION_230A 0x5533230a
unsigned is_selfpowered:1;
unsigned three_stage_setup:1;
@@ -633,6 +683,12 @@
u8 test_mode;
u8 test_mode_nr;
+
+ /* Indicate if the gadget was powered by the otg driver */
+ bool vbus_active;
+
+ /* Indicate if software connect was issued by the usb_gadget_driver */
+ bool softconnect;
};
/* -------------------------------------------------------------------------- */
@@ -772,6 +828,9 @@
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
+int dwc3_otg_init(struct dwc3 *dwc);
+void dwc3_otg_exit(struct dwc3 *dwc);
+
int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 5a79cae..d216f17 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/ioport.h>
+#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -30,6 +31,7 @@
#include <mach/rpm-regulator.h>
+#include "dwc3_otg.h"
#include "core.h"
#include "gadget.h"
@@ -87,6 +89,16 @@
#define DBM_TRB_DATA_SRC 0x40000000
#define DBM_TRB_DMA 0x20000000
#define DBM_TRB_EP_NUM(ep) (ep<<24)
+/**
+ * USB QSCRATCH Hardware registers
+ *
+ */
+#define QSCRATCH_REG_OFFSET (0x000F8800)
+#define CHARGING_DET_CTRL_REG (QSCRATCH_REG_OFFSET + 0x18)
+#define CHARGING_DET_OUTPUT_REG (QSCRATCH_REG_OFFSET + 0x1C)
+#define ALT_INTERRUPT_EN_REG (QSCRATCH_REG_OFFSET + 0x20)
+#define HS_PHY_IRQ_STAT_REG (QSCRATCH_REG_OFFSET + 0x24)
+
struct dwc3_msm_req_complete {
struct list_head list_item;
@@ -104,6 +116,7 @@
u8 ep_num_mapping[DBM_MAX_EPS];
const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
struct list_head req_complete_list;
+ struct clk *core_clk;
struct regulator *hsusb_3p3;
struct regulator *hsusb_1p8;
struct regulator *hsusb_vddcx;
@@ -111,6 +124,11 @@
struct regulator *ssusb_vddcx;
enum usb_vdd_type ss_vdd_type;
enum usb_vdd_type hs_vdd_type;
+ struct dwc3_charger charger;
+ struct usb_phy *otg_xceiv;
+ struct delayed_work chg_work;
+ enum usb_chg_state chg_state;
+ u8 dcd_retries;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -150,6 +168,7 @@
};
static struct dwc3_msm *context;
+static u64 dwc3_msm_dma_mask = DMA_BIT_MASK(64);
/**
*
@@ -221,6 +240,34 @@
}
/**
+ * Write register and read back masked value to confirm it is written
+ *
+ * @base - DWC3 base virtual address.
+ * @offset - register offset.
+ * @mask - register bitmask specifying what should be updated
+ * @val - value to write.
+ *
+ */
+static inline void dwc3_msm_write_readback(void *base, u32 offset,
+ const u32 mask, u32 val)
+{
+ u32 write_val, tmp = ioread32(base + offset);
+
+ tmp &= ~mask; /* retain other bits */
+ write_val = tmp | val;
+
+ iowrite32(write_val, base + offset);
+
+ /* Read back to see if val was written */
+ tmp = ioread32(base + offset);
+ tmp &= mask; /* clear other bits */
+
+ if (tmp != val)
+ dev_err(context->dev, "%s: write: %x to QSCRATCH: %x FAILED\n",
+ __func__, val, offset);
+}
+
+/**
* Return DBM EP number which is not already configured.
*
*/
@@ -996,6 +1043,184 @@
return rc < 0 ? rc : 0;
}
+static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
+{
+ u32 chg_ctrl;
+
+ /* Turn off VDP_SRC */
+ dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
+ msleep(20);
+
+ /* Before proceeding make sure VDP_SRC is OFF */
+ chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
+ if (chg_ctrl & 0x3F)
+ dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
+ __func__, chg_ctrl);
+ /*
+ * Configure DM as current source, DP as current sink
+ * and enable battery charging comparators.
+ */
+ dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x34);
+}
+
+static bool dwc3_chg_det_check_output(struct dwc3_msm *mdwc)
+{
+ u32 chg_det;
+ bool ret = false;
+
+ chg_det = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
+ ret = chg_det & 1;
+
+ return ret;
+}
+
+static void dwc3_chg_enable_primary_det(struct dwc3_msm *mdwc)
+{
+ /*
+ * Configure DP as current source, DM as current sink
+ * and enable battery charging comparators.
+ */
+ dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x30);
+}
+
+static inline bool dwc3_chg_check_dcd(struct dwc3_msm *mdwc)
+{
+ u32 chg_state;
+ bool ret = false;
+
+ chg_state = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
+ ret = chg_state & 2;
+
+ return ret;
+}
+
+static inline void dwc3_chg_disable_dcd(struct dwc3_msm *mdwc)
+{
+ dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x0);
+}
+
+static inline void dwc3_chg_enable_dcd(struct dwc3_msm *mdwc)
+{
+ /* Data contact detection enable, DCDENB */
+ dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x2);
+}
+
+static void dwc3_chg_block_reset(struct dwc3_msm *mdwc)
+{
+ u32 chg_ctrl;
+
+ /* Clear charger detecting control bits */
+ dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
+
+ /* Clear alt interrupt latch and enable bits */
+ dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
+ dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x0);
+
+ udelay(100);
+
+ /* Before proceeding make sure charger block is RESET */
+ chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
+ if (chg_ctrl & 0x3F)
+ dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
+ __func__, chg_ctrl);
+}
+
+static const char *chg_to_string(enum dwc3_chg_type chg_type)
+{
+ switch (chg_type) {
+ case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
+ case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
+ case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
+ default: return "INVALID_CHARGER";
+ }
+}
+
+#define DWC3_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
+#define DWC3_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
+#define DWC3_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
+#define DWC3_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
+
+static void dwc3_chg_detect_work(struct work_struct *w)
+{
+ struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, chg_work.work);
+ bool is_dcd = false, tmout, vout;
+ unsigned long delay;
+
+ dev_dbg(mdwc->dev, "chg detection work\n");
+ switch (mdwc->chg_state) {
+ case USB_CHG_STATE_UNDEFINED:
+ dwc3_chg_block_reset(mdwc);
+ dwc3_chg_enable_dcd(mdwc);
+ mdwc->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
+ mdwc->dcd_retries = 0;
+ delay = DWC3_CHG_DCD_POLL_TIME;
+ break;
+ case USB_CHG_STATE_WAIT_FOR_DCD:
+ is_dcd = dwc3_chg_check_dcd(mdwc);
+ tmout = ++mdwc->dcd_retries == DWC3_CHG_DCD_MAX_RETRIES;
+ if (is_dcd || tmout) {
+ dwc3_chg_disable_dcd(mdwc);
+ dwc3_chg_enable_primary_det(mdwc);
+ delay = DWC3_CHG_PRIMARY_DET_TIME;
+ mdwc->chg_state = USB_CHG_STATE_DCD_DONE;
+ } else {
+ delay = DWC3_CHG_DCD_POLL_TIME;
+ }
+ break;
+ case USB_CHG_STATE_DCD_DONE:
+ vout = dwc3_chg_det_check_output(mdwc);
+ if (vout) {
+ dwc3_chg_enable_secondary_det(mdwc);
+ delay = DWC3_CHG_SECONDARY_DET_TIME;
+ mdwc->chg_state = USB_CHG_STATE_PRIMARY_DONE;
+ } else {
+ mdwc->charger.chg_type = USB_SDP_CHARGER;
+ mdwc->chg_state = USB_CHG_STATE_DETECTED;
+ delay = 0;
+ }
+ break;
+ case USB_CHG_STATE_PRIMARY_DONE:
+ vout = dwc3_chg_det_check_output(mdwc);
+ if (vout)
+ mdwc->charger.chg_type = USB_DCP_CHARGER;
+ else
+ mdwc->charger.chg_type = USB_CDP_CHARGER;
+ mdwc->chg_state = USB_CHG_STATE_SECONDARY_DONE;
+ /* fall through */
+ case USB_CHG_STATE_SECONDARY_DONE:
+ mdwc->chg_state = USB_CHG_STATE_DETECTED;
+ /* fall through */
+ case USB_CHG_STATE_DETECTED:
+ dwc3_chg_block_reset(mdwc);
+ dev_dbg(mdwc->dev, "chg_type = %s\n",
+ chg_to_string(mdwc->charger.chg_type));
+ mdwc->charger.notify_detection_complete(mdwc->otg_xceiv->otg,
+ &mdwc->charger);
+ return;
+ default:
+ return;
+ }
+
+ queue_delayed_work(system_nrt_wq, &mdwc->chg_work, delay);
+}
+
+static void dwc3_start_chg_det(struct dwc3_charger *charger, bool start)
+{
+ struct dwc3_msm *mdwc = context;
+
+ if (start == false) {
+ cancel_delayed_work_sync(&mdwc->chg_work);
+ mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
+ charger->chg_type = DWC3_INVALID_CHARGER;
+ return;
+ }
+
+ mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
+ charger->chg_type = DWC3_INVALID_CHARGER;
+ queue_delayed_work(system_nrt_wq, &mdwc->chg_work, 0);
+}
+
+
static int __devinit dwc3_msm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -1015,6 +1240,19 @@
msm->dev = &pdev->dev;
INIT_LIST_HEAD(&msm->req_complete_list);
+ INIT_DELAYED_WORK(&msm->chg_work, dwc3_chg_detect_work);
+
+ /*
+ * DWC3 Core requires its CORE CLK (aka master / bus clk) to
+ * run at 125Mhz in SSUSB mode and >60MHZ for HSUSB mode.
+ */
+ msm->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(msm->core_clk)) {
+ dev_err(&pdev->dev, "failed to get core_clk\n");
+ return PTR_ERR(msm->core_clk);
+ }
+ clk_set_rate(msm->core_clk, 125000000);
+ clk_prepare_enable(msm->core_clk);
/* SS PHY */
msm->ss_vdd_type = VDDCX_CORNER;
@@ -1024,7 +1262,8 @@
"SSUSB_VDDCX");
if (IS_ERR(msm->ssusb_vddcx)) {
dev_err(&pdev->dev, "unable to get ssusb vddcx\n");
- return PTR_ERR(msm->ssusb_vddcx);
+ ret = PTR_ERR(msm->ssusb_vddcx);
+ goto disable_core_clk;
}
msm->ss_vdd_type = VDDCX;
dev_dbg(&pdev->dev, "ss_vdd_type: VDDCX\n");
@@ -1033,7 +1272,7 @@
ret = dwc3_ssusb_config_vddcx(1);
if (ret) {
dev_err(&pdev->dev, "ssusb vddcx configuration failed\n");
- return ret;
+ goto disable_core_clk;
}
ret = regulator_enable(context->ssusb_vddcx);
@@ -1115,10 +1354,9 @@
goto disable_hs_ldo;
}
- dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
-
dwc3->dev.parent = &pdev->dev;
- dwc3->dev.dma_mask = pdev->dev.dma_mask;
+ dwc3->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ dwc3->dev.dma_mask = &dwc3_msm_dma_mask;
dwc3->dev.dma_parms = pdev->dev.dma_parms;
msm->resource_size = resource_size(res);
msm->dwc3 = dwc3;
@@ -1155,8 +1393,24 @@
/* Reset the DBM */
dwc3_msm_dbm_soft_reset();
+ msm->otg_xceiv = usb_get_transceiver();
+ if (msm->otg_xceiv) {
+ msm->charger.start_detection = dwc3_start_chg_det;
+ ret = dwc3_set_charger(msm->otg_xceiv->otg, &msm->charger);
+ if (ret || !msm->charger.notify_detection_complete) {
+ dev_err(&pdev->dev, "failed to register charger: %d\n",
+ ret);
+ goto put_xcvr;
+ }
+ } else {
+ dev_err(&pdev->dev, "%s: No OTG transceiver found\n", __func__);
+ }
+
return 0;
+put_xcvr:
+ usb_put_transceiver(msm->otg_xceiv);
+ platform_device_del(dwc3);
put_pdev:
platform_device_put(dwc3);
disable_hs_ldo:
@@ -1175,6 +1429,8 @@
regulator_disable(context->ssusb_vddcx);
unconfig_ss_vddcx:
dwc3_ssusb_config_vddcx(0);
+disable_core_clk:
+ clk_disable_unprepare(msm->core_clk);
return ret;
}
@@ -1183,6 +1439,10 @@
{
struct dwc3_msm *msm = platform_get_drvdata(pdev);
+ if (msm->otg_xceiv) {
+ dwc3_start_chg_det(&msm->charger, false);
+ usb_put_transceiver(msm->otg_xceiv);
+ }
platform_device_unregister(msm->dwc3);
dwc3_hsusb_ldo_enable(0);
@@ -1193,6 +1453,7 @@
dwc3_ssusb_ldo_init(0);
regulator_disable(msm->ssusb_vddcx);
dwc3_ssusb_config_vddcx(0);
+ clk_disable_unprepare(msm->core_clk);
return 0;
}
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index d7d9c0e..a5c77ad 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -49,7 +49,6 @@
#include <linux/of.h>
#include "core.h"
-#include "io.h"
/*
* All these registers belong to OMAP's Wrapper around the
@@ -143,6 +142,17 @@
u32 dma_status:1;
};
+static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
+{
+ return readl_relaxed(base + offset);
+}
+
+static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
+{
+ writel_relaxed(value, base + offset);
+}
+
+
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
struct dwc3_omap *omap = _omap;
@@ -150,7 +160,7 @@
spin_lock(&omap->lock);
- reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_1);
if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
dev_dbg(omap->dev, "DMA Disable was Cleared\n");
@@ -184,10 +194,10 @@
if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
dev_dbg(omap->dev, "IDPULLUP Fall\n");
- dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
- reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
- dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
spin_unlock(&omap->lock);
@@ -270,7 +280,7 @@
omap->base = base;
omap->dwc3 = dwc3;
- reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
utmi_mode = of_get_property(node, "utmi-mode", &size);
if (utmi_mode && size == sizeof(*utmi_mode)) {
@@ -293,10 +303,10 @@
}
}
- dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
/* check the DMA Status */
- reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
/* Set No-Idle and No-Standby */
@@ -306,7 +316,7 @@
reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
- dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap);
@@ -318,7 +328,7 @@
/* enable all IRQs */
reg = USBOTGSS_IRQO_COREIRQ_ST;
- dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
reg = (USBOTGSS_IRQ1_OEVT |
USBOTGSS_IRQ1_DRVVBUS_RISE |
@@ -330,7 +340,7 @@
USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
USBOTGSS_IRQ1_IDPULLUP_FALL);
- dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
new file mode 100644
index 0000000..5df030a
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -0,0 +1,664 @@
+/**
+ * dwc3_otg.c - DesignWare USB3 DRD Controller OTG
+ *
+ * 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/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_device.h>
+
+#include "core.h"
+#include "dwc3_otg.h"
+#include "io.h"
+#include "xhci.h"
+
+
+/**
+ * dwc3_otg_set_host_regs - reset dwc3 otg registers to host operation.
+ *
+ * This function sets the OTG registers to work in A-Device host mode.
+ * This function should be called just before entering to A-Device mode.
+ *
+ * @w: Pointer to the dwc3 otg workqueue.
+ */
+static void dwc3_otg_set_host_regs(struct dwc3_otg *dotg)
+{
+ u32 octl;
+
+ /* Set OCTL[6](PeriMode) to 0 (host) */
+ octl = dwc3_readl(dotg->regs, DWC3_OCTL);
+ octl &= ~DWC3_OTG_OCTL_PERIMODE;
+ dwc3_writel(dotg->regs, DWC3_OCTL, octl);
+
+ /*
+ * TODO: add more OTG registers writes for HOST mode here,
+ * see figure 12-10 A-device flow in dwc3 Synopsis spec
+ */
+}
+
+/**
+ * dwc3_otg_set_peripheral_regs - reset dwc3 otg registers to peripheral operation.
+ *
+ * This function sets the OTG registers to work in B-Device peripheral mode.
+ * This function should be called just before entering to B-Device mode.
+ *
+ * @w: Pointer to the dwc3 otg workqueue.
+ */
+static void dwc3_otg_set_peripheral_regs(struct dwc3_otg *dotg)
+{
+ u32 octl;
+
+ /* Set OCTL[6](PeriMode) to 1 (peripheral) */
+ octl = dwc3_readl(dotg->regs, DWC3_OCTL);
+ octl |= DWC3_OTG_OCTL_PERIMODE;
+ dwc3_writel(dotg->regs, DWC3_OCTL, octl);
+
+ /*
+ * TODO: add more OTG registers writes for PERIPHERAL mode here,
+ * see figure 12-19 B-device flow in dwc3 Synopsis spec
+ */
+}
+
+/**
+ * dwc3_otg_start_host - helper function for starting/stoping the host controller driver.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @on: start / stop the host controller driver.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_start_host(struct usb_otg *otg, int on)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+ struct usb_hcd *hcd;
+ struct xhci_hcd *xhci;
+ int ret = 0;
+
+ if (!otg->host)
+ return -EINVAL;
+
+ hcd = bus_to_hcd(otg->host);
+ xhci = hcd_to_xhci(hcd);
+ if (on) {
+ dev_dbg(otg->phy->dev, "%s: turn on host %s\n",
+ __func__, otg->host->bus_name);
+ dwc3_otg_set_host_regs(dotg);
+
+ /*
+ * This should be revisited for more testing post-silicon.
+ * In worst case we may need to disconnect the root hub
+ * before stopping the controller so that it does not
+ * interfere with runtime pm/system pm.
+ * We can also consider registering and unregistering xhci
+ * platform device. It is almost similar to add_hcd and
+ * remove_hcd, But we may not use standard set_host method
+ * anymore.
+ */
+ ret = hcd->driver->start(hcd);
+ if (ret) {
+ dev_err(otg->phy->dev,
+ "%s: failed to start primary hcd, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = xhci->shared_hcd->driver->start(xhci->shared_hcd);
+ if (ret) {
+ dev_err(otg->phy->dev,
+ "%s: failed to start secondary hcd, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ } else {
+ dev_dbg(otg->phy->dev, "%s: turn off host %s\n",
+ __func__, otg->host->bus_name);
+ hcd->driver->stop(hcd);
+ }
+
+ return 0;
+}
+
+/**
+ * dwc3_otg_set_host - bind/unbind the host controller driver.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @host: Pointer to the usb_bus structure.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ if (host) {
+ dev_dbg(otg->phy->dev, "%s: set host %s\n",
+ __func__, host->bus_name);
+ otg->host = host;
+
+ /*
+ * Only after both peripheral and host are set then check
+ * OTG sm. This prevents unnecessary activation of the sm
+ * in case the ID is high.
+ */
+ if (otg->gadget)
+ schedule_work(&dotg->sm_work);
+ } else {
+ if (otg->phy->state == OTG_STATE_A_HOST) {
+ dwc3_otg_start_host(otg, 0);
+ otg->host = NULL;
+ otg->phy->state = OTG_STATE_UNDEFINED;
+ schedule_work(&dotg->sm_work);
+ } else {
+ otg->host = NULL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * dwc3_otg_start_peripheral - bind/unbind the peripheral controller.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @gadget: pointer to the usb_gadget structure.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_start_peripheral(struct usb_otg *otg, int on)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ if (!otg->gadget)
+ return -EINVAL;
+
+ if (on) {
+ dev_dbg(otg->phy->dev, "%s: turn on gadget %s\n",
+ __func__, otg->gadget->name);
+ dwc3_otg_set_peripheral_regs(dotg);
+ usb_gadget_vbus_connect(otg->gadget);
+ } else {
+ dev_dbg(otg->phy->dev, "%s: turn off gadget %s\n",
+ __func__, otg->gadget->name);
+ usb_gadget_vbus_disconnect(otg->gadget);
+ }
+
+ return 0;
+}
+
+/**
+ * dwc3_otg_set_peripheral - bind/unbind the peripheral controller driver.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @gadget: pointer to the usb_gadget structure.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ if (gadget) {
+ dev_dbg(otg->phy->dev, "%s: set gadget %s\n",
+ __func__, gadget->name);
+ otg->gadget = gadget;
+
+ /*
+ * Only after both peripheral and host are set then check
+ * OTG sm. This prevents unnecessary activation of the sm
+ * in case the ID is grounded.
+ */
+ if (otg->host)
+ schedule_work(&dotg->sm_work);
+ } else {
+ if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
+ dwc3_otg_start_peripheral(otg, 0);
+ otg->gadget = NULL;
+ otg->phy->state = OTG_STATE_UNDEFINED;
+ schedule_work(&dotg->sm_work);
+ } else {
+ otg->gadget = NULL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * dwc3_ext_chg_det_done - callback to handle charger detection completion
+ * @otg: Pointer to the otg transceiver structure
+ * @charger: Pointer to the external charger structure
+ *
+ * Returns 0 on success
+ */
+static void dwc3_ext_chg_det_done(struct usb_otg *otg, struct dwc3_charger *chg)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ /*
+ * Ignore chg_detection notification if BSV has gone off by this time.
+ * STOP chg_det as part of !BSV handling would reset the chg_det flags
+ */
+ if (test_bit(B_SESS_VLD, &dotg->inputs))
+ schedule_work(&dotg->sm_work);
+}
+
+/**
+ * dwc3_set_charger - bind/unbind external charger driver
+ * @otg: Pointer to the otg transceiver structure
+ * @charger: Pointer to the external charger structure
+ *
+ * Returns 0 on success
+ */
+int dwc3_set_charger(struct usb_otg *otg, struct dwc3_charger *charger)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ dotg->charger = charger;
+ if (charger)
+ charger->notify_detection_complete = dwc3_ext_chg_det_done;
+
+ return 0;
+}
+
+/* IRQs which OTG driver is interested in handling */
+#define DWC3_OEVT_MASK (DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | \
+ DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)
+
+/**
+ * dwc3_otg_interrupt - interrupt handler for dwc3 otg events.
+ * @_dotg: Pointer to out controller context structure
+ *
+ * Returns IRQ_HANDLED on success otherwise IRQ_NONE.
+ */
+static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg)
+{
+ struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;
+ u32 osts, oevt_reg;
+ int ret = IRQ_NONE;
+ int handled_irqs = 0;
+
+ oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT);
+
+ if (!(oevt_reg & DWC3_OEVT_MASK))
+ return IRQ_NONE;
+
+ osts = dwc3_readl(dotg->regs, DWC3_OSTS);
+
+ if ((oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ||
+ (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)) {
+ /*
+ * ID sts has changed, set inputs later, in the workqueue
+ * function, switch from A to B or from B to A.
+ */
+
+ if (osts & DWC3_OTG_OSTS_CONIDSTS)
+ set_bit(ID, &dotg->inputs);
+ else
+ clear_bit(ID, &dotg->inputs);
+
+ if (osts & DWC3_OTG_OSTS_BSESVALID)
+ set_bit(B_SESS_VLD, &dotg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &dotg->inputs);
+
+ schedule_work(&dotg->sm_work);
+
+ handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ?
+ DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT : 0;
+ handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) ?
+ DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT : 0;
+
+ ret = IRQ_HANDLED;
+
+ /* Clear the interrupts we handled */
+ dwc3_writel(dotg->regs, DWC3_OEVT, handled_irqs);
+ }
+
+ return ret;
+}
+
+/**
+ * dwc3_otg_init_sm - initialize OTG statemachine input
+ * @dotg: Pointer to the dwc3_otg structure
+ *
+ */
+void dwc3_otg_init_sm(struct dwc3_otg *dotg)
+{
+ u32 osts = dwc3_readl(dotg->regs, DWC3_OSTS);
+ struct usb_phy *phy = dotg->otg.phy;
+
+ /*
+ * TODO: If using external notifications then wait here till initial
+ * state is reported
+ */
+
+ dev_dbg(phy->dev, "Initialize OTG inputs, osts: 0x%x\n", osts);
+
+ if (osts & DWC3_OTG_OSTS_CONIDSTS)
+ set_bit(ID, &dotg->inputs);
+ else
+ clear_bit(ID, &dotg->inputs);
+
+ if (osts & DWC3_OTG_OSTS_BSESVALID)
+ set_bit(B_SESS_VLD, &dotg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &dotg->inputs);
+}
+
+/**
+ * dwc3_otg_sm_work - workqueue function.
+ *
+ * @w: Pointer to the dwc3 otg workqueue
+ *
+ * NOTE: After any change in phy->state,
+ * we must reschdule the state machine.
+ */
+static void dwc3_otg_sm_work(struct work_struct *w)
+{
+ struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work);
+ struct usb_phy *phy = dotg->otg.phy;
+ struct dwc3_charger *charger = dotg->charger;
+ bool work = 0;
+
+ dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));
+
+ /* Check OTG state */
+ switch (phy->state) {
+ case OTG_STATE_UNDEFINED:
+ dwc3_otg_init_sm(dotg);
+ /* Switch to A or B-Device according to ID / BSV */
+ if (!test_bit(ID, &dotg->inputs) && phy->otg->host) {
+ dev_dbg(phy->dev, "!id\n");
+ phy->state = OTG_STATE_A_IDLE;
+ work = 1;
+ } else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
+ dev_dbg(phy->dev, "b_sess_vld\n");
+ phy->state = OTG_STATE_B_IDLE;
+ work = 1;
+ } else {
+ phy->state = OTG_STATE_B_IDLE;
+ /* TODO: Enter low power state */
+ }
+ break;
+
+ case OTG_STATE_B_IDLE:
+ if (!test_bit(ID, &dotg->inputs) && phy->otg->host) {
+ dev_dbg(phy->dev, "!id\n");
+ phy->state = OTG_STATE_A_IDLE;
+ work = 1;
+ if (charger) {
+ if (charger->chg_type == DWC3_INVALID_CHARGER)
+ charger->start_detection(dotg->charger,
+ false);
+ else
+ charger->chg_type =
+ DWC3_INVALID_CHARGER;
+ }
+ } else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
+ dev_dbg(phy->dev, "b_sess_vld\n");
+ if (charger) {
+ /* Has charger been detected? If no detect it */
+ switch (charger->chg_type) {
+ case DWC3_DCP_CHARGER:
+ /* TODO: initiate LPM */
+ break;
+ case DWC3_CDP_CHARGER:
+ dwc3_otg_start_peripheral(&dotg->otg,
+ 1);
+ phy->state = OTG_STATE_B_PERIPHERAL;
+ work = 1;
+ break;
+ case DWC3_SDP_CHARGER:
+ dwc3_otg_start_peripheral(&dotg->otg,
+ 1);
+ phy->state = OTG_STATE_B_PERIPHERAL;
+ work = 1;
+ break;
+ default:
+ dev_dbg(phy->dev, "chg_det started\n");
+ charger->start_detection(charger, true);
+ break;
+ }
+ } else {
+ /* no charger registered, start peripheral */
+ if (dwc3_otg_start_peripheral(&dotg->otg, 1)) {
+ /*
+ * Probably set_peripheral not called
+ * yet. We will re-try as soon as it
+ * will be called
+ */
+ dev_err(phy->dev,
+ "unable to start B-device\n");
+ phy->state = OTG_STATE_UNDEFINED;
+ return;
+ }
+ }
+ } else {
+ if (charger) {
+ if (charger->chg_type == DWC3_INVALID_CHARGER)
+ charger->start_detection(dotg->charger,
+ false);
+ else
+ charger->chg_type =
+ DWC3_INVALID_CHARGER;
+ }
+ /* TODO: Enter low power state */
+ }
+ break;
+
+ case OTG_STATE_B_PERIPHERAL:
+ if (!test_bit(B_SESS_VLD, &dotg->inputs) ||
+ !test_bit(ID, &dotg->inputs)) {
+ dev_dbg(phy->dev, "!id || !bsv\n");
+ dwc3_otg_start_peripheral(&dotg->otg, 0);
+ phy->state = OTG_STATE_B_IDLE;
+ if (charger)
+ charger->chg_type = DWC3_INVALID_CHARGER;
+ work = 1;
+ }
+ break;
+
+ case OTG_STATE_A_IDLE:
+ /* Switch to A-Device*/
+ if (test_bit(ID, &dotg->inputs)) {
+ dev_dbg(phy->dev, "id\n");
+ phy->state = OTG_STATE_B_IDLE;
+ work = 1;
+ } else {
+ if (dwc3_otg_start_host(&dotg->otg, 1)) {
+ /*
+ * Probably set_host was not called yet.
+ * We will re-try as soon as it will be called
+ */
+ dev_dbg(phy->dev,
+ "unable to start A-device\n");
+ phy->state = OTG_STATE_UNDEFINED;
+ return;
+ }
+ phy->state = OTG_STATE_A_HOST;
+ }
+ break;
+
+ case OTG_STATE_A_HOST:
+ if (test_bit(ID, &dotg->inputs)) {
+ dev_dbg(phy->dev, "id\n");
+ dwc3_otg_start_host(&dotg->otg, 0);
+ phy->state = OTG_STATE_B_IDLE;
+ work = 1;
+ }
+ break;
+
+ default:
+ dev_err(phy->dev, "%s: invalid otg-state\n", __func__);
+
+ }
+
+ if (work)
+ schedule_work(&dotg->sm_work);
+}
+
+
+/**
+ * dwc3_otg_reset - reset dwc3 otg registers.
+ *
+ * @w: Pointer to the dwc3 otg workqueue
+ */
+static void dwc3_otg_reset(struct dwc3_otg *dotg)
+{
+ /*
+ * OCFG[2] - OTG-Version = 1
+ * OCFG[1] - HNPCap = 0
+ * OCFG[0] - SRPCap = 0
+ */
+ dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
+
+ /*
+ * OCTL[6] - PeriMode = 1
+ * OCTL[5] - PrtPwrCtl = 0
+ * OCTL[4] - HNPReq = 0
+ * OCTL[3] - SesReq = 0
+ * OCTL[2] - TermSelDLPulse = 0
+ * OCTL[1] - DevSetHNPEn = 0
+ * OCTL[0] - HstSetHNPEn = 0
+ */
+ dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
+
+ /* Clear all otg events (interrupts) indications */
+ dwc3_writel(dotg->regs, DWC3_OEVT, 0xFFFF);
+
+ /* Enable ID/BSV StsChngEn event*/
+ dwc3_writel(dotg->regs, DWC3_OEVTEN,
+ DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
+ DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
+}
+
+/**
+ * dwc3_otg_init - Initializes otg related registers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+int dwc3_otg_init(struct dwc3 *dwc)
+{
+ u32 reg;
+ int ret = 0;
+ struct dwc3_otg *dotg;
+
+ dev_dbg(dwc->dev, "dwc3_otg_init\n");
+
+ /*
+ * GHWPARAMS6[10] bit is SRPSupport.
+ * This bit also reflects DWC_USB3_EN_OTG
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
+ if (!(reg & DWC3_GHWPARAMS6_SRP_SUPPORT)) {
+ /*
+ * No OTG support in the HW core.
+ * We return 0 to indicate no error, since this is acceptable
+ * situation, just continue probe the dwc3 driver without otg.
+ */
+ dev_dbg(dwc->dev, "dwc3_otg address space is not supported\n");
+ return 0;
+ }
+
+ /* Allocate and init otg instance */
+ dotg = kzalloc(sizeof(struct dwc3_otg), GFP_KERNEL);
+ if (!dotg) {
+ dev_err(dwc->dev, "unable to allocate dwc3_otg\n");
+ return -ENOMEM;
+ }
+
+ dotg->irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ if (dotg->irq < 0) {
+ dev_err(dwc->dev, "%s: missing IRQ\n", __func__);
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ dotg->regs = dwc->regs;
+
+ dotg->otg.set_peripheral = dwc3_otg_set_peripheral;
+ dotg->otg.set_host = dwc3_otg_set_host;
+
+ /* This reference is used by dwc3 modules for checking otg existance */
+ dwc->dotg = dotg;
+
+ dotg->otg.phy = kzalloc(sizeof(struct usb_phy), GFP_KERNEL);
+ if (!dotg->otg.phy) {
+ dev_err(dwc->dev, "unable to allocate dwc3_otg.phy\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ dotg->otg.phy->otg = &dotg->otg;
+ dotg->otg.phy->dev = dwc->dev;
+
+ ret = usb_set_transceiver(dotg->otg.phy);
+ if (ret) {
+ dev_err(dotg->otg.phy->dev,
+ "%s: failed to set transceiver, already exists\n",
+ __func__);
+ goto err2;
+ }
+
+ dwc3_otg_reset(dotg);
+
+ dotg->otg.phy->state = OTG_STATE_UNDEFINED;
+
+ INIT_WORK(&dotg->sm_work, dwc3_otg_sm_work);
+
+ ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
+ "dwc3_otg", dotg);
+ if (ret) {
+ dev_err(dotg->otg.phy->dev, "failed to request irq #%d --> %d\n",
+ dotg->irq, ret);
+ goto err3;
+ }
+
+ return 0;
+
+err3:
+ cancel_work_sync(&dotg->sm_work);
+ usb_set_transceiver(NULL);
+err2:
+ kfree(dotg->otg.phy);
+err1:
+ dwc->dotg = NULL;
+ kfree(dotg);
+
+ return ret;
+}
+
+/**
+ * dwc3_otg_exit
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+void dwc3_otg_exit(struct dwc3 *dwc)
+{
+ struct dwc3_otg *dotg = dwc->dotg;
+
+ /* dotg is null when GHWPARAMS6[10]=SRPSupport=0, see dwc3_otg_init */
+ if (dotg) {
+ if (dotg->charger)
+ dotg->charger->start_detection(dotg->charger, false);
+ cancel_work_sync(&dotg->sm_work);
+ usb_set_transceiver(NULL);
+ free_irq(dotg->irq, dotg);
+ kfree(dotg->otg.phy);
+ kfree(dotg);
+ dwc->dotg = NULL;
+ }
+}
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
new file mode 100644
index 0000000..0d8b61b
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -0,0 +1,76 @@
+/**
+ * dwc3_otg.h - DesignWare USB3 DRD Controller OTG
+ *
+ * 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 __LINUX_USB_DWC3_OTG_H
+#define __LINUX_USB_DWC3_OTG_H
+
+#include <linux/workqueue.h>
+
+#include <linux/usb/otg.h>
+
+struct dwc3_charger;
+
+/**
+ * struct dwc3_otg: OTG driver data. Shared by HCD and DCD.
+ * @otg: USB OTG Transceiver structure.
+ * @irq: IRQ number assigned for HSUSB controller.
+ * @regs: ioremapped register base address.
+ * @sm_work: OTG state machine work.
+ * @charger: DWC3 external charger detector
+ * @inputs: OTG state machine inputs
+ */
+struct dwc3_otg {
+ struct usb_otg otg;
+ int irq;
+ void __iomem *regs;
+ struct work_struct sm_work;
+ struct dwc3_charger *charger;
+#define ID 0
+#define B_SESS_VLD 1
+ unsigned long inputs;
+};
+
+/**
+ * USB charger types
+ *
+ * DWC3_INVALID_CHARGER Invalid USB charger.
+ * DWC3_SDP_CHARGER Standard downstream port. Refers to a downstream port
+ * on USB compliant host/hub.
+ * DWC3_DCP_CHARGER Dedicated charger port (AC charger/ Wall charger).
+ * DWC3_CDP_CHARGER Charging downstream port. Enumeration can happen and
+ * IDEV_CHG_MAX can be drawn irrespective of USB state.
+ */
+enum dwc3_chg_type {
+ DWC3_INVALID_CHARGER = 0,
+ DWC3_SDP_CHARGER,
+ DWC3_DCP_CHARGER,
+ DWC3_CDP_CHARGER,
+};
+
+struct dwc3_charger {
+ enum dwc3_chg_type chg_type;
+
+ /* start/stop charger detection, provided by external charger module */
+ void (*start_detection)(struct dwc3_charger *charger, bool start);
+
+ /* to notify OTG about charger detection completion, provided by OTG */
+ void (*notify_detection_complete)(struct usb_otg *otg,
+ struct dwc3_charger *charger);
+};
+
+/* for external charger driver */
+extern int dwc3_set_charger(struct usb_otg *otg, struct dwc3_charger *charger);
+
+#endif /* __LINUX_USB_DWC3_OTG_H */
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index a988c43..060144f 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -49,6 +49,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
#include "core.h"
#include "gadget.h"
@@ -1326,7 +1327,59 @@
is_on = !!is_on;
spin_lock_irqsave(&dwc->lock, flags);
+
+ dwc->softconnect = is_on;
+
+ if ((dwc->dotg && !dwc->vbus_active) ||
+ !dwc->gadget_driver) {
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ /*
+ * Need to wait for vbus_session(on) from otg driver or to
+ * the udc_start.
+ */
+ return 0;
+ }
+
dwc3_gadget_run_stop(dwc, is_on);
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+
+static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+ struct dwc3 *dwc = gadget_to_dwc(_gadget);
+ unsigned long flags;
+
+ if (!dwc->dotg)
+ return -EPERM;
+
+ is_active = !!is_active;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ /* Mark that the vbus was powered */
+ dwc->vbus_active = is_active;
+
+ /*
+ * Check if upper level usb_gadget_driver was already registerd with
+ * this udc controller driver (if dwc3_gadget_start was called)
+ */
+ if (dwc->gadget_driver && dwc->softconnect) {
+ if (dwc->vbus_active) {
+ /*
+ * Both vbus was activated by otg and pullup was
+ * signaled by the gadget driver.
+ */
+ dwc3_gadget_run_stop(dwc, 1);
+ } else {
+ dwc3_gadget_run_stop(dwc, 0);
+ }
+ }
+
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
@@ -1417,6 +1470,7 @@
.get_frame = dwc3_gadget_get_frame,
.wakeup = dwc3_gadget_wakeup,
.set_selfpowered = dwc3_gadget_set_selfpowered,
+ .vbus_session = dwc3_gadget_vbus_session,
.pullup = dwc3_gadget_pullup,
.udc_start = dwc3_gadget_start,
.udc_stop = dwc3_gadget_stop,
@@ -2153,6 +2207,33 @@
break;
case DWC3_DEVICE_EVENT_OVERFLOW:
dev_vdbg(dwc->dev, "Overflow\n");
+ /*
+ * Controllers prior to 2.30a revision has a bug where
+ * Overflow Event may overwrite an unacknowledged event
+ * in the event buffer. The severity of the issue depends
+ * on the overwritten event type. Add a warning message
+ * saying that an event is overwritten.
+ *
+ * TODO: In future we may need to see if we can re-enumerate
+ * with host.
+ */
+ if (dwc->revision < DWC3_REVISION_230A)
+ dev_warn(dwc->dev, "Unacknowledged event overwritten\n");
+ break;
+ case DWC3_DEVICE_EVENT_VENDOR_DEV_TEST_LMP:
+ /*
+ * Controllers prior to 2.30a revision has a bug, due to which
+ * a vendor device test LMP event can not be filtered. But
+ * this event is not handled in the current code. This is a
+ * special event and 8 bytes of data will follow the event.
+ * Handling this event is tricky when event buffer is almost
+ * full. Moreover this event will not occur in normal scenario
+ * and can only happen with special hosts in testing scenarios.
+ * Add a warning message to indicate that this event is received
+ * which means that event buffer might have corrupted.
+ */
+ if (dwc->revision < DWC3_REVISION_230A)
+ dev_warn(dwc->dev, "Vendor Device Test LMP Received\n");
break;
default:
dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
@@ -2314,8 +2395,7 @@
}
/* Enable all but Start and End of Frame IRQs */
- reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
- DWC3_DEVTEN_EVNTOVERFLOWEN |
+ reg = (DWC3_DEVTEN_EVNTOVERFLOWEN |
DWC3_DEVTEN_CMDCMPLTEN |
DWC3_DEVTEN_ERRTICERREN |
DWC3_DEVTEN_WKUPEVTEN |
@@ -2338,6 +2418,15 @@
goto err7;
}
+ if (dwc->dotg) {
+ /* dwc3 otg driver is active (DRD mode + SRPSupport=1) */
+ ret = otg_set_peripheral(&dwc->dotg->otg, &dwc->gadget);
+ if (ret) {
+ dev_err(dwc->dev, "failed to set peripheral to otg\n");
+ goto err7;
+ }
+ }
+
return 0;
err7:
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index b108d18..099708b 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -38,20 +38,13 @@
#include <linux/platform_device.h>
#include "core.h"
-
-static struct resource generic_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
- {
- .flags = IORESOURCE_MEM,
- },
-};
+#include "xhci.h"
int dwc3_host_init(struct dwc3 *dwc)
{
struct platform_device *xhci;
int ret;
+ struct xhci_plat_data pdata;
xhci = platform_device_alloc("xhci-hcd", -1);
if (!xhci) {
@@ -67,15 +60,19 @@
xhci->dev.dma_parms = dwc->dev->dma_parms;
dwc->xhci = xhci;
+ pdata.vendor = ((dwc->revision & DWC3_GSNPSID_MASK) >>
+ __ffs(DWC3_GSNPSID_MASK) & DWC3_GSNPSREV_MASK);
+ pdata.revision = dwc->revision & DWC3_GSNPSREV_MASK;
- /* setup resources */
- generic_resources[0].start = dwc->irq;
+ ret = platform_device_add_data(xhci, (const void *) &pdata,
+ sizeof(struct xhci_plat_data));
+ if (ret) {
+ dev_err(dwc->dev, "couldn't add pdata to xHCI device\n");
+ goto err1;
+ }
- generic_resources[1].start = dwc->res->start;
- generic_resources[1].end = dwc->res->start + 0x7fff;
-
- ret = platform_device_add_resources(xhci, generic_resources,
- ARRAY_SIZE(generic_resources));
+ ret = platform_device_add_resources(xhci, dwc->xhci_resources,
+ DWC3_XHCI_RESOURCES_NUM);
if (ret) {
dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
goto err1;
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 071d561..90de7a4 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -41,14 +41,26 @@
#include <linux/io.h>
+#include "core.h"
+
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{
- return readl(base + offset);
+ /*
+ * We requested the mem region starting from the Globals address
+ * space, see dwc3_probe in core.c.
+ * However, the offsets are given starting from xHCI address space.
+ */
+ return readl_relaxed(base + (offset - DWC3_GLOBALS_REGS_START));
}
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
- writel(value, base + offset);
+ /*
+ * We requested the mem region starting from the Globals address
+ * space, see dwc3_probe in core.c.
+ * However, the offsets are given starting from xHCI address space.
+ */
+ writel_relaxed(value, base + (offset - DWC3_GLOBALS_REGS_START));
}
#endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 95f11c1..87b307c 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -854,6 +854,16 @@
Say "y" to link the driver statically, or "m" to build
a dynamically linked module called "g_mass_storage".
+config USB_GADGET_TARGET
+ tristate "USB Gadget Target Fabric Module"
+ depends on TARGET_CORE
+ help
+ This fabric is an USB gadget. Two USB protocols are supported that is
+ BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is
+ advertised on alternative interface 0 (primary) and UAS is on
+ alternative interface 1. Both protocols can work on USB2.0 and USB3.0.
+ UAS utilizes the USB 3.0 feature called streams support.
+
config USB_G_SERIAL
tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
help
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index c646c9f..b8f5149 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -54,6 +54,7 @@
g_webcam-y := webcam.o
g_ncm-y := ncm.o
g_acm_ms-y := acm_ms.o
+g_tcm_usb_gadget-y := tcm_usb_gadget.o
g_android-y := android.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
@@ -74,4 +75,5 @@
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
obj-$(CONFIG_USB_G_NCM) += g_ncm.o
obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o
+obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o
obj-$(CONFIG_USB_G_ANDROID) += g_android.o
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index be8e6aa..b5a7291 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1438,7 +1438,6 @@
sscanf(buff, "%d", &enabled);
if (enabled && !dev->enabled) {
- cdev->next_string_id = 0;
/*
* Update values in composite driver's copy of
* device descriptor.
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index 30b45eb..f353b07 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -381,7 +381,7 @@
*/
mb();
- if (!mhsic->pdata->keep_core_clk_on_suspend_workaround) {
+ if (!mhsic->pdata->core_clk_always_on_workaround) {
clk_disable(mhsic->iface_clk);
clk_disable(mhsic->core_clk);
}
@@ -438,7 +438,7 @@
dev_err(mhsic->dev, "%s failed to vote for TCXO %d\n",
__func__, ret);
- if (!mhsic->pdata->keep_core_clk_on_suspend_workaround) {
+ if (!mhsic->pdata->core_clk_always_on_workaround) {
clk_enable(mhsic->iface_clk);
clk_enable(mhsic->core_clk);
}
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 41a1777..6883b78 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -795,6 +795,7 @@
spin_unlock(&mbim->lock);
mbim_clear_queues(mbim);
mbim_reset_function_queue(mbim);
+ spin_lock(&mbim->lock);
break;
default:
pr_err("Unknown event %02x --> %d\n",
@@ -1450,8 +1451,6 @@
mbim->cdev = c->cdev;
- spin_lock_init(&mbim->lock);
-
mbim_reset_values(mbim);
mbim->function.name = "usb_mbim";
@@ -1615,6 +1614,7 @@
pr_debug("Exit(%d)", count);
return count;
+
}
static int mbim_open(struct inode *ip, struct file *fp)
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
new file mode 100644
index 0000000..c46439c
--- /dev/null
+++ b/drivers/usb/gadget/tcm_usb_gadget.c
@@ -0,0 +1,2480 @@
+/* Target based USB-Gadget
+ *
+ * UAS protocol handling, target callbacks, configfs handling,
+ * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
+ *
+ * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
+ * License: GPLv2 as published by FSF.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <asm/unaligned.h>
+
+#include "usbstring.c"
+#include "epautoconf.c"
+#include "config.c"
+#include "composite.c"
+
+#include "tcm_usb_gadget.h"
+
+static struct target_fabric_configfs *usbg_fabric_configfs;
+
+static inline struct f_uas *to_f_uas(struct usb_function *f)
+{
+ return container_of(f, struct f_uas, function);
+}
+
+static void usbg_cmd_release(struct kref *);
+
+static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
+{
+ kref_put(&cmd->ref, usbg_cmd_release);
+}
+
+/* Start bot.c code */
+
+static int bot_enqueue_cmd_cbw(struct f_uas *fu)
+{
+ int ret;
+
+ if (fu->flags & USBG_BOT_CMD_PEND)
+ return 0;
+
+ ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
+ if (!ret)
+ fu->flags |= USBG_BOT_CMD_PEND;
+ return ret;
+}
+
+static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct f_uas *fu = cmd->fu;
+
+ usbg_cleanup_cmd(cmd);
+ if (req->status < 0) {
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+ return;
+ }
+
+ /* CSW completed, wait for next CBW */
+ bot_enqueue_cmd_cbw(fu);
+}
+
+static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
+{
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ int ret;
+ u8 *sense;
+ unsigned int csw_stat;
+
+ csw_stat = cmd->csw_code;
+
+ /*
+ * We can't send SENSE as a response. So we take ASC & ASCQ from our
+ * sense buffer and queue it and hope the host sends a REQUEST_SENSE
+ * command where it learns why we failed.
+ */
+ sense = cmd->sense_iu.sense;
+
+ csw->Tag = cmd->bot_tag;
+ csw->Status = csw_stat;
+ fu->bot_status.req->context = cmd;
+ ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+}
+
+static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct f_uas *fu = cmd->fu;
+
+ if (req->status < 0)
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+ if (cmd->data_len) {
+ if (cmd->data_len > ep->maxpacket) {
+ req->length = ep->maxpacket;
+ cmd->data_len -= ep->maxpacket;
+ } else {
+ req->length = cmd->data_len;
+ cmd->data_len = 0;
+ }
+
+ usb_ep_queue(ep, req, GFP_ATOMIC);
+ return ;
+ }
+ bot_enqueue_sense_code(fu, cmd);
+}
+
+static void bot_send_bad_status(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ struct usb_request *req;
+ struct usb_ep *ep;
+
+ csw->Residue = cpu_to_le32(cmd->data_len);
+
+ if (cmd->data_len) {
+ if (cmd->is_read) {
+ ep = fu->ep_in;
+ req = fu->bot_req_in;
+ } else {
+ ep = fu->ep_out;
+ req = fu->bot_req_out;
+ }
+
+ if (cmd->data_len > fu->ep_in->maxpacket) {
+ req->length = ep->maxpacket;
+ cmd->data_len -= ep->maxpacket;
+ } else {
+ req->length = cmd->data_len;
+ cmd->data_len = 0;
+ }
+ req->complete = bot_err_compl;
+ req->context = cmd;
+ req->buf = fu->cmd.buf;
+ usb_ep_queue(ep, req, GFP_KERNEL);
+ } else {
+ bot_enqueue_sense_code(fu, cmd);
+ }
+}
+
+static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
+{
+ struct f_uas *fu = cmd->fu;
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ int ret;
+
+ if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
+ if (!moved_data && cmd->data_len) {
+ /*
+ * the host wants to move data, we don't. Fill / empty
+ * the pipe and then send the csw with reside set.
+ */
+ cmd->csw_code = US_BULK_STAT_OK;
+ bot_send_bad_status(cmd);
+ return 0;
+ }
+
+ csw->Tag = cmd->bot_tag;
+ csw->Residue = cpu_to_le32(0);
+ csw->Status = US_BULK_STAT_OK;
+ fu->bot_status.req->context = cmd;
+
+ ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
+ if (ret)
+ pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+ } else {
+ cmd->csw_code = US_BULK_STAT_FAIL;
+ bot_send_bad_status(cmd);
+ }
+ return 0;
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+static int bot_send_status_response(struct usbg_cmd *cmd)
+{
+ bool moved_data = false;
+
+ if (!cmd->is_read)
+ moved_data = true;
+ return bot_send_status(cmd, moved_data);
+}
+
+/* Read request completed, now we have to send the CSW */
+static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+
+ if (req->status < 0)
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+ bot_send_status(cmd, true);
+}
+
+static int bot_send_read_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ int ret;
+
+ if (!cmd->data_len) {
+ cmd->csw_code = US_BULK_STAT_PHASE;
+ bot_send_bad_status(cmd);
+ return 0;
+ }
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ sg_copy_to_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+
+ fu->bot_req_in->buf = cmd->data_buf;
+ } else {
+ fu->bot_req_in->buf = NULL;
+ fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
+ fu->bot_req_in->sg = se_cmd->t_data_sg;
+ }
+
+ fu->bot_req_in->complete = bot_read_compl;
+ fu->bot_req_in->length = se_cmd->data_length;
+ fu->bot_req_in->context = cmd;
+ ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+ return 0;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
+static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
+
+static int bot_send_write_request(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ int ret;
+
+ init_completion(&cmd->write_complete);
+ cmd->fu = fu;
+
+ if (!cmd->data_len) {
+ cmd->csw_code = US_BULK_STAT_PHASE;
+ return -EINVAL;
+ }
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ fu->bot_req_out->buf = cmd->data_buf;
+ } else {
+ fu->bot_req_out->buf = NULL;
+ fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
+ fu->bot_req_out->sg = se_cmd->t_data_sg;
+ }
+
+ fu->bot_req_out->complete = usbg_data_write_cmpl;
+ fu->bot_req_out->length = se_cmd->data_length;
+ fu->bot_req_out->context = cmd;
+
+ ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+
+ wait_for_completion(&cmd->write_complete);
+ transport_generic_process_write(se_cmd);
+cleanup:
+ return ret;
+}
+
+static int bot_submit_command(struct f_uas *, void *, unsigned int);
+
+static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_uas *fu = req->context;
+ int ret;
+
+ fu->flags &= ~USBG_BOT_CMD_PEND;
+
+ if (req->status < 0)
+ return;
+
+ ret = bot_submit_command(fu, req->buf, req->actual);
+ if (ret)
+ pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
+}
+
+static int bot_prepare_reqs(struct f_uas *fu)
+{
+ int ret;
+
+ fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!fu->bot_req_in)
+ goto err;
+
+ fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!fu->bot_req_out)
+ goto err_out;
+
+ fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!fu->cmd.req)
+ goto err_cmd;
+
+ fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!fu->bot_status.req)
+ goto err_sts;
+
+ fu->bot_status.req->buf = &fu->bot_status.csw;
+ fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
+ fu->bot_status.req->complete = bot_status_complete;
+ fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
+
+ fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
+ if (!fu->cmd.buf)
+ goto err_buf;
+
+ fu->cmd.req->complete = bot_cmd_complete;
+ fu->cmd.req->buf = fu->cmd.buf;
+ fu->cmd.req->length = fu->ep_out->maxpacket;
+ fu->cmd.req->context = fu;
+
+ ret = bot_enqueue_cmd_cbw(fu);
+ if (ret)
+ goto err_queue;
+ return 0;
+err_queue:
+ kfree(fu->cmd.buf);
+ fu->cmd.buf = NULL;
+err_buf:
+ usb_ep_free_request(fu->ep_in, fu->bot_status.req);
+err_sts:
+ usb_ep_free_request(fu->ep_out, fu->cmd.req);
+ fu->cmd.req = NULL;
+err_cmd:
+ usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+ fu->bot_req_out = NULL;
+err_out:
+ usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+ fu->bot_req_in = NULL;
+err:
+ pr_err("BOT: endpoint setup failed\n");
+ return -ENOMEM;
+}
+
+void bot_cleanup_old_alt(struct f_uas *fu)
+{
+ if (!(fu->flags & USBG_ENABLED))
+ return;
+
+ usb_ep_disable(fu->ep_in);
+ usb_ep_disable(fu->ep_out);
+
+ if (!fu->bot_req_in)
+ return;
+
+ usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+ usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+ usb_ep_free_request(fu->ep_out, fu->cmd.req);
+ usb_ep_free_request(fu->ep_out, fu->bot_status.req);
+
+ kfree(fu->cmd.buf);
+
+ fu->bot_req_in = NULL;
+ fu->bot_req_out = NULL;
+ fu->cmd.req = NULL;
+ fu->bot_status.req = NULL;
+ fu->cmd.buf = NULL;
+}
+
+static void bot_set_alt(struct f_uas *fu)
+{
+ struct usb_function *f = &fu->function;
+ struct usb_gadget *gadget = f->config->cdev->gadget;
+ int ret;
+
+ fu->flags = USBG_IS_BOT;
+
+ config_ep_by_speed(gadget, f, fu->ep_in);
+ ret = usb_ep_enable(fu->ep_in);
+ if (ret)
+ goto err_b_in;
+
+ config_ep_by_speed(gadget, f, fu->ep_out);
+ ret = usb_ep_enable(fu->ep_out);
+ if (ret)
+ goto err_b_out;
+
+ ret = bot_prepare_reqs(fu);
+ if (ret)
+ goto err_wq;
+ fu->flags |= USBG_ENABLED;
+ pr_info("Using the BOT protocol\n");
+ return;
+err_wq:
+ usb_ep_disable(fu->ep_out);
+err_b_out:
+ usb_ep_disable(fu->ep_in);
+err_b_in:
+ fu->flags = USBG_IS_BOT;
+}
+
+static int usbg_bot_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct f_uas *fu = to_f_uas(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+ int luns;
+ u8 *ret_lun;
+
+ switch (ctrl->bRequest) {
+ case US_BULK_GET_MAX_LUN:
+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE))
+ return -ENOTSUPP;
+
+ if (w_length < 1)
+ return -EINVAL;
+ if (w_value != 0)
+ return -EINVAL;
+ luns = atomic_read(&fu->tpg->tpg_port_count);
+ if (!luns) {
+ pr_err("No LUNs configured?\n");
+ return -EINVAL;
+ }
+ /*
+ * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
+ * accessed. The upper limit is 0xf
+ */
+ luns--;
+ if (luns > 0xf) {
+ pr_info_once("Limiting the number of luns to 16\n");
+ luns = 0xf;
+ }
+ ret_lun = cdev->req->buf;
+ *ret_lun = luns;
+ cdev->req->length = 1;
+ return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+ break;
+
+ case US_BULK_RESET_REQUEST:
+ /* XXX maybe we should remove previous requests for IN + OUT */
+ bot_enqueue_cmd_cbw(fu);
+ return 0;
+ break;
+ };
+ return -ENOTSUPP;
+}
+
+/* Start uas.c code */
+
+static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
+{
+ /* We have either all three allocated or none */
+ if (!stream->req_in)
+ return;
+
+ usb_ep_free_request(fu->ep_in, stream->req_in);
+ usb_ep_free_request(fu->ep_out, stream->req_out);
+ usb_ep_free_request(fu->ep_status, stream->req_status);
+
+ stream->req_in = NULL;
+ stream->req_out = NULL;
+ stream->req_status = NULL;
+}
+
+static void uasp_free_cmdreq(struct f_uas *fu)
+{
+ usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+ kfree(fu->cmd.buf);
+ fu->cmd.req = NULL;
+ fu->cmd.buf = NULL;
+}
+
+static void uasp_cleanup_old_alt(struct f_uas *fu)
+{
+ int i;
+
+ if (!(fu->flags & USBG_ENABLED))
+ return;
+
+ usb_ep_disable(fu->ep_in);
+ usb_ep_disable(fu->ep_out);
+ usb_ep_disable(fu->ep_status);
+ usb_ep_disable(fu->ep_cmd);
+
+ for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
+ uasp_cleanup_one_stream(fu, &fu->stream[i]);
+ uasp_free_cmdreq(fu);
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
+
+static int uasp_prepare_r_request(struct usbg_cmd *cmd)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct f_uas *fu = cmd->fu;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ struct uas_stream *stream = cmd->stream;
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ sg_copy_to_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+
+ stream->req_in->buf = cmd->data_buf;
+ } else {
+ stream->req_in->buf = NULL;
+ stream->req_in->num_sgs = se_cmd->t_data_nents;
+ stream->req_in->sg = se_cmd->t_data_sg;
+ }
+
+ stream->req_in->complete = uasp_status_data_cmpl;
+ stream->req_in->length = se_cmd->data_length;
+ stream->req_in->context = cmd;
+
+ cmd->state = UASP_SEND_STATUS;
+ return 0;
+}
+
+static void uasp_prepare_status(struct usbg_cmd *cmd)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct sense_iu *iu = &cmd->sense_iu;
+ struct uas_stream *stream = cmd->stream;
+
+ cmd->state = UASP_QUEUE_COMMAND;
+ iu->iu_id = IU_ID_STATUS;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ /*
+ * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
+ */
+ iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
+ iu->status = se_cmd->scsi_status;
+ stream->req_status->context = cmd;
+ stream->req_status->length = se_cmd->scsi_sense_length + 16;
+ stream->req_status->buf = iu;
+ stream->req_status->complete = uasp_status_data_cmpl;
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct uas_stream *stream = cmd->stream;
+ struct f_uas *fu = cmd->fu;
+ int ret;
+
+ if (req->status < 0)
+ goto cleanup;
+
+ switch (cmd->state) {
+ case UASP_SEND_DATA:
+ ret = uasp_prepare_r_request(cmd);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_RECEIVE_DATA:
+ ret = usbg_prepare_w_request(cmd, stream->req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_SEND_STATUS:
+ uasp_prepare_status(cmd);
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_QUEUE_COMMAND:
+ usbg_cleanup_cmd(cmd);
+ usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+ break;
+
+ default:
+ BUG();
+ };
+ return;
+
+cleanup:
+ usbg_cleanup_cmd(cmd);
+}
+
+static int uasp_send_status_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+ cmd->fu = fu;
+ uasp_prepare_status(cmd);
+ return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
+}
+
+static int uasp_send_read_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+ int ret;
+
+ cmd->fu = fu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+ if (fu->flags & USBG_USE_STREAMS) {
+
+ ret = uasp_prepare_r_request(cmd);
+ if (ret)
+ goto out;
+ ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+ if (ret) {
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ kfree(cmd->data_buf);
+ cmd->data_buf = NULL;
+ }
+
+ } else {
+
+ iu->iu_id = IU_ID_READ_READY;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+
+ cmd->state = UASP_SEND_DATA;
+ stream->req_status->buf = iu;
+ stream->req_status->length = sizeof(struct iu);
+
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ }
+out:
+ return ret;
+}
+
+static int uasp_send_write_request(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+ int ret;
+
+ init_completion(&cmd->write_complete);
+ cmd->fu = fu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ if (fu->flags & USBG_USE_STREAMS) {
+
+ ret = usbg_prepare_w_request(cmd, stream->req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+
+ } else {
+
+ iu->iu_id = IU_ID_WRITE_READY;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+
+ cmd->state = UASP_RECEIVE_DATA;
+ stream->req_status->buf = iu;
+ stream->req_status->length = sizeof(struct iu);
+
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+ }
+
+ wait_for_completion(&cmd->write_complete);
+ transport_generic_process_write(se_cmd);
+cleanup:
+ return ret;
+}
+
+static int usbg_submit_command(struct f_uas *, void *, unsigned int);
+
+static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_uas *fu = req->context;
+ int ret;
+
+ if (req->status < 0)
+ return;
+
+ ret = usbg_submit_command(fu, req->buf, req->actual);
+ /*
+ * Once we tune for performance enqueue the command req here again so
+ * we can receive a second command while we processing this one. Pay
+ * attention to properly sync STAUS endpoint with DATA IN + OUT so you
+ * don't break HS.
+ */
+ if (!ret)
+ return;
+ usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+}
+
+static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
+{
+ stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!stream->req_in)
+ goto out;
+
+ stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!stream->req_out)
+ goto err_out;
+
+ stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
+ if (!stream->req_status)
+ goto err_sts;
+
+ return 0;
+err_sts:
+ usb_ep_free_request(fu->ep_status, stream->req_status);
+ stream->req_status = NULL;
+err_out:
+ usb_ep_free_request(fu->ep_out, stream->req_out);
+ stream->req_out = NULL;
+out:
+ return -ENOMEM;
+}
+
+static int uasp_alloc_cmd(struct f_uas *fu)
+{
+ fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
+ if (!fu->cmd.req)
+ goto err;
+
+ fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
+ if (!fu->cmd.buf)
+ goto err_buf;
+
+ fu->cmd.req->complete = uasp_cmd_complete;
+ fu->cmd.req->buf = fu->cmd.buf;
+ fu->cmd.req->length = fu->ep_cmd->maxpacket;
+ fu->cmd.req->context = fu;
+ return 0;
+
+err_buf:
+ usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+err:
+ return -ENOMEM;
+}
+
+static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
+{
+ int i;
+
+ for (i = 0; i < max_streams; i++) {
+ struct uas_stream *s = &fu->stream[i];
+
+ s->req_in->stream_id = i + 1;
+ s->req_out->stream_id = i + 1;
+ s->req_status->stream_id = i + 1;
+ }
+}
+
+static int uasp_prepare_reqs(struct f_uas *fu)
+{
+ int ret;
+ int i;
+ int max_streams;
+
+ if (fu->flags & USBG_USE_STREAMS)
+ max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
+ else
+ max_streams = 1;
+
+ for (i = 0; i < max_streams; i++) {
+ ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
+ if (ret)
+ goto err_cleanup;
+ }
+
+ ret = uasp_alloc_cmd(fu);
+ if (ret)
+ goto err_free_stream;
+ uasp_setup_stream_res(fu, max_streams);
+
+ ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+ if (ret)
+ goto err_free_stream;
+
+ return 0;
+
+err_free_stream:
+ uasp_free_cmdreq(fu);
+
+err_cleanup:
+ if (i) {
+ do {
+ uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
+ i--;
+ } while (i);
+ }
+ pr_err("UASP: endpoint setup failed\n");
+ return ret;
+}
+
+static void uasp_set_alt(struct f_uas *fu)
+{
+ struct usb_function *f = &fu->function;
+ struct usb_gadget *gadget = f->config->cdev->gadget;
+ int ret;
+
+ fu->flags = USBG_IS_UAS;
+
+ if (gadget->speed == USB_SPEED_SUPER)
+ fu->flags |= USBG_USE_STREAMS;
+
+ config_ep_by_speed(gadget, f, fu->ep_in);
+ ret = usb_ep_enable(fu->ep_in);
+ if (ret)
+ goto err_b_in;
+
+ config_ep_by_speed(gadget, f, fu->ep_out);
+ ret = usb_ep_enable(fu->ep_out);
+ if (ret)
+ goto err_b_out;
+
+ config_ep_by_speed(gadget, f, fu->ep_cmd);
+ ret = usb_ep_enable(fu->ep_cmd);
+ if (ret)
+ goto err_cmd;
+ config_ep_by_speed(gadget, f, fu->ep_status);
+ ret = usb_ep_enable(fu->ep_status);
+ if (ret)
+ goto err_status;
+
+ ret = uasp_prepare_reqs(fu);
+ if (ret)
+ goto err_wq;
+ fu->flags |= USBG_ENABLED;
+
+ pr_info("Using the UAS protocol\n");
+ return;
+err_wq:
+ usb_ep_disable(fu->ep_status);
+err_status:
+ usb_ep_disable(fu->ep_cmd);
+err_cmd:
+ usb_ep_disable(fu->ep_out);
+err_b_out:
+ usb_ep_disable(fu->ep_in);
+err_b_in:
+ fu->flags = 0;
+}
+
+static int get_cmd_dir(const unsigned char *cdb)
+{
+ int ret;
+
+ switch (cdb[0]) {
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case INQUIRY:
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ case SERVICE_ACTION_IN:
+ case MAINTENANCE_IN:
+ case PERSISTENT_RESERVE_IN:
+ case SECURITY_PROTOCOL_IN:
+ case ACCESS_CONTROL_IN:
+ case REPORT_LUNS:
+ case READ_BLOCK_LIMITS:
+ case READ_POSITION:
+ case READ_CAPACITY:
+ case READ_TOC:
+ case READ_FORMAT_CAPACITIES:
+ case REQUEST_SENSE:
+ ret = DMA_FROM_DEVICE;
+ break;
+
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ case MODE_SELECT:
+ case MODE_SELECT_10:
+ case WRITE_VERIFY:
+ case WRITE_VERIFY_12:
+ case PERSISTENT_RESERVE_OUT:
+ case MAINTENANCE_OUT:
+ case SECURITY_PROTOCOL_OUT:
+ case ACCESS_CONTROL_OUT:
+ ret = DMA_TO_DEVICE;
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case TEST_UNIT_READY:
+ case SYNCHRONIZE_CACHE:
+ case START_STOP:
+ case ERASE:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case SPACE:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ ret = DMA_NONE;
+ break;
+ default:
+ pr_warn("target: Unknown data direction for SCSI Opcode "
+ "0x%02x\n", cdb[0]);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+
+ if (req->status < 0) {
+ pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
+ goto cleanup;
+ }
+
+ if (req->num_sgs == 0) {
+ sg_copy_from_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+ }
+
+ complete(&cmd->write_complete);
+ return;
+
+cleanup:
+ usbg_cleanup_cmd(cmd);
+}
+
+static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct f_uas *fu = cmd->fu;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ req->buf = cmd->data_buf;
+ } else {
+ req->buf = NULL;
+ req->num_sgs = se_cmd->t_data_nents;
+ req->sg = se_cmd->t_data_sg;
+ }
+
+ req->complete = usbg_data_write_cmpl;
+ req->length = se_cmd->data_length;
+ req->context = cmd;
+ return 0;
+}
+
+static int usbg_send_status_response(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_status_response(cmd);
+ else
+ return uasp_send_status_response(cmd);
+}
+
+static int usbg_send_write_request(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_write_request(cmd);
+ else
+ return uasp_send_write_request(cmd);
+}
+
+static int usbg_send_read_response(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_read_response(cmd);
+ else
+ return uasp_send_read_response(cmd);
+}
+
+static void usbg_cmd_work(struct work_struct *work)
+{
+ struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ struct usbg_tpg *tpg;
+ int dir;
+
+ se_cmd = &cmd->se_cmd;
+ tpg = cmd->fu->tpg;
+ tv_nexus = tpg->tpg_nexus;
+ dir = get_cmd_dir(cmd->cmd_buf);
+ if (dir < 0) {
+ transport_init_se_cmd(se_cmd,
+ tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+ tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+ cmd->prio_attr, cmd->sense_iu.sense);
+
+ transport_send_check_condition_and_sense(se_cmd,
+ TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+ usbg_cleanup_cmd(cmd);
+ return;
+ }
+
+ target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+ cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+ 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE);
+}
+
+static int usbg_submit_command(struct f_uas *fu,
+ void *cmdbuf, unsigned int len)
+{
+ struct command_iu *cmd_iu = cmdbuf;
+ struct usbg_cmd *cmd;
+ struct usbg_tpg *tpg;
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ u32 cmd_len;
+ int ret;
+
+ if (cmd_iu->iu_id != IU_ID_COMMAND) {
+ pr_err("Unsupported type %d\n", cmd_iu->iu_id);
+ return -EINVAL;
+ }
+
+ cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->fu = fu;
+
+ /* XXX until I figure out why I can't free in on complete */
+ kref_init(&cmd->ref);
+ kref_get(&cmd->ref);
+
+ tpg = fu->tpg;
+ cmd_len = (cmd_iu->len & ~0x3) + 16;
+ if (cmd_len > USBG_MAX_CMD)
+ goto err;
+
+ memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
+
+ cmd->tag = be16_to_cpup(&cmd_iu->tag);
+ if (fu->flags & USBG_USE_STREAMS) {
+ if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
+ goto err;
+ if (!cmd->tag)
+ cmd->stream = &fu->stream[0];
+ else
+ cmd->stream = &fu->stream[cmd->tag - 1];
+ } else {
+ cmd->stream = &fu->stream[0];
+ }
+
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ pr_err("Missing nexus, ignoring command\n");
+ goto err;
+ }
+
+ switch (cmd_iu->prio_attr & 0x7) {
+ case UAS_HEAD_TAG:
+ cmd->prio_attr = MSG_HEAD_TAG;
+ break;
+ case UAS_ORDERED_TAG:
+ cmd->prio_attr = MSG_ORDERED_TAG;
+ break;
+ case UAS_ACA:
+ cmd->prio_attr = MSG_ACA_TAG;
+ break;
+ default:
+ pr_debug_once("Unsupported prio_attr: %02x.\n",
+ cmd_iu->prio_attr);
+ case UAS_SIMPLE_TAG:
+ cmd->prio_attr = MSG_SIMPLE_TAG;
+ break;
+ }
+
+ se_cmd = &cmd->se_cmd;
+ cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
+
+ INIT_WORK(&cmd->work, usbg_cmd_work);
+ ret = queue_work(tpg->workqueue, &cmd->work);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+err:
+ kfree(cmd);
+ return -EINVAL;
+}
+
+static void bot_cmd_work(struct work_struct *work)
+{
+ struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ struct usbg_tpg *tpg;
+ int dir;
+
+ se_cmd = &cmd->se_cmd;
+ tpg = cmd->fu->tpg;
+ tv_nexus = tpg->tpg_nexus;
+ dir = get_cmd_dir(cmd->cmd_buf);
+ if (dir < 0) {
+ transport_init_se_cmd(se_cmd,
+ tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+ tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+ cmd->prio_attr, cmd->sense_iu.sense);
+
+ transport_send_check_condition_and_sense(se_cmd,
+ TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+ usbg_cleanup_cmd(cmd);
+ return;
+ }
+
+ target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+ cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+ cmd->data_len, cmd->prio_attr, dir, 0);
+}
+
+static int bot_submit_command(struct f_uas *fu,
+ void *cmdbuf, unsigned int len)
+{
+ struct bulk_cb_wrap *cbw = cmdbuf;
+ struct usbg_cmd *cmd;
+ struct usbg_tpg *tpg;
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ u32 cmd_len;
+ int ret;
+
+ if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
+ pr_err("Wrong signature on CBW\n");
+ return -EINVAL;
+ }
+ if (len != 31) {
+ pr_err("Wrong length for CBW\n");
+ return -EINVAL;
+ }
+
+ cmd_len = cbw->Length;
+ if (cmd_len < 1 || cmd_len > 16)
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->fu = fu;
+
+ /* XXX until I figure out why I can't free in on complete */
+ kref_init(&cmd->ref);
+ kref_get(&cmd->ref);
+
+ tpg = fu->tpg;
+
+ memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
+
+ cmd->bot_tag = cbw->Tag;
+
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ pr_err("Missing nexus, ignoring command\n");
+ goto err;
+ }
+
+ cmd->prio_attr = MSG_SIMPLE_TAG;
+ se_cmd = &cmd->se_cmd;
+ cmd->unpacked_lun = cbw->Lun;
+ cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
+ cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
+
+ INIT_WORK(&cmd->work, bot_cmd_work);
+ ret = queue_work(tpg->workqueue, &cmd->work);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+err:
+ kfree(cmd);
+ return -EINVAL;
+}
+
+/* Start fabric.c code */
+
+static int usbg_check_true(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int usbg_check_false(struct se_portal_group *se_tpg)
+{
+ return 0;
+}
+
+static char *usbg_get_fabric_name(void)
+{
+ return "usb_gadget";
+}
+
+static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ u8 proto_id;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ proto_id = sas_get_fabric_proto_ident(se_tpg);
+ break;
+ }
+
+ return proto_id;
+}
+
+static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+
+ return &tport->tport_name[0];
+}
+
+static u16 usbg_get_tag(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ return tpg->tport_tpgt;
+}
+
+static u32 usbg_get_default_depth(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static u32 usbg_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ int ret = 0;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+ format_code, buf);
+ break;
+ }
+
+ return ret;
+}
+
+static u32 usbg_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ int ret = 0;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+ format_code);
+ break;
+ }
+
+ return ret;
+}
+
+static char *usbg_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ char *tid = NULL;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+ port_nexus_ptr);
+ }
+
+ return tid;
+}
+
+static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+ struct usbg_nacl *nacl;
+
+ nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL);
+ if (!nacl) {
+ printk(KERN_ERR "Unable to alocate struct usbg_nacl\n");
+ return NULL;
+ }
+
+ return &nacl->se_node_acl;
+}
+
+static void usbg_release_fabric_acl(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl)
+{
+ struct usbg_nacl *nacl = container_of(se_nacl,
+ struct usbg_nacl, se_node_acl);
+ kfree(nacl);
+}
+
+static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int usbg_new_cmd(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ int ret;
+
+ ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf);
+ if (ret)
+ return ret;
+
+ return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
+}
+
+static void usbg_cmd_release(struct kref *ref)
+{
+ struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
+ ref);
+
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
+}
+
+static void usbg_release_cmd(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ kfree(cmd->data_buf);
+ kfree(cmd);
+ return;
+}
+
+static int usbg_shutdown_session(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static void usbg_close_session(struct se_session *se_sess)
+{
+ return;
+}
+
+static u32 usbg_sess_get_index(struct se_session *se_sess)
+{
+ return 0;
+}
+
+/*
+ * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
+ */
+static int usbg_write_pending_status(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
+{
+ return;
+}
+
+static u32 usbg_get_task_tag(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return le32_to_cpu(cmd->bot_tag);
+ else
+ return cmd->tag;
+}
+
+static int usbg_get_cmd_state(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+ return 0;
+}
+
+static u16 usbg_get_fabric_sense_len(void)
+{
+ return 0;
+}
+
+static const char *usbg_check_wwn(const char *name)
+{
+ const char *n;
+ unsigned int len;
+
+ n = strstr(name, "naa.");
+ if (!n)
+ return NULL;
+ n += 4;
+ len = strlen(n);
+ if (len == 0 || len > USBG_NAMELEN - 1)
+ return NULL;
+ return n;
+}
+
+static struct se_node_acl *usbg_make_nodeacl(
+ struct se_portal_group *se_tpg,
+ struct config_group *group,
+ const char *name)
+{
+ struct se_node_acl *se_nacl, *se_nacl_new;
+ struct usbg_nacl *nacl;
+ u64 wwpn = 0;
+ u32 nexus_depth;
+ const char *wnn_name;
+
+ wnn_name = usbg_check_wwn(name);
+ if (!wnn_name)
+ return ERR_PTR(-EINVAL);
+ se_nacl_new = usbg_alloc_fabric_acl(se_tpg);
+ if (!(se_nacl_new))
+ return ERR_PTR(-ENOMEM);
+
+ nexus_depth = 1;
+ /*
+ * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+ * when converting a NodeACL from demo mode -> explict
+ */
+ se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+ name, nexus_depth);
+ if (IS_ERR(se_nacl)) {
+ usbg_release_fabric_acl(se_tpg, se_nacl_new);
+ return se_nacl;
+ }
+ /*
+ * Locate our struct usbg_nacl and set the FC Nport WWPN
+ */
+ nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl);
+ nacl->iport_wwpn = wwpn;
+ snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name);
+ return se_nacl;
+}
+
+static void usbg_drop_nodeacl(struct se_node_acl *se_acl)
+{
+ struct usbg_nacl *nacl = container_of(se_acl,
+ struct usbg_nacl, se_node_acl);
+ core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+ kfree(nacl);
+}
+
+struct usbg_tpg *the_only_tpg_I_currently_have;
+
+static struct se_portal_group *usbg_make_tpg(
+ struct se_wwn *wwn,
+ struct config_group *group,
+ const char *name)
+{
+ struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
+ tport_wwn);
+ struct usbg_tpg *tpg;
+ unsigned long tpgt;
+ int ret;
+
+ if (strstr(name, "tpgt_") != name)
+ return ERR_PTR(-EINVAL);
+ if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
+ return ERR_PTR(-EINVAL);
+ if (the_only_tpg_I_currently_have) {
+ pr_err("Until the gadget framework can't handle multiple\n");
+ pr_err("gadgets, you can't do this here.\n");
+ return ERR_PTR(-EBUSY);
+ }
+
+ tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
+ if (!tpg) {
+ printk(KERN_ERR "Unable to allocate struct usbg_tpg");
+ return ERR_PTR(-ENOMEM);
+ }
+ mutex_init(&tpg->tpg_mutex);
+ atomic_set(&tpg->tpg_port_count, 0);
+ tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
+ if (!tpg->workqueue) {
+ kfree(tpg);
+ return NULL;
+ }
+
+ tpg->tport = tport;
+ tpg->tport_tpgt = tpgt;
+
+ ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
+ &tpg->se_tpg, tpg,
+ TRANSPORT_TPG_TYPE_NORMAL);
+ if (ret < 0) {
+ destroy_workqueue(tpg->workqueue);
+ kfree(tpg);
+ return NULL;
+ }
+ the_only_tpg_I_currently_have = tpg;
+ return &tpg->se_tpg;
+}
+
+static void usbg_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+
+ core_tpg_deregister(se_tpg);
+ destroy_workqueue(tpg->workqueue);
+ kfree(tpg);
+ the_only_tpg_I_currently_have = NULL;
+}
+
+static struct se_wwn *usbg_make_tport(
+ struct target_fabric_configfs *tf,
+ struct config_group *group,
+ const char *name)
+{
+ struct usbg_tport *tport;
+ const char *wnn_name;
+ u64 wwpn = 0;
+
+ wnn_name = usbg_check_wwn(name);
+ if (!wnn_name)
+ return ERR_PTR(-EINVAL);
+
+ tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
+ if (!(tport)) {
+ printk(KERN_ERR "Unable to allocate struct usbg_tport");
+ return ERR_PTR(-ENOMEM);
+ }
+ tport->tport_wwpn = wwpn;
+ snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name);
+ return &tport->tport_wwn;
+}
+
+static void usbg_drop_tport(struct se_wwn *wwn)
+{
+ struct usbg_tport *tport = container_of(wwn,
+ struct usbg_tport, tport_wwn);
+ kfree(tport);
+}
+
+/*
+ * If somebody feels like dropping the version property, go ahead.
+ */
+static ssize_t usbg_wwn_show_attr_version(
+ struct target_fabric_configfs *tf,
+ char *page)
+{
+ return sprintf(page, "usb-gadget fabric module\n");
+}
+TF_WWN_ATTR_RO(usbg, version);
+
+static struct configfs_attribute *usbg_wwn_attrs[] = {
+ &usbg_wwn_version.attr,
+ NULL,
+};
+
+static ssize_t tcm_usbg_tpg_show_enable(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
+}
+
+static int usbg_attach(struct usbg_tpg *);
+static void usbg_detach(struct usbg_tpg *);
+
+static ssize_t tcm_usbg_tpg_store_enable(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ unsigned long op;
+ ssize_t ret;
+
+ ret = kstrtoul(page, 0, &op);
+ if (ret < 0)
+ return -EINVAL;
+ if (op > 1)
+ return -EINVAL;
+
+ if (op && tpg->gadget_connect)
+ goto out;
+ if (!op && !tpg->gadget_connect)
+ goto out;
+
+ if (op) {
+ ret = usbg_attach(tpg);
+ if (ret)
+ goto out;
+ } else {
+ usbg_detach(tpg);
+ }
+ tpg->gadget_connect = op;
+out:
+ return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR);
+
+static ssize_t tcm_usbg_tpg_show_nexus(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ struct tcm_usbg_nexus *tv_nexus;
+ ssize_t ret;
+
+ mutex_lock(&tpg->tpg_mutex);
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ ret = -ENODEV;
+ goto out;
+ }
+ ret = snprintf(page, PAGE_SIZE, "%s\n",
+ tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+out:
+ mutex_unlock(&tpg->tpg_mutex);
+ return ret;
+}
+
+static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
+{
+ struct se_portal_group *se_tpg;
+ struct tcm_usbg_nexus *tv_nexus;
+ int ret;
+
+ mutex_lock(&tpg->tpg_mutex);
+ if (tpg->tpg_nexus) {
+ ret = -EEXIST;
+ pr_debug("tpg->tpg_nexus already exists\n");
+ goto err_unlock;
+ }
+ se_tpg = &tpg->se_tpg;
+
+ ret = -ENOMEM;
+ tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
+ if (!tv_nexus) {
+ pr_err("Unable to allocate struct tcm_vhost_nexus\n");
+ goto err_unlock;
+ }
+ tv_nexus->tvn_se_sess = transport_init_session();
+ if (IS_ERR(tv_nexus->tvn_se_sess))
+ goto err_free;
+
+ /*
+ * Since we are running in 'demo mode' this call with generate a
+ * struct se_node_acl for the tcm_vhost struct se_portal_group with
+ * the SCSI Initiator port name of the passed configfs group 'name'.
+ */
+ tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+ se_tpg, name);
+ if (!tv_nexus->tvn_se_sess->se_node_acl) {
+ pr_debug("core_tpg_check_initiator_node_acl() failed"
+ " for %s\n", name);
+ goto err_session;
+ }
+ /*
+ * Now register the TCM vHost virtual I_T Nexus as active with the
+ * call to __transport_register_session()
+ */
+ __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+ tv_nexus->tvn_se_sess, tv_nexus);
+ tpg->tpg_nexus = tv_nexus;
+ mutex_unlock(&tpg->tpg_mutex);
+ return 0;
+
+err_session:
+ transport_free_session(tv_nexus->tvn_se_sess);
+err_free:
+ kfree(tv_nexus);
+err_unlock:
+ mutex_unlock(&tpg->tpg_mutex);
+ return ret;
+}
+
+static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
+{
+ struct se_session *se_sess;
+ struct tcm_usbg_nexus *tv_nexus;
+ int ret = -ENODEV;
+
+ mutex_lock(&tpg->tpg_mutex);
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus)
+ goto out;
+
+ se_sess = tv_nexus->tvn_se_sess;
+ if (!se_sess)
+ goto out;
+
+ if (atomic_read(&tpg->tpg_port_count)) {
+ ret = -EPERM;
+ pr_err("Unable to remove Host I_T Nexus with"
+ " active TPG port count: %d\n",
+ atomic_read(&tpg->tpg_port_count));
+ goto out;
+ }
+
+ pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
+ tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+ /*
+ * Release the SCSI I_T Nexus to the emulated vHost Target Port
+ */
+ transport_deregister_session(tv_nexus->tvn_se_sess);
+ tpg->tpg_nexus = NULL;
+
+ kfree(tv_nexus);
+out:
+ mutex_unlock(&tpg->tpg_mutex);
+ return 0;
+}
+
+static ssize_t tcm_usbg_tpg_store_nexus(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ unsigned char i_port[USBG_NAMELEN], *ptr;
+ int ret;
+
+ if (!strncmp(page, "NULL", 4)) {
+ ret = tcm_usbg_drop_nexus(tpg);
+ return (!ret) ? count : ret;
+ }
+ if (strlen(page) > USBG_NAMELEN) {
+ pr_err("Emulated NAA Sas Address: %s, exceeds"
+ " max: %d\n", page, USBG_NAMELEN);
+ return -EINVAL;
+ }
+ snprintf(i_port, USBG_NAMELEN, "%s", page);
+
+ ptr = strstr(i_port, "naa.");
+ if (!ptr) {
+ pr_err("Missing 'naa.' prefix\n");
+ return -EINVAL;
+ }
+
+ if (i_port[strlen(i_port) - 1] == '\n')
+ i_port[strlen(i_port) - 1] = '\0';
+
+ ret = tcm_usbg_make_nexus(tpg, &i_port[4]);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *usbg_base_attrs[] = {
+ &tcm_usbg_tpg_enable.attr,
+ &tcm_usbg_tpg_nexus.attr,
+ NULL,
+};
+
+static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ atomic_inc(&tpg->tpg_port_count);
+ smp_mb__after_atomic_inc();
+ return 0;
+}
+
+static void usbg_port_unlink(struct se_portal_group *se_tpg,
+ struct se_lun *se_lun)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ atomic_dec(&tpg->tpg_port_count);
+ smp_mb__after_atomic_dec();
+}
+
+static int usbg_check_stop_free(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+
+ kref_put(&cmd->ref, usbg_cmd_release);
+ return 1;
+}
+
+static struct target_core_fabric_ops usbg_ops = {
+ .get_fabric_name = usbg_get_fabric_name,
+ .get_fabric_proto_ident = usbg_get_fabric_proto_ident,
+ .tpg_get_wwn = usbg_get_fabric_wwn,
+ .tpg_get_tag = usbg_get_tag,
+ .tpg_get_default_depth = usbg_get_default_depth,
+ .tpg_get_pr_transport_id = usbg_get_pr_transport_id,
+ .tpg_get_pr_transport_id_len = usbg_get_pr_transport_id_len,
+ .tpg_parse_pr_out_transport_id = usbg_parse_pr_out_transport_id,
+ .tpg_check_demo_mode = usbg_check_true,
+ .tpg_check_demo_mode_cache = usbg_check_false,
+ .tpg_check_demo_mode_write_protect = usbg_check_false,
+ .tpg_check_prod_mode_write_protect = usbg_check_false,
+ .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl,
+ .tpg_release_fabric_acl = usbg_release_fabric_acl,
+ .tpg_get_inst_index = usbg_tpg_get_inst_index,
+ .new_cmd_map = usbg_new_cmd,
+ .release_cmd = usbg_release_cmd,
+ .shutdown_session = usbg_shutdown_session,
+ .close_session = usbg_close_session,
+ .sess_get_index = usbg_sess_get_index,
+ .sess_get_initiator_sid = NULL,
+ .write_pending = usbg_send_write_request,
+ .write_pending_status = usbg_write_pending_status,
+ .set_default_node_attributes = usbg_set_default_node_attrs,
+ .get_task_tag = usbg_get_task_tag,
+ .get_cmd_state = usbg_get_cmd_state,
+ .queue_data_in = usbg_send_read_response,
+ .queue_status = usbg_send_status_response,
+ .queue_tm_rsp = usbg_queue_tm_rsp,
+ .get_fabric_sense_len = usbg_get_fabric_sense_len,
+ .set_fabric_sense_len = usbg_set_fabric_sense_len,
+ .check_stop_free = usbg_check_stop_free,
+
+ .fabric_make_wwn = usbg_make_tport,
+ .fabric_drop_wwn = usbg_drop_tport,
+ .fabric_make_tpg = usbg_make_tpg,
+ .fabric_drop_tpg = usbg_drop_tpg,
+ .fabric_post_link = usbg_port_link,
+ .fabric_pre_unlink = usbg_port_unlink,
+ .fabric_make_np = NULL,
+ .fabric_drop_np = NULL,
+ .fabric_make_nodeacl = usbg_make_nodeacl,
+ .fabric_drop_nodeacl = usbg_drop_nodeacl,
+};
+
+static int usbg_register_configfs(void)
+{
+ struct target_fabric_configfs *fabric;
+ int ret;
+
+ fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
+ if (IS_ERR(fabric)) {
+ printk(KERN_ERR "target_fabric_configfs_init() failed\n");
+ return PTR_ERR(fabric);
+ }
+
+ fabric->tf_ops = usbg_ops;
+ TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+ ret = target_fabric_configfs_register(fabric);
+ if (ret < 0) {
+ printk(KERN_ERR "target_fabric_configfs_register() failed"
+ " for usb-gadget\n");
+ return ret;
+ }
+ usbg_fabric_configfs = fabric;
+ return 0;
+};
+
+static void usbg_deregister_configfs(void)
+{
+ if (!(usbg_fabric_configfs))
+ return;
+
+ target_fabric_configfs_deregister(usbg_fabric_configfs);
+ usbg_fabric_configfs = NULL;
+};
+
+/* Start gadget.c code */
+
+static struct usb_interface_descriptor bot_intf_desc = {
+ .bLength = sizeof(bot_intf_desc),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bAlternateSetting = USB_G_ALT_INT_BBB,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = USB_SC_SCSI,
+ .bInterfaceProtocol = USB_PR_BULK,
+ .iInterface = USB_G_STR_INT_UAS,
+};
+
+static struct usb_interface_descriptor uasp_intf_desc = {
+ .bLength = sizeof(uasp_intf_desc),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 4,
+ .bAlternateSetting = USB_G_ALT_INT_UAS,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = USB_SC_SCSI,
+ .bInterfaceProtocol = USB_PR_UAS,
+ .iInterface = USB_G_STR_INT_BBB,
+};
+
+static struct usb_endpoint_descriptor uasp_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
+ .bLength = sizeof(uasp_bi_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = DATA_IN_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
+ .bLength = sizeof(uasp_bi_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+ .wBytesPerInterval = 0,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
+ .bLength = sizeof(bot_bi_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+};
+
+static struct usb_endpoint_descriptor uasp_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
+ .bLength = sizeof(uasp_bo_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = DATA_OUT_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(0x400),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
+ .bLength = sizeof(uasp_bo_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
+ .bLength = sizeof(bot_bo_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_endpoint_descriptor uasp_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
+ .bLength = sizeof(uasp_status_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = STATUS_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
+ .bLength = sizeof(uasp_status_in_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_endpoint_descriptor uasp_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
+ .bLength = sizeof(uasp_cmd_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = CMD_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
+ .bLength = sizeof(uasp_cmd_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *uasp_fs_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bi_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bo_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+};
+
+static struct usb_descriptor_header *uasp_hs_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bo_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *uasp_ss_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bi_desc,
+ (struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bo_desc,
+ (struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_comp_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+ NULL,
+};
+
+#define UAS_VENDOR_ID 0x0525 /* NetChip */
+#define UAS_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
+
+static struct usb_device_descriptor usbg_device_desc = {
+ .bLength = sizeof(usbg_device_desc),
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+ .idVendor = cpu_to_le16(UAS_VENDOR_ID),
+ .idProduct = cpu_to_le16(UAS_PRODUCT_ID),
+ .iManufacturer = USB_G_STR_MANUFACTOR,
+ .iProduct = USB_G_STR_PRODUCT,
+ .iSerialNumber = USB_G_STR_SERIAL,
+
+ .bNumConfigurations = 1,
+};
+
+static struct usb_string usbg_us_strings[] = {
+ { USB_G_STR_MANUFACTOR, "Target Manufactor"},
+ { USB_G_STR_PRODUCT, "Target Product"},
+ { USB_G_STR_SERIAL, "000000000001"},
+ { USB_G_STR_CONFIG, "default config"},
+ { USB_G_STR_INT_UAS, "USB Attached SCSI"},
+ { USB_G_STR_INT_BBB, "Bulk Only Transport"},
+ { },
+};
+
+static struct usb_gadget_strings usbg_stringtab = {
+ .language = 0x0409,
+ .strings = usbg_us_strings,
+};
+
+static struct usb_gadget_strings *usbg_strings[] = {
+ &usbg_stringtab,
+ NULL,
+};
+
+static int guas_unbind(struct usb_composite_dev *cdev)
+{
+ return 0;
+}
+
+static struct usb_configuration usbg_config_driver = {
+ .label = "Linux Target",
+ .bConfigurationValue = 1,
+ .iConfiguration = USB_G_STR_CONFIG,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};
+
+static void give_back_ep(struct usb_ep **pep)
+{
+ struct usb_ep *ep = *pep;
+ if (!ep)
+ return;
+ ep->driver_data = NULL;
+}
+
+static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+ struct usb_gadget *gadget = c->cdev->gadget;
+ struct usb_ep *ep;
+ int iface;
+
+ iface = usb_interface_id(c, f);
+ if (iface < 0)
+ return iface;
+
+ bot_intf_desc.bInterfaceNumber = iface;
+ uasp_intf_desc.bInterfaceNumber = iface;
+ fu->iface = iface;
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
+ &uasp_bi_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+
+ ep->driver_data = fu;
+ fu->ep_in = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
+ &uasp_bo_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ ep->driver_data = fu;
+ fu->ep_out = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
+ &uasp_status_in_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ ep->driver_data = fu;
+ fu->ep_status = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
+ &uasp_cmd_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ ep->driver_data = fu;
+ fu->ep_cmd = ep;
+
+ /* Assume endpoint addresses are the same for both speeds */
+ uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+ uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+ uasp_status_desc.bEndpointAddress =
+ uasp_ss_status_desc.bEndpointAddress;
+ uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+ uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+ uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+ uasp_fs_status_desc.bEndpointAddress =
+ uasp_ss_status_desc.bEndpointAddress;
+ uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+ return 0;
+ep_fail:
+ pr_err("Can't claim all required eps\n");
+
+ give_back_ep(&fu->ep_in);
+ give_back_ep(&fu->ep_out);
+ give_back_ep(&fu->ep_status);
+ give_back_ep(&fu->ep_cmd);
+ return -ENOTSUPP;
+}
+
+static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ kfree(fu);
+}
+
+struct guas_setup_wq {
+ struct work_struct work;
+ struct f_uas *fu;
+ unsigned int alt;
+};
+
+static void usbg_delayed_set_alt(struct work_struct *wq)
+{
+ struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
+ work);
+ struct f_uas *fu = work->fu;
+ int alt = work->alt;
+
+ kfree(work);
+
+ if (fu->flags & USBG_IS_BOT)
+ bot_cleanup_old_alt(fu);
+ if (fu->flags & USBG_IS_UAS)
+ uasp_cleanup_old_alt(fu);
+
+ if (alt == USB_G_ALT_INT_BBB)
+ bot_set_alt(fu);
+ else if (alt == USB_G_ALT_INT_UAS)
+ uasp_set_alt(fu);
+ usb_composite_setup_continue(fu->function.config->cdev);
+}
+
+static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
+ struct guas_setup_wq *work;
+
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work)
+ return -ENOMEM;
+ INIT_WORK(&work->work, usbg_delayed_set_alt);
+ work->fu = fu;
+ work->alt = alt;
+ schedule_work(&work->work);
+ return USB_GADGET_DELAYED_STATUS;
+ }
+ return -EOPNOTSUPP;
+}
+
+static void usbg_disable(struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if (fu->flags & USBG_IS_UAS)
+ uasp_cleanup_old_alt(fu);
+ else if (fu->flags & USBG_IS_BOT)
+ bot_cleanup_old_alt(fu);
+ fu->flags = 0;
+}
+
+static int usbg_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if (!(fu->flags & USBG_IS_BOT))
+ return -EOPNOTSUPP;
+
+ return usbg_bot_setup(f, ctrl);
+}
+
+static int usbg_cfg_bind(struct usb_configuration *c)
+{
+ struct f_uas *fu;
+ int ret;
+
+ fu = kzalloc(sizeof(*fu), GFP_KERNEL);
+ if (!fu)
+ return -ENOMEM;
+ fu->function.name = "Target Function";
+ fu->function.descriptors = uasp_fs_function_desc;
+ fu->function.hs_descriptors = uasp_hs_function_desc;
+ fu->function.ss_descriptors = uasp_ss_function_desc;
+ fu->function.bind = usbg_bind;
+ fu->function.unbind = usbg_unbind;
+ fu->function.set_alt = usbg_set_alt;
+ fu->function.setup = usbg_setup;
+ fu->function.disable = usbg_disable;
+ fu->tpg = the_only_tpg_I_currently_have;
+
+ ret = usb_add_function(c, &fu->function);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ kfree(fu);
+ return ret;
+}
+
+static int usb_target_bind(struct usb_composite_dev *cdev)
+{
+ int ret;
+
+ ret = usb_add_config(cdev, &usbg_config_driver,
+ usbg_cfg_bind);
+ return 0;
+}
+
+static struct usb_composite_driver usbg_driver = {
+ .name = "g_target",
+ .dev = &usbg_device_desc,
+ .strings = usbg_strings,
+ .max_speed = USB_SPEED_SUPER,
+ .unbind = guas_unbind,
+};
+
+static int usbg_attach(struct usbg_tpg *tpg)
+{
+ return usb_composite_probe(&usbg_driver, usb_target_bind);
+}
+
+static void usbg_detach(struct usbg_tpg *tpg)
+{
+ usb_composite_unregister(&usbg_driver);
+}
+
+static int __init usb_target_gadget_init(void)
+{
+ int ret;
+
+ ret = usbg_register_configfs();
+ return ret;
+}
+module_init(usb_target_gadget_init);
+
+static void __exit usb_target_gadget_exit(void)
+{
+ usbg_deregister_configfs();
+}
+module_exit(usb_target_gadget_exit);
+
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
+MODULE_DESCRIPTION("usb-gadget fabric");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/tcm_usb_gadget.h b/drivers/usb/gadget/tcm_usb_gadget.h
new file mode 100644
index 0000000..bb18999
--- /dev/null
+++ b/drivers/usb/gadget/tcm_usb_gadget.h
@@ -0,0 +1,146 @@
+#ifndef __TARGET_USB_GADGET_H__
+#define __TARGET_USB_GADGET_H__
+
+#include <linux/kref.h>
+/* #include <linux/usb/uas.h> */
+#include <linux/usb/composite.h>
+#include <linux/usb/uas.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#define USBG_NAMELEN 32
+
+#define fuas_to_gadget(f) (f->function.config->cdev->gadget)
+#define UASP_SS_EP_COMP_LOG_STREAMS 4
+#define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS)
+
+#define USB_G_STR_MANUFACTOR 1
+#define USB_G_STR_PRODUCT 2
+#define USB_G_STR_SERIAL 3
+#define USB_G_STR_CONFIG 4
+#define USB_G_STR_INT_UAS 5
+#define USB_G_STR_INT_BBB 6
+
+#define USB_G_ALT_INT_BBB 0
+#define USB_G_ALT_INT_UAS 1
+
+struct usbg_nacl {
+ /* Binary World Wide unique Port Name for SAS Initiator port */
+ u64 iport_wwpn;
+ /* ASCII formatted WWPN for Sas Initiator port */
+ char iport_name[USBG_NAMELEN];
+ /* Returned by usbg_make_nodeacl() */
+ struct se_node_acl se_node_acl;
+};
+
+struct tcm_usbg_nexus {
+ struct se_session *tvn_se_sess;
+};
+
+struct usbg_tpg {
+ struct mutex tpg_mutex;
+ /* SAS port target portal group tag for TCM */
+ u16 tport_tpgt;
+ /* Pointer back to usbg_tport */
+ struct usbg_tport *tport;
+ struct workqueue_struct *workqueue;
+ /* Returned by usbg_make_tpg() */
+ struct se_portal_group se_tpg;
+ u32 gadget_connect;
+ struct tcm_usbg_nexus *tpg_nexus;
+ atomic_t tpg_port_count;
+};
+
+struct usbg_tport {
+ /* SCSI protocol the tport is providing */
+ u8 tport_proto_id;
+ /* Binary World Wide unique Port Name for SAS Target port */
+ u64 tport_wwpn;
+ /* ASCII formatted WWPN for SAS Target port */
+ char tport_name[USBG_NAMELEN];
+ /* Returned by usbg_make_tport() */
+ struct se_wwn tport_wwn;
+};
+
+enum uas_state {
+ UASP_SEND_DATA,
+ UASP_RECEIVE_DATA,
+ UASP_SEND_STATUS,
+ UASP_QUEUE_COMMAND,
+};
+
+#define USBG_MAX_CMD 64
+struct usbg_cmd {
+ /* common */
+ u8 cmd_buf[USBG_MAX_CMD];
+ u32 data_len;
+ struct work_struct work;
+ int unpacked_lun;
+ struct se_cmd se_cmd;
+ void *data_buf; /* used if no sg support available */
+ struct f_uas *fu;
+ struct completion write_complete;
+ struct kref ref;
+
+ /* UAS only */
+ u16 tag;
+ u16 prio_attr;
+ struct sense_iu sense_iu;
+ enum uas_state state;
+ struct uas_stream *stream;
+
+ /* BOT only */
+ __le32 bot_tag;
+ unsigned int csw_code;
+ unsigned is_read:1;
+
+};
+
+struct uas_stream {
+ struct usb_request *req_in;
+ struct usb_request *req_out;
+ struct usb_request *req_status;
+};
+
+struct usbg_cdb {
+ struct usb_request *req;
+ void *buf;
+};
+
+struct bot_status {
+ struct usb_request *req;
+ struct bulk_cs_wrap csw;
+};
+
+struct f_uas {
+ struct usbg_tpg *tpg;
+ struct usb_function function;
+ u16 iface;
+
+ u32 flags;
+#define USBG_ENABLED (1 << 0)
+#define USBG_IS_UAS (1 << 1)
+#define USBG_USE_STREAMS (1 << 2)
+#define USBG_IS_BOT (1 << 3)
+#define USBG_BOT_CMD_PEND (1 << 4)
+
+ struct usbg_cdb cmd;
+ struct usb_ep *ep_in;
+ struct usb_ep *ep_out;
+
+ /* UAS */
+ struct usb_ep *ep_status;
+ struct usb_ep *ep_cmd;
+ struct uas_stream stream[UASP_SS_EP_COMP_NUM_STREAMS];
+
+ /* BOT */
+ struct bot_status bot_status;
+ struct usb_request *bot_req_in;
+ struct usb_request *bot_req_out;
+};
+
+extern struct usbg_tpg *the_only_tpg_I_currently_have;
+
+#endif
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index caf86ca..3098fbe 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -823,7 +823,7 @@
u32 __iomem *status_reg = &ehci->regs->port_status[
(wIndex & 0xff) - 1];
u32 __iomem *hostpc_reg = NULL;
- u32 temp, temp1, status;
+ u32 temp, temp1, status, cmd = 0;
unsigned long flags;
int retval = 0;
unsigned selector;
@@ -1202,7 +1202,32 @@
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (50);
}
+
+ if (ehci->reset_sof_bug && (temp & PORT_RESET)) {
+ cmd = ehci_readl(ehci, &ehci->regs->command);
+ cmd &= ~CMD_RUN;
+ ehci_writel(ehci, cmd, &ehci->regs->command);
+ if (handshake(ehci, &ehci->regs->status,
+ STS_HALT, STS_HALT, 16 * 125))
+ ehci_info(ehci,
+ "controller halt failed\n");
+ }
ehci_writel(ehci, temp, status_reg);
+ if (ehci->reset_sof_bug && (temp & PORT_RESET)
+ && hcd->driver->enable_ulpi_control) {
+ hcd->driver->enable_ulpi_control(hcd,
+ PORT_RESET);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ usleep_range(50000, 55000);
+ if (handshake(ehci, status_reg,
+ PORT_RESET, 0, 10 * 1000))
+ ehci_info(ehci,
+ "failed to clear reset\n");
+ spin_lock_irqsave(&ehci->lock, flags);
+ hcd->driver->disable_ulpi_control(hcd);
+ cmd |= CMD_RUN;
+ ehci_writel(ehci, cmd, &ehci->regs->command);
+ }
break;
/* For downstream facing ports (these): one hub port is put
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index a6b7dee..a95198c 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -328,6 +328,29 @@
}
+static int ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
+{
+ struct usb_hcd *hcd = hsic_to_hcd(mehci);
+ unsigned long timeout;
+
+ /* initiate read operation */
+ writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+ USB_ULPI_VIEWPORT);
+
+ /* wait for completion */
+ timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USEC);
+ while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
+ if (time_after(jiffies, timeout)) {
+ dev_err(mehci->dev, "ulpi_read: timeout %08x\n",
+ readl_relaxed(USB_ULPI_VIEWPORT));
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+
+ return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT));
+}
+
static int ulpi_write(struct msm_hsic_hcd *mehci, u32 val, u32 reg)
{
struct usb_hcd *hcd = hsic_to_hcd(mehci);
@@ -354,6 +377,37 @@
return 0;
}
+#define HSIC_DBG1 0X38
+#define ULPI_MANUAL_ENABLE BIT(4)
+#define ULPI_LINESTATE_DATA BIT(5)
+#define ULPI_LINESTATE_STROBE BIT(6)
+static void ehci_msm_enable_ulpi_control(struct usb_hcd *hcd, u32 linestate)
+{
+ struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ int val;
+
+ switch (linestate) {
+ case PORT_RESET:
+ val = ulpi_read(mehci, HSIC_DBG1);
+ val |= ULPI_MANUAL_ENABLE;
+ val &= ~(ULPI_LINESTATE_DATA | ULPI_LINESTATE_STROBE);
+ ulpi_write(mehci, val, HSIC_DBG1);
+ break;
+ default:
+ pr_info("%s: Unknown linestate:%0x\n", __func__, linestate);
+ }
+}
+
+static void ehci_msm_disable_ulpi_control(struct usb_hcd *hcd)
+{
+ struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ int val;
+
+ val = ulpi_read(mehci, HSIC_DBG1);
+ val &= ~ULPI_MANUAL_ENABLE;
+ ulpi_write(mehci, val, HSIC_DBG1);
+}
+
static int msm_hsic_config_gpios(struct msm_hsic_hcd *mehci, int gpio_en)
{
int rc = 0;
@@ -406,50 +460,28 @@
return rc;
}
-static int msm_hsic_phy_clk_reset(struct msm_hsic_hcd *mehci)
+static void msm_hsic_clk_reset(struct msm_hsic_hcd *mehci)
{
int ret;
- clk_prepare_enable(mehci->alt_core_clk);
-
ret = clk_reset(mehci->core_clk, CLK_RESET_ASSERT);
if (ret) {
- clk_disable_unprepare(mehci->alt_core_clk);
- dev_err(mehci->dev, "usb phy clk assert failed\n");
- return ret;
+ dev_err(mehci->dev, "hsic clk assert failed:%d\n", ret);
+ return;
}
- usleep_range(10000, 12000);
- clk_disable_unprepare(mehci->alt_core_clk);
+ clk_disable(mehci->core_clk);
ret = clk_reset(mehci->core_clk, CLK_RESET_DEASSERT);
if (ret)
- dev_err(mehci->dev, "usb phy clk deassert failed\n");
+ dev_err(mehci->dev, "hsic clk deassert failed:%d\n", ret);
- return ret;
+ usleep_range(10000, 12000);
+
+ clk_enable(mehci->core_clk);
}
-static int msm_hsic_phy_reset(struct msm_hsic_hcd *mehci)
-{
- struct usb_hcd *hcd = hsic_to_hcd(mehci);
- u32 val;
- int ret;
-
- ret = msm_hsic_phy_clk_reset(mehci);
- if (ret)
- return ret;
-
- val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
- writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
-
- /* Ensure that RESET operation is completed before turning off clock */
- mb();
- dev_dbg(mehci->dev, "phy_reset: success\n");
-
- return 0;
-}
-
-#define HSIC_GPIO150_PAD_CTL (MSM_TLMM_BASE+0x20C0)
-#define HSIC_GPIO151_PAD_CTL (MSM_TLMM_BASE+0x20C4)
+#define HSIC_STROBE_GPIO_PAD_CTL (MSM_TLMM_BASE+0x20C0)
+#define HSIC_DATA_GPIO_PAD_CTL (MSM_TLMM_BASE+0x20C4)
#define HSIC_CAL_PAD_CTL (MSM_TLMM_BASE+0x20C8)
#define HSIC_LV_MODE 0x04
#define HSIC_PAD_CALIBRATION 0xA8
@@ -458,33 +490,15 @@
static int msm_hsic_reset(struct msm_hsic_hcd *mehci)
{
struct usb_hcd *hcd = hsic_to_hcd(mehci);
- int cnt = 0;
int ret;
struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
- ret = msm_hsic_phy_reset(mehci);
- if (ret) {
- dev_err(mehci->dev, "phy_reset failed\n");
- return ret;
- }
+ msm_hsic_clk_reset(mehci);
- writel_relaxed(USBCMD_RESET, USB_USBCMD);
- while (cnt < LINK_RESET_TIMEOUT_USEC) {
- if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
- break;
- udelay(1);
- cnt++;
- }
- if (cnt >= LINK_RESET_TIMEOUT_USEC)
- return -ETIMEDOUT;
-
- /* Reset PORTSC and select ULPI phy */
+ /* select ulpi phy */
writel_relaxed(0x80000000, USB_PORTSC);
- /* TODO: Need to confirm if HSIC PHY also requires delay after RESET */
- msleep(100);
-
- /* HSIC PHY Initialization */
+ mb();
/* HSIC init sequence when HSIC signals (Strobe/Data) are
routed via GPIOs */
@@ -493,6 +507,8 @@
/* Enable LV_MODE in HSIC_CAL_PAD_CTL register */
writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL);
+ mb();
+
/*set periodic calibration interval to ~2.048sec in
HSIC_IO_CAL_REG */
ulpi_write(mehci, 0xFF, 0x33);
@@ -500,16 +516,18 @@
/* Enable periodic IO calibration in HSIC_CFG register */
ulpi_write(mehci, HSIC_PAD_CALIBRATION, 0x30);
- /* Configure GPIO 150/151 pins for HSIC functionality mode */
+ /* Configure GPIO pins for HSIC functionality mode */
ret = msm_hsic_config_gpios(mehci, 1);
if (ret) {
dev_err(mehci->dev, " gpio configuarion failed\n");
return ret;
}
- /* Set LV_MODE=0x1 and DCC=0x2 in HSIC_GPIO150/151_PAD_CTL
- register */
- writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_GPIO150_PAD_CTL);
- writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_GPIO151_PAD_CTL);
+ /* Set LV_MODE=0x1 and DCC=0x2 in HSIC_GPIO PAD_CTL register */
+ writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_STROBE_GPIO_PAD_CTL);
+ writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_DATA_GPIO_PAD_CTL);
+
+ mb();
+
/* Enable HSIC mode in HSIC_CFG register */
ulpi_write(mehci, 0x01, 0x31);
} else {
@@ -824,7 +842,7 @@
* generic hardware linkage
*/
.irq = msm_hsic_irq,
- .flags = HCD_USB2 | HCD_MEMORY,
+ .flags = HCD_USB2 | HCD_MEMORY | HCD_OLD_ENUM,
.reset = ehci_hsic_reset,
.start = ehci_run,
@@ -861,6 +879,9 @@
.bus_resume = ehci_hsic_bus_resume,
.log_urb_complete = dbg_log_event,
+
+ .enable_ulpi_control = ehci_msm_enable_ulpi_control,
+ .disable_ulpi_control = ehci_msm_disable_ulpi_control,
};
static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
@@ -1223,6 +1244,7 @@
mehci->dev = &pdev->dev;
mehci->ehci.susp_sof_bug = 1;
+ mehci->ehci.reset_sof_bug = 1;
mehci->ehci.max_log2_irq_thresh = 6;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 6afb70b..5754170 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -152,6 +152,7 @@
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
unsigned susp_sof_bug:1; /*Chip Idea HC*/
+ unsigned reset_sof_bug:1; /*Chip Idea HC*/
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 673ad12..78ece8d 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -343,6 +343,8 @@
/* Write 1 to disable the port */
xhci_writel(xhci, port_status | PORT_PE, addr);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
port_status = xhci_readl(xhci, addr);
xhci_dbg(xhci, "disable port, actual port %d status = 0x%x\n",
wIndex, port_status);
@@ -389,6 +391,8 @@
}
/* Change bits are all write 1 to clear */
xhci_writel(xhci, port_status | status, addr);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
port_status = xhci_readl(xhci, addr);
xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n",
port_change_bit, wIndex, port_status);
@@ -420,6 +424,8 @@
temp &= ~PORT_PLS_MASK;
temp |= PORT_LINK_STROBE | link_state;
xhci_writel(xhci, temp, port_array[port_id]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
}
void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
@@ -446,6 +452,8 @@
temp &= ~PORT_WKOC_E;
xhci_writel(xhci, temp, port_array[port_id]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
}
/* Test and clear port RWC bit */
@@ -459,6 +467,8 @@
temp = xhci_port_state_to_neutral(temp);
temp |= port_bit;
xhci_writel(xhci, temp, port_array[port_id]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
}
}
@@ -721,6 +731,8 @@
*/
xhci_writel(xhci, temp | PORT_POWER,
port_array[wIndex]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
temp = xhci_readl(xhci, port_array[wIndex]);
xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp);
@@ -728,6 +740,8 @@
case USB_PORT_FEAT_RESET:
temp = (temp | PORT_RESET);
xhci_writel(xhci, temp, port_array[wIndex]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
temp = xhci_readl(xhci, port_array[wIndex]);
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
@@ -743,6 +757,8 @@
case USB_PORT_FEAT_BH_PORT_RESET:
temp |= PORT_WR;
xhci_writel(xhci, temp, port_array[wIndex]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
temp = xhci_readl(xhci, port_array[wIndex]);
break;
@@ -936,8 +952,11 @@
t2 &= ~PORT_WAKE_BITS;
t1 = xhci_port_state_to_neutral(t1);
- if (t1 != t2)
+ if (t1 != t2) {
xhci_writel(xhci, t2, port_array[port_index]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
+ }
if (hcd->speed != HCD_USB3) {
/* enable remote wake up for USB 2.0 */
@@ -951,6 +970,8 @@
tmp = xhci_readl(xhci, addr);
tmp |= PORT_RWE;
xhci_writel(xhci, tmp, addr);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
}
}
hcd->state = HC_STATE_SUSPENDED;
@@ -1028,8 +1049,11 @@
xhci, port_index + 1);
if (slot_id)
xhci_ring_device(xhci, slot_id);
- } else
+ } else {
xhci_writel(xhci, temp, port_array[port_index]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
+ }
if (hcd->speed != HCD_USB3) {
/* disable remote wake up for USB 2.0 */
@@ -1043,6 +1067,8 @@
tmp = xhci_readl(xhci, addr);
tmp &= ~PORT_RWE;
xhci_writel(xhci, tmp, addr);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
}
}
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 689bc18..8467dc0 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -14,17 +14,30 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/usb/otg.h>
#include "xhci.h"
+#define SYNOPSIS_DWC3_VENDOR 0x5533
+
+static struct usb_phy *phy;
+
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
{
+ struct xhci_plat_data *pdata = dev->platform_data;
+
/*
* As of now platform drivers don't provide MSI support so we ensure
* here that the generic code does not try to make a pci_dev from our
* dev struct in order to setup MSI
*/
xhci->quirks |= XHCI_BROKEN_MSI;
+
+ if (!pdata)
+ return;
+ else if (pdata->vendor == SYNOPSIS_DWC3_VENDOR &&
+ pdata->revision < 0x230A)
+ xhci->quirks |= XHCI_PORTSC_DELAY;
}
/* called during probe() after chip reset completes */
@@ -149,6 +162,19 @@
if (ret)
goto put_usb3_hcd;
+ phy = usb_get_transceiver();
+ if (phy && phy->otg) {
+ dev_dbg(&pdev->dev, "%s otg support available\n", __func__);
+ hcd->driver->stop(hcd);
+ ret = otg_set_host(phy->otg, &hcd->self);
+ if (ret) {
+ dev_err(&pdev->dev, "%s otg_set_host failed\n",
+ __func__);
+ usb_put_transceiver(phy);
+ goto put_usb3_hcd;
+ }
+ }
+
return 0;
put_usb3_hcd:
@@ -182,6 +208,11 @@
usb_put_hcd(hcd);
kfree(xhci);
+ if (phy && phy->otg) {
+ otg_set_host(phy->otg, NULL);
+ usb_put_transceiver(phy);
+ }
+
return 0;
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 36641a7..2c26998 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -318,16 +318,6 @@
return;
}
-static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
-{
- int i;
-
- if (xhci->msix_entries) {
- for (i = 0; i < xhci->msix_count; i++)
- synchronize_irq(xhci->msix_entries[i].vector);
- }
-}
-
static int xhci_try_enable_msi(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -383,11 +373,7 @@
{
}
-static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
-{
-}
-
-#endif
+#endif /* CONFIG_PCI */
/*
* Initialize memory for HCD and xHC (one-time init).
@@ -513,6 +499,13 @@
xhci_dbg(xhci, "xhci_run\n");
+ xhci_dbg(xhci, "Calling HCD init\n");
+ /* Initialize HCD and host controller data structures. */
+ ret = xhci_init(hcd);
+ if (ret)
+ return ret;
+ xhci_dbg(xhci, "Called HCD init\n");
+
ret = xhci_try_enable_msi(hcd);
if (ret)
return ret;
@@ -661,6 +654,23 @@
}
#ifdef CONFIG_PM
+
+#ifdef CONFIG_PCI
+static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+{
+ int i;
+
+ if (xhci->msix_entries) {
+ for (i = 0; i < xhci->msix_count; i++)
+ synchronize_irq(xhci->msix_entries[i].vector);
+ }
+}
+#else
+static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+{
+}
+#endif /* CONFIG_PCI */
+
static void xhci_save_registers(struct xhci_hcd *xhci)
{
xhci->s3.command = xhci_readl(xhci, &xhci->op_regs->command);
@@ -3712,6 +3722,8 @@
hird = xhci_calculate_hird_besl(xhci, udev);
temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
xhci_writel(xhci, temp, pm_addr);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
/* Set port link state to U2(L1) */
addr = port_array[port_num];
@@ -3789,6 +3801,7 @@
unsigned int port_num;
unsigned long flags;
int hird;
+ bool delay;
if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
!udev->lpm_capable)
@@ -3801,6 +3814,9 @@
if (udev->usb2_hw_lpm_capable != 1)
return -EPERM;
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ delay = true;
+
spin_lock_irqsave(&xhci->lock, flags);
port_array = xhci->usb2_ports;
@@ -3817,12 +3833,18 @@
temp &= ~PORT_HIRD_MASK;
temp |= PORT_HIRD(hird) | PORT_RWE;
xhci_writel(xhci, temp, pm_addr);
+ if (delay)
+ ndelay(100);
temp = xhci_readl(xhci, pm_addr);
temp |= PORT_HLE;
xhci_writel(xhci, temp, pm_addr);
+ if (delay)
+ ndelay(100);
} else {
temp &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK);
xhci_writel(xhci, temp, pm_addr);
+ if (delay)
+ ndelay(100);
}
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -4043,12 +4065,6 @@
dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
}
- xhci_dbg(xhci, "Calling HCD init\n");
- /* Initialize HCD and host controller data structures. */
- retval = xhci_init(hcd);
- if (retval)
- goto error;
- xhci_dbg(xhci, "Called HCD init\n");
return 0;
error:
kfree(xhci);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3d69c4b..127b0e9 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1479,6 +1479,21 @@
#define XHCI_RESET_ON_RESUME (1 << 7)
#define XHCI_SW_BW_CHECKING (1 << 8)
#define XHCI_AMD_0x96_HOST (1 << 9)
+/*
+ * In Synopsis DWC3 controller, PORTSC register access involves multiple clock
+ * domains. When the software does a PORTSC write, handshakes are needed
+ * across these clock domains. This results in long access times, especially
+ * for USB 2.0 ports. In order to solve this issue, when the PORTSC write
+ * operations happen on the system bus, the command is latched and system bus
+ * is released immediately. However, the real PORTSC write access will take
+ * some time internally to complete. If the software quickly does a read to the
+ * PORTSC, some fields (port status change related fields like OCC, etc.) may
+ * not have correct value due to the current way of handling these bits.
+ *
+ * The workaround is to give some delay (5 mac2_clk -> UTMI clock = 60 MHz ->
+ * (16.66 ns x 5 = 84ns) ~100ns after writing to the PORTSC register.
+ */
+#define XHCI_PORTSC_DELAY (1 << 10)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
@@ -1667,6 +1682,11 @@
static inline void xhci_unregister_pci(void) {}
#endif
+struct xhci_plat_data {
+ unsigned vendor;
+ unsigned revision;
+};
+
#if defined(CONFIG_USB_XHCI_PLATFORM) \
|| defined(CONFIG_USB_XHCI_PLATFORM_MODULE)
int xhci_register_plat(void);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c0f9346..dedad53 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -827,8 +827,10 @@
/* Ensure that above operation is completed before turning off clocks */
mb();
- clk_disable_unprepare(motg->pclk);
- clk_disable_unprepare(motg->core_clk);
+ if (!motg->pdata->core_clk_always_on_workaround) {
+ clk_disable_unprepare(motg->pclk);
+ clk_disable_unprepare(motg->core_clk);
+ }
/* usb phy no more require TCXO clock, hence vote for TCXO disable */
if (!host_bus_suspend) {
@@ -891,9 +893,10 @@
motg->lpm_flags &= ~XO_SHUTDOWN;
}
- clk_prepare_enable(motg->core_clk);
-
- clk_prepare_enable(motg->pclk);
+ if (!motg->pdata->core_clk_always_on_workaround) {
+ clk_prepare_enable(motg->core_clk);
+ clk_prepare_enable(motg->pclk);
+ }
if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
msm_hsusb_ldo_enable(motg, 1);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index cad6e02..79bbce4 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -1099,31 +1099,21 @@
goto error;
}
- if (mgmt->hist == NULL) {
- if ((mgmt->mdp_is_hist_init == TRUE) &&
- ((!completion_done(&mgmt->mdp_hist_comp)) &&
- waitqueue_active(&mgmt->mdp_hist_comp.wait)))
- pr_err("mgmt->hist invalid NULL\n");
+ switch (mgmt->block) {
+ case MDP_BLOCK_DMA_P:
+ case MDP_BLOCK_DMA_S:
+ ret = _mdp_histogram_read_dma_data(mgmt);
+ break;
+ case MDP_BLOCK_VG_1:
+ case MDP_BLOCK_VG_2:
+ ret = _mdp_histogram_read_vg_data(mgmt);
+ break;
+ default:
+ pr_err("%s, invalid MDP block = %d\n", __func__, mgmt->block);
ret = -EINVAL;
+ goto error;
}
- if (!ret) {
- switch (mgmt->block) {
- case MDP_BLOCK_DMA_P:
- case MDP_BLOCK_DMA_S:
- ret = _mdp_histogram_read_dma_data(mgmt);
- break;
- case MDP_BLOCK_VG_1:
- case MDP_BLOCK_VG_2:
- ret = _mdp_histogram_read_vg_data(mgmt);
- break;
- default:
- pr_err("%s, invalid MDP block = %d\n", __func__,
- mgmt->block);
- ret = -EINVAL;
- goto error;
- }
- }
/*
* if read was triggered by an underrun or failed copying,
* don't wake up readers
@@ -1624,7 +1614,16 @@
__mdp_histogram_kickoff(mgmt);
if (isr & INTR_HIST_DONE) {
- queue_work(mdp_hist_wq, &mgmt->mdp_histogram_worker);
+ if ((waitqueue_active(&mgmt->mdp_hist_comp.wait))
+ && (mgmt->hist != NULL)) {
+ if (!queue_work(mdp_hist_wq,
+ &mgmt->mdp_histogram_worker)) {
+ pr_err("%s %d- can't queue hist_read\n",
+ __func__, mgmt->block);
+ }
+ } else {
+ __mdp_histogram_reset(mgmt);
+ }
}
}
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 2a61f07..780e0c6 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,5 +1,8 @@
mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
+mdss-mdp-objs += mdss_mdp_pp.o
+mdss-mdp-objs += mdss_mdp_intf_video.o
mdss-mdp-objs += mdss_mdp_intf_writeback.o
+mdss-mdp-objs += mdss_mdp_rotator.o
mdss-mdp-objs += mdss_mdp_overlay.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index aaf6690..a58c3e6 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -23,13 +23,20 @@
extern unsigned char *mdss_reg_base;
+enum mdss_mdp_clk_type {
+ MDSS_CLK_AHB,
+ MDSS_CLK_AXI,
+ MDSS_CLK_MDP_SRC,
+ MDSS_CLK_MDP_CORE,
+ MDSS_CLK_MDP_LUT,
+ MDSS_CLK_MDP_VSYNC,
+ MDSS_MAX_CLK
+};
+
struct mdss_res_type {
u32 rev;
u32 mdp_rev;
- struct clk *mdp_clk;
- struct clk *mdp_pclk;
- struct clk *mdp_lut_clk;
- struct clk *vsync_clk;
+ struct clk *mdp_clk[MDSS_MAX_CLK];
struct regulator *fs;
struct workqueue_struct *clk_ctrl_wq;
@@ -40,6 +47,8 @@
u32 irq_ena;
u32 irq_buzy;
+ u32 mdp_irq_mask;
+
u32 clk_ena;
u32 suspend;
u32 timeout;
@@ -60,4 +69,22 @@
u32 *mixer_type_map;
};
extern struct mdss_res_type *mdss_res;
+
+enum mdss_hw_index {
+ MDSS_HW_MDP,
+ MDSS_HW_DSI0,
+ MDSS_HW_DSI1,
+ MDSS_HW_HDMI,
+ MDSS_HW_EDP,
+ MDSS_MAX_HW_BLK
+};
+
+struct mdss_hw {
+ u32 hw_ndx;
+ irqreturn_t (*irq_handler)(int irq, void *ptr);
+};
+
+void mdss_enable_irq(struct mdss_hw *hw);
+void mdss_disable_irq(struct mdss_hw *hw);
+void mdss_disable_irq_nosync(struct mdss_hw *hw);
#endif /* MDSS_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index d1847c3..41e0c18 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -39,14 +39,13 @@
#include <mach/board.h>
#include <mach/clk.h>
#include <mach/hardware.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
#include "mdss.h"
#include "mdss_fb.h"
#include "mdss_mdp.h"
-/* 1.15 mdp clk factor */
-#define MDP_CLK_FACTOR(rate) (((rate) * 23) / 20)
-
unsigned char *mdss_reg_base;
struct mdss_res_type *mdss_res;
@@ -75,45 +74,261 @@
MDSS_MDP_MIXER_TYPE_WRITEBACK,
};
-irqreturn_t mdss_irq_handler(int mdss_irq, void *ptr)
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
+ { \
+ .src = MSM_BUS_MASTER_MDP_PORT0, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ab = (ab_val), \
+ .ib = (ib_val), \
+ }
+
+#define MDP_BUS_VECTOR_ENTRY_NDX(n) \
+ MDP_BUS_VECTOR_ENTRY((n) * 100000000, (n) * 200000000)
+
+static struct msm_bus_vectors mdp_bus_vectors[] = {
+ MDP_BUS_VECTOR_ENTRY_NDX(0),
+ MDP_BUS_VECTOR_ENTRY_NDX(1),
+ MDP_BUS_VECTOR_ENTRY_NDX(2),
+ MDP_BUS_VECTOR_ENTRY_NDX(3),
+ MDP_BUS_VECTOR_ENTRY_NDX(4),
+ MDP_BUS_VECTOR_ENTRY_NDX(5),
+ MDP_BUS_VECTOR_ENTRY_NDX(6),
+ MDP_BUS_VECTOR_ENTRY_NDX(7),
+ MDP_BUS_VECTOR_ENTRY_NDX(8),
+ MDP_BUS_VECTOR_ENTRY_NDX(9),
+ MDP_BUS_VECTOR_ENTRY_NDX(10),
+ MDP_BUS_VECTOR_ENTRY(200000000, 200000000)
+};
+static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
+static struct msm_bus_scale_pdata mdp_bus_scale_table = {
+ .usecase = mdp_bus_usecases,
+ .num_usecases = ARRAY_SIZE(mdp_bus_usecases),
+ .name = "mdss_mdp",
+};
+
+struct mdss_hw mdss_mdp_hw = {
+ .hw_ndx = MDSS_HW_MDP,
+ .irq_handler = mdss_mdp_isr,
+};
+
+static DEFINE_SPINLOCK(mdss_lock);
+struct mdss_hw *mdss_irq_handlers[MDSS_MAX_HW_BLK];
+
+static inline int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr)
+{
+ struct mdss_hw *hw;
+
+ spin_lock(&mdss_lock);
+ hw = mdss_irq_handlers[hw_ndx];
+ spin_unlock(&mdss_lock);
+ if (hw)
+ return hw->irq_handler(irq, ptr);
+
+ return -ENODEV;
+}
+
+static irqreturn_t mdss_irq_handler(int irq, void *ptr)
{
u32 intr = MDSS_MDP_REG_READ(MDSS_REG_HW_INTR_STATUS);
mdss_res->irq_buzy = true;
if (intr & MDSS_INTR_MDP)
- mdss_mdp_isr(mdss_irq, ptr);
+ mdss_irq_dispatch(MDSS_HW_MDP, irq, ptr);
+
+ if (intr & MDSS_INTR_DSI0)
+ mdss_irq_dispatch(MDSS_HW_DSI0, irq, ptr);
+
+ if (intr & MDSS_INTR_DSI1)
+ mdss_irq_dispatch(MDSS_HW_DSI1, irq, ptr);
+
+ if (intr & MDSS_INTR_EDP)
+ mdss_irq_dispatch(MDSS_HW_EDP, irq, ptr);
+
+ if (intr & MDSS_INTR_HDMI)
+ mdss_irq_dispatch(MDSS_HW_HDMI, irq, ptr);
mdss_res->irq_buzy = false;
return IRQ_HANDLED;
}
+
+void mdss_enable_irq(struct mdss_hw *hw)
+{
+ unsigned long irq_flags;
+ u32 ndx_bit;
+
+ if (hw->hw_ndx >= MDSS_MAX_HW_BLK)
+ return;
+
+ ndx_bit = BIT(hw->hw_ndx);
+
+ pr_debug("Enable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
+ mdss_res->irq_ena, mdss_res->irq_mask);
+
+ spin_lock_irqsave(&mdss_lock, irq_flags);
+ if (mdss_res->irq_mask & ndx_bit) {
+ pr_debug("MDSS HW ndx=%d is already set, mask=%x\n",
+ hw->hw_ndx, mdss_res->irq_mask);
+ } else {
+ mdss_irq_handlers[hw->hw_ndx] = hw;
+ mdss_res->irq_mask |= ndx_bit;
+ if (!mdss_res->irq_ena) {
+ mdss_res->irq_ena = true;
+ enable_irq(mdss_res->irq);
+ }
+ }
+ spin_unlock_irqrestore(&mdss_lock, irq_flags);
+}
+EXPORT_SYMBOL(mdss_enable_irq);
+
+void mdss_disable_irq(struct mdss_hw *hw)
+{
+ unsigned long irq_flags;
+ u32 ndx_bit;
+
+ if (hw->hw_ndx >= MDSS_MAX_HW_BLK)
+ return;
+
+ ndx_bit = BIT(hw->hw_ndx);
+
+ pr_debug("Disable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
+ mdss_res->irq_ena, mdss_res->irq_mask);
+
+ spin_lock_irqsave(&mdss_lock, irq_flags);
+ if (!(mdss_res->irq_mask & ndx_bit)) {
+ pr_warn("MDSS HW ndx=%d is NOT set, mask=%x\n",
+ hw->hw_ndx, mdss_res->mdp_irq_mask);
+ } else {
+ mdss_irq_handlers[hw->hw_ndx] = NULL;
+ mdss_res->irq_mask &= ~ndx_bit;
+ if (mdss_res->irq_mask == 0) {
+ mdss_res->irq_ena = false;
+ disable_irq(mdss_res->irq);
+ }
+ }
+ spin_unlock_irqrestore(&mdss_lock, irq_flags);
+}
+EXPORT_SYMBOL(mdss_disable_irq);
+
+void mdss_disable_irq_nosync(struct mdss_hw *hw)
+{
+ u32 ndx_bit;
+
+ if (hw->hw_ndx >= MDSS_MAX_HW_BLK)
+ return;
+
+ ndx_bit = BIT(hw->hw_ndx);
+
+ pr_debug("Disable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
+ mdss_res->irq_ena, mdss_res->irq_mask);
+
+ spin_lock(&mdss_lock);
+ if (!(mdss_res->irq_mask & ndx_bit)) {
+ pr_warn("MDSS HW ndx=%d is NOT set, mask=%x\n",
+ hw->hw_ndx, mdss_res->mdp_irq_mask);
+ } else {
+ mdss_irq_handlers[hw->hw_ndx] = NULL;
+ mdss_res->irq_mask &= ~ndx_bit;
+ if (mdss_res->irq_mask == 0) {
+ mdss_res->irq_ena = false;
+ disable_irq_nosync(mdss_res->irq);
+ }
+ }
+ spin_unlock(&mdss_lock);
+}
+EXPORT_SYMBOL(mdss_disable_irq_nosync);
+
+static int mdss_mdp_bus_scale_register(void)
+{
+ if (!mdss_res->bus_hdl) {
+ struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
+ int i;
+
+ for (i = 0; i < bus_pdata->num_usecases; i++) {
+ mdp_bus_usecases[i].num_paths = 1;
+ mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i];
+ }
+
+ mdss_res->bus_hdl = msm_bus_scale_register_client(bus_pdata);
+ if (!mdss_res->bus_hdl) {
+ pr_err("not able to get bus scale\n");
+ return -ENOMEM;
+ }
+
+ pr_debug("register bus_hdl=%x\n", mdss_res->bus_hdl);
+ }
+ return 0;
+}
+
+static void mdss_mdp_bus_scale_unregister(void)
+{
+ pr_debug("unregister bus_hdl=%x\n", mdss_res->bus_hdl);
+
+ if (mdss_res->bus_hdl)
+ msm_bus_scale_unregister_client(mdss_res->bus_hdl);
+}
+
+int mdss_mdp_bus_scale_set_min_quota(u32 quota)
+{
+ struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
+ struct msm_bus_vectors *vect = NULL;
+ int lvl;
+
+ if (mdss_res->bus_hdl < 1) {
+ pr_err("invalid bus handle %d\n", mdss_res->bus_hdl);
+ return -EINVAL;
+ }
+
+ for (lvl = 0; lvl < bus_pdata->num_usecases; lvl++) {
+ if (bus_pdata->usecase[lvl].num_paths) {
+ vect = &bus_pdata->usecase[lvl].vectors[0];
+ if (vect->ab >= quota) {
+ pr_debug("lvl=%d quota=%u ab=%u\n", lvl, quota,
+ vect->ab);
+ break;
+ }
+ }
+ }
+
+ if (lvl == bus_pdata->num_usecases) {
+ pr_warn("cannot match quota=%u try with max level\n", quota);
+ lvl--;
+ }
+
+ return msm_bus_scale_client_update_request(mdss_res->bus_hdl, lvl);
+}
+
+static inline u32 mdss_mdp_irq_mask(u32 intr_type, u32 intf_num)
+{
+ if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+ intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+ intf_num = (intf_num - MDSS_MDP_INTF0) * 2;
+ return 1 << (intr_type + intf_num);
+}
+
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num)
{
u32 irq;
unsigned long irq_flags;
int ret = 0;
- if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
- intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
- intf_num = intf_num << 1;
-
- irq = BIT(intr_type + intf_num);
+ irq = mdss_mdp_irq_mask(intr_type, intf_num);
spin_lock_irqsave(&mdp_lock, irq_flags);
- if (mdss_res->irq_mask & irq) {
- pr_warn("MDSS IRQ-0x%x is already set, mask=%x irq=%d\n",
- irq, mdss_res->irq_mask, mdss_res->irq_ena);
+ if (mdss_res->mdp_irq_mask & irq) {
+ pr_warn("MDSS MDP IRQ-0x%x is already set, mask=%x\n",
+ irq, mdss_res->mdp_irq_mask);
ret = -EBUSY;
} else {
- mdss_res->irq_mask |= irq;
+ pr_debug("MDP IRQ mask old=%x new=%x\n",
+ mdss_res->mdp_irq_mask, irq);
+ mdss_res->mdp_irq_mask |= irq;
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, irq);
- MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
- if (!mdss_res->irq_ena) {
- mdss_res->irq_ena = true;
- enable_irq(mdss_res->irq);
- }
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
+ mdss_res->mdp_irq_mask);
+ mdss_enable_irq(&mdss_mdp_hw);
}
spin_unlock_irqrestore(&mdp_lock, irq_flags);
@@ -125,24 +340,17 @@
u32 irq;
unsigned long irq_flags;
-
- if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
- intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
- intf_num = intf_num << 1;
-
- irq = BIT(intr_type + intf_num);
+ irq = mdss_mdp_irq_mask(intr_type, intf_num);
spin_lock_irqsave(&mdp_lock, irq_flags);
- if (!(mdss_res->irq_mask & irq)) {
- pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
- irq, mdss_res->irq_mask, mdss_res->irq_ena);
+ if (!(mdss_res->mdp_irq_mask & irq)) {
+ pr_warn("MDSS MDP IRQ-%x is NOT set, mask=%x\n",
+ irq, mdss_res->mdp_irq_mask);
} else {
- mdss_res->irq_mask &= ~irq;
- MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
- if (!mdss_res->irq_mask) {
- mdss_res->irq_ena = false;
- disable_irq(mdss_res->irq);
- }
+ mdss_res->mdp_irq_mask &= ~irq;
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
+ mdss_res->mdp_irq_mask);
+ mdss_disable_irq(&mdss_mdp_hw);
}
spin_unlock_irqrestore(&mdp_lock, irq_flags);
}
@@ -151,34 +359,114 @@
{
u32 irq;
- if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
- intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
- intf_num = intf_num << 1;
-
- irq = BIT(intr_type + intf_num);
+ irq = mdss_mdp_irq_mask(intr_type, intf_num);
spin_lock(&mdp_lock);
- if (!(mdss_res->irq_mask & irq)) {
- pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
- irq, mdss_res->irq_mask, mdss_res->irq_ena);
+ if (!(mdss_res->mdp_irq_mask & irq)) {
+ pr_warn("MDSS MDP IRQ-%x is NOT set, mask=%x\n",
+ irq, mdss_res->mdp_irq_mask);
} else {
- mdss_res->irq_mask &= ~irq;
- MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
- if (!mdss_res->irq_mask) {
- mdss_res->irq_ena = false;
- disable_irq_nosync(mdss_res->irq);
- }
+ mdss_res->mdp_irq_mask &= ~irq;
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
+ mdss_res->mdp_irq_mask);
+ mdss_disable_irq_nosync(&mdss_mdp_hw);
}
spin_unlock(&mdp_lock);
}
+static inline struct clk *mdss_mdp_get_clk(u32 clk_idx)
+{
+ if (clk_idx < MDSS_MAX_CLK)
+ return mdss_res->mdp_clk[clk_idx];
+ return NULL;
+}
+
+static int mdss_mdp_clk_update(u32 clk_idx, u32 enable)
+{
+ int ret = -ENODEV;
+ struct clk *clk = mdss_mdp_get_clk(clk_idx);
+
+ if (clk) {
+ pr_debug("clk=%d en=%d\n", clk_idx, enable);
+ if (enable) {
+ ret = clk_prepare_enable(clk);
+ } else {
+ clk_disable_unprepare(clk);
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+int mdss_mdp_vsync_clk_enable(int enable)
+{
+ int ret = 0;
+ pr_debug("clk enable=%d\n", enable);
+ mutex_lock(&mdp_clk_lock);
+ if (mdss_res->vsync_ena != enable) {
+ mdss_res->vsync_ena = enable;
+ ret = mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
+ }
+ mutex_unlock(&mdp_clk_lock);
+ return ret;
+}
+
+void mdss_mdp_set_clk_rate(unsigned long min_clk_rate)
+{
+ unsigned long clk_rate;
+ struct clk *clk = mdss_mdp_get_clk(MDSS_CLK_MDP_SRC);
+ if (clk) {
+ mutex_lock(&mdp_clk_lock);
+ clk_rate = clk_round_rate(clk, min_clk_rate);
+ if (IS_ERR_VALUE(clk_rate)) {
+ pr_err("unable to round rate err=%ld\n", clk_rate);
+ } else if (clk_rate != clk_get_rate(clk)) {
+ if (IS_ERR_VALUE(clk_set_rate(clk, clk_rate)))
+ pr_err("clk_set_rate failed\n");
+ else
+ pr_debug("mdp clk rate=%lu\n", clk_rate);
+ }
+ mutex_unlock(&mdp_clk_lock);
+ }
+}
+
+unsigned long mdss_mdp_get_clk_rate(u32 clk_idx)
+{
+ unsigned long clk_rate = 0;
+ struct clk *clk = mdss_mdp_get_clk(clk_idx);
+ mutex_lock(&mdp_clk_lock);
+ if (clk)
+ clk_rate = clk_get_rate(clk);
+ mutex_unlock(&mdp_clk_lock);
+
+ return clk_rate;
+}
+
static void mdss_mdp_clk_ctrl_update(int enable)
{
if (mdss_res->clk_ena == enable)
return;
pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable"));
+
+ mutex_lock(&mdp_clk_lock);
mdss_res->clk_ena = enable;
+ mb();
+
+ mdss_mdp_clk_update(MDSS_CLK_AHB, enable);
+ mdss_mdp_clk_update(MDSS_CLK_AXI, enable);
+
+ mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, enable);
+ mdss_mdp_clk_update(MDSS_CLK_MDP_LUT, enable);
+ if (mdss_res->vsync_ena)
+ mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
+
+ mutex_unlock(&mdp_clk_lock);
+}
+
+static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
+{
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
}
void mdss_mdp_clk_ctrl(int enable, int isr)
@@ -233,14 +521,30 @@
}
}
-static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
+static inline int mdss_mdp_irq_clk_register(struct platform_device *pdev,
+ char *clk_name, int clk_idx)
{
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ struct clk *tmp;
+ if (clk_idx >= MDSS_MAX_CLK) {
+ pr_err("invalid clk index %d\n", clk_idx);
+ return -EINVAL;
+ }
+
+
+ tmp = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(tmp)) {
+ pr_err("unable to get clk: %s\n", clk_name);
+ return PTR_ERR(tmp);
+ }
+
+ mdss_res->mdp_clk[clk_idx] = tmp;
+ return 0;
}
-static int mdss_mdp_irq_clk_setup(void)
+static int mdss_mdp_irq_clk_setup(struct platform_device *pdev)
{
int ret;
+ int i;
ret = request_irq(mdss_res->irq, mdss_irq_handler, IRQF_DISABLED,
"MDSS", 0);
@@ -250,15 +554,38 @@
}
disable_irq(mdss_res->irq);
- mdss_res->fs = regulator_get(NULL, "fs_mdp");
- if (IS_ERR(mdss_res->fs))
+ mdss_res->fs = regulator_get(NULL, "gdsc_mdss");
+ if (IS_ERR_OR_NULL(mdss_res->fs)) {
mdss_res->fs = NULL;
- else {
- regulator_enable(mdss_res->fs);
- mdss_res->fs_ena = true;
+ pr_err("unable to get gdsc_mdss regulator\n");
+ goto error;
}
+ regulator_enable(mdss_res->fs);
+
+ if (mdss_mdp_irq_clk_register(pdev, "bus_clk", MDSS_CLK_AXI) ||
+ mdss_mdp_irq_clk_register(pdev, "iface_clk", MDSS_CLK_AHB) ||
+ mdss_mdp_irq_clk_register(pdev, "core_clk_src", MDSS_CLK_MDP_SRC) ||
+ mdss_mdp_irq_clk_register(pdev, "core_clk", MDSS_CLK_MDP_CORE) ||
+ mdss_mdp_irq_clk_register(pdev, "lut_clk", MDSS_CLK_MDP_LUT) ||
+ mdss_mdp_irq_clk_register(pdev, "vsync_clk", MDSS_CLK_MDP_VSYNC))
+ goto error;
+
+ mdss_mdp_set_clk_rate(MDP_CLK_DEFAULT_RATE);
+ pr_debug("mdp clk rate=%ld\n", mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC));
return 0;
+error:
+ for (i = 0; i < MDSS_MAX_CLK; i++) {
+ if (mdss_res->mdp_clk[i])
+ clk_put(mdss_res->mdp_clk[i]);
+ }
+ if (mdss_res->fs)
+ regulator_put(mdss_res->fs);
+ if (mdss_res->irq)
+ free_irq(mdss_res->irq, 0);
+
+ return -EINVAL;
+
}
static struct msm_panel_common_pdata *mdss_mdp_populate_pdata(
@@ -272,11 +599,11 @@
return pdata;
}
-static u32 mdss_mdp_res_init(void)
+static u32 mdss_mdp_res_init(struct platform_device *pdev)
{
u32 rc;
- rc = mdss_mdp_irq_clk_setup();
+ rc = mdss_mdp_irq_clk_setup(pdev);
if (rc)
return rc;
@@ -365,12 +692,12 @@
goto probe_done;
}
- rc = mdss_mdp_res_init();
+ rc = mdss_mdp_res_init(pdev);
if (rc) {
pr_err("unable to initialize mdss mdp resources\n");
goto probe_done;
}
-
+ rc = mdss_mdp_bus_scale_register();
probe_done:
if (IS_ERR_VALUE(rc)) {
if (mdss_res) {
@@ -448,6 +775,7 @@
regulator_put(mdss_res->fs);
iounmap(mdss_reg_base);
pm_runtime_disable(&pdev->dev);
+ mdss_mdp_bus_scale_unregister();
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index c65d5a7..2cdd9f6 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -93,9 +93,18 @@
MDSS_MDP_BLOCK_MAX
};
+enum mdss_mdp_csc_type {
+ MDSS_MDP_CSC_RGB2RGB,
+ MDSS_MDP_CSC_YUV2RGB,
+ MDSS_MDP_CSC_RGB2YUV,
+ MDSS_MDP_CSC_YUV2YUV,
+ MDSS_MDP_MAX_CSC
+};
+
struct mdss_mdp_ctl {
u32 num;
u32 ref_cnt;
+ int power_on;
u32 intf_num;
u32 intf_type;
@@ -109,6 +118,8 @@
u16 height;
u32 dst_format;
+ u32 bus_quota;
+
struct msm_fb_data_type *mfd;
struct mdss_mdp_mixer *mixer_left;
struct mdss_mdp_mixer *mixer_right;
@@ -133,6 +144,8 @@
u8 cursor_enabled;
u8 rotator_mode;
+ u32 bus_quota;
+
struct mdss_mdp_ctl *ctl;
struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
};
@@ -218,6 +231,7 @@
struct mdss_mdp_format_params *src_fmt;
struct mdss_mdp_plane_sizes src_planes;
+ u32 bus_quota;
u8 mixer_stage;
u8 is_fg;
u8 alpha;
@@ -253,17 +267,22 @@
int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
void (*fnc_ptr)(void *), void *arg);
+int mdss_mdp_bus_scale_set_min_quota(u32 quota);
+void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
int mdss_mdp_vsync_clk_enable(int enable);
void mdss_mdp_clk_ctrl(int enable, int isr);
void mdss_mdp_footswitch_ctrl(int on);
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
+int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd);
int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd);
+struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator);
+int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer);
struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
int mux, int stage);
@@ -271,6 +290,9 @@
int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
+int mdss_mdp_csc_setup(u32 block, u32 blk_idx, u32 tbl_idx, u32 csc_type);
+int mdss_mdp_dspp_setup(struct mdss_mdp_ctl *ctl, struct mdss_mdp_mixer *mixer);
+
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index d89347e..c80527d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -20,10 +20,127 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
+enum {
+ MDSS_MDP_BUS_UPDATE_SKIP,
+ MDSS_MDP_BUS_UPDATE_EARLY,
+ MDSS_MDP_BUS_UPDATE_LATE,
+};
+
static DEFINE_MUTEX(mdss_mdp_ctl_lock);
static struct mdss_mdp_ctl mdss_mdp_ctl_list[MDSS_MDP_MAX_CTL];
static struct mdss_mdp_mixer mdss_mdp_mixer_list[MDSS_MDP_MAX_LAYERMIXER];
+static int mdss_mdp_ctl_update_clk_rate(void)
+{
+ struct mdss_mdp_ctl *ctl;
+ int cnum;
+ unsigned long clk_rate = MDP_CLK_DEFAULT_RATE;
+
+ mutex_lock(&mdss_mdp_ctl_lock);
+ for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
+ ctl = &mdss_mdp_ctl_list[cnum];
+ if (ctl->power_on && ctl->mfd) {
+ unsigned long tmp;
+ pr_debug("ctl=%d pclk_rate=%u\n", ctl->num,
+ ctl->mfd->panel_info.clk_rate);
+ tmp = (ctl->mfd->panel_info.clk_rate * 23) / 20;
+ if (tmp > clk_rate)
+ clk_rate = tmp;
+ }
+ }
+ mdss_mdp_set_clk_rate(clk_rate);
+ mutex_unlock(&mdss_mdp_ctl_lock);
+
+ return 0;
+}
+
+static int mdss_mdp_ctl_update_bus_scale(void)
+{
+ struct mdss_mdp_ctl *ctl;
+ int cnum;
+ u32 bus_quota = 0;
+
+ mutex_lock(&mdss_mdp_ctl_lock);
+ for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
+ ctl = &mdss_mdp_ctl_list[cnum];
+ if (ctl->power_on)
+ bus_quota += ctl->bus_quota;
+ }
+ mdss_mdp_bus_scale_set_min_quota(bus_quota);
+ mutex_unlock(&mdss_mdp_ctl_lock);
+
+ return 0;
+}
+
+static void mdss_mdp_bus_update_pipe_quota(struct mdss_mdp_pipe *pipe)
+{
+ u32 quota;
+
+ quota = pipe->img_width * pipe->img_height * 60 * pipe->src_fmt->bpp;
+ quota *= 5 / 4; /* 1.25 factor */
+
+ pr_debug("pipe=%d quota old=%u new=%u\n", pipe->num,
+ pipe->bus_quota, quota);
+ pipe->bus_quota = quota;
+}
+
+static int mdss_mdp_bus_update_mixer_quota(struct mdss_mdp_mixer *mixer)
+{
+ struct mdss_mdp_pipe *pipe;
+ u32 quota, stage;
+
+ if (!mixer)
+ return 0;
+
+ quota = 0;
+ for (stage = 0; stage < MDSS_MDP_MAX_STAGE; stage++) {
+ pipe = mixer->stage_pipe[stage];
+ if (pipe == NULL)
+ continue;
+
+ quota += pipe->bus_quota;
+ }
+
+ pr_debug("mixer=%d quota old=%u new=%u\n", mixer->num,
+ mixer->bus_quota, quota);
+
+ if (quota != mixer->bus_quota) {
+ mixer->bus_quota = quota;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int mdss_mdp_bus_update_ctl_quota(struct mdss_mdp_ctl *ctl)
+{
+ int ret = MDSS_MDP_BUS_UPDATE_SKIP;
+
+ if (mdss_mdp_bus_update_mixer_quota(ctl->mixer_left) ||
+ mdss_mdp_bus_update_mixer_quota(ctl->mixer_right)) {
+ u32 quota = 0;
+
+ if (ctl->mixer_left)
+ quota += ctl->mixer_left->bus_quota;
+ if (ctl->mixer_right)
+ quota += ctl->mixer_right->bus_quota;
+
+ pr_debug("ctl=%d quota old=%u new=%u\n",
+ ctl->num, ctl->bus_quota, quota);
+
+ if (quota != ctl->bus_quota) {
+ if (quota > ctl->bus_quota)
+ ret = MDSS_MDP_BUS_UPDATE_EARLY;
+ else
+ ret = MDSS_MDP_BUS_UPDATE_LATE;
+
+ ctl->bus_quota = quota;
+ }
+ }
+
+ return ret;
+}
+
static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(void)
{
struct mdss_mdp_ctl *ctl = NULL;
@@ -110,6 +227,71 @@
return 0;
}
+struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator)
+{
+ struct mdss_mdp_ctl *ctl = NULL;
+ struct mdss_mdp_mixer *mixer = NULL;
+
+ ctl = mdss_mdp_ctl_alloc();
+
+ if (!ctl)
+ return NULL;
+
+ mixer = mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_WRITEBACK);
+ if (!mixer)
+ goto error;
+
+ mixer->rotator_mode = rotator;
+
+ switch (mixer->num) {
+ case MDSS_MDP_LAYERMIXER3:
+ ctl->opmode = (rotator ? MDSS_MDP_CTL_OP_ROT0_MODE :
+ MDSS_MDP_CTL_OP_WB0_MODE);
+ break;
+ case MDSS_MDP_LAYERMIXER4:
+ ctl->opmode = (rotator ? MDSS_MDP_CTL_OP_ROT1_MODE :
+ MDSS_MDP_CTL_OP_WB1_MODE);
+ break;
+ default:
+ pr_err("invalid layer mixer=%d\n", mixer->num);
+ goto error;
+ }
+
+ ctl->mixer_left = mixer;
+ mixer->ctl = ctl;
+
+ ctl->start_fnc = mdss_mdp_writeback_start;
+
+ if (ctl->start_fnc)
+ ctl->start_fnc(ctl);
+
+ return mixer;
+error:
+ if (mixer)
+ mdss_mdp_mixer_free(mixer);
+ if (ctl)
+ mdss_mdp_ctl_free(ctl);
+
+ return NULL;
+}
+
+int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer)
+{
+ struct mdss_mdp_ctl *ctl;
+
+ ctl = mixer->ctl;
+
+ pr_debug("destroy ctl=%d mixer=%d\n", ctl->num, mixer->num);
+
+ if (ctl->stop_fnc)
+ ctl->stop_fnc(ctl);
+
+ mdss_mdp_mixer_free(mixer);
+ mdss_mdp_ctl_free(ctl);
+
+ return 0;
+}
+
static int mdss_mdp_ctl_init(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_ctl *ctl;
@@ -166,6 +348,27 @@
}
switch (mfd->panel_info.type) {
+ case EDP_PANEL:
+ ctl->intf_num = MDSS_MDP_INTF0;
+ ctl->intf_type = MDSS_INTF_EDP;
+ ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
+ ctl->start_fnc = mdss_mdp_video_start;
+ break;
+ case MIPI_VIDEO_PANEL:
+ if (mfd->panel_info.pdest == DISPLAY_1)
+ ctl->intf_num = MDSS_MDP_INTF1;
+ else
+ ctl->intf_num = MDSS_MDP_INTF2;
+ ctl->intf_type = MDSS_INTF_DSI;
+ ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
+ ctl->start_fnc = mdss_mdp_video_start;
+ break;
+ case DTV_PANEL:
+ ctl->intf_num = MDSS_MDP_INTF3;
+ ctl->intf_type = MDSS_INTF_HDMI;
+ ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
+ ctl->start_fnc = mdss_mdp_video_start;
+ break;
case WRITEBACK_PANEL:
ctl->intf_num = MDSS_MDP_NO_INTF;
ctl->opmode = MDSS_MDP_CTL_OP_WFD_MODE;
@@ -237,6 +440,10 @@
ctl = mfd->ctl;
mutex_lock(&ctl->lock);
+
+ ctl->power_on = true;
+ mdss_mdp_ctl_update_clk_rate();
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (ctl->start_fnc)
ret = ctl->start_fnc(ctl);
@@ -255,7 +462,7 @@
mixer->params_changed++;
temp = MDSS_MDP_REG_READ(MDSS_MDP_REG_DISP_INTF_SEL);
- temp |= (ctl->intf_type << (ctl->intf_num * 8));
+ temp |= (ctl->intf_type << ((ctl->intf_num - MDSS_MDP_INTF0) * 8));
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_DISP_INTF_SEL, temp);
outsize = (mixer->height << 16) | mixer->width;
@@ -308,6 +515,8 @@
pr_debug("ctl_num=%d\n", mfd->ctl->num);
mutex_lock(&ctl->lock);
+ ctl->power_on = false;
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (ctl->stop_fnc)
ret = ctl->stop_fnc(ctl);
@@ -321,6 +530,10 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
ctl->play_cnt = 0;
+
+ mdss_mdp_ctl_update_bus_scale();
+ mdss_mdp_ctl_update_clk_rate();
+
mutex_unlock(&ctl->lock);
mdss_mdp_pipe_release_all(mfd);
@@ -328,7 +541,6 @@
if (!mfd->ref_cnt)
mdss_mdp_ctl_destroy(mfd);
-
return ret;
}
@@ -493,6 +705,7 @@
if (params_changed) {
mixer->params_changed++;
mixer->stage_pipe[pipe->mixer_stage] = pipe;
+ mdss_mdp_bus_update_pipe_quota(pipe);
}
if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
@@ -537,6 +750,9 @@
{
mixer->params_changed = 0;
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+ mdss_mdp_dspp_setup(mixer->ctl, mixer);
+
/* skip mixer setup for rotator */
if (!mixer->rotator_mode)
mdss_mdp_mixer_setup(mixer->ctl, mixer);
@@ -548,6 +764,7 @@
{
int mixer1_changed, mixer2_changed;
int ret = 0;
+ int bus_update = MDSS_MDP_BUS_UPDATE_SKIP;
if (!ctl) {
pr_err("display function not set\n");
@@ -564,6 +781,8 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (mixer1_changed || mixer2_changed) {
+ bus_update = mdss_mdp_bus_update_ctl_quota(ctl);
+
if (ctl->prepare_fnc)
ret = ctl->prepare_fnc(ctl, arg);
if (ret) {
@@ -571,6 +790,9 @@
goto done;
}
+ if (bus_update == MDSS_MDP_BUS_UPDATE_EARLY)
+ mdss_mdp_ctl_update_bus_scale();
+
if (mixer1_changed)
mdss_mdp_mixer_update(ctl->mixer_left);
if (mixer2_changed)
@@ -591,6 +813,9 @@
ctl->play_cnt++;
+ if (bus_update == MDSS_MDP_BUS_UPDATE_LATE)
+ mdss_mdp_ctl_update_bus_scale();
+
done:
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
new file mode 100644
index 0000000..21ef290
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -0,0 +1,319 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+/* intf timing settings */
+struct intf_timing_params {
+ u32 width;
+ u32 height;
+ u32 xres;
+ u32 yres;
+
+ u32 h_back_porch;
+ u32 h_front_porch;
+ u32 v_back_porch;
+ u32 v_front_porch;
+ u32 hsync_pulse_width;
+ u32 vsync_pulse_width;
+
+ u32 border_clr;
+ u32 underflow_clr;
+ u32 hsync_skew;
+};
+
+#define MAX_SESSIONS 3
+struct mdss_mdp_video_ctx {
+ u32 ctl_num;
+ u32 pp_num;
+ u8 ref_cnt;
+
+ u8 timegen_en;
+ struct completion pp_comp;
+ struct completion vsync_comp;
+};
+
+struct mdss_mdp_video_ctx mdss_mdp_video_ctx_list[MAX_SESSIONS];
+
+static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
+ struct intf_timing_params *p)
+{
+ u32 hsync_period, vsync_period;
+ u32 hsync_start_x, hsync_end_x, display_v_start, display_v_end;
+ u32 active_h_start, active_h_end, active_v_start, active_v_end;
+ u32 display_hctl, active_hctl, hsync_ctl, polarity_ctl;
+ int off;
+
+ off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+
+ hsync_period = p->hsync_pulse_width + p->h_back_porch +
+ p->width + p->h_front_porch;
+ vsync_period = p->vsync_pulse_width + p->v_back_porch +
+ p->height + p->v_front_porch;
+
+ display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
+ hsync_period) + p->hsync_skew;
+ display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
+ p->hsync_skew - 1;
+
+ if (ctl->intf_type == MDSS_INTF_EDP) {
+ display_v_start += p->hsync_pulse_width + p->h_back_porch;
+ display_v_end -= p->h_front_porch;
+ }
+
+ hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
+ hsync_end_x = hsync_period - p->h_front_porch - 1;
+
+ if (p->width != p->xres) {
+ active_h_start = hsync_start_x;
+ active_h_end = active_h_start + p->xres - 1;
+ } else {
+ active_h_start = 0;
+ active_h_end = 0;
+ }
+
+ if (p->height != p->yres) {
+ active_v_start = display_v_start;
+ active_v_end = active_v_start + (p->yres * hsync_period) - 1;
+ } else {
+ active_v_start = 0;
+ active_v_end = 0;
+ }
+
+
+ if (active_h_end) {
+ active_hctl = (active_h_end << 16) | active_h_start;
+ active_hctl |= BIT(31); /* ACTIVE_H_ENABLE */
+ } else {
+ active_hctl = 0;
+ }
+
+ if (active_v_end)
+ active_v_start |= BIT(31); /* ACTIVE_V_ENABLE */
+
+ hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
+ display_hctl = (hsync_end_x << 16) | hsync_start_x;
+ polarity_ctl = (0 << 2) | /* DEN Polarity */
+ (0 << 1) | /* VSYNC Polarity */
+ (0); /* HSYNC Polarity */
+
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_HSYNC_CTL, hsync_ctl);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
+ vsync_period * hsync_period);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F0,
+ p->vsync_pulse_width * hsync_period);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_DISPLAY_HCTL,
+ display_hctl);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_DISPLAY_V_START_F0,
+ display_v_start);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_DISPLAY_V_END_F0,
+ display_v_end);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_ACTIVE_HCTL, active_hctl);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_ACTIVE_V_START_F0,
+ active_v_start);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_ACTIVE_V_END_F0,
+ active_v_end);
+
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_BORDER_COLOR,
+ p->border_clr);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_UNDERFLOW_COLOR,
+ p->underflow_clr);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_HSYNC_SKEW,
+ p->hsync_skew);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_POLARITY_CTL,
+ polarity_ctl);
+
+ return 0;
+}
+
+static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_video_ctx *ctx;
+ int off;
+
+ pr_debug("stop ctl=%d\n", ctl->num);
+
+ ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx for ctl=%d\n", ctl->num);
+ return -ENODEV;
+ }
+
+ if (ctx->timegen_en) {
+ off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ ctx->timegen_en = false;
+ }
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ return 0;
+}
+
+static void mdss_mdp_video_pp_intr_done(void *arg)
+{
+ struct mdss_mdp_video_ctx *ctx;
+
+ ctx = (struct mdss_mdp_video_ctx *) arg;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return;
+ }
+
+ pr_debug("intr mixer=%d\n", ctx->pp_num);
+
+ complete(&ctx->pp_comp);
+}
+
+static void mdss_mdp_video_vsync_intr_done(void *arg)
+{
+ struct mdss_mdp_video_ctx *ctx;
+
+ ctx = (struct mdss_mdp_video_ctx *) arg;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return;
+ }
+
+ pr_debug("intr ctl=%d\n", ctx->ctl_num);
+
+ complete(&ctx->vsync_comp);
+}
+
+static int mdss_mdp_video_prepare(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ struct mdss_mdp_video_ctx *ctx;
+
+ ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return -ENODEV;
+ }
+
+ if (ctx->timegen_en) {
+ u32 intr_type = MDSS_MDP_IRQ_PING_PONG_COMP;
+
+ pr_debug("waiting for ping pong %d done\n", ctx->pp_num);
+ mdss_mdp_set_intr_callback(intr_type, ctx->pp_num,
+ mdss_mdp_video_pp_intr_done, ctx);
+ mdss_mdp_irq_enable(intr_type, ctx->pp_num);
+
+ wait_for_completion_interruptible(&ctx->pp_comp);
+ mdss_mdp_irq_disable(intr_type, ctx->pp_num);
+ }
+
+ return 0;
+}
+
+static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ struct mdss_mdp_video_ctx *ctx;
+ u32 intr_type = MDSS_MDP_IRQ_INTF_VSYNC;
+
+ pr_debug("kickoff ctl=%d\n", ctl->num);
+
+ ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return -ENODEV;
+ }
+ mdss_mdp_set_intr_callback(intr_type, ctl->intf_num,
+ mdss_mdp_video_vsync_intr_done, ctx);
+ mdss_mdp_irq_enable(intr_type, ctl->intf_num);
+
+ if (!ctx->timegen_en) {
+ int off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+
+ pr_debug("enabling timing gen for intf=%d\n", ctl->intf_num);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
+ ctx->timegen_en = true;
+ wmb();
+ }
+
+ wait_for_completion_interruptible(&ctx->vsync_comp);
+ mdss_mdp_irq_disable(intr_type, ctl->intf_num);
+
+ return 0;
+}
+
+int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
+{
+ struct msm_fb_data_type *mfd;
+ struct mdss_panel_info *pinfo;
+ struct mdss_mdp_video_ctx *ctx;
+ struct mdss_mdp_mixer *mixer;
+ struct intf_timing_params itp = {0};
+ struct fb_info *fbi;
+ int i;
+
+ mfd = ctl->mfd;
+ fbi = mfd->fbi;
+ pinfo = &mfd->panel_info;
+ mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+
+ if (!mixer) {
+ pr_err("mixer not setup correctly\n");
+ return -ENODEV;
+ }
+
+ pr_debug("start ctl=%u\n", ctl->num);
+
+ for (i = 0; i < MAX_SESSIONS; i++) {
+ ctx = &mdss_mdp_video_ctx_list[i];
+ if (ctx->ref_cnt == 0) {
+ ctx->ref_cnt++;
+ break;
+ }
+ }
+ if (i == MAX_SESSIONS) {
+ pr_err("too many sessions\n");
+ return -ENOMEM;
+ }
+ ctl->priv_data = ctx;
+ ctx->ctl_num = ctl->num;
+ ctx->pp_num = mixer->num;
+ init_completion(&ctx->pp_comp);
+ init_completion(&ctx->vsync_comp);
+
+ itp.width = pinfo->xres + pinfo->lcdc.xres_pad;
+ itp.height = pinfo->yres + pinfo->lcdc.yres_pad;
+ itp.border_clr = pinfo->lcdc.border_clr;
+ itp.underflow_clr = pinfo->lcdc.underflow_clr;
+ itp.hsync_skew = pinfo->lcdc.hsync_skew;
+
+ itp.xres = fbi->var.xres;
+ itp.yres = fbi->var.yres;
+ itp.h_back_porch = fbi->var.left_margin;
+ itp.h_front_porch = fbi->var.right_margin;
+ itp.v_back_porch = fbi->var.upper_margin;
+ itp.v_front_porch = fbi->var.lower_margin;
+ itp.hsync_pulse_width = fbi->var.hsync_len;
+ itp.vsync_pulse_width = fbi->var.vsync_len;
+
+ if (mdss_mdp_video_timegen_setup(ctl, &itp)) {
+ pr_err("unable to get timing parameters\n");
+ return -EINVAL;
+ }
+
+ ctl->stop_fnc = mdss_mdp_video_stop;
+ ctl->prepare_fnc = mdss_mdp_video_prepare;
+ ctl->display_fnc = mdss_mdp_video_display;
+
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 99d4b4c..c1bc58a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -15,6 +15,7 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
+#include "mdss_mdp_rotator.h"
#define ROT_BLK_SIZE 128
@@ -193,6 +194,35 @@
return 0;
}
+static int mdss_mdp_writeback_rot_setup(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_writeback_ctx *ctx,
+ struct mdss_mdp_rotator_session *rot)
+{
+ pr_debug("rotator wb_num=%d\n", ctx->wb_num);
+
+ ctx->opmode = BIT(6); /* ROT EN */
+ if (ROT_BLK_SIZE == 128)
+ ctx->opmode |= BIT(4); /* block size 128 */
+
+ ctx->opmode |= rot->bwc_mode;
+
+ ctx->width = rot->src_rect.w;
+ ctx->height = rot->src_rect.h;
+
+ ctx->format = rot->format;
+
+ ctx->rot90 = !!(rot->rotations & MDP_ROT_90);
+ if (ctx->rot90) {
+ ctx->opmode |= BIT(5); /* ROT 90 */
+ swap(ctx->width, ctx->height);
+ }
+
+ if (mdss_mdp_writeback_format_setup(ctx))
+ return -EINVAL;
+
+ return 0;
+}
+
static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_writeback_ctx *ctx;
@@ -208,6 +238,27 @@
return 0;
}
+static int mdss_mdp_writeback_prepare(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ struct mdss_mdp_writeback_ctx *ctx;
+ ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+ if (!ctx)
+ return -ENODEV;
+
+ if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR) {
+ struct mdss_mdp_rotator_session *rot;
+ rot = (struct mdss_mdp_rotator_session *) arg;
+ if (!rot) {
+ pr_err("unable to retrieve rot session ctl=%d\n",
+ ctl->num);
+ return -ENODEV;
+ }
+ mdss_mdp_writeback_rot_setup(ctl, ctx, rot);
+ }
+
+ return 0;
+}
+
static void mdss_mdp_writeback_intr_done(void *arg)
{
struct mdss_mdp_writeback_ctx *ctx;
@@ -229,6 +280,7 @@
static int mdss_mdp_writeback_display(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_writeback_ctx *ctx;
+ struct mdss_mdp_rotator_session *rot = NULL;
struct mdss_mdp_data *wb_data;
u32 flush_bits;
int ret;
@@ -237,7 +289,17 @@
if (!ctx)
return -ENODEV;
- wb_data = &ctx->wb_data;
+ if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR) {
+ rot = (struct mdss_mdp_rotator_session *) arg;
+ if (!rot) {
+ pr_err("unable to retrieve rot session ctl=%d\n",
+ ctl->num);
+ return -ENODEV;
+ }
+ wb_data = rot->dst_data;
+ } else {
+ wb_data = &ctx->wb_data;
+ }
ret = mdss_mdp_writeback_addr_setup(ctx, wb_data);
if (ret) {
@@ -257,8 +319,16 @@
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
wmb();
- pr_debug("writeback kickoff wb_num=%d\n", ctx->wb_num);
- wait_for_completion_interruptible(&ctx->comp);
+ if (rot) {
+ pr_debug("rotator kickoff wb_num=%d\n", ctx->wb_num);
+ mutex_lock(&rot->lock);
+ rot->comp = &ctx->comp;
+ rot->busy = 1;
+ mutex_unlock(&rot->lock);
+ } else {
+ pr_debug("writeback kickoff wb_num=%d\n", ctx->wb_num);
+ wait_for_completion_interruptible(&ctx->comp);
+ }
return 0;
}
@@ -290,6 +360,8 @@
if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_WFD)
ret = mdss_mdp_writeback_wfd_setup(ctl, ctx);
+ else if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR)
+ ctl->prepare_fnc = mdss_mdp_writeback_prepare;
else /* line mode not supported */
return -ENOSYS;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index bd4a974..f1b158d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -21,6 +21,7 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
+#include "mdss_mdp_rotator.h"
#define CHECK_BOUNDS(offset, size, max_size) \
(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
@@ -85,28 +86,30 @@
dst_h = req->dst_rect.h;
}
- if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
- pr_err("too much upscaling Width %d->%d\n",
- req->src_rect.w, req->dst_rect.w);
- return -EINVAL;
- }
+ if (!(req->flags & MDSS_MDP_ROT_ONLY)) {
+ if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
+ pr_err("too much upscaling Width %d->%d\n",
+ req->src_rect.w, req->dst_rect.w);
+ return -EINVAL;
+ }
- if ((req->src_rect.h * MAX_UPSCALE_RATIO) < dst_h) {
- pr_err("too much upscaling. Height %d->%d\n",
- req->src_rect.h, req->dst_rect.h);
- return -EINVAL;
- }
+ if ((req->src_rect.h * MAX_UPSCALE_RATIO) < dst_h) {
+ pr_err("too much upscaling. Height %d->%d\n",
+ req->src_rect.h, req->dst_rect.h);
+ return -EINVAL;
+ }
- if (req->src_rect.w > (dst_w * MAX_DOWNSCALE_RATIO)) {
- pr_err("too much downscaling. Width %d->%d\n",
- req->src_rect.w, req->dst_rect.w);
- return -EINVAL;
- }
+ if (req->src_rect.w > (dst_w * MAX_DOWNSCALE_RATIO)) {
+ pr_err("too much downscaling. Width %d->%d\n",
+ req->src_rect.w, req->dst_rect.w);
+ return -EINVAL;
+ }
- if (req->src_rect.h > (dst_h * MAX_DOWNSCALE_RATIO)) {
- pr_err("too much downscaling. Height %d->%d\n",
- req->src_rect.h, req->dst_rect.h);
- return -EINVAL;
+ if (req->src_rect.h > (dst_h * MAX_DOWNSCALE_RATIO)) {
+ pr_err("too much downscaling. Height %d->%d\n",
+ req->src_rect.h, req->dst_rect.h);
+ return -EINVAL;
+ }
}
if (fmt->is_yuv) {
@@ -141,6 +144,61 @@
return 0;
}
+static int mdss_mdp_overlay_rotator_setup(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req)
+{
+ struct mdss_mdp_rotator_session *rot;
+ struct mdss_mdp_format_params *fmt;
+ int ret = 0;
+
+ pr_debug("rot ctl=%u req id=%x\n", mfd->ctl->num, req->id);
+
+ fmt = mdss_mdp_get_format_params(req->src.format);
+ if (!fmt) {
+ pr_err("invalid rot format %d\n", req->src.format);
+ return -EINVAL;
+ }
+
+ ret = mdss_mdp_overlay_req_check(mfd, req, fmt);
+ if (ret)
+ return ret;
+
+ if (req->id == MSMFB_NEW_REQUEST) {
+ rot = mdss_mdp_rotator_session_alloc();
+
+ if (!rot) {
+ pr_err("unable to allocate rotator session\n");
+ return -ENOMEM;
+ }
+ } else if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
+ rot = mdss_mdp_rotator_session_get(req->id);
+
+ if (!rot) {
+ pr_err("rotator session=%x not found\n", req->id);
+ return -ENODEV;
+ }
+ } else {
+ pr_err("invalid rotator session id=%x\n", req->id);
+ return -EINVAL;
+ }
+
+ rot->rotations = req->flags & (MDP_ROT_90 | MDP_FLIP_LR | MDP_FLIP_UD);
+
+ rot->format = fmt->format;
+ rot->img_width = req->src.width;
+ rot->img_height = req->src.height;
+ rot->src_rect.x = req->src_rect.x;
+ rot->src_rect.y = req->src_rect.y;
+ rot->src_rect.w = req->src_rect.w;
+ rot->src_rect.h = req->src_rect.h;
+
+ rot->params_changed++;
+
+ req->id = rot->session_id;
+
+ return ret;
+}
+
static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
struct mdp_overlay *req,
struct mdss_mdp_pipe **ppipe)
@@ -256,14 +314,19 @@
struct mdp_overlay *req)
{
int ret;
- struct mdss_mdp_pipe *pipe;
- /* userspace zorder start with stage 0 */
- req->z_order += MDSS_MDP_STAGE_0;
+ if (req->flags & MDSS_MDP_ROT_ONLY) {
+ ret = mdss_mdp_overlay_rotator_setup(mfd, req);
+ } else {
+ struct mdss_mdp_pipe *pipe;
- ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe);
+ /* userspace zorder start with stage 0 */
+ req->z_order += MDSS_MDP_STAGE_0;
- req->z_order -= MDSS_MDP_STAGE_0;
+ ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe);
+
+ req->z_order -= MDSS_MDP_STAGE_0;
+ }
return ret;
}
@@ -280,6 +343,19 @@
pr_debug("unset ndx=%x\n", ndx);
+ if (ndx & MDSS_MDP_ROT_SESSION_MASK) {
+ struct mdss_mdp_rotator_session *rot;
+ rot = mdss_mdp_rotator_session_get(ndx);
+ if (rot) {
+ mdss_mdp_rotator_finish(rot);
+ } else {
+ pr_warn("unknown session id=%x\n", ndx);
+ ret = -ENODEV;
+ }
+
+ return ret;
+ }
+
for (i = 0; unset_ndx != ndx && i < MDSS_MDP_MAX_SSPP; i++) {
pipe_ndx = BIT(i);
if (pipe_ndx & ndx) {
@@ -319,6 +395,28 @@
return ret;
}
+static int mdss_mdp_overlay_rotate(struct msmfb_overlay_data *req,
+ struct mdss_mdp_data *src_data,
+ struct mdss_mdp_data *dst_data)
+{
+ struct mdss_mdp_rotator_session *rot;
+ int ret;
+
+ rot = mdss_mdp_rotator_session_get(req->id);
+ if (!rot) {
+ pr_err("invalid session id=%x\n", req->id);
+ return -ENODEV;
+ }
+
+ ret = mdss_mdp_rotator_queue(rot, src_data, dst_data);
+ if (ret) {
+ pr_err("rotator queue error session id=%x\n", req->id);
+ return ret;
+ }
+
+ return 0;
+}
+
static int mdss_mdp_overlay_queue(struct msmfb_overlay_data *req,
struct mdss_mdp_data *src_data)
{
@@ -364,7 +462,23 @@
}
src_data.num_planes = 1;
- ret = mdss_mdp_overlay_queue(req, &src_data);
+ if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
+ struct mdss_mdp_data dst_data;
+ memset(&dst_data, 0, sizeof(dst_data));
+
+ mdss_mdp_get_img(mfd->iclient, &req->dst_data, &dst_data.p[0]);
+ if (dst_data.p[0].len == 0) {
+ pr_err("dst data pmem error\n");
+ return -ENOMEM;
+ }
+ dst_data.num_planes = 1;
+
+ ret = mdss_mdp_overlay_rotate(req, &src_data, &dst_data);
+
+ mdss_mdp_put_img(&dst_data.p[0]);
+ } else {
+ ret = mdss_mdp_overlay_queue(req, &src_data);
+ }
mdss_mdp_put_img(&src_data.p[0]);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index b52cff5..52f4324 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -581,6 +581,11 @@
(1 << 18) | /* SRC_DATA=YCBCR */
(1 << 17); /* CSC_1_EN */
+ /* only need to program once */
+ if (pipe->play_cnt == 0) {
+ mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
+ MDSS_MDP_CSC_YUV2RGB);
+ }
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, opmode);
return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
new file mode 100644
index 0000000..db840a8
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -0,0 +1,175 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include "mdss_mdp.h"
+
+struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = {
+ [MDSS_MDP_CSC_RGB2RGB] = {
+ 0,
+ {
+ 0x0200, 0x0000, 0x0000,
+ 0x0000, 0x0200, 0x0000,
+ 0x0000, 0x0000, 0x0200,
+ },
+ { 0x0, 0x0, 0x0,},
+ { 0x0, 0x0, 0x0,},
+ { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+ { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+ },
+ [MDSS_MDP_CSC_YUV2RGB] = {
+ 0,
+ {
+ 0x0254, 0x0000, 0x0331,
+ 0x0254, 0xff37, 0xfe60,
+ 0x0254, 0x0409, 0x0000,
+ },
+ { 0xfff0, 0xff80, 0xff80,},
+ { 0x0, 0x0, 0x0,},
+ { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+ { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+ },
+ [MDSS_MDP_CSC_RGB2YUV] = {
+ 0,
+ {
+ 0x0083, 0x0102, 0x0032,
+ 0x1fb5, 0x1f6c, 0x00e1,
+ 0x00e1, 0x1f45, 0x1fdc
+ },
+ { 0x0, 0x0, 0x0,},
+ { 0x0010, 0x0080, 0x0080,},
+ { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+ { 0x0010, 0x00eb, 0x0010, 0x00f0, 0x0010, 0x00f0,},
+ },
+ [MDSS_MDP_CSC_YUV2YUV] = {
+ 0,
+ {
+ 0x0200, 0x0000, 0x0000,
+ 0x0000, 0x0200, 0x0000,
+ 0x0000, 0x0000, 0x0200,
+ },
+ { 0x0, 0x0, 0x0,},
+ { 0x0, 0x0, 0x0,},
+ { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+ { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+ },
+};
+
+#define CSC_MV_OFF 0x0
+#define CSC_BV_OFF 0x2C
+#define CSC_LV_OFF 0x14
+#define CSC_POST_OFF 0xC
+
+static int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
+ struct mdp_csc_cfg *data)
+{
+ int i, ret = 0;
+ u32 *off, base, val = 0;
+
+ if (data == NULL) {
+ pr_err("no csc matrix specified\n");
+ return -EINVAL;
+ }
+
+ switch (block) {
+ case MDSS_MDP_BLOCK_SSPP:
+ if (blk_idx < MDSS_MDP_SSPP_RGB0) {
+ base = MDSS_MDP_REG_SSPP_OFFSET(blk_idx);
+ if (tbl_idx == 1)
+ base += MDSS_MDP_REG_VIG_CSC_1_BASE;
+ else
+ base += MDSS_MDP_REG_VIG_CSC_0_BASE;
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ case MDSS_MDP_BLOCK_WB:
+ if (blk_idx < MDSS_MDP_MAX_WRITEBACK) {
+ base = MDSS_MDP_REG_WB_OFFSET(blk_idx) +
+ MDSS_MDP_REG_WB_CSC_BASE;
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret != 0) {
+ pr_err("unsupported block id for csc\n");
+ return ret;
+ }
+
+ off = (u32 *) (base + CSC_MV_OFF);
+ for (i = 0; i < 9; i++) {
+ if (i & 0x1) {
+ val |= data->csc_mv[i] << 16;
+ MDSS_MDP_REG_WRITE(off, val);
+ off++;
+ } else {
+ val = data->csc_mv[i];
+ }
+ }
+ MDSS_MDP_REG_WRITE(off, val); /* COEFF_33 */
+
+ off = (u32 *) (base + CSC_BV_OFF);
+ for (i = 0; i < 3; i++) {
+ MDSS_MDP_REG_WRITE(off, data->csc_pre_bv[i]);
+ MDSS_MDP_REG_WRITE((u32 *)(((u32)off) + CSC_POST_OFF),
+ data->csc_post_bv[i]);
+ off++;
+ }
+
+ off = (u32 *) (base + CSC_LV_OFF);
+ for (i = 0; i < 6; i += 2) {
+ val = (data->csc_pre_lv[i] << 8) | data->csc_pre_lv[i+1];
+ MDSS_MDP_REG_WRITE(off, val);
+
+ val = (data->csc_post_lv[i] << 8) | data->csc_post_lv[i+1];
+ MDSS_MDP_REG_WRITE((u32 *)(((u32)off) + CSC_POST_OFF), val);
+ off++;
+ }
+
+ return ret;
+}
+
+int mdss_mdp_csc_setup(u32 block, u32 blk_idx, u32 tbl_idx, u32 csc_type)
+{
+ struct mdp_csc_cfg *data;
+
+ if (csc_type >= MDSS_MDP_MAX_CSC) {
+ pr_err("invalid csc matrix index %d\n", csc_type);
+ return -ERANGE;
+ }
+
+ pr_debug("csc type=%d blk=%d idx=%d tbl=%d\n", csc_type,
+ block, blk_idx, tbl_idx);
+
+ data = &mdp_csc_convert[csc_type];
+ return mdss_mdp_csc_setup_data(block, blk_idx, tbl_idx, data);
+}
+
+int mdss_mdp_dspp_setup(struct mdss_mdp_ctl *ctl, struct mdss_mdp_mixer *mixer)
+{
+ int dspp_num;
+
+ if (!ctl || !mixer)
+ return -EINVAL;
+
+ dspp_num = mixer->num;
+
+ ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */
+
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
new file mode 100644
index 0000000..628b7f5
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -0,0 +1,228 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#include "mdss_mdp.h"
+#include "mdss_mdp_rotator.h"
+
+#define MAX_ROTATOR_SESSIONS 8
+
+static DEFINE_MUTEX(rotator_lock);
+static struct mdss_mdp_rotator_session rotator_session[MAX_ROTATOR_SESSIONS];
+static LIST_HEAD(rotator_queue);
+
+struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void)
+{
+ struct mdss_mdp_rotator_session *rot;
+ int i;
+
+ mutex_lock(&rotator_lock);
+ for (i = 0; i < MAX_ROTATOR_SESSIONS; i++) {
+ rot = &rotator_session[i];
+ if (rot->ref_cnt == 0) {
+ rot->ref_cnt++;
+ rot->session_id = i | MDSS_MDP_ROT_SESSION_MASK;
+ mutex_init(&rot->lock);
+ break;
+ }
+ }
+ mutex_unlock(&rotator_lock);
+ if (i == MAX_ROTATOR_SESSIONS) {
+ pr_err("max rotator sessions reached\n");
+ return NULL;
+ }
+
+ return rot;
+}
+
+struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id)
+{
+ struct mdss_mdp_rotator_session *rot;
+ u32 ndx;
+
+ ndx = session_id & ~MDSS_MDP_ROT_SESSION_MASK;
+ if (ndx < MAX_ROTATOR_SESSIONS) {
+ rot = &rotator_session[ndx];
+ if (rot->ref_cnt && rot->session_id == session_id)
+ return rot;
+ }
+ return NULL;
+}
+
+static int mdss_mdp_rotator_busy_wait(struct mdss_mdp_rotator_session *rot)
+{
+ mutex_lock(&rot->lock);
+ if (rot->busy) {
+ pr_debug("waiting for rot=%d to complete\n", rot->pipe->num);
+ wait_for_completion_interruptible(rot->comp);
+ rot->busy = 0;
+ }
+ mutex_unlock(&rot->lock);
+
+ return 0;
+}
+
+static struct mdss_mdp_pipe *mdss_mdp_rotator_pipe_alloc(void)
+{
+ struct mdss_mdp_mixer *mixer;
+ struct mdss_mdp_pipe *pipe = NULL;
+ int pnum;
+
+ mixer = mdss_mdp_wb_mixer_alloc(1);
+ if (!mixer)
+ return NULL;
+
+ switch (mixer->num) {
+ case MDSS_MDP_LAYERMIXER3:
+ pnum = MDSS_MDP_SSPP_DMA0;
+ break;
+ case MDSS_MDP_LAYERMIXER4:
+ pnum = MDSS_MDP_SSPP_DMA1;
+ break;
+ default:
+ goto done;
+ }
+
+ pipe = mdss_mdp_pipe_alloc_pnum(pnum);
+
+ if (pipe)
+ pipe->mixer = mixer;
+done:
+ if (!pipe)
+ mdss_mdp_wb_mixer_destroy(mixer);
+
+ return pipe;
+}
+
+static int mdss_mdp_rotator_pipe_dequeue(struct mdss_mdp_rotator_session *rot)
+{
+ if (rot->pipe) {
+ pr_debug("reusing existing session=%d\n", rot->pipe->num);
+ mdss_mdp_rotator_busy_wait(rot);
+ list_move_tail(&rot->head, &rotator_queue);
+ } else {
+ struct mdss_mdp_rotator_session *tmp;
+
+ rot->params_changed++;
+ rot->pipe = mdss_mdp_rotator_pipe_alloc();
+ if (rot->pipe) {
+ pr_debug("use new rotator pipe=%d\n", rot->pipe->num);
+
+ rot->pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED;
+ list_add_tail(&rot->head, &rotator_queue);
+ } else if (!list_empty(&rotator_queue)) {
+ tmp = list_first_entry(&rotator_queue,
+ struct mdss_mdp_rotator_session,
+ head);
+
+ pr_debug("wait for rotator pipe=%d\n", tmp->pipe->num);
+ mdss_mdp_rotator_busy_wait(tmp);
+ rot->pipe = tmp->pipe;
+ tmp->pipe = NULL;
+
+ list_del(&tmp->head);
+ list_add_tail(&rot->head, &rotator_queue);
+ } else {
+ pr_err("no available rotator pipes\n");
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
+ struct mdss_mdp_data *src_data,
+ struct mdss_mdp_data *dst_data)
+{
+ struct mdss_mdp_pipe *rot_pipe;
+ struct mdss_mdp_ctl *ctl;
+ int ret;
+
+ if (!rot)
+ return -ENODEV;
+
+ mutex_lock(&rotator_lock);
+ ret = mdss_mdp_rotator_pipe_dequeue(rot);
+ if (ret) {
+ pr_err("unable to acquire rotator\n");
+ goto done;
+ }
+
+ rot_pipe = rot->pipe;
+
+ pr_debug("queue rotator pnum=%d\n", rot_pipe->num);
+
+ ctl = rot_pipe->mixer->ctl;
+
+ if (rot->params_changed) {
+ rot->params_changed = 0;
+ rot_pipe->flags = rot->rotations;
+ rot_pipe->src_fmt = mdss_mdp_get_format_params(rot->format);
+ rot_pipe->img_width = rot->img_width;
+ rot_pipe->img_height = rot->img_height;
+ rot_pipe->src = rot->src_rect;
+ rot_pipe->bwc_mode = rot->bwc_mode;
+ rot_pipe->params_changed++;
+ }
+
+ rot->dst_data = dst_data;
+
+ ret = mdss_mdp_pipe_queue_data(rot->pipe, src_data);
+ if (ret) {
+ pr_err("unable to queue rot data\n");
+ goto done;
+ }
+
+ ret = mdss_mdp_display_commit(ctl, rot);
+
+done:
+ mutex_unlock(&rotator_lock);
+
+ if (!rot->no_wait)
+ mdss_mdp_rotator_busy_wait(rot);
+
+ return ret;
+}
+
+int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot)
+{
+ struct mdss_mdp_pipe *rot_pipe;
+
+ if (!rot)
+ return -ENODEV;
+
+ pr_debug("finish rot id=%x\n", rot->session_id);
+
+ mutex_lock(&rotator_lock);
+ rot_pipe = rot->pipe;
+ if (rot_pipe) {
+ mdss_mdp_rotator_busy_wait(rot);
+ list_del(&rot->head);
+ }
+ memset(rot, 0, sizeof(*rot));
+ if (rot_pipe) {
+ struct mdss_mdp_mixer *mixer = rot_pipe->mixer;
+ mdss_mdp_pipe_destroy(rot_pipe);
+ mdss_mdp_wb_mixer_destroy(mixer);
+ }
+ mutex_unlock(&rotator_lock);
+
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
new file mode 100644
index 0000000..8940c46
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -0,0 +1,55 @@
+/* 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 MDSS_MDP_ROTATOR_H
+#define MDSS_MDP_ROTATOR_H
+
+#include <linux/types.h>
+
+#include "mdss_mdp.h"
+
+#define MDSS_MDP_ROT_SESSION_MASK 0x80000000
+
+struct mdss_mdp_rotator_session {
+ u32 session_id;
+ u32 ref_cnt;
+ u32 params_changed;
+
+ u32 format;
+ u32 rotations;
+
+ u16 img_width;
+ u16 img_height;
+ struct mdss_mdp_img_rect src_rect;
+
+ u32 bwc_mode;
+ struct mdss_mdp_pipe *pipe;
+ struct mdss_mdp_data *dst_data;
+
+ struct mutex lock;
+ u8 busy;
+ u8 no_wait;
+ struct completion *comp;
+
+ struct list_head head;
+};
+
+struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void);
+struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id);
+
+int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
+ struct mdss_mdp_data *src_data,
+ struct mdss_mdp_data *dst_data);
+int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot);
+int mdss_mdp_rotator_ctl_busy_wait(struct mdss_mdp_ctl *ctl);
+
+#endif /* MDSS_MDP_ROTATOR_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 25c9ac4..2e86806 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -10,7 +10,6 @@
* GNU General Public License for more details.
*
*/
-
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/android_pmem.h>
@@ -53,7 +52,7 @@
int index = -1;
switch (intr_type) {
case MDSS_MDP_IRQ_INTF_VSYNC:
- index = MDP_INTR_VSYNC_INTF_0 + intf_num;
+ index = MDP_INTR_VSYNC_INTF_0 + (intf_num - MDSS_MDP_INTF0);
break;
case MDSS_MDP_IRQ_PING_PONG_COMP:
index = MDP_INTR_PING_PONG_0 + intf_num;
@@ -116,11 +115,12 @@
isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_STATUS);
+
+ pr_debug("isr=%x\n", isr);
+
if (isr == 0)
goto done;
- pr_devel("isr=%x\n", isr);
-
mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
diff --git a/include/linux/i2c/isa1200.h b/include/linux/i2c/isa1200.h
index 9dab3eb..ffadf96 100644
--- a/include/linux/i2c/isa1200.h
+++ b/include/linux/i2c/isa1200.h
@@ -49,6 +49,7 @@
bool smart_en; /* smart mode enable/disable */
bool is_erm;
bool ext_clk_en;
+ bool need_pwm_clk;
unsigned int chip_en;
unsigned int duty;
struct isa1200_regulator *regulator_info;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 447fbbb..05a6b5b 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -241,7 +241,6 @@
#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */
#define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* On I/O err check card removal */
#define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */
-#define MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND (1 << 10)
#define MMC_CAP2_PACKED_RD (1 << 10) /* Allow packed read */
#define MMC_CAP2_PACKED_WR (1 << 11) /* Allow packed write */
#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
@@ -250,6 +249,7 @@
#define MMC_CAP2_SANITIZE (1 << 13) /* Support Sanitize */
#define MMC_CAP2_BKOPS (1 << 14) /* BKOPS supported */
#define MMC_CAP2_INIT_BKOPS (1 << 15) /* Need to set BKOPS_EN */
+#define MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND (1 << 16)
mmc_pm_flag_t pm_caps; /* supported pm features */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 8b6351f..19728fe 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -120,6 +120,7 @@
NUM_HSIC_PARAM,
};
+#define MDSS_MDP_ROT_ONLY 0x80
#define MDSS_MDP_RIGHT_MIXER 0x100
/* mdp_blit_req flag values */
@@ -249,6 +250,7 @@
uint32_t version_key;
struct msmfb_data plane1_data;
struct msmfb_data plane2_data;
+ struct msmfb_data dst_data;
};
struct msmfb_img {
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
new file mode 100644
index 0000000..fe9be89
--- /dev/null
+++ b/include/linux/msm_thermal.h
@@ -0,0 +1,34 @@
+/*
+ * 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_THERMAL_H
+#define __MSM_THERMAL_H
+
+struct msm_thermal_data {
+ uint32_t sensor_id;
+ uint32_t poll_ms;
+ uint32_t limit_temp;
+ uint32_t temp_hysteresis;
+ uint32_t limit_freq;
+};
+
+#ifdef CONFIG_THERMAL_MONITOR
+extern int msm_thermal_init(struct msm_thermal_data *pdata);
+#else
+static inline int msm_thermal_init(struct msm_thermal_data *pdata)
+{
+ return -ENOSYS;
+}
+#endif
+
+#endif /*__MSM_THERMAL_H*/
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index d9ec332..eabe4e8 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -212,6 +212,7 @@
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
#define HCD_SHARED 0x0004 /* Two (or more) usb_hcds share HW */
+#define HCD_OLD_ENUM 0x0008 /* HC supports short enumeration */
#define HCD_USB11 0x0010 /* USB 1.1 */
#define HCD_USB2 0x0020 /* USB 2.0 */
#define HCD_USB3 0x0040 /* USB 3.0 */
@@ -348,6 +349,8 @@
/* to log completion events*/
void (*log_urb_complete)(struct urb *urb, char * event,
unsigned extra);
+ void (*enable_ulpi_control)(struct usb_hcd *hcd, u32 linestate);
+ void (*disable_ulpi_control)(struct usb_hcd *hcd);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 22d4997..9da1999 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -24,6 +24,7 @@
#include <linux/usb/otg.h>
#include <linux/wakelock.h>
#include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
/*
* The following are bit fields describing the usb_request.udc_priv word.
@@ -191,6 +192,8 @@
* @enable_lpm_on_suspend: Enable the USB core to go into Low
* Power Mode, when USB bus is suspended but cable
* is connected.
+ * @core_clk_always_on_workaround: Don't disable core_clk when
+ * USB enters LPM.
* @bus_scale_table: parameters for bus bandwidth requirements
*/
struct msm_otg_platform_data {
@@ -207,6 +210,7 @@
bool disable_reset_on_disconnect;
bool enable_dcd;
bool enable_lpm_on_dev_suspend;
+ bool core_clk_always_on_workaround;
struct msm_bus_scale_pdata *bus_scale_table;
};
@@ -365,8 +369,14 @@
unsigned int dock_connect_irq;
};
+/**
+ * struct msm_hsic_peripheral_platform_data: HSIC peripheral
+ * platform data.
+ * @core_clk_always_on_workaround: Don't disable core_clk when
+ * HSIC enters LPM.
+ */
struct msm_hsic_peripheral_platform_data {
- bool keep_core_clk_on_suspend_workaround;
+ bool core_clk_always_on_workaround;
};
struct usb_bam_pipe_connect {
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 320ac8b..3308243 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -446,10 +446,12 @@
#define CMD_VFE_BUFFER_RELEASE 51
#define CMD_VFE_PROCESS_IRQ 52
-#define CMD_AXI_CFG_PRIM 0xF1
-#define CMD_AXI_CFG_PRIM_ALL_CHNLS 0xF2
-#define CMD_AXI_CFG_SEC 0xF4
-#define CMD_AXI_CFG_SEC_ALL_CHNLS 0xF8
+#define CMD_AXI_CFG_PRIM 0xc1
+#define CMD_AXI_CFG_PRIM_ALL_CHNLS 0xc2
+#define CMD_AXI_CFG_SEC 0xc4
+#define CMD_AXI_CFG_SEC_ALL_CHNLS 0xc8
+#define CMD_AXI_CFG_TERT1 0xd0
+
#define CMD_AXI_START 0xE1
#define CMD_AXI_STOP 0xE2
@@ -549,10 +551,11 @@
#define OUTPUT_ZSL_ALL_CHNLS 10
#define LAST_AXI_OUTPUT_MODE_ENUM = OUTPUT_ZSL_ALL_CHNLS
-#define OUTPUT_PRIM 0xF1
-#define OUTPUT_PRIM_ALL_CHNLS 0xF2
-#define OUTPUT_SEC 0xF4
-#define OUTPUT_SEC_ALL_CHNLS 0xF8
+#define OUTPUT_PRIM 0xC1
+#define OUTPUT_PRIM_ALL_CHNLS 0xC2
+#define OUTPUT_SEC 0xC4
+#define OUTPUT_SEC_ALL_CHNLS 0xC8
+#define OUTPUT_TERT1 0xD0
#define MSM_FRAME_PREV_1 0
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 333d0df..93f6c8b 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -59,6 +59,8 @@
#define MSG_ID_OUTPUT_PRIMARY 40
#define MSG_ID_OUTPUT_SECONDARY 41
#define MSG_ID_STATS_COMPOSITE 42
+#define MSG_ID_OUTPUT_TERTIARY1 43
+
/* ISP command IDs */
#define VFE_CMD_DUMMY_0 0
@@ -326,6 +328,9 @@
#define VFE_OUTPUTS_RAW BIT(8)
#define VFE_OUTPUTS_JPEG_AND_THUMB BIT(9)
#define VFE_OUTPUTS_THUMB_AND_JPEG BIT(10)
+#define VFE_OUTPUTS_RDI0 BIT(11)
+
+
struct msm_frame_info {
uint32_t image_mode;
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 695fea9..8e8778a 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -2322,6 +2322,9 @@
} __packed;
#define ASM_END_POINT_DEVICE_MATRIX 0
+
+#define PCM_CHANNEL_NULL 0
+
/* Front left channel. */
#define PCM_CHANNEL_FL 1
@@ -2444,7 +2447,7 @@
} __packed;
struct asm_stream_cmd_set_encdec_param {
- u32 param_id;
+ u32 param_id;
/* ID of the parameter. */
u32 param_size;
@@ -2573,9 +2576,6 @@
* - 6 -- 5.1 content
*/
- u16 reserved;
- /* Reserved. Clients must set this field to zero. */
-
u16 total_size_of_PCE_bits;
/* greater or equal to zero. * -In case of RAW formats and
* channel config = 0 (PCE), client can send * the bit stream
@@ -2986,6 +2986,8 @@
u16 enc_options;
/* Options used during encoding. */
+ u16 reserved;
+
} __packed;
#define ASM_MEDIA_FMT_WMA_V8 0x00010D91
@@ -4495,7 +4497,6 @@
struct asm_dec_out_chan_map_param {
struct apr_hdr hdr;
struct asm_stream_cmd_set_encdec_param encdec;
- struct asm_enc_cfg_blk_param_v2 encblk;
u32 num_channels;
/* Number of decoder output channels.
* Supported values: 0 to #MAX_CHAN_MAP_CHANNELS
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index ec8d73e..431dedf 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1176,6 +1176,7 @@
} __attribute__((packed));
#define ADM_CMD_CONNECT_AFE_PORT 0x00010320
+#define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
struct adm_cmd_connect_afe_port {
struct apr_hdr hdr;
diff --git a/include/sound/q6adm.h b/include/sound/q6adm.h
index 29fb606..56594d4 100644
--- a/include/sound/q6adm.h
+++ b/include/sound/q6adm.h
@@ -41,6 +41,7 @@
unsigned int *port_id, int copp_id);
int adm_connect_afe_port(int mode, int session_id, int port_id);
+int adm_disconnect_afe_port(int mode, int session_id, int port_id);
#ifdef CONFIG_RTAC
int adm_get_copp_id(int port_id);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 7ef15ac..2a555b2 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -64,8 +64,11 @@
/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
#define SR_CM_NOTIFY_ENABLE 0x0004
-#define ASYNC_IO_MODE 0x0002
#define SYNC_IO_MODE 0x0001
+#define ASYNC_IO_MODE 0x0002
+#define NT_MODE 0x0400
+
+
#define NO_TIMESTAMP 0xFF00
#define SET_TIMESTAMP 0x0000
@@ -230,6 +233,9 @@
int q6asm_set_encdec_chan_map(struct audio_client *ac,
uint32_t num_channels);
+int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
+ uint32_t rate, uint32_t channels);
+
int q6asm_enable_sbrps(struct audio_client *ac,
uint32_t sbr_ps);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index ee90797..1e647a2 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -239,6 +239,9 @@
int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels);
+int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
+ uint32_t rate, uint32_t channels);
+
int q6asm_enc_cfg_blk_multi_ch_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels);
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index aaccc5f..372c60d 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -234,6 +234,7 @@
enum target_sc_flags_table {
TARGET_SCF_BIDI_OP = 0x01,
TARGET_SCF_ACK_KREF = 0x02,
+ TARGET_SCF_UNKNOWN_SIZE = 0x04,
};
/* fabric independent task management function values */
@@ -538,6 +539,7 @@
/* Used to signal cmd->se_tfo->check_release_cmd() usage per cmd */
unsigned check_release:1;
unsigned cmd_wait_set:1;
+ unsigned unknown_data_length:1;
/* See se_cmd_flags_table */
u32 se_cmd_flags;
u32 se_ordered_id;
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index 10c6908..f27f575 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -112,7 +112,7 @@
void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *,
struct se_session *, u32, int, int, unsigned char *);
int transport_lookup_cmd_lun(struct se_cmd *, u32);
-int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
+int target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
void target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
unsigned char *, u32, u32, int, int, int);
int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 5034393..947bd85 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2779,7 +2779,7 @@
pcm_file = file->private_data;
- if (((cmd >> 8) & 0xff) != 'A')
+ if ((((cmd >> 8) & 0xff) != 'A') && (((cmd >> 8) & 0xff) != 'C'))
return -ENOTTY;
return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 9ade172..be31953 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1930,6 +1930,20 @@
};
+static const struct snd_soc_dapm_route audio_i2s_map[] = {
+ {"RX_I2S_CLK", NULL, "CP"},
+ {"RX_I2S_CLK", NULL, "CDC_CONN"},
+ {"SLIM RX1", NULL, "RX_I2S_CLK"},
+ {"SLIM RX2", NULL, "RX_I2S_CLK"},
+ {"SLIM RX3", NULL, "RX_I2S_CLK"},
+ {"SLIM RX4", NULL, "RX_I2S_CLK"},
+
+ {"SLIM TX1", NULL, "TX_I2S_CLK"},
+ {"SLIM TX2", NULL, "TX_I2S_CLK"},
+ {"SLIM TX3", NULL, "TX_I2S_CLK"},
+ {"SLIM TX4", NULL, "TX_I2S_CLK"},
+};
+
static const struct snd_soc_dapm_route audio_map[] = {
/* Earpiece (RX MIX1) */
{"EAR", NULL, "EAR PA"},
@@ -2618,9 +2632,9 @@
}
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
0x03, tx_fs_rate);
+ } else {
+ sitar->dai[dai->id - 1].rate = params_rate(params);
}
- } else {
- sitar->dai[dai->id - 1].rate = params_rate(params);
}
/**
@@ -2665,9 +2679,9 @@
}
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
0x03, (rx_fs_rate >> 0x05));
+ } else {
+ sitar->dai[dai->id - 1].rate = params_rate(params);
}
- } else {
- sitar->dai[dai->id - 1].rate = params_rate(params);
}
return 0;
@@ -2714,6 +2728,37 @@
},
};
+static struct snd_soc_dai_driver sitar_i2s_dai[] = {
+ {
+ .name = "sitar_i2s_rx1",
+ .id = AIF1_PB,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .rates = WCD9304_RATES,
+ .formats = SITAR_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &sitar_dai_ops,
+ },
+ {
+ .name = "sitar_i2s_tx1",
+ .id = AIF1_CAP,
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .rates = WCD9304_RATES,
+ .formats = SITAR_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &sitar_dai_ops,
+ },
+};
+
static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -4638,6 +4683,11 @@
sitar_1_1_reg_defaults[i].val);
}
+
+static const struct sitar_reg_mask_val sitar_i2c_codec_reg_init_val[] = {
+ {WCD9XXX_A_CHIP_CTL, 0x1, 0x1},
+};
+
static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
/* Initialize current threshold to 350MA
* number of wait and run cycles to 4096
@@ -4679,6 +4729,15 @@
{SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01},
};
+static void sitar_i2c_codec_init_reg(struct snd_soc_codec *codec)
+{
+ u32 i;
+ for (i = 0; i < ARRAY_SIZE(sitar_i2c_codec_reg_init_val); i++)
+ snd_soc_update_bits(codec, sitar_i2c_codec_reg_init_val[i].reg,
+ sitar_i2c_codec_reg_init_val[i].mask,
+ sitar_i2c_codec_reg_init_val[i].val);
+}
+
static void sitar_codec_init_reg(struct snd_soc_codec *codec)
{
u32 i;
@@ -4734,6 +4793,9 @@
sitar->pdata = dev_get_platdata(codec->dev->parent);
sitar_update_reg_defaults(codec);
sitar_codec_init_reg(codec);
+ sitar->intf_type = wcd9xxx_get_intf_type();
+ if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
+ sitar_i2c_codec_init_reg(codec);
ret = sitar_handle_pdata(sitar);
if (IS_ERR_VALUE(ret)) {
@@ -4745,6 +4807,12 @@
ARRAY_SIZE(sitar_snd_controls));
snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
ARRAY_SIZE(sitar_dapm_widgets));
+ if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ snd_soc_dapm_new_controls(dapm, sitar_dapm_i2s_widgets,
+ ARRAY_SIZE(sitar_dapm_i2s_widgets));
+ snd_soc_dapm_add_routes(dapm, audio_i2s_map,
+ ARRAY_SIZE(audio_i2s_map));
+ }
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
@@ -4972,8 +5040,12 @@
S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
#endif
- ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
sitar_dai, ARRAY_SIZE(sitar_dai));
+ else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
+ sitar_i2s_dai, ARRAY_SIZE(sitar_i2s_dai));
return ret;
}
static int __devexit sitar_remove(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 8061b06..d4045e1 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -103,7 +103,6 @@
break;
} else
atomic_set(&prtd->pending_buffer, 0);
-
if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
break;
buf = prtd->audio_client->port[IN].buf;
@@ -261,7 +260,8 @@
compr->info.codec_param.codec.bit_rate/8;
wma_pro_cfg.block_align = compr->info.codec_param.codec.align;
wma_pro_cfg.valid_bits_per_sample =
- compr->info.codec_param.codec.options.wma.bits_per_sample;
+ compr->info.codec_param.codec\
+ .options.wma.bits_per_sample;
wma_pro_cfg.ch_mask =
compr->info.codec_param.codec.options.wma.channelmask;
wma_pro_cfg.encode_opt =
@@ -297,7 +297,7 @@
SND_AUDIOCODEC_AC3_PASS_THROUGH) {
msm_pcm_routing_reg_psthr_stream(
soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream);
+ prtd->session_id, substream->stream, 1);
}
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -307,6 +307,12 @@
break;
case SNDRV_PCM_TRIGGER_STOP:
pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ if (compr->info.codec_param.codec.id ==
+ SND_AUDIOCODEC_AC3_PASS_THROUGH) {
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream, 0);
+ }
atomic_set(&prtd->start, 0);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -452,9 +458,11 @@
compressed_audio.prtd = NULL;
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
-
- msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
- SNDRV_PCM_STREAM_PLAYBACK);
+ if (!(compr->info.codec_param.codec.id ==
+ SND_AUDIOCODEC_AC3_PASS_THROUGH))
+ msm_pcm_routing_dereg_phy_stream(
+ soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
q6asm_audio_client_free(prtd->audio_client);
kfree(prtd);
return 0;
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 8051c92..cc51a0f6 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -244,7 +244,7 @@
}
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
- int stream_type)
+ int stream_type, int enable)
{
int i, session_type, path_type, port_type;
u32 mode = 0;
@@ -274,8 +274,13 @@
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
mode = afe_get_port_type(msm_bedais[i].port_id);
- adm_connect_afe_port(mode, dspst_id,
+ if (enable)
+ adm_connect_afe_port(mode, dspst_id,
msm_bedais[i].port_id);
+ else
+ adm_disconnect_afe_port(mode, dspst_id,
+ msm_bedais[i].port_id);
+
break;
}
}
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 2f213e7..45dbf40 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -114,7 +114,7 @@
void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id,
int stream_type);
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
- int stream_type);
+ int stream_type, int enable);
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index bf6f743..bc57ef3 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -278,6 +278,7 @@
case ADM_CMD_MEMORY_UNMAP_REGIONS:
case ADM_CMD_MATRIX_MAP_ROUTINGS:
case ADM_CMD_CONNECT_AFE_PORT:
+ case ADM_CMD_DISCONNECT_AFE_PORT:
atomic_set(&this_adm.copp_stat[index], 1);
wake_up(&this_adm.wait);
break;
@@ -523,6 +524,76 @@
return ret;
}
+int adm_disconnect_afe_port(int mode, int session_id, int port_id)
+{
+ struct adm_cmd_connect_afe_port cmd;
+ int ret = 0;
+ int index;
+
+ pr_debug("%s: port %d session id:%d mode:%d\n", __func__,
+ port_id, session_id, mode);
+
+ port_id = afe_convert_virtual_to_portid(port_id);
+
+ if (afe_validate_port(port_id) < 0) {
+ pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+ return -ENODEV;
+ }
+ if (this_adm.apr == NULL) {
+ this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+ 0xFFFFFFFF, &this_adm);
+ if (this_adm.apr == NULL) {
+ pr_err("%s: Unable to register ADM\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ rtac_set_adm_handle(this_adm.apr);
+ }
+ index = afe_get_port_index(port_id);
+ pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+ cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cmd.hdr.pkt_size = sizeof(cmd);
+ cmd.hdr.src_svc = APR_SVC_ADM;
+ cmd.hdr.src_domain = APR_DOMAIN_APPS;
+ cmd.hdr.src_port = port_id;
+ cmd.hdr.dest_svc = APR_SVC_ADM;
+ cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
+ cmd.hdr.dest_port = port_id;
+ cmd.hdr.token = port_id;
+ cmd.hdr.opcode = ADM_CMD_DISCONNECT_AFE_PORT;
+
+ cmd.mode = mode;
+ cmd.session_id = session_id;
+ cmd.afe_port_id = port_id;
+
+ atomic_set(&this_adm.copp_stat[index], 0);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
+ if (ret < 0) {
+ pr_err("%s:ADM enable for port %d failed\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Wait for the callback with copp id */
+ ret = wait_event_timeout(this_adm.wait,
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s ADM connect AFE failed for port %d\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ atomic_dec(&this_adm.copp_cnt[index]);
+ return 0;
+
+fail_cmd:
+
+ return ret;
+}
+
int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
{
struct adm_copp_open_command open;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 09bfd94..50011a1 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -246,21 +246,20 @@
port->buf[cnt].handle);
ion_client_destroy(port->buf[cnt].client);
#else
- pr_debug("%s:data[%p]phys[%p][%p] cnt[%d]"
- "mem_buffer[%p]\n",
+ pr_debug("%s:data[%p]phys[%p][%p] cnt[%d] mem_buffer[%p]\n",
__func__, (void *)port->buf[cnt].data,
- (void *)port->buf[cnt].phys,
- (void *)&port->buf[cnt].phys, cnt,
- (void *)port->buf[cnt].mem_buffer);
+ (void *)port->buf[cnt].phys,
+ (void *)&port->buf[cnt].phys, cnt,
+ (void *)port->buf[cnt].mem_buffer);
if (IS_ERR((void *)port->buf[cnt].mem_buffer))
- pr_err("%s:mem buffer invalid, error ="
- "%ld\n", __func__,
+ pr_err("%s:mem buffer invalid, error = %ld\n",
+ __func__,
PTR_ERR((void *)port->buf[cnt].mem_buffer));
else {
if (iounmap(
port->buf[cnt].mem_buffer) < 0)
- pr_err("%s: unmap buffer"
- " failed\n", __func__);
+ pr_err("%s: unmap buffer failed\n",
+ __func__);
}
free_contiguous_memory_by_paddr(
port->buf[cnt].phys);
@@ -306,8 +305,7 @@
ion_unmap_kernel(port->buf[0].client, port->buf[0].handle);
ion_free(port->buf[0].client, port->buf[0].handle);
ion_client_destroy(port->buf[0].client);
- pr_debug("%s:data[%p]phys[%p][%p]"
- ", client[%p] handle[%p]\n",
+ pr_debug("%s:data[%p]phys[%p][%p], client[%p] handle[%p]\n",
__func__,
(void *)port->buf[0].data,
(void *)port->buf[0].phys,
@@ -315,22 +313,20 @@
(void *)port->buf[0].client,
(void *)port->buf[0].handle);
#else
- pr_debug("%s:data[%p]phys[%p][%p]"
- "mem_buffer[%p]\n",
+ pr_debug("%s:data[%p]phys[%p][%p] mem_buffer[%p]\n",
__func__,
(void *)port->buf[0].data,
(void *)port->buf[0].phys,
(void *)&port->buf[0].phys,
(void *)port->buf[0].mem_buffer);
if (IS_ERR((void *)port->buf[0].mem_buffer))
- pr_err("%s:mem buffer invalid, error ="
- "%ld\n", __func__,
+ pr_err("%s:mem buffer invalid, error = %ld\n",
+ __func__,
PTR_ERR((void *)port->buf[0].mem_buffer));
else {
if (iounmap(
port->buf[0].mem_buffer) < 0)
- pr_err("%s: unmap buffer"
- " failed\n", __func__);
+ pr_err("%s: unmap buffer failed\n", __func__);
}
free_contiguous_memory_by_paddr(port->buf[0].phys);
#endif
@@ -433,8 +429,8 @@
(apr_fn)q6asm_mmapcallback,\
0x0FFFFFFFF, &this_mmap);
if (this_mmap.apr == NULL) {
- pr_debug("%s Unable to register \
- APR ASM common port \n", __func__);
+ pr_debug("%s Unable to register APR ASM common port\n",
+ __func__);
goto fail;
}
}
@@ -523,8 +519,7 @@
(UINT_MAX, "audio_client");
if (IS_ERR_OR_NULL((void *)
buf[cnt].client)) {
- pr_err("%s: ION create client"
- " for AUDIO failed\n",
+ pr_err("%s: ION create client for AUDIO failed\n",
__func__);
mutex_unlock(&ac->cmd_lock);
goto fail;
@@ -534,8 +529,7 @@
(0x1 << ION_AUDIO_HEAP_ID));
if (IS_ERR_OR_NULL((void *)
buf[cnt].handle)) {
- pr_err("%s: ION memory"
- " allocation for AUDIO failed\n",
+ pr_err("%s: ION memory allocation for AUDIO failed\n",
__func__);
mutex_unlock(&ac->cmd_lock);
goto fail;
@@ -547,8 +541,7 @@
&buf[cnt].phys,
(size_t *)&len);
if (rc) {
- pr_err("%s: ION Get Physical"
- " for AUDIO failed, rc = %d\n",
+ pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
__func__, rc);
mutex_unlock(&ac->cmd_lock);
goto fail;
@@ -559,8 +552,8 @@
0);
if (IS_ERR_OR_NULL((void *)
buf[cnt].data)) {
- pr_err("%s: ION memory"
- " mapping for AUDIO failed\n", __func__);
+ pr_err("%s: ION memory mapping for AUDIO failed\n",
+ __func__);
mutex_unlock(&ac->cmd_lock);
goto fail;
}
@@ -571,8 +564,8 @@
allocate_contiguous_ebi_nomap(bufsz,
SZ_4K);
if (!buf[cnt].phys) {
- pr_err("%s:Buf alloc failed "
- " size=%d\n", __func__,
+ pr_err("%s:Buf alloc failed size=%d\n",
+ __func__,
bufsz);
mutex_unlock(&ac->cmd_lock);
goto fail;
@@ -581,17 +574,17 @@
ioremap(buf[cnt].phys, bufsz);
if (IS_ERR(
(void *)buf[cnt].mem_buffer)) {
- pr_err("%s:map_buffer failed,"
- "error = %ld\n",
- __func__, PTR_ERR((void *)buf[cnt].mem_buffer));
+ pr_err("%s:map_buffer failed, error = %ld\n",
+ __func__,
+ PTR_ERR((void *)buf[cnt].mem_buffer));
mutex_unlock(&ac->cmd_lock);
goto fail;
}
buf[cnt].data =
buf[cnt].mem_buffer;
if (!buf[cnt].data) {
- pr_err("%s:invalid vaddr,"
- " iomap failed\n", __func__);
+ pr_err("%s:invalid vaddr, iomap failed\n",
+ __func__);
mutex_unlock(&ac->cmd_lock);
goto fail;
}
@@ -697,17 +690,15 @@
buf[0].phys = allocate_contiguous_ebi_nomap(bufsz * bufcnt,
SZ_4K);
if (!buf[0].phys) {
- pr_err("%s:Buf alloc failed "
- " size=%d, bufcnt=%d\n", __func__,
- bufsz, bufcnt);
+ pr_err("%s:Buf alloc failed size=%d, bufcnt=%d\n",
+ __func__, bufsz, bufcnt);
mutex_unlock(&ac->cmd_lock);
goto fail;
}
buf[0].mem_buffer = ioremap(buf[0].phys, bufsz * bufcnt);
if (IS_ERR((void *)buf[cnt].mem_buffer)) {
- pr_err("%s:map_buffer failed,"
- "error = %ld\n",
+ pr_err("%s:map_buffer failed, error = %ld\n",
__func__, PTR_ERR((void *)buf[0].mem_buffer));
mutex_unlock(&ac->cmd_lock);
@@ -716,8 +707,7 @@
buf[0].data = buf[0].mem_buffer;
#endif
if (!buf[0].data) {
- pr_err("%s:invalid vaddr,"
- " iomap failed\n", __func__);
+ pr_err("%s:invalid vaddr, iomap failed\n", __func__);
mutex_unlock(&ac->cmd_lock);
goto fail;
}
@@ -776,9 +766,8 @@
return 0;
}
- pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x]"
- "token[0x%x]payload_s[%d] src[%d] dest[%d]\n", __func__,
- payload[0], payload[1], data->opcode, data->token,
+ pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]\n",
+ __func__, payload[0], payload[1], data->opcode, data->token,
data->payload_size, data->src_port, data->dest_port);
if (data->opcode == APR_BASIC_RSP_RESULT) {
@@ -836,8 +825,8 @@
return 0;
}
- pr_debug("%s: session[%d]opcode[0x%x] \
- token[0x%x]payload_s[%d] src[%d] dest[%d]\n", __func__,
+ pr_debug("%s: session[%d]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]\n",
+ __func__,
ac->session, data->opcode,
data->token, data->payload_size, data->src_port,
data->dest_port);
@@ -915,9 +904,8 @@
out_cold_index*/
if (out_cold_index != 1) {
do_gettimeofday(&out_cold_tv);
- pr_debug("COLD: apr_send_pkt at %ld \
- sec %ld microsec\n",\
- out_cold_tv.tv_sec,\
+ pr_debug("COLD: apr_send_pkt at %ld sec %ld microsec\n",
+ out_cold_tv.tv_sec,
out_cold_tv.tv_usec);
out_cold_index = 1;
}
@@ -953,8 +941,7 @@
*/
if (in_cont_index == 7) {
do_gettimeofday(&in_cont_tv);
- pr_err("In_CONT:previous read buffer done \
- at %ld sec %ld microsec\n",\
+ pr_err("In_CONT:previous read buffer done at %ld sec %ld microsec\n",
in_cont_tv.tv_sec, in_cont_tv.tv_usec);
}
}
@@ -971,9 +958,8 @@
payload[READDONE_IDX_ID],
payload[READDONE_IDX_NUMFRAMES]);
#ifdef CONFIG_DEBUG_FS
- if (in_enable_flag) {
+ if (in_enable_flag)
in_cont_index++;
- }
#endif
if (ac->io_mode == SYNC_IO_MODE) {
if (port->buf == NULL) {
@@ -1009,9 +995,8 @@
pr_err("ASM_SESSION_EVENT_TX_OVERFLOW\n");
break;
case ASM_SESSION_CMDRSP_GET_SESSION_TIME:
- pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSION_TIME, "
- "payload[0] = %d, payload[1] = %d, "
- "payload[2] = %d\n", __func__,
+ pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSION_TIME, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
+ __func__,
payload[0], payload[1], payload[2]);
ac->time_stamp = (uint64_t)(((uint64_t)payload[1] << 32) |
payload[2]);
@@ -1022,9 +1007,8 @@
break;
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
- pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
- "payload[0] = %d, payload[1] = %d, "
- "payload[2] = %d, payload[3] = %d\n", __func__,
+ pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n",
+ __func__,
payload[0], payload[1], payload[2],
payload[3]);
break;
@@ -1061,8 +1045,8 @@
if (port->buf[idx].used == dir) {
/* To make it more robust, we could loop and get the
next avail buf, its risky though */
- pr_debug("%s:Next buf idx[0x%x] not available,\
- dir[%d]\n", __func__, idx, dir);
+ pr_debug("%s:Next buf idx[0x%x] not available,dir[%d]\n",
+ __func__, idx, dir);
mutex_unlock(&port->lock);
return NULL;
}
@@ -1111,8 +1095,8 @@
* To make it more robust, we could loop and get the
* next avail buf, its risky though
*/
- pr_debug("%s:Next buf idx[0x%x] not available,\
- dir[%d]\n", __func__, idx, dir);
+ pr_debug("%s:Next buf idx[0x%x] not available, dir[%d]\n",
+ __func__, idx, dir);
return NULL;
}
*size = port->buf[idx].actual_size;
@@ -1594,8 +1578,8 @@
struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
int rc = 0;
- pr_debug("%s:session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d]"
- "format[%d]", __func__, ac->session, frames_per_buf,
+ pr_debug("%s:session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d] format[%d]",
+ __func__, ac->session, frames_per_buf,
sample_rate, channels, bit_rate, mode, format);
q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
@@ -1670,6 +1654,47 @@
return -EINVAL;
}
+int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
+ uint32_t rate, uint32_t channels)
+{
+ struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+
+ int rc = 0;
+
+ pr_debug("%s: Session %d, rate = %d, channels = %d, setting the rate and channels to 0 for native\n",
+ __func__, ac->session, rate, channels);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+ enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+ enc_cfg.enc_blk.frames_per_buf = 1;
+ enc_cfg.enc_blk.format_id = LINEAR_PCM;
+ enc_cfg.enc_blk.cfg_size = sizeof(struct asm_pcm_cfg);
+ enc_cfg.enc_blk.cfg.pcm.ch_cfg = 0;/*channels;*/
+ enc_cfg.enc_blk.cfg.pcm.bits_per_sample = 16;
+ enc_cfg.enc_blk.cfg.pcm.sample_rate = 0;/*rate;*/
+ enc_cfg.enc_blk.cfg.pcm.is_signed = 1;
+ enc_cfg.enc_blk.cfg.pcm.interleaved = 1;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("Comamnd open failed\n");
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout opcode[0x%x] ", enc_cfg.hdr.opcode);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_enc_cfg_blk_multi_ch_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels)
{
@@ -1861,8 +1886,8 @@
struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
int rc = 0;
- pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] \
- reduced_rate_level[0x%4x]rate_modulation_cmd[0x%4x]", __func__,
+ pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] reduced_rate_level[0x%4x]rate_modulation_cmd[0x%4x]",
+ __func__,
ac->session, frames_per_buf, min_rate, max_rate,
reduced_rate_level, rate_modulation_cmd);
@@ -1904,8 +1929,8 @@
struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
int rc = 0;
- pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] \
- rate_modulation_cmd[0x%4x]", __func__, ac->session,
+ pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] rate_modulation_cmd[0x%4x]",
+ __func__, ac->session,
frames_per_buf, min_rate, max_rate, rate_modulation_cmd);
q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
@@ -2267,8 +2292,7 @@
struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
int rc = 0;
- pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d],\
- balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x]\n",
+ pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d], balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x]\n",
ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
@@ -2319,9 +2343,7 @@
struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
int rc = 0;
- pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d],"
- "balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x],\
- adv_enc_opt[0x%4x], adv_enc_opt2[0x%8x]\n",
+ pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d], balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x], adv_enc_opt[0x%4x], adv_enc_opt2[0x%8x]\n",
ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
wmapro_cfg->ch_cfg, wmapro_cfg->avg_bytes_per_sec,
wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
@@ -2778,8 +2800,8 @@
params->period = pause_param->period;
params->step = pause_param->step;
params->rampingcurve = pause_param->rampingcurve;
- pr_debug("%s: soft Pause Command: enable = %d, period = %d,"
- "step = %d, curve = %d\n", __func__, params->enable,
+ pr_debug("%s: soft Pause Command: enable = %d, period = %d, step = %d, curve = %d\n",
+ __func__, params->enable,
params->period, params->step, params->rampingcurve);
rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
if (rc < 0) {
@@ -2791,8 +2813,8 @@
rc = wait_event_timeout(ac->cmd_wait,
(atomic_read(&ac->cmd_state) == 0), 5*HZ);
if (!rc) {
- pr_err("%s: timeout in sending volume command(soft_pause)"
- "to apr\n", __func__);
+ pr_err("%s: timeout in sending volume command(soft_pause) to apr\n",
+ __func__);
rc = -EINVAL;
goto fail_cmd;
}
@@ -2837,13 +2859,13 @@
params->period = softvol_param->period;
params->step = softvol_param->step;
params->rampingcurve = softvol_param->rampingcurve;
- pr_debug("%s: soft Volume:opcode = %d,payload_sz =%d,module_id =%d,"
- "param_id = %d, param_sz = %d\n", __func__,
+ pr_debug("%s: soft Volume:opcode = %d,payload_sz =%d,module_id =%d, param_id = %d, param_sz = %d\n",
+ __func__,
cmd->hdr.opcode, cmd->payload_size,
cmd->params.module_id, cmd->params.param_id,
cmd->params.param_size);
- pr_debug("%s: soft Volume Command: period = %d,"
- "step = %d, curve = %d\n", __func__, params->period,
+ pr_debug("%s: soft Volume Command: period = %d, step = %d, curve = %d\n",
+ __func__, params->period,
params->step, params->rampingcurve);
rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
if (rc < 0) {
@@ -2855,8 +2877,8 @@
rc = wait_event_timeout(ac->cmd_wait,
(atomic_read(&ac->cmd_state) == 0), 5*HZ);
if (!rc) {
- pr_err("%s: timeout in sending volume command(soft_volume)"
- "to apr\n", __func__);
+ pr_err("%s: timeout in sending volume command(soft_volume) to apr\n",
+ __func__);
rc = -EINVAL;
goto fail_cmd;
}
@@ -3197,8 +3219,8 @@
if ((strncmp(((char *)ab->data), zero_pattern, 2)) &&
(!strncmp(((char *)ab->data + 2), zero_pattern, 2))) {
do_gettimeofday(&out_warm_tv);
- pr_debug("WARM:apr_send_pkt at \
- %ld sec %ld microsec\n", out_warm_tv.tv_sec,\
+ pr_debug("WARM:apr_send_pkt at %ld sec %ld microsec\n",
+ out_warm_tv.tv_sec,\
out_warm_tv.tv_usec);
pr_debug("Warm Pattern Matched");
}
@@ -3207,8 +3229,8 @@
else if ((!strncmp(((char *)ab->data), zero_pattern, 2))
&& (strncmp(((char *)ab->data + 2), zero_pattern, 2))) {
do_gettimeofday(&out_cont_tv);
- pr_debug("CONT:apr_send_pkt at \
- %ld sec %ld microsec\n", out_cont_tv.tv_sec,\
+ pr_debug("CONT:apr_send_pkt at %ld sec %ld microsec\n",
+ out_cont_tv.tv_sec,\
out_cont_tv.tv_usec);
pr_debug("Cont Pattern Matched");
}
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index f982134..0bb88e8 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -84,6 +84,8 @@
uint32_t bufsz, uint32_t bufcnt);
static void q6asm_reset_buf_state(struct audio_client *ac);
+static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels);
+
#ifdef CONFIG_DEBUG_FS
#define OUT_BUFFER_SIZE 56
@@ -196,8 +198,7 @@
out_cold_index*/
if (out_cold_index != 1) {
do_gettimeofday(&out_cold_tv);
- pr_debug("COLD: apr_send_pkt at %ld"
- "sec %ld microsec\n",\
+ pr_debug("COLD: apr_send_pkt at %ld sec %ld microsec\n",
out_cold_tv.tv_sec,\
out_cold_tv.tv_usec);
out_cold_index = 1;
@@ -222,8 +223,7 @@
*/
if (in_cont_index == 7) {
do_gettimeofday(&in_cont_tv);
- pr_err("In_CONT:previous read buffer done"
- "at %ld sec %ld microsec\n",\
+ pr_err("In_CONT:previous read buffer done at %ld sec %ld microsec\n",
in_cont_tv.tv_sec, in_cont_tv.tv_usec);
}
in_cont_index++;
@@ -253,8 +253,8 @@
if ((strncmp(((char *)ab->data), zero_pattern, 2)) &&
(!strncmp(((char *)ab->data + 2), zero_pattern, 2))) {
do_gettimeofday(&out_warm_tv);
- pr_debug("WARM:apr_send_pkt at"
- "%ld sec %ld microsec\n", out_warm_tv.tv_sec,\
+ pr_debug("WARM:apr_send_pkt at %ld sec %ld microsec\n",
+ out_warm_tv.tv_sec,\
out_warm_tv.tv_usec);
pr_debug("Warm Pattern Matched");
}
@@ -263,8 +263,8 @@
else if ((!strncmp(((char *)ab->data), zero_pattern, 2))
&& (strncmp(((char *)ab->data + 2), zero_pattern, 2))) {
do_gettimeofday(&out_cont_tv);
- pr_debug("CONT:apr_send_pkt at"
- "%ld sec %ld microsec\n", out_cont_tv.tv_sec,\
+ pr_debug("CONT:apr_send_pkt at %ld sec %ld microsec\n",
+ out_cont_tv.tv_sec,\
out_cont_tv.tv_usec);
pr_debug("Cont Pattern Matched");
}
@@ -410,8 +410,7 @@
ion_unmap_kernel(port->buf[0].client, port->buf[0].handle);
ion_free(port->buf[0].client, port->buf[0].handle);
ion_client_destroy(port->buf[0].client);
- pr_debug("%s:data[%p]phys[%p][%p]"
- ", client[%p] handle[%p]\n",
+ pr_debug("%s:data[%p]phys[%p][%p] , client[%p] handle[%p]\n",
__func__,
(void *)port->buf[0].data,
(void *)port->buf[0].phys,
@@ -479,13 +478,16 @@
int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode)
{
+ ac->io_mode &= 0xFF00;
+ pr_debug("%s ac->mode after anding with FF00:0x[%x],\n",
+ __func__, ac->io_mode);
if (ac == NULL) {
pr_err("%s APR handle NULL\n", __func__);
return -EINVAL;
}
if ((mode == ASYNC_IO_MODE) || (mode == SYNC_IO_MODE)) {
- ac->io_mode = mode;
- pr_debug("%s:Set Mode to %d\n", __func__, ac->io_mode);
+ ac->io_mode |= mode;
+ pr_debug("%s:Set Mode to 0x[%x]\n", __func__, ac->io_mode);
return 0;
} else {
pr_err("%s:Not an valid IO Mode:%d\n", __func__, ac->io_mode);
@@ -500,8 +502,8 @@
(apr_fn)q6asm_mmapcallback,\
0x0FFFFFFFF, &this_mmap);
if (this_mmap.apr == NULL) {
- pr_debug("%s Unable to register"
- "APR ASM common port\n", __func__);
+ pr_debug("%s Unable to register APR ASM common port\n",
+ __func__);
goto fail;
}
}
@@ -624,8 +626,7 @@
(UINT_MAX, "audio_client");
if (IS_ERR_OR_NULL((void *)
buf[cnt].client)) {
- pr_err("%s: ION create client"
- " for AUDIO failed\n",
+ pr_err("%s: ION create client for AUDIO failed\n",
__func__);
goto fail;
}
@@ -634,8 +635,7 @@
(0x1 << ION_AUDIO_HEAP_ID));
if (IS_ERR_OR_NULL((void *)
buf[cnt].handle)) {
- pr_err("%s: ION memory"
- " allocation for AUDIO failed\n",
+ pr_err("%s: ION memory allocation for AUDIO failed\n",
__func__);
goto fail;
}
@@ -646,8 +646,7 @@
&buf[cnt].phys,
(size_t *)&len);
if (rc) {
- pr_err("%s: ION Get Physical"
- " for AUDIO failed, rc = %d\n",
+ pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
__func__, rc);
goto fail;
}
@@ -657,8 +656,8 @@
0);
if (IS_ERR_OR_NULL((void *)
buf[cnt].data)) {
- pr_err("%s: ION memory"
- " mapping for AUDIO failed\n", __func__);
+ pr_err("%s: ION memory mapping for AUDIO failed\n",
+ __func__);
goto fail;
}
memset((void *)buf[cnt].data, 0, bufsz);
@@ -752,8 +751,7 @@
}
memset((void *)buf[0].data, 0, (bufsz * bufcnt));
if (!buf[0].data) {
- pr_err("%s:invalid vaddr,"
- " iomap failed\n", __func__);
+ pr_err("%s:invalid vaddr, iomap failed\n", __func__);
mutex_unlock(&ac->cmd_lock);
goto fail;
}
@@ -822,8 +820,7 @@
}
sid = (data->token >> 8) & 0x0F;
ac = q6asm_get_audio_client(sid);
- pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x]"
- "token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
+ pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
__func__, payload[0], payload[1], data->opcode, data->token,
data->payload_size, data->src_port, data->dest_port, sid, dir);
pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
@@ -918,8 +915,8 @@
return 0;
}
- pr_debug("%s: session[%d]opcode[0x%x]"
- "token[0x%x]payload_s[%d] src[%d] dest[%d]\n", __func__,
+ pr_debug("%s: session[%d]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]\n",
+ __func__,
ac->session, data->opcode,
data->token, data->payload_size, data->src_port,
data->dest_port);
@@ -1060,9 +1057,8 @@
pr_err("ASM_SESSION_EVENTX_OVERFLOW\n");
break;
case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
- pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, "
- "payload[0] = %d, payload[1] = %d, "
- "payload[2] = %d\n", __func__,
+ pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
+ __func__,
payload[0], payload[1], payload[2]);
ac->time_stamp = (uint64_t)(((uint64_t)payload[1] << 32) |
payload[2]);
@@ -1073,9 +1069,8 @@
break;
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
- pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
- "payload[0] = %d, payload[1] = %d, "
- "payload[2] = %d, payload[3] = %d\n", __func__,
+ pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n",
+ __func__,
payload[0], payload[1], payload[2],
payload[3]);
break;
@@ -1112,8 +1107,8 @@
if (port->buf[idx].used == dir) {
/* To make it more robust, we could loop and get the
next avail buf, its risky though */
- pr_debug("%s:Next buf idx[0x%x] not available,"
- "dir[%d]\n", __func__, idx, dir);
+ pr_debug("%s:Next buf idx[0x%x] not available, dir[%d]\n",
+ __func__, idx, dir);
mutex_unlock(&port->lock);
return NULL;
}
@@ -1162,8 +1157,8 @@
* To make it more robust, we could loop and get the
* next avail buf, its risky though
*/
- pr_debug("%s:Next buf idx[0x%x] not available,"
- "dir[%d]\n", __func__, idx, dir);
+ pr_debug("%s:Next buf idx[0x%x] not available, dir[%d]\n",
+ __func__, idx, dir);
return NULL;
}
*size = port->buf[idx].actual_size;
@@ -1427,6 +1422,7 @@
pr_debug("wr_format[0x%x]rd_format[0x%x]",
wr_format, rd_format);
+ ac->io_mode |= NT_MODE;
q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE_V2;
@@ -1593,8 +1589,8 @@
struct asm_aac_enc_cfg_v2 enc_cfg;
int rc = 0;
- pr_debug("%s:session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d]"
- "format[%d]", __func__, ac->session, frames_per_buf,
+ pr_debug("%s:session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d] format[%d]",
+ __func__, ac->session, frames_per_buf,
sample_rate, channels, bit_rate, mode, format);
q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
@@ -1632,8 +1628,41 @@
int q6asm_set_encdec_chan_map(struct audio_client *ac,
uint32_t num_channels)
{
- /* Todo: */
+ struct asm_dec_out_chan_map_param chan_map;
+ u8 *channel_mapping;
+ int rc = 0;
+ pr_debug("%s: Session %d, num_channels = %d\n",
+ __func__, ac->session, num_channels);
+ q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
+ chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ chan_map.encdec.param_id = ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP;
+ chan_map.encdec.param_size = sizeof(struct asm_dec_out_chan_map_param) -
+ (sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_encdec_param));
+ chan_map.num_channels = num_channels;
+ channel_mapping = chan_map.channel_mapping;
+ memset(channel_mapping, PCM_CHANNEL_NULL, MAX_CHAN_MAP_CHANNELS);
+ if (q6asm_map_channels(channel_mapping, num_channels))
+ return -EINVAL;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &chan_map);
+ if (rc < 0) {
+ pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+ ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout opcode[0x%x]\n", __func__,
+ chan_map.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
return 0;
+fail_cmd:
+ return rc;
}
int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
@@ -1665,23 +1694,8 @@
memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
- if (channels == 1) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- } else if (channels == 2) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- channel_mapping[1] = PCM_CHANNEL_FR;
- } else if (channels == 6) {
- channel_mapping[0] = PCM_CHANNEL_FC;
- channel_mapping[1] = PCM_CHANNEL_FL;
- channel_mapping[2] = PCM_CHANNEL_FR;
- channel_mapping[3] = PCM_CHANNEL_LB;
- channel_mapping[4] = PCM_CHANNEL_RB;
- channel_mapping[5] = PCM_CHANNEL_LFE;
- } else {
- pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
- channels);
+ if (q6asm_map_channels(channel_mapping, channels))
return -EINVAL;
- }
rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
if (rc < 0) {
@@ -1700,6 +1714,96 @@
return -EINVAL;
}
+int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
+ uint32_t rate, uint32_t channels)
+{
+ struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
+ u8 *channel_mapping;
+ u32 frames_per_buf = 0;
+
+ int rc = 0;
+
+ pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
+ ac->session, rate, channels);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
+ sizeof(enc_cfg.encdec);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+
+ enc_cfg.num_channels = 0;/*channels;*/
+ enc_cfg.bits_per_sample = 16;
+ enc_cfg.sample_rate = 0;/*rate;*/
+ enc_cfg.is_signed = 1;
+ channel_mapping = enc_cfg.channel_mapping; /* ??? PHANI */
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (q6asm_map_channels(channel_mapping, channels))
+ return -EINVAL;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("Comamnd open failed\n");
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout opcode[0x%x] ", enc_cfg.hdr.opcode);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels)
+{
+ u8 *lchannel_mapping;
+ lchannel_mapping = channel_mapping;
+ pr_debug("%s channels passed: %d\n", __func__, channels);
+ if (channels == 1) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channels == 2) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channels == 3) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ } else if (channels == 4) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LB;
+ } else if (channels == 5) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LB;
+ lchannel_mapping[4] = PCM_CHANNEL_RB;
+ } else if (channels == 6) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LB;
+ lchannel_mapping[4] = PCM_CHANNEL_RB;
+ lchannel_mapping[5] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ return 0;
+}
+
int q6asm_enable_sbrps(struct audio_client *ac,
uint32_t sbr_ps_enable)
{
@@ -1791,8 +1895,8 @@
struct asm_v13k_enc_cfg enc_cfg;
int rc = 0;
- pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x]"
- "reduced_rate_level[0x%4x]rate_modulation_cmd[0x%4x]", __func__,
+ pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] reduced_rate_level[0x%4x]rate_modulation_cmd[0x%4x]",
+ __func__,
ac->session, frames_per_buf, min_rate, max_rate,
reduced_rate_level, rate_modulation_cmd);
@@ -1833,8 +1937,8 @@
struct asm_evrc_enc_cfg enc_cfg;
int rc = 0;
- pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x]"
- "rate_modulation_cmd[0x%4x]", __func__, ac->session,
+ pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] rate_modulation_cmd[0x%4x]",
+ __func__, ac->session,
frames_per_buf, min_rate, max_rate, rate_modulation_cmd);
q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
@@ -1972,23 +2076,8 @@
memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
- if (channels == 1) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- } else if (channels == 2) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- channel_mapping[1] = PCM_CHANNEL_FR;
- } else if (channels == 6) {
- channel_mapping[0] = PCM_CHANNEL_FC;
- channel_mapping[1] = PCM_CHANNEL_FL;
- channel_mapping[2] = PCM_CHANNEL_FR;
- channel_mapping[3] = PCM_CHANNEL_LB;
- channel_mapping[4] = PCM_CHANNEL_RB;
- channel_mapping[5] = PCM_CHANNEL_LFE;
- } else {
- pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
- channels);
+ if (q6asm_map_channels(channel_mapping, channels))
return -EINVAL;
- }
rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
if (rc < 0) {
@@ -2056,8 +2145,7 @@
struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
int rc = 0;
- pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d],"
- "balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x]\n",
+ pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d], balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x]\n",
ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
@@ -2065,8 +2153,9 @@
q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
- fmt.hdr.opcode = ASM_MEDIA_FMT_WMA_V9_V2;
-
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
fmt.fmtag = wma_cfg->format_tag;
fmt.num_channels = wma_cfg->ch_cfg;
fmt.sample_rate = wma_cfg->sample_rate;
@@ -2100,9 +2189,7 @@
struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
int rc = 0;
- pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d],"
- "balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x],"
- "adv_enc_opt[0x%4x], adv_enc_opt2[0x%8x]\n",
+ pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d], balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x], adv_enc_opt[0x%4x], adv_enc_opt2[0x%8x]\n",
ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
wmapro_cfg->ch_cfg, wmapro_cfg->avg_bytes_per_sec,
wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
@@ -2111,7 +2198,9 @@
q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
- fmt.hdr.opcode = ASM_MEDIA_FMT_WMA_V10PRO_V2;
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
fmt.fmtag = wmapro_cfg->format_tag;
fmt.num_channels = wmapro_cfg->ch_cfg;
@@ -2147,12 +2236,10 @@
struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
struct avs_shared_map_region_payload *mregions = NULL;
struct audio_port_data *port = NULL;
- struct audio_buffer *ab = NULL;
void *mmap_region_cmd = NULL;
void *payload = NULL;
struct asm_buffer_node *buffer_node = NULL;
int rc = 0;
- int i = 0;
int cmd_size = 0;
if (!ac || ac->apr == NULL || ac->mmap_apr == NULL) {
@@ -2181,21 +2268,18 @@
mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
mmap_regions->num_regions = bufcnt & 0x00ff;
mmap_regions->property_flag = 0x00;
- pr_debug("map_regions->nregions = %d\n", mmap_regions->num_regions);
payload = ((u8 *) mmap_region_cmd +
sizeof(struct avs_cmd_shared_mem_map_regions));
mregions = (struct avs_shared_map_region_payload *)payload;
ac->port[dir].tmp_hdl = 0;
port = &ac->port[dir];
- for (i = 0; i < bufcnt; i++) {
- ab = &port->buf[i];
- mregions->shm_addr_lsw = ab->phys;
- /* Using only 32 bit address */
- mregions->shm_addr_msw = 0;
- mregions->mem_size_bytes = ab->size;
- ++mregions;
- }
+ pr_debug("%s, buf_add 0x%x, bufsz: %d\n", __func__, buf_add, bufsz);
+ mregions->shm_addr_lsw = buf_add;
+ /* Using only 32 bit address */
+ mregions->shm_addr_msw = 0;
+ mregions->mem_size_bytes = bufsz;
+ ++mregions;
rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
if (rc < 0) {
@@ -2295,7 +2379,7 @@
void *payload = NULL;
struct asm_buffer_node *buffer_node = NULL;
int rc = 0;
- int i = 0;
+ int i = 0;
int cmd_size = 0;
if (!ac || ac->apr == NULL || ac->mmap_apr == NULL) {
@@ -2351,7 +2435,6 @@
rc = wait_event_timeout(ac->cmd_wait,
(atomic_read(&ac->cmd_state) == 0)
, 5*HZ);
- /*ac->port[dir].tmp_hdl), 5*HZ);*/
if (!rc) {
pr_err("timeout. waited for memory_map\n");
rc = -EINVAL;
@@ -2843,8 +2926,6 @@
read.buf_addr_lsw,
read.hdr.token,
read.seq_id);
- pr_debug("q6asm_read_nolock mem-map handle is %x",
- read.mem_map_handle);
rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
if (rc < 0) {
pr_err("read op[0x%x]rc[%d]\n", read.hdr.opcode, rc);
@@ -2865,6 +2946,8 @@
struct list_head *ptr, *next;
struct audio_buffer *ab;
struct audio_port_data *port;
+ u32 lbuf_addr_lsw;
+ u32 liomode;
if (!ac || ac->apr == NULL) {
pr_err("%s: APR handle NULL\n", __func__);
@@ -2884,11 +2967,21 @@
write.buf_size = param->len;
write.timestamp_msw = param->msw_ts;
write.timestamp_lsw = param->lsw_ts;
- pr_debug("%s: token[0x%x], buf_addr_lsw[0x%x], buf_size[0x%x],"
- "ts_msw[0x%x], ts_lsw[0x%x]\n",
- __func__, write.hdr.token, write.buf_addr_lsw,
+ liomode = (ASYNC_IO_MODE | NT_MODE);
+
+ if (ac->io_mode == liomode) {
+ pr_info("%s: subtracting 32 for header\n", __func__);
+ lbuf_addr_lsw = (write.buf_addr_lsw - 32);
+ } else{
+ lbuf_addr_lsw = write.buf_addr_lsw;
+ }
+
+ pr_debug("%s: token[0x%x], buf_addr_lsw[0x%x], buf_size[0x%x], ts_msw[0x%x], ts_lsw[0x%x], lbuf_addr_lsw: 0x[%x]\n",
+ __func__,
+ write.hdr.token, write.buf_addr_lsw,
write.buf_size, write.timestamp_msw,
- write.timestamp_lsw);
+ write.timestamp_lsw, lbuf_addr_lsw);
+
/* Use 0xFF00 for disabling timestamps */
if (param->flags == 0xFF00)
write.flags = (0x00000000 | (param->flags & 0x800000FF));
@@ -2899,21 +2992,12 @@
list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
buf_node = list_entry(ptr, struct asm_buffer_node,
list);
- if (buf_node->buf_addr_lsw == (uint32_t)write.buf_addr_lsw) {
+ if (buf_node->buf_addr_lsw == lbuf_addr_lsw) {
write.mem_map_handle = buf_node->mmap_hdl;
- pr_debug("%s:buf_node->mmap_hdl = 0x%x,"
- "write.mem_map_handle = 0x%x\n",
- __func__,
- buf_node->mmap_hdl,
- (uint32_t)write.mem_map_handle);
break;
}
}
- pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x],"
- "mem_map_handle[0x%x]\n", __func__, ac->session,
- write.buf_addr_lsw, write.buf_size, write.mem_map_handle);
-
rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
if (rc < 0) {
pr_debug("[%s] write op[0x%x]rc[%d]\n", __func__,
@@ -2932,6 +3016,8 @@
struct asm_data_cmd_read_v2 read;
struct asm_buffer_node *buf_node = NULL;
struct list_head *ptr, *next;
+ u32 lbuf_addr_lsw;
+ u32 liomode;
if (!ac || ac->apr == NULL) {
pr_err("%s: APR handle NULL\n", __func__);
@@ -2947,16 +3033,21 @@
read.buf_addr_msw = 0;
read.buf_size = param->len;
read.seq_id = param->uid;
-
- list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
- buf_node = list_entry(ptr, struct asm_buffer_node,
- list);
- if (buf_node->buf_addr_lsw == param->paddr)
- read.mem_map_handle = buf_node->mmap_hdl;
+ liomode = (NT_MODE | ASYNC_IO_MODE);
+ if (ac->io_mode == liomode) {
+ pr_info("%s: subtracting 32 for header\n", __func__);
+ lbuf_addr_lsw = (read.buf_addr_lsw - 32);
+ } else{
+ lbuf_addr_lsw = read.buf_addr_lsw;
}
- pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x]", __func__, ac->session,
- read.buf_addr_lsw, read.buf_size);
+ list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node, list);
+ if (buf_node->buf_addr_lsw == lbuf_addr_lsw) {
+ read.mem_map_handle = buf_node->mmap_hdl;
+ break;
+ }
+ }
rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
if (rc < 0) {
@@ -3013,8 +3104,7 @@
list);
write.mem_map_handle = buf_node->mmap_hdl;
- pr_debug("%s:ab->phys[0x%x]bufadd[0x%x]"
- "token[0x%x]buf_id[0x%x]buf_size[0x%x]mmaphdl[0x%x]"
+ pr_debug("%s:ab->phys[0x%x]bufadd[0x%x] token[0x%x]buf_id[0x%x]buf_size[0x%x]mmaphdl[0x%x]"
, __func__,
ab->phys,
write.buf_addr_lsw,
@@ -3081,8 +3171,7 @@
write.flags = (0x80000000 | flags);
port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
- pr_err("%s:ab->phys[0x%x]bufadd[0x%x]token[0x%x]"
- "buf_id[0x%x]buf_size[0x%x]mmaphdl[0x%x]"
+ pr_debug("%s:ab->phys[0x%x]bufadd[0x%x]token[0x%x] buf_id[0x%x]buf_size[0x%x]mmaphdl[0x%x]"
, __func__,
ab->phys,
write.buf_addr_lsw,