diff options
75 files changed, 4285 insertions, 1440 deletions
diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi index 69067f5f1cc7..364b83320015 100644 --- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi @@ -11,53 +11,53 @@ */ qcom,ascent_3450mah { - /* #Ascent_860_82209_0000_3450mAh_averaged_MasterSlave_Jul20th2016*/ + /* Ascent_with_connector_3450mAh_averaged_MasterSlave_Nov28th2016 */ qcom,max-voltage-uv = <4350000>; qcom,fg-cc-cv-threshold-mv = <4340>; qcom,nom-batt-capacity-mah = <3450>; qcom,batt-id-kohm = <60>; qcom,battery-beta = <3435>; - qcom,battery-type = "ascent_860_82209_0000_3450mah"; - qcom,checksum = <0xD1D9>; - qcom,gui-version = "PMI8998GUI - 0.0.0.82"; + qcom,battery-type = "ascent_3450mah_averaged_masterslave_nov28th2016"; + qcom,checksum = <0x2232>; + qcom,gui-version = "PMI8998GUI - 2.0.0.52"; qcom,fg-profile-data = [ - 2C 1F 3F FC - E9 03 A1 FD - 58 1D FD F5 - 27 12 2C 14 - 3F 18 FF 22 - 9B 45 A3 52 + 9C 1F 85 05 + 82 0A 73 FC + 2B 1D 6A EA + F2 03 63 0C + C8 17 F3 22 + E0 45 1F 52 + 5C 00 00 00 + 10 00 00 00 + 00 00 4A C4 + C7 BC 48 C2 + 0F 00 08 00 + 92 00 5D ED + 8D FD B1 F3 + 27 00 A6 12 + 77 F4 0F 3B + 24 06 09 20 + 27 00 14 00 + 83 1F EE 05 + 1F 0A 45 FD + 6B 1D 52 E5 + EC 0B 31 14 + 44 18 49 23 + 18 45 A6 53 55 00 00 00 0E 00 00 00 - 00 00 1C AC - F7 CD 71 B5 - 1A 00 0C 00 - 3C EB 54 E4 - EC 05 7F FA - 76 05 F5 02 - CA F3 82 3A - 2A 09 40 40 - 07 00 05 00 - 58 1F 42 06 - 85 03 35 F4 - 4D 1D 37 F2 - 23 0A 79 15 - B7 18 32 23 - 26 45 72 53 - 55 00 00 00 - 0D 00 00 00 - 00 00 13 CC - 03 00 98 BD - 16 00 00 00 - 3C EB 54 E4 - 9F FC A3 F3 - 0F FC DF FA - FF E5 A9 23 - CB 33 08 33 + 00 00 61 CC + B7 C3 0F BC + 0F 00 00 00 + 92 00 5D ED + E3 06 81 F3 + 75 FD 9C 03 + 43 DB B3 22 + CB 33 CC FF 07 10 00 00 - 81 0D 99 45 - 16 00 19 00 - 75 01 0A FA + 99 0D 99 45 + 0F 00 40 00 + AB 01 0A FA FF 00 00 00 00 00 00 00 00 00 00 00 diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd.dtsi index 03abb5d69b52..8c51aa643382 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd.dtsi @@ -206,7 +206,7 @@ reg = <0x0>; qcom,csiphy-sd-index = <0>; qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; + qcom,mount-angle = <270>; qcom,led-flash-src = <&led_flash0>; qcom,actuator-src = <&actuator0>; qcom,ois-src = <&ois0>; @@ -294,7 +294,7 @@ reg = <0x02>; qcom,csiphy-sd-index = <2>; qcom,csid-sd-index = <2>; - qcom,mount-angle = <270>; + qcom,mount-angle = <90>; qcom,eeprom-src = <&eeprom2>; qcom,led-flash-src = <&led_flash1>; qcom,actuator-src = <&actuator1>; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi index 32f9dcdecb0c..76326e7ae86f 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi @@ -69,12 +69,12 @@ }; &sdhc_2 { - vdd-supply = <&pm8998_l21>; - qcom,vdd-voltage-level = <2950000 2960000>; + vdd-supply = <&pm2falcon_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; qcom,vdd-current-level = <200 800000>; - vdd-io-supply = <&pm8998_l13>; - qcom,vdd-io-voltage-level = <1808000 2960000>; + vdd-io-supply = <&pm2falcon_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; qcom,vdd-io-current-level = <200 22000>; pinctrl-names = "active", "sleep"; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi index e73ffc884210..5c55732e0de7 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi @@ -70,12 +70,12 @@ }; &sdhc_2 { - vdd-supply = <&pm8998_l21>; - qcom,vdd-voltage-level = <2950000 2960000>; + vdd-supply = <&pm2falcon_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; qcom,vdd-current-level = <200 800000>; - vdd-io-supply = <&pm8998_l13>; - qcom,vdd-io-voltage-level = <1808000 2960000>; + vdd-io-supply = <&pm2falcon_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; qcom,vdd-io-current-level = <200 22000>; pinctrl-names = "active", "sleep"; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi index cd0e20a295d9..0c49c4246f10 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi @@ -21,8 +21,10 @@ &ufsphy1 { vdda-phy-supply = <&pm2falcon_l1>; - vdda-pll-supply = <&pmfalcon_l10>; - vddp-ref-clk-supply = <&pmfalcon_l8>; + vdda-pll-supply = <&pmfalcon_l1>; + vddp-ref-clk-supply = <&pmfalcon_l1>; + vdda-phy-max-uv = <925000>; + vdda-phy-min-uv = <800000>; vdda-phy-max-microamp = <51400>; vdda-pll-max-microamp = <14600>; vddp-ref-clk-max-microamp = <100>; @@ -34,11 +36,9 @@ vdd-hba-supply = <&gdsc_ufs>; vdd-hba-fixed-regulator; vcc-supply = <&pm2falcon_l4>; - vccq-supply = <&pmfalcon_l8>; vccq2-supply = <&pmfalcon_l8>; - vcc-max-microamp = <750000>; - vccq-max-microamp = <560000>; - vccq2-max-microamp = <750000>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; status = "ok"; }; @@ -71,10 +71,12 @@ }; &sdhc_2 { - qcom,vdd-voltage-level = <2950000 2960000>; + vdd-supply = <&pm2falcon_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; qcom,vdd-current-level = <200 800000>; - qcom,vdd-io-voltage-level = <1808000 2960000>; + vdd-io-supply = <&pm2falcon_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; qcom,vdd-io-current-level = <200 22000>; pinctrl-names = "active", "sleep"; diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index 79cdc2b701e1..6ef443c4de11 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -1293,8 +1293,6 @@ #include "msm-gdsc-falcon.dtsi" &gdsc_usb30 { - clock-names = "core_clk"; - clocks = <&clock_gcc GCC_USB30_MASTER_CLK>; status = "ok"; }; @@ -1351,9 +1349,6 @@ }; &gdsc_mdss { - clock-names = "bus_clk", "rot_clk"; - clocks = <&clock_mmss MMSS_MDSS_AXI_CLK>, - <&clock_mmss MMSS_MDSS_ROT_CLK>; proxy-supply = <&gdsc_mdss>; qcom,proxy-consumer-enable; status = "ok"; diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi index e7416ebb8f58..2a22772c8d1d 100644 --- a/arch/arm/boot/dts/qcom/msmtriton.dtsi +++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi @@ -787,8 +787,6 @@ #include "msmfalcon-common.dtsi" &gdsc_usb30 { - clock-names = "core_clk"; - clocks = <&clock_gcc GCC_USB30_MASTER_CLK>; status = "ok"; }; @@ -837,9 +835,6 @@ }; &gdsc_mdss { - clock-names = "bus_clk", "rot_clk"; - clocks = <&clock_mmss MMSS_MDSS_AXI_CLK>, - <&clock_mmss MMSS_MDSS_ROT_CLK>; proxy-supply = <&gdsc_mdss>; qcom,proxy-consumer-enable; status = "ok"; diff --git a/arch/arm/configs/msmfalcon-perf_defconfig b/arch/arm/configs/msmfalcon-perf_defconfig index 1f8d22153a32..272f760117a7 100644 --- a/arch/arm/configs/msmfalcon-perf_defconfig +++ b/arch/arm/configs/msmfalcon-perf_defconfig @@ -602,6 +602,5 @@ CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_XZ_DEC=y diff --git a/arch/arm/configs/msmfalcon_defconfig b/arch/arm/configs/msmfalcon_defconfig index 06faf702156f..c09e02e53a07 100644 --- a/arch/arm/configs/msmfalcon_defconfig +++ b/arch/arm/configs/msmfalcon_defconfig @@ -641,6 +641,5 @@ CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_XZ_DEC=y diff --git a/arch/arm64/configs/msmfalcon-perf_defconfig b/arch/arm64/configs/msmfalcon-perf_defconfig index 1074672d252f..4d26ad79196d 100644 --- a/arch/arm64/configs/msmfalcon-perf_defconfig +++ b/arch/arm64/configs/msmfalcon-perf_defconfig @@ -616,7 +616,6 @@ CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y diff --git a/arch/arm64/configs/msmfalcon_defconfig b/arch/arm64/configs/msmfalcon_defconfig index 6d8d9eeab2d5..c568f005e70b 100644 --- a/arch/arm64/configs/msmfalcon_defconfig +++ b/arch/arm64/configs/msmfalcon_defconfig @@ -681,7 +681,6 @@ CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y diff --git a/drivers/gpu/msm/adreno_iommu.c b/drivers/gpu/msm/adreno_iommu.c index aa00dcb84185..4bb7f6286664 100644 --- a/drivers/gpu/msm/adreno_iommu.c +++ b/drivers/gpu/msm/adreno_iommu.c @@ -856,6 +856,17 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb, int result = 0; int cpu_path = 0; + /* Just do the context switch incase of NOMMU */ + if (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE) { + if ((!(flags & ADRENO_CONTEXT_SWITCH_FORCE_GPU)) && + adreno_isidle(device)) + _set_ctxt_cpu(rb, drawctxt); + else + result = _set_ctxt_gpu(rb, drawctxt); + + return result; + } + if (rb->drawctxt_active) cur_pt = rb->drawctxt_active->base.proc_priv->pagetable; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 699d99651f2c..993f22b26294 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -353,8 +353,10 @@ static int kgsl_mem_entry_track_gpuaddr(struct kgsl_device *device, /* * If SVM is enabled for this object then the address needs to be * assigned elsewhere + * Also do not proceed further in case of NoMMU. */ - if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) + if (kgsl_memdesc_use_cpu_map(&entry->memdesc) || + (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE)) return 0; pagetable = kgsl_memdesc_is_secured(&entry->memdesc) ? @@ -491,21 +493,18 @@ void kgsl_context_dump(struct kgsl_context *context) EXPORT_SYMBOL(kgsl_context_dump); /* Allocate a new context ID */ -static int _kgsl_get_context_id(struct kgsl_device *device, - struct kgsl_context *context) +static int _kgsl_get_context_id(struct kgsl_device *device) { int id; idr_preload(GFP_KERNEL); write_lock(&device->context_lock); - id = idr_alloc(&device->context_idr, context, 1, + /* Allocate the slot but don't put a pointer in it yet */ + id = idr_alloc(&device->context_idr, NULL, 1, KGSL_MEMSTORE_MAX, GFP_NOWAIT); write_unlock(&device->context_lock); idr_preload_end(); - if (id > 0) - context->id = id; - return id; } @@ -529,7 +528,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, char name[64]; int ret = 0, id; - id = _kgsl_get_context_id(device, context); + id = _kgsl_get_context_id(device); if (id == -ENOSPC) { /* * Before declaring that there are no contexts left try @@ -538,7 +537,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, */ flush_workqueue(device->events_wq); - id = _kgsl_get_context_id(device, context); + id = _kgsl_get_context_id(device); } if (id < 0) { @@ -550,6 +549,8 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, return id; } + context->id = id; + kref_init(&context->refcount); /* * Get a refernce to the process private so its not destroyed, until @@ -1733,6 +1734,12 @@ long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv, goto done; } trace_kgsl_context_create(dev_priv->device, context, param->flags); + + /* Commit the pointer to the context in context_idr */ + write_lock(&device->context_lock); + idr_replace(&device->context_idr, context, context->id); + write_unlock(&device->context_lock); + param->drawctxt_id = context->id; done: return result; diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index 03f278ead20f..c1c2afa68756 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -284,7 +284,8 @@ static inline int kgsl_allocate_global(struct kgsl_device *device, memdesc->flags = flags; memdesc->priv = priv; - if ((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0) + if (((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0) || + (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE)) ret = kgsl_sharedmem_alloc_contig(device, memdesc, (size_t) size); else { diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c index f001706236ab..0ec16e606545 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c @@ -358,6 +358,7 @@ static struct device_attribute attrs[] = { static struct synaptics_rmi4_fwu_handle *fwu; DECLARE_COMPLETION(fwu_dsx_remove_complete); +DEFINE_MUTEX(dsx_fwu_sysfs_mutex); static unsigned int extract_uint_le(const unsigned char *ptr) { @@ -1589,28 +1590,49 @@ static ssize_t fwu_sysfs_show_image(struct file *data_file, char *buf, loff_t pos, size_t count) { struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + ssize_t retval; + + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; if (count < fwu->config_size) { dev_err(rmi4_data->pdev->dev.parent, "%s: Not enough space (%zu bytes) in buffer\n", __func__, count); - return -EINVAL; + retval = -EINVAL; + goto show_image_exit; } memcpy(buf, fwu->read_config_buf, fwu->config_size); - - return fwu->config_size; + retval = fwu->config_size; +show_image_exit: + mutex_unlock(&dsx_fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_store_image(struct file *data_file, struct kobject *kobj, struct bin_attribute *attributes, char *buf, loff_t pos, size_t count) { + ssize_t retval; + + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + if (count > (fwu->image_size - fwu->data_pos)) { dev_err(fwu->rmi4_data->pdev->dev.parent, "%s: Not enough space in buffer\n", __func__); - return -EINVAL; + retval = -EINVAL; + goto exit; + } + + if (!fwu->ext_data_source) { + dev_err(fwu->rmi4_data->pdev->dev.parent, + "%s: Need to set imagesize\n", + __func__); + retval = -EINVAL; + goto exit; } memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]), @@ -1619,16 +1641,21 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file, fwu->data_pos += count; +exit: + mutex_unlock(&dsx_fwu_sysfs_mutex); return count; } static ssize_t fwu_sysfs_force_reflash_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int retval; + ssize_t retval; unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; goto exit; @@ -1657,6 +1684,9 @@ exit: fwu->ext_data_source = NULL; fwu->force_update = FORCE_UPDATE; fwu->do_lockdown = DO_LOCKDOWN; + fwu->data_pos = 0; + fwu->image_size = 0; + mutex_unlock(&dsx_fwu_sysfs_mutex); return retval; } @@ -1667,6 +1697,9 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; goto exit; @@ -1700,6 +1733,9 @@ exit: fwu->ext_data_source = NULL; fwu->force_update = FORCE_UPDATE; fwu->do_lockdown = DO_LOCKDOWN; + fwu->data_pos = 0; + fwu->image_size = 0; + mutex_unlock(&dsx_fwu_sysfs_mutex); return retval; } @@ -1710,6 +1746,9 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev, unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; goto exit; @@ -1733,6 +1772,9 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev, exit: kfree(fwu->ext_data_source); fwu->ext_data_source = NULL; + fwu->data_pos = 0; + fwu->image_size = 0; + mutex_unlock(&dsx_fwu_sysfs_mutex); return retval; } @@ -1749,7 +1791,11 @@ static ssize_t fwu_sysfs_read_config_store(struct device *dev, if (input != 1) return -EINVAL; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; retval = fwu_do_read_config(); + mutex_unlock(&dsx_fwu_sysfs_mutex); + if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to read config\n", @@ -1770,7 +1816,10 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev, if (retval) return retval; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; fwu->config_area = config_area; + mutex_unlock(&dsx_fwu_sysfs_mutex); return count; } @@ -1778,17 +1827,30 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev, static ssize_t fwu_sysfs_image_name_show(struct device *dev, struct device_attribute *attr, char *buf) { + ssize_t retval; + + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; if (strnlen(fwu->rmi4_data->fw_name, SYNA_FW_NAME_MAX_LEN) > 0) - return snprintf(buf, PAGE_SIZE, "%s\n", + retval = snprintf(buf, PAGE_SIZE, "%s\n", fwu->rmi4_data->fw_name); else - return snprintf(buf, PAGE_SIZE, "No firmware name given\n"); + retval = snprintf(buf, PAGE_SIZE, "No firmware name given\n"); + mutex_unlock(&dsx_fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_image_name_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - if (sscanf(buf, "%s", fwu->image_name) != 1) + ssize_t retval; + + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + retval = sscanf(buf, "%49s", fwu->image_name); + mutex_unlock(&dsx_fwu_sysfs_mutex); + + if (retval != 1) return -EINVAL; return count; @@ -1801,9 +1863,12 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev, unsigned long size; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&dsx_fwu_sysfs_mutex)) + return -EBUSY; + retval = sstrtoul(buf, 10, &size); if (retval) - return retval; + goto exit; fwu->image_size = size; fwu->data_pos = 0; @@ -1814,10 +1879,14 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev, dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to alloc mem for image data\n", __func__); - return -ENOMEM; + retval = -ENOMEM; + goto exit; } - return count; + retval = count; +exit: + mutex_unlock(&dsx_fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_block_size_show(struct device *dev, diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c index 437af72a6a55..de27e585f63d 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -71,8 +71,8 @@ static long msm_jpeg_compat_ioctl(struct file *filp, unsigned int cmd, int rc; struct msm_jpeg_device *pgmn_dev = filp->private_data; - JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%lx arg=0x%lx\n", __func__, - __LINE__, _IOC_NR(cmd), (unsigned long)pgmn_dev, + JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__, + __LINE__, _IOC_NR(cmd), pgmn_dev, (unsigned long)arg); rc = __msm_jpeg_compat_ioctl(pgmn_dev, cmd, arg); @@ -87,8 +87,8 @@ static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd, int rc; struct msm_jpeg_device *pgmn_dev = filp->private_data; - JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%lx arg=0x%lx\n", __func__, - __LINE__, _IOC_NR(cmd), (unsigned long)pgmn_dev, + JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__, + __LINE__, _IOC_NR(cmd), pgmn_dev, (unsigned long)arg); rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg); @@ -114,9 +114,9 @@ int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd) struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)jpeg_sd->host_priv; - JPEG_DBG("%s:%d: jpeg_sd=0x%lx pgmn_dev=0x%lx\n", + JPEG_DBG("%s:%d: jpeg_sd=0x%lx pgmn_dev=0x%pK\n", __func__, __LINE__, (unsigned long)jpeg_sd, - (unsigned long)pgmn_dev); + pgmn_dev); rc = __msm_jpeg_open(pgmn_dev); JPEG_DBG("%s:%d: rc=%d\n", __func__, __LINE__, rc); @@ -132,7 +132,7 @@ static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd, JPEG_DBG("%s: cmd=%d\n", __func__, cmd); - JPEG_DBG("%s: pgmn_dev 0x%lx", __func__, (unsigned long)pgmn_dev); + JPEG_DBG("%s: pgmn_dev 0x%pK", __func__, pgmn_dev); JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__); @@ -146,7 +146,7 @@ void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd) int rc; struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)jpeg_sd->host_priv; - JPEG_DBG("%s:pgmn_dev=0x%lx", __func__, (unsigned long)pgmn_dev); + JPEG_DBG("%s:pgmn_dev=0x%pK", __func__, pgmn_dev); rc = __msm_jpeg_release(pgmn_dev); JPEG_DBG("%s:rc=%d", __func__, rc); } diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c index 071ce0a41ed9..e40869d41a5d 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c @@ -847,7 +847,7 @@ int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, uint32_t data; while (m_cmds--) { - if (hw_cmd_p->offset > max_size) { + if (hw_cmd_p->offset >= max_size) { JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__, __LINE__, hw_cmd_p->offset, max_size); return -EFAULT; diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c index 63d7e715162b..3301fc446193 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c @@ -128,6 +128,21 @@ static inline void msm_jpegdma_schedule_next_config(struct jpegdma_ctx *ctx) } /* + * msm_jpegdma_cast_long_to_buff_ptr - Cast long to buffer pointer. + * @vaddr: vaddr as long + * @buff_ptr_head: buffer pointer head + */ +static inline void msm_jpegdma_cast_long_to_buff_ptr(unsigned long vaddr, + struct msm_jpeg_dma_buff **buff_ptr_head) +{ +#ifdef CONFIG_COMPAT + *buff_ptr_head = compat_ptr(vaddr); +#else + *buff_ptr_head = (struct msm_jpeg_dma_buff *) vaddr; +#endif +} + +/* * msm_jpegdma_get_format_idx - Get jpeg dma format lookup index. * @ctx: Pointer to dma ctx. * @f: v4l2 format. @@ -410,10 +425,12 @@ static void *msm_jpegdma_get_userptr(void *alloc_ctx, { struct msm_jpegdma_device *dma = alloc_ctx; struct msm_jpegdma_buf_handle *buf; - struct msm_jpeg_dma_buff __user *up_buff = compat_ptr(vaddr); + struct msm_jpeg_dma_buff __user *up_buff; struct msm_jpeg_dma_buff kp_buff; int ret; + msm_jpegdma_cast_long_to_buff_ptr(vaddr, &up_buff); + if (!access_ok(VERIFY_READ, up_buff, sizeof(struct msm_jpeg_dma_buff)) || get_user(kp_buff.fd, &up_buff->fd)) { @@ -813,10 +830,12 @@ static int msm_jpegdma_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh); - struct msm_jpeg_dma_buff __user *up_buff = compat_ptr(buf->m.userptr); + struct msm_jpeg_dma_buff __user *up_buff; struct msm_jpeg_dma_buff kp_buff; int ret; + msm_jpegdma_cast_long_to_buff_ptr(buf->m.userptr, &up_buff); + if (!access_ok(VERIFY_READ, up_buff, sizeof(struct msm_jpeg_dma_buff)) || get_user(kp_buff.fd, &up_buff->fd) || diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index b9018a226f2f..7e452e9e4ee2 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -220,6 +220,7 @@ void msm_cpp_deinit_bandwidth_mgr(struct cpp_device *cpp_dev) static int msm_cpp_update_bandwidth_setting(struct cpp_device *cpp_dev, uint64_t ab, uint64_t ib) { int rc; + if (cpp_dev->bus_master_flag) rc = msm_cpp_update_bandwidth(cpp_dev, ab, ib); else @@ -242,6 +243,7 @@ static void msm_enqueue(struct msm_device_queue *queue, struct list_head *entry) { unsigned long flags; + spin_lock_irqsave(&queue->lock, flags); queue->len++; if (queue->len > queue->max) { @@ -302,6 +304,7 @@ static void msm_cpp_timer_queue_update(struct cpp_device *cpp_dev) { uint32_t i; unsigned long flags; + CPP_DBG("Frame done qlen %d\n", cpp_dev->processing_q.len); if (cpp_dev->processing_q.len <= 1) { msm_cpp_clear_timer(cpp_dev); @@ -323,6 +326,7 @@ static void msm_cpp_timer_queue_update(struct cpp_device *cpp_dev) static uint32_t msm_cpp_read(void __iomem *cpp_base) { uint32_t tmp, retry = 0; + do { tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_STAT); } while (((tmp & 0x2) == 0x0) && (retry++ < 10)); @@ -409,14 +413,22 @@ static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev, pr_err("error allocating memory\n"); goto error; } - buff->map_info.buff_info = *buffer_info; + buff->map_info.buff_info = *buffer_info; buff->map_info.buf_fd = buffer_info->fd; - rc = cam_smmu_get_phy_addr(cpp_dev->iommu_hdl, buffer_info->fd, - CAM_SMMU_MAP_RW, &buff->map_info.phy_addr, - (size_t *)&buff->map_info.len); + + if (buff_queue->security_mode == SECURE_MODE) + rc = cam_smmu_get_stage2_phy_addr(cpp_dev->iommu_hdl, + buffer_info->fd, CAM_SMMU_MAP_RW, + cpp_dev->ion_client, &buff->map_info.phy_addr, + (size_t *)&buff->map_info.len); + else + rc = cam_smmu_get_phy_addr(cpp_dev->iommu_hdl, + buffer_info->fd, CAM_SMMU_MAP_RW, + &buff->map_info.phy_addr, + (size_t *)&buff->map_info.len); if (rc < 0) { - pr_err("ION mmap failed\n"); + pr_err("ION mmap for CPP buffer failed\n"); kzfree(buff); goto error; } @@ -430,10 +442,17 @@ error: } static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue, struct msm_cpp_buffer_map_list_t *buff) { int ret = -1; - ret = cam_smmu_put_phy_addr(cpp_dev->iommu_hdl, buff->map_info.buf_fd); + + if (buff_queue->security_mode == SECURE_MODE) + ret = cam_smmu_put_stage2_phy_addr(cpp_dev->iommu_hdl, + buff->map_info.buf_fd); + else + ret = cam_smmu_put_phy_addr(cpp_dev->iommu_hdl, + buff->map_info.buf_fd); if (ret < 0) pr_err("Error: cannot put the iommu handle back to ion fd\n"); @@ -466,6 +485,7 @@ static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev, buffer_info); *fd = buffer_info->fd; } + return phy_addr; } @@ -477,12 +497,12 @@ static int32_t msm_cpp_dequeue_buff_info_list(struct cpp_device *cpp_dev, buff_head = &buff_queue_info->native_buff_head; list_for_each_entry_safe(buff, save, buff_head, entry) { - msm_cpp_dequeue_buffer_info(cpp_dev, buff); + msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info, buff); } buff_head = &buff_queue_info->vb2_buff_head; list_for_each_entry_safe(buff, save, buff_head, entry) { - msm_cpp_dequeue_buffer_info(cpp_dev, buff); + msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info, buff); } return 0; @@ -502,7 +522,8 @@ static int32_t msm_cpp_dequeue_buff(struct cpp_device *cpp_dev, list_for_each_entry_safe(buff, save, buff_head, entry) { if (buff->map_info.buff_info.index == buff_index) { - msm_cpp_dequeue_buffer_info(cpp_dev, buff); + msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info, + buff); break; } } @@ -522,6 +543,8 @@ static int32_t msm_cpp_add_buff_queue_entry(struct cpp_device *cpp_dev, buff_queue_info->used = 1; buff_queue_info->session_id = session_id; buff_queue_info->stream_id = stream_id; + buff_queue_info->security_mode = + cpp_dev->security_mode; INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); INIT_LIST_HEAD(&buff_queue_info->native_buff_head); return 0; @@ -548,6 +571,7 @@ static int32_t msm_cpp_free_buff_queue_entry(struct cpp_device *cpp_dev, buff_queue_info->used = 0; buff_queue_info->session_id = 0; buff_queue_info->stream_id = 0; + buff_queue_info->security_mode = NON_SECURE_MODE; INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); INIT_LIST_HEAD(&buff_queue_info->native_buff_head); return 0; @@ -557,6 +581,7 @@ static int32_t msm_cpp_create_buff_queue(struct cpp_device *cpp_dev, uint32_t num_buffq) { struct msm_cpp_buff_queue_info_t *buff_queue; + buff_queue = kzalloc( sizeof(struct msm_cpp_buff_queue_info_t) * num_buffq, GFP_KERNEL); @@ -602,6 +627,7 @@ static int32_t msm_cpp_poll(void __iomem *cpp_base, u32 val) { uint32_t tmp, retry = 0; int32_t rc = 0; + do { tmp = msm_cpp_read(cpp_base); if (tmp != 0xDEADBEEF) @@ -796,6 +822,7 @@ static irqreturn_t msm_cpp_irq(int irq_num, void *data) uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; struct cpp_device *cpp_dev = data; struct msm_cpp_tasklet_queue_cmd *queue_cmd; + irq_status = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_IRQGEN_STAT); if (irq_status & 0x8) { @@ -1028,6 +1055,7 @@ reg_enable_failed: static void cpp_release_hardware(struct cpp_device *cpp_dev) { int32_t rc; + if (cpp_dev->state != CPP_STATE_BOOT) { msm_camera_unregister_irq(cpp_dev->pdev, cpp_dev->irq, cpp_dev); tasklet_kill(&cpp_dev->cpp_tasklet); @@ -1061,7 +1089,7 @@ static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin) goto end; } pr_debug("%s:%d] FW file: %s\n", __func__, __LINE__, fw_name_bin); - if (NULL == cpp_dev->fw) { + if (cpp_dev->fw == NULL) { pr_err("%s:%d] fw NULL", __func__, __LINE__); rc = -EINVAL; goto end; @@ -1192,7 +1220,8 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) int rc; uint32_t i; struct cpp_device *cpp_dev = NULL; - CPP_DBG("E\n"); + + CPP_DBG("E"); if (!sd || !fh) { pr_err("Wrong input parameters sd %pK fh %pK!", @@ -1246,6 +1275,14 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return rc; } cpp_dev->state = CPP_STATE_IDLE; + + CPP_DBG("Invoking msm_ion_client_create()\n"); + cpp_dev->ion_client = msm_ion_client_create("cpp"); + if (cpp_dev->ion_client == NULL) { + pr_err("msm_ion_client_create() failed\n"); + mutex_unlock(&cpp_dev->mutex); + rc = -ENOMEM; + } } mutex_unlock(&cpp_dev->mutex); return 0; @@ -1338,6 +1375,12 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) msm_cpp_empty_list(processing_q, list_frame); msm_cpp_empty_list(eventData_q, list_eventdata); cpp_dev->state = CPP_STATE_OFF; + + if (cpp_dev->ion_client) { + CPP_DBG("Invoking ion_client_destroy()\n"); + ion_client_destroy(cpp_dev->ion_client); + cpp_dev->ion_client = NULL; + } } mutex_unlock(&cpp_dev->mutex); @@ -1415,7 +1458,8 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev, SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(processed_frame, iden, processed_frame->duplicate_identity); - memset(&buff_mgr_info, 0 , + + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); buff_mgr_info.session_id = ((iden >> 16) & 0xFFFF); @@ -1460,7 +1504,7 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev, SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(processed_frame, iden, processed_frame->identity); - memset(&buff_mgr_info, 0 , + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); buff_mgr_info.session_id = ((iden >> 16) & 0xFFFF); @@ -1500,6 +1544,7 @@ static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info) { int i, i1, i2; struct cpp_device *cpp_dev = cpp_timer.data.cpp_dev; + CPP_DBG("-- start: cpp frame cmd for identity=0x%x, frame_id=%d --\n", frame_info->identity, frame_info->frame_id); @@ -1935,6 +1980,7 @@ static int msm_cpp_check_buf_type(struct msm_buf_mngr_info *buff_mgr_info, { int32_t num_output_bufs = 0; uint32_t i = 0; + if (buff_mgr_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) { new_frame->batch_info.cont_idx = buff_mgr_info->index; @@ -2009,7 +2055,7 @@ static void msm_cpp_update_frame_msg_phy_address(struct cpp_device *cpp_dev, dup_we_mmu_pf_ptr_off = cpp_dev->payload_params.dup_we_mmu_pf_ptr_off; ref_we_mmu_pf_ptr_off = cpp_dev->payload_params.ref_we_mmu_pf_ptr_off; - pr_debug("%s: feature_mask 0x%x\n", __func__, new_frame->feature_mask); + pr_debug("feature_mask 0x%x\n", new_frame->feature_mask); /* Update individual module status from feature mask */ tnr_enabled = ((new_frame->feature_mask & TNR_MASK) >> 2); @@ -2460,6 +2506,7 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev, /* get buffer for duplicate output */ if (new_frame->duplicate_output) { int32_t iden = new_frame->duplicate_identity; + CPP_DBG("duplication enabled, dup_id=0x%x", new_frame->duplicate_identity); @@ -2599,7 +2646,7 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev, int32_t rc = 0; int32_t i = 0; int32_t num_buff = sizeof(k_frame_info.output_buffer_info)/ - sizeof(struct msm_cpp_buffer_info_t); + sizeof(struct msm_cpp_buffer_info_t); if (copy_from_user(&k_frame_info, (void __user *)ioctl_ptr->ioctl_ptr, sizeof(k_frame_info))) @@ -2660,6 +2707,7 @@ static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr, struct msm_camera_v4l2_ioctl_t *ioctl_ptr) { int ret; + if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) { pr_err("%s: Wrong ioctl_ptr %pK / len %zu\n", __func__, ioctl_ptr, ioctl_ptr->len); @@ -2683,6 +2731,7 @@ static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr, struct msm_camera_v4l2_ioctl_t *ioctl_ptr) { int ret; + if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) { pr_err("%s: Wrong ioctl_ptr %pK / len %zu\n", __func__, ioctl_ptr, ioctl_ptr->len); @@ -2758,14 +2807,15 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg, break; default: { if (ioctl_ptr == NULL) { - pr_err("Wrong ioctl_ptr for cmd %u\n", cmd); + pr_err("Wrong ioctl_ptr %pK for cmd %u\n", + ioctl_ptr, cmd); return -EINVAL; } *ioctl_ptr = arg; if ((*ioctl_ptr == NULL) || - (*ioctl_ptr)->ioctl_ptr == NULL) { - pr_err("Error invalid ioctl argument cmd %u", cmd); + ((*ioctl_ptr)->ioctl_ptr == NULL)) { + pr_err("Wrong arg %pK for cmd %u\n", arg, cmd); return -EINVAL; } break; @@ -3007,7 +3057,7 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, mutex_unlock(&cpp_dev->mutex); return -EINVAL; } - if (VIDIOC_MSM_CPP_DELETE_STREAM_BUFF == cmd) { + if (cmd == VIDIOC_MSM_CPP_DELETE_STREAM_BUFF) { for (j = 0; j < k_stream_buff_info.num_buffs; j++) { msm_cpp_dequeue_buff(cpp_dev, buff_queue_info, k_stream_buff_info.buffer_info[j].index, @@ -3030,6 +3080,7 @@ STREAM_BUFF_END: case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: { uint32_t identity; struct msm_cpp_buff_queue_info_t *buff_queue_info; + CPP_DBG("VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO\n"); if (ioctl_ptr->len != sizeof(uint32_t)) { mutex_unlock(&cpp_dev->mutex); @@ -3078,6 +3129,7 @@ STREAM_BUFF_END: struct msm_device_queue *queue = &cpp_dev->eventData_q; struct msm_queue_cmd *event_qcmd; struct msm_cpp_frame_info_t *process_frame; + CPP_DBG("VIDIOC_MSM_CPP_GET_EVENTPAYLOAD\n"); event_qcmd = msm_dequeue(queue, list_eventdata, POP_FRONT); if (!event_qcmd) { @@ -3106,6 +3158,7 @@ STREAM_BUFF_END: uint32_t msm_cpp_core_clk_idx; struct msm_cpp_clock_settings_t clock_settings; unsigned long clock_rate = 0; + CPP_DBG("VIDIOC_MSM_CPP_SET_CLOCK\n"); if (ioctl_ptr->len == 0) { pr_err("ioctl_ptr->len is 0\n"); @@ -3184,6 +3237,7 @@ STREAM_BUFF_END: break; case VIDIOC_MSM_CPP_QUEUE_BUF: { struct msm_pproc_queue_buf_info queue_buf_info; + CPP_DBG("VIDIOC_MSM_CPP_QUEUE_BUF\n"); if (ioctl_ptr->len != sizeof(struct msm_pproc_queue_buf_info)) { @@ -3266,9 +3320,27 @@ STREAM_BUFF_END: break; case VIDIOC_MSM_CPP_IOMMU_ATTACH: { if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) { - rc = cam_smmu_ops(cpp_dev->iommu_hdl, CAM_SMMU_ATTACH); + struct msm_camera_smmu_attach_type cpp_attach_info; + + memset(&cpp_attach_info, 0, sizeof(cpp_attach_info)); + rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info, + ioctl_ptr); if (rc < 0) { - pr_err("%s:%dError iommu_attach_device failed\n", + ERR_COPY_FROM_USER(); + return -EINVAL; + } + + cpp_dev->security_mode = cpp_attach_info.attach; + + if (cpp_dev->security_mode == SECURE_MODE) { + rc = cam_smmu_ops(cpp_dev->iommu_hdl, + CAM_SMMU_ATTACH_SEC_CPP); + } else { + rc = cam_smmu_ops(cpp_dev->iommu_hdl, + CAM_SMMU_ATTACH); + } + if (rc < 0) { + pr_err("%s:%diommu_attach_device failed\n", __func__, __LINE__); rc = -EINVAL; break; @@ -3284,10 +3356,28 @@ STREAM_BUFF_END: case VIDIOC_MSM_CPP_IOMMU_DETACH: { if ((cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) && (cpp_dev->stream_cnt == 0)) { - rc = cam_smmu_ops(cpp_dev->iommu_hdl, CAM_SMMU_DETACH); + + struct msm_camera_smmu_attach_type cpp_attach_info; + + memset(&cpp_attach_info, 0, sizeof(cpp_attach_info)); + rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info, + ioctl_ptr); if (rc < 0) { - pr_err("%s:%dError iommu atach failed\n", - __func__, __LINE__); + ERR_COPY_FROM_USER(); + return -EINVAL; + } + + cpp_dev->security_mode = cpp_attach_info.attach; + + if (cpp_dev->security_mode == SECURE_MODE) + rc = cam_smmu_ops(cpp_dev->iommu_hdl, + CAM_SMMU_DETACH_SEC_CPP); + else + rc = cam_smmu_ops(cpp_dev->iommu_hdl, + CAM_SMMU_DETACH); + if (rc < 0) { + pr_err("%s:%diommu detach failed\n", __func__, + __LINE__); rc = -EINVAL; break; } @@ -3367,6 +3457,7 @@ static long msm_cpp_subdev_do_ioctl( struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; struct msm_cpp_frame_info_t inst_info; + memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t)); for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) { @@ -3735,6 +3826,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, struct msm_cpp_frame_info32_t inst_info; struct v4l2_fh *vfh = NULL; uint32_t i; + vfh = file->private_data; memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info32_t)); for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { @@ -3978,6 +4070,7 @@ static int msm_cpp_update_gdscr_status(struct cpp_device *cpp_dev, { int rc = 0; int value = 0; + if (!cpp_dev) { pr_err("%s: cpp device invalid\n", __func__); rc = -EINVAL; @@ -4080,6 +4173,7 @@ static int cpp_probe(struct platform_device *pdev) struct cpp_device *cpp_dev; int rc = 0; int i = 0; + CPP_DBG("E"); cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL); @@ -4251,6 +4345,8 @@ static int cpp_probe(struct platform_device *pdev) cpp_timer_callback, (unsigned long)&cpp_timer); cpp_dev->fw_name_bin = NULL; cpp_dev->max_timeout_trial_cnt = MSM_CPP_MAX_TIMEOUT_TRIAL; + + if (rc == 0) CPP_DBG("SUCCESS."); else @@ -4293,6 +4389,7 @@ static int cpp_device_remove(struct platform_device *dev) { struct v4l2_subdev *sd = platform_get_drvdata(dev); struct cpp_device *cpp_dev; + if (!sd) { pr_err("%s: Subdevice is NULL\n", __func__); return 0; @@ -4303,6 +4400,7 @@ static int cpp_device_remove(struct platform_device *dev) pr_err("%s: cpp device is NULL\n", __func__); return 0; } + if (cpp_dev->fw) { release_firmware(cpp_dev->fw); cpp_dev->fw = NULL; @@ -4366,6 +4464,7 @@ DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_error, NULL, static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev) { struct dentry *debugfs_base; + debugfs_base = debugfs_create_dir("msm_cpp", NULL); if (!debugfs_base) return -ENOMEM; diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h index d5abe0202717..f46cc10cef46 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h @@ -169,6 +169,7 @@ struct msm_cpp_buff_queue_info_t { uint32_t used; uint16_t session_id; uint16_t stream_id; + enum smmu_attach_mode security_mode; struct list_head vb2_buff_head; struct list_head native_buff_head; }; @@ -234,6 +235,8 @@ struct cpp_device { uint32_t min_clk_rate; int iommu_hdl; + struct ion_client *ion_client; + enum smmu_attach_mode security_mode; /* Reusing proven tasklet from msm isp */ atomic_t irq_cnt; uint8_t taskletq_idx; diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c index 56ddf8467d16..011d5bd88d90 100644 --- a/drivers/misc/hdcp.c +++ b/drivers/misc/hdcp.c @@ -65,7 +65,8 @@ #define REPEATER_AUTH_SEND_ACK_MESSAGE_ID 15 #define REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID 16 #define REPEATER_AUTH_STREAM_READY_MESSAGE_ID 17 -#define HDCP2P2_MAX_MESSAGES 18 +#define SKE_SEND_TYPE_ID 18 +#define HDCP2P2_MAX_MESSAGES 19 #define HDCP1_SET_KEY_MESSAGE_ID 202 #define HDCP1_SET_ENC_MESSAGE_ID 205 @@ -94,7 +95,7 @@ * minimum wait as per standard is 200 ms. keep it 300 ms * to be on safe side. */ -#define SLEEP_SET_HW_KEY_MS 300 +#define SLEEP_SET_HW_KEY_MS 220 #define QSEECOM_ALIGN_SIZE 0x40 #define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1) @@ -187,6 +188,9 @@ static const struct hdcp_msg_data hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = { [SKE_SEND_EKS_MESSAGE_ID] = { 2, { {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} }, 0 }, + [SKE_SEND_TYPE_ID] = { 1, + { {"type", 0x69494, 1} }, + 0 }, [REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID] = { 4, { {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3}, {"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} }, @@ -499,8 +503,10 @@ struct hdcp_lib_handle { uint32_t tz_ctxhandle; uint32_t hdcp_timeout; uint32_t timeout_left; + uint32_t wait_timeout; bool no_stored_km_flag; bool feature_supported; + bool authenticated; void *client_ctx; struct hdcp_client_ops *client_ops; struct mutex msg_lock; @@ -521,7 +527,7 @@ struct hdcp_lib_handle { enum hdcp_device_type device_type; struct task_struct *thread; - struct completion topo_wait; + struct completion poll_wait; struct kthread_worker worker; struct kthread_work wk_init; @@ -529,7 +535,7 @@ struct hdcp_lib_handle { struct kthread_work wk_msg_recvd; struct kthread_work wk_timeout; struct kthread_work wk_clean; - struct kthread_work wk_topology; + struct kthread_work wk_wait; struct kthread_work wk_stream; int (*hdcp_app_init)(struct hdcp_lib_handle *handle); @@ -574,6 +580,7 @@ static const char *hdcp_lib_message_name(int msg_id) {15, "REPEATER_AUTH_SEND_ACK"}, {16, "REPEATER_AUTH_STREAM_MANAGE"}, {17, "REPEATER_AUTH_STREAM_READY"}, + {18, "SKE_SEND_TYPE_ID"}, }; int i; @@ -612,8 +619,14 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle, case LC_SEND_L_PRIME_MESSAGE_ID: return SKE_SEND_EKS_MESSAGE_ID; case SKE_SEND_EKS_MESSAGE_ID: + if (!handle->repeater_flag) + return SKE_SEND_TYPE_ID; + case SKE_SEND_TYPE_ID: case REPEATER_AUTH_STREAM_READY_MESSAGE_ID: case REPEATER_AUTH_SEND_ACK_MESSAGE_ID: + if (!handle->repeater_flag) + return INVALID_MESSAGE_ID; + if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE) return REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID; else @@ -628,6 +641,33 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle, } } +static void hdcp_lib_wait_for_response(struct hdcp_lib_handle *handle, + struct hdmi_hdcp_wakeup_data *data) +{ + switch (handle->last_msg) { + case AKE_SEND_H_PRIME_MESSAGE_ID: + if (handle->no_stored_km_flag) + handle->wait_timeout = HZ; + else + handle->wait_timeout = HZ / 4; + break; + case AKE_SEND_PAIRING_INFO_MESSAGE_ID: + handle->wait_timeout = HZ / 4; + break; + case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID: + if (!handle->authenticated) + handle->wait_timeout = HZ * 3; + else + handle->wait_timeout = 0; + break; + default: + handle->wait_timeout = 0; + } + + if (handle->wait_timeout) + queue_kthread_work(&handle->worker, &handle->wk_wait); +} + static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle, struct hdmi_hdcp_wakeup_data *data) { @@ -639,43 +679,42 @@ static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle, data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE; - if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE || - data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE || - data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL) { + if (data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE || + data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL) handle->last_msg = hdcp_lib_get_next_message(handle, data); + if (handle->last_msg != INVALID_MESSAGE_ID && + data->cmd != HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS && + data->cmd != HDMI_HDCP_WKUP_CMD_STATUS_FAILED) { + u32 msg_num, rx_status; + const struct hdcp_msg_part *msg; + pr_debug("lib->client: %s (%s)\n", hdmi_hdcp_cmd_to_str(data->cmd), hdcp_lib_message_name(handle->last_msg)); - if (handle->last_msg > INVALID_MESSAGE_ID && - handle->last_msg < HDCP2P2_MAX_MESSAGES) { - u32 msg_num, rx_status; - const struct hdcp_msg_part *msg; - - data->message_data = &hdcp_msg_lookup[handle->last_msg]; + data->message_data = &hdcp_msg_lookup[handle->last_msg]; - msg_num = data->message_data->num_messages; - msg = data->message_data->messages; - rx_status = data->message_data->rx_status; + msg_num = data->message_data->num_messages; + msg = data->message_data->messages; + rx_status = data->message_data->rx_status; - pr_debug("rxstatus 0x%x\n", rx_status); - pr_debug("%10s | %6s | %4s\n", "name", "offset", "len"); + pr_debug("%10s | %6s | %4s\n", "name", "offset", "len"); - for (i = 0; i < msg_num; i++) - pr_debug("%10s | %6x | %4d\n", - msg[i].name, msg[i].offset, - msg[i].length); - } + for (i = 0; i < msg_num; i++) + pr_debug("%10s | %6x | %4d\n", + msg[i].name, msg[i].offset, + msg[i].length); } else { - pr_debug("lib->client: %s\n", - hdmi_hdcp_cmd_to_str(data->cmd)); + pr_debug("lib->client: %s\n", hdmi_hdcp_cmd_to_str(data->cmd)); } rc = handle->client_ops->wakeup(data); if (rc) pr_err("error sending %s to client\n", hdmi_hdcp_cmd_to_str(data->cmd)); + + hdcp_lib_wait_for_response(handle, data); } static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle) @@ -1286,6 +1325,8 @@ static int hdcp_lib_txmtr_init_legacy(struct hdcp_lib_handle *handle) hdcp_lib_message_name((int)rsp_buf->message[0]), jiffies_to_msecs(jiffies)); + handle->last_msg = (int)rsp_buf->message[0]; + /* send the response to HDMI driver */ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE); memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message, @@ -1404,6 +1445,8 @@ static int hdcp_lib_start_auth(struct hdcp_lib_handle *handle) hdcp_lib_message_name((int)rsp_buf->message[0]), jiffies_to_msecs(jiffies)); + handle->last_msg = (int)rsp_buf->message[0]; + /* send the response to HDMI driver */ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE); memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message, @@ -1470,6 +1513,8 @@ static void hdcp_lib_stream(struct hdcp_lib_handle *handle) pr_debug("message received from TZ: %s\n", hdcp_lib_message_name((int)rsp_buf->msg[0])); + handle->last_msg = (int)rsp_buf->msg[0]; + memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE); memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg, rsp_buf->msglen); @@ -1550,11 +1595,11 @@ static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle) if (handle->worker.current_work == &handle->wk_clean) pr_debug("clean work executing\n"); - if (!list_empty(&handle->wk_topology.node)) - pr_debug("topology work queued\n"); + if (!list_empty(&handle->wk_wait.node)) + pr_debug("wait work queued\n"); - if (handle->worker.current_work == &handle->wk_topology) - pr_debug("topology work executing\n"); + if (handle->worker.current_work == &handle->wk_wait) + pr_debug("wait work executing\n"); if (!list_empty(&handle->wk_stream.node)) pr_debug("stream work queued\n"); @@ -1613,7 +1658,7 @@ static void hdcp_lib_update_exec_type(void *ctx, bool tethered) mutex_unlock(&handle->wakeup_mutex); } -static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) +static int hdcp_lib_wakeup_thread(struct hdcp_lib_wakeup_data *data) { struct hdcp_lib_handle *handle; int rc = 0; @@ -1630,8 +1675,9 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) handle->wakeup_cmd = data->cmd; handle->timeout_left = data->timeout; - pr_debug("client->lib: %s\n", - hdcp_lib_cmd_to_str(handle->wakeup_cmd)); + pr_debug("client->lib: %s (%s)\n", + hdcp_lib_cmd_to_str(data->cmd), + hdcp_lib_message_name(handle->last_msg)); rc = hdcp_lib_check_valid_state(handle); if (rc) @@ -1655,8 +1701,8 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) } mutex_unlock(&handle->msg_lock); - if (!completion_done(&handle->topo_wait)) - complete_all(&handle->topo_wait); + if (!completion_done(&handle->poll_wait)) + complete_all(&handle->poll_wait); switch (handle->wakeup_cmd) { case HDCP_LIB_WKUP_CMD_START: @@ -1719,22 +1765,30 @@ static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle) cdata.context = handle->client_ctx; switch (handle->last_msg_sent) { - case SKE_SEND_EKS_MESSAGE_ID: - if (handle->repeater_flag) { - if (!atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, - &handle->wk_topology); - } - + case SKE_SEND_TYPE_ID: if (!hdcp_lib_enable_encryption(handle)) { + handle->authenticated = true; + cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS; hdcp_lib_wakeup_client(handle, &cdata); + } + /* poll for link check */ + cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL; + break; + case SKE_SEND_EKS_MESSAGE_ID: + if (handle->repeater_flag) { /* poll for link check */ cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL; } else { - if (!atomic_read(&handle->hdcp_off)) - HDCP_LIB_EXECUTE(clean); + memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE); + handle->listener_buf[0] = SKE_SEND_TYPE_ID; + handle->msglen = 2; + cdata.cmd = HDMI_HDCP_WKUP_CMD_SEND_MESSAGE; + cdata.send_msg_buf = handle->listener_buf; + cdata.send_msg_len = handle->msglen; + handle->last_msg = hdcp_lib_get_next_message(handle, + &cdata); } break; case REPEATER_AUTH_SEND_ACK_MESSAGE_ID: @@ -1915,6 +1969,8 @@ static void hdcp_lib_clean(struct hdcp_lib_handle *handle) return; } + handle->authenticated = false; + hdcp_lib_txmtr_deinit(handle); if (!handle->legacy_app) hdcp_lib_session_deinit(handle); @@ -2040,6 +2096,13 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle) (rc == 0) && (rsp_buf->status == 0)) { pr_debug("Got Auth_Stream_Ready, nothing sent to rx\n"); + if (!hdcp_lib_enable_encryption(handle)) { + handle->authenticated = true; + + cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS; + hdcp_lib_wakeup_client(handle, &cdata); + } + cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL; goto exit; } @@ -2057,6 +2120,8 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle) hdcp_lib_message_name((int)rsp_buf->msg[0]), jiffies_to_msecs(jiffies)); + handle->last_msg = (int)rsp_buf->msg[0]; + /* set the flag if response is AKE_No_Stored_km */ if (((int)rsp_buf->msg[0] == AKE_NO_STORED_KM_MESSAGE_ID)) { pr_debug("Setting no_stored_km_flag\n"); @@ -2101,12 +2166,11 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work) hdcp_lib_msg_recvd(handle); } -static void hdcp_lib_topology_work(struct kthread_work *work) +static void hdcp_lib_wait_work(struct kthread_work *work) { u32 timeout; struct hdcp_lib_handle *handle = container_of(work, - struct hdcp_lib_handle, - wk_topology); + struct hdcp_lib_handle, wk_wait); if (!handle) { pr_err("invalid input\n"); @@ -2123,14 +2187,17 @@ static void hdcp_lib_topology_work(struct kthread_work *work) return; } - reinit_completion(&handle->topo_wait); - timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3); + reinit_completion(&handle->poll_wait); + timeout = wait_for_completion_timeout(&handle->poll_wait, + handle->wait_timeout); if (!timeout) { - pr_err("topology receiver id list timeout\n"); + pr_err("wait timeout\n"); if (!atomic_read(&handle->hdcp_off)) HDCP_LIB_EXECUTE(clean); } + + handle->wait_timeout = 0; } bool hdcp1_check_if_supported_load_app(void) @@ -2266,7 +2333,7 @@ int hdcp_library_register(struct hdcp_register_data *data) /* populate ops to be called by client */ data->txmtr_ops->feature_supported = hdcp_lib_client_feature_supported; - data->txmtr_ops->wakeup = hdcp_lib_wakeup; + data->txmtr_ops->wakeup = hdcp_lib_wakeup_thread; data->txmtr_ops->update_exec_type = hdcp_lib_update_exec_type; handle = kzalloc(sizeof(*handle), GFP_KERNEL); @@ -2296,10 +2363,10 @@ int hdcp_library_register(struct hdcp_register_data *data) init_kthread_work(&handle->wk_msg_recvd, hdcp_lib_msg_recvd_work); init_kthread_work(&handle->wk_timeout, hdcp_lib_manage_timeout_work); init_kthread_work(&handle->wk_clean, hdcp_lib_cleanup_work); - init_kthread_work(&handle->wk_topology, hdcp_lib_topology_work); + init_kthread_work(&handle->wk_wait, hdcp_lib_wait_work); init_kthread_work(&handle->wk_stream, hdcp_lib_query_stream_work); - init_completion(&handle->topo_wait); + init_completion(&handle->poll_wait); handle->listener_buf = kzalloc(MAX_TX_MESSAGE_SIZE, GFP_KERNEL); if (!(handle->listener_buf)) { diff --git a/drivers/misc/qcom/qdsp6v2/Makefile b/drivers/misc/qcom/qdsp6v2/Makefile index 7006ff4a272f..90a123adbb7f 100644 --- a/drivers/misc/qcom/qdsp6v2/Makefile +++ b/drivers/misc/qcom/qdsp6v2/Makefile @@ -1,5 +1,6 @@ -obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o +obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o g711mlaw_in.o g711alaw_in.o audio_utils.o obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_alac.o audio_ape.o audio_utils_aio.o obj-$(CONFIG_MSM_QDSP6V2_CODECS) += q6audio_v2.o q6audio_v2_aio.o +obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_g711mlaw.o audio_g711alaw.o obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_amrwbplus.o audio_evrc.o audio_qcelp.o amrwb_in.o audio_hwacc_effects.o obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/ diff --git a/drivers/misc/qcom/qdsp6v2/audio_amrnb.c b/drivers/misc/qcom/qdsp6v2/audio_amrnb.c index 78bcdb74af0e..9e4f74bfacd9 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_amrnb.c +++ b/drivers/misc/qcom/qdsp6v2/audio_amrnb.c @@ -14,6 +14,9 @@ * GNU General Public License for more details. * */ + +#include <linux/types.h> +#include <linux/compat.h> #include "audio_utils_aio.h" static struct miscdevice audio_amrnb_misc; @@ -68,6 +71,52 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return rc; } +static long audio_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__, + audio, audio->ac->session); + if (audio->feedback == NON_TUNNEL_MODE) { + /* Configure PCM output block */ + rc = q6asm_enc_cfg_blk_pcm(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count); + if (rc < 0) { + pr_err("%s: pcm output block config failed rc=%d\n", + __func__, rc); + break; + } + } + + rc = audio_aio_enable(audio); + audio->eos_rsp = 0; + audio->eos_flag = 0; + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s: Audio Start procedure failed rc=%d\n", + __func__, rc); + break; + } + pr_debug("AUDIO_START success enable[%d]\n", audio->enabled); + if (audio->stopped == 1) + audio->stopped = 0; + break; + } + default: + pr_debug("%s[%pK]: Calling compat ioctl\n", __func__, audio); + rc = audio->codec_compat_ioctl(file, cmd, arg); + } + return rc; +} + + static int audio_open(struct inode *inode, struct file *file) { struct q6audio_aio *audio = NULL; @@ -155,6 +204,7 @@ static const struct file_operations audio_amrnb_fops = { .release = audio_aio_release, .unlocked_ioctl = audio_ioctl, .fsync = audio_aio_fsync, + .compat_ioctl = audio_compat_ioctl, }; static struct miscdevice audio_amrnb_misc = { diff --git a/drivers/misc/qcom/qdsp6v2/audio_amrwb.c b/drivers/misc/qcom/qdsp6v2/audio_amrwb.c index 2283cf26bda9..2403dbbe426b 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_amrwb.c +++ b/drivers/misc/qcom/qdsp6v2/audio_amrwb.c @@ -15,6 +15,8 @@ * */ +#include <linux/compat.h> +#include <linux/types.h> #include "audio_utils_aio.h" static struct miscdevice audio_amrwb_misc; @@ -71,6 +73,53 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return rc; } +static long audio_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__, + audio, audio->ac->session); + if (audio->feedback == NON_TUNNEL_MODE) { + /* Configure PCM output block */ + rc = q6asm_enc_cfg_blk_pcm(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count); + if (rc < 0) { + pr_err("%s: pcm output block config failed rc=%d\n", + __func__, rc); + break; + } + } + + rc = audio_aio_enable(audio); + audio->eos_rsp = 0; + audio->eos_flag = 0; + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s: Audio Start procedure failed rc=%d\n", + __func__, rc); + break; + } + pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__, + audio->ac->session, + audio->enabled); + if (audio->stopped == 1) + audio->stopped = 0; + break; + } + default: + pr_debug("%s[%pK]: Calling compat ioctl\n", __func__, audio); + rc = audio->codec_compat_ioctl(file, cmd, arg); + } + return rc; +} + static int audio_open(struct inode *inode, struct file *file) { struct q6audio_aio *audio = NULL; @@ -159,6 +208,7 @@ static const struct file_operations audio_amrwb_fops = { .release = audio_aio_release, .unlocked_ioctl = audio_ioctl, .fsync = audio_aio_fsync, + .compat_ioctl = audio_compat_ioctl, }; static struct miscdevice audio_amrwb_misc = { diff --git a/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c b/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c new file mode 100644 index 000000000000..6f02654d3d4c --- /dev/null +++ b/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c @@ -0,0 +1,396 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/types.h> +#include <linux/msm_audio_g711_dec.h> +#include <linux/compat.h> +#include "audio_utils_aio.h" + +static struct miscdevice audio_g711alaw_misc; +static struct ws_mgr audio_g711_ws_mgr; + +static const struct file_operations audio_g711_debug_fops = { + .read = audio_aio_debug_read, + .open = audio_aio_debug_open, +}; + +static struct dentry *config_debugfs_create_file(const char *name, void *data) +{ + return debugfs_create_file(name, S_IFREG | S_IRUGO, + NULL, (void *)data, &audio_g711_debug_fops); +} + +static int g711_channel_map(u8 *channel_mapping, uint32_t channels); + +static long audio_ioctl_shared(struct file *file, unsigned int cmd, + void *arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + struct asm_g711_dec_cfg g711_dec_cfg; + struct msm_audio_g711_dec_config *g711_dec_config; + u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL]; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + memset(&g711_dec_cfg, 0, sizeof(g711_dec_cfg)); + + if (g711_channel_map(channel_mapping, + audio->pcm_cfg.channel_count)) { + pr_err("%s: setting channel map failed %d\n", + __func__, audio->pcm_cfg.channel_count); + } + + pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__, + audio, audio->ac->session); + if (audio->feedback == NON_TUNNEL_MODE) { + /* Configure PCM output block */ + rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count, + 16, /*bits per sample*/ + false, false, channel_mapping); + if (rc < 0) { + pr_err("%s: pcm output block config failed rc=%d\n", + __func__, rc); + break; + } + } + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_cfg.sample_rate = g711_dec_config->sample_rate; + /* Configure Media format block */ + rc = q6asm_media_format_block_g711(audio->ac, &g711_dec_cfg, + audio->ac->stream_id); + if (rc < 0) { + pr_err("%s: cmd media format block failed rc=%d\n", + __func__, rc); + break; + } + rc = audio_aio_enable(audio); + audio->eos_rsp = 0; + audio->eos_flag = 0; + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s: Audio Start procedure failed rc=%d\n", + __func__, rc); + break; + } + pr_debug("%s: AUDIO_START success enable[%d]\n", + __func__, audio->enabled); + if (audio->stopped == 1) + audio->stopped = 0; + break; + } + default: + pr_debug("%s: Unknown ioctl cmd = %d", __func__, cmd); + break; + } + return rc; +} + +static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + rc = audio_ioctl_shared(file, cmd, (void *)arg); + break; + } + case AUDIO_GET_G711_DEC_CONFIG: { + if (copy_to_user((void *)arg, audio->codec_cfg, + sizeof(struct msm_audio_g711_dec_config))) { + pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_DEC_CONFIG: { + if (copy_from_user(audio->codec_cfg, (void *)arg, + sizeof(struct msm_audio_g711_dec_config))) { + pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + } + break; + } + default: { + rc = audio->codec_ioctl(file, cmd, arg); + if (rc) + pr_err("%s: Failed in audio_aio_ioctl: %d cmd=%d\n", + __func__, rc, cmd); + break; + } + } + return rc; +} + +#ifdef CONFIG_COMPAT +struct msm_audio_g711_dec_config_32 { + u32 sample_rate; +}; + +enum { + AUDIO_SET_G711_DEC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config_32), + AUDIO_GET_G711_DEC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config_32) +}; + +static long audio_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + rc = audio_ioctl_shared(file, cmd, (void *)arg); + break; + } + case AUDIO_GET_G711_DEC_CONFIG_32: { + struct msm_audio_g711_dec_config *g711_dec_config; + struct msm_audio_g711_dec_config_32 g711_dec_config_32; + + memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32)); + + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_config_32.sample_rate = g711_dec_config->sample_rate; + + if (copy_to_user((void *)arg, &g711_dec_config_32, + sizeof(g711_dec_config_32))) { + pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_DEC_CONFIG_32: { + struct msm_audio_g711_dec_config *g711_dec_config; + struct msm_audio_g711_dec_config_32 g711_dec_config_32; + + memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32)); + + if (copy_from_user(&g711_dec_config_32, (void *)arg, + sizeof(g711_dec_config_32))) { + pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + break; + } + + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_config->sample_rate = g711_dec_config_32.sample_rate; + + break; + } + default: { + rc = audio->codec_compat_ioctl(file, cmd, arg); + if (rc) + pr_err("%s: Failed in audio_aio_compat_ioctl: %d cmd=%d\n", + __func__, rc, cmd); + break; + } + } + return rc; +} +#else +#define audio_compat_ioctl NULL +#endif + +static int audio_open(struct inode *inode, struct file *file) +{ + struct q6audio_aio *audio = NULL; + int rc = 0; + /* 4 bytes represents decoder number, 1 byte for terminate string */ + char name[sizeof "msm_g711_" + 5]; + + audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL); + + if (!audio) + return -ENOMEM; + audio->codec_cfg = kzalloc(sizeof(struct msm_audio_g711_dec_config), + GFP_KERNEL); + if (!audio->codec_cfg) { + kfree(audio); + return -ENOMEM; + } + + audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN; + audio->miscdevice = &audio_g711alaw_misc; + audio->wakelock_voted = false; + audio->audio_ws_mgr = &audio_g711_ws_mgr; + + init_waitqueue_head(&audio->event_wait); + + audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb, + (void *)audio); + + if (!audio->ac) { + pr_err("%s: Could not allocate memory for audio client\n", + __func__); + kfree(audio->codec_cfg); + kfree(audio); + return -ENOMEM; + } + rc = audio_aio_open(audio, file); + if (rc < 0) { + pr_err("%s: audio_aio_open rc=%d\n", + __func__, rc); + goto fail; + } + /* open in T/NT mode */ /*foramt:G711_ALAW*/ + if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { + rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM, + FORMAT_G711_ALAW_FS); + if (rc < 0) { + pr_err("%s: NT mode Open failed rc=%d\n", __func__, rc); + goto fail; + } + audio->feedback = NON_TUNNEL_MODE; + /* open G711 decoder, expected frames is always 1*/ + audio->buf_cfg.frames_per_buf = 0x01; + audio->buf_cfg.meta_info_enable = 0x01; + } else if ((file->f_mode & FMODE_WRITE) && + !(file->f_mode & FMODE_READ)) { + rc = q6asm_open_write(audio->ac, FORMAT_G711_ALAW_FS); + if (rc < 0) { + pr_err("%s: T mode Open failed rc=%d\n", __func__, rc); + goto fail; + } + audio->feedback = TUNNEL_MODE; + audio->buf_cfg.meta_info_enable = 0x00; + } else { + pr_err("%s: %d mode is not supported mode\n", + __func__, file->f_mode); + rc = -EACCES; + goto fail; + } + + snprintf(name, sizeof(name), "msm_g711_%04x", audio->ac->session); + audio->dentry = config_debugfs_create_file(name, (void *)audio); + + if (IS_ERR_OR_NULL(audio->dentry)) + pr_debug("%s: debugfs_create_file failed\n", __func__); + pr_debug("%s: g711dec success mode[%d]session[%d]\n", __func__, + audio->feedback, + audio->ac->session); + return rc; +fail: + q6asm_audio_client_free(audio->ac); + kfree(audio->codec_cfg); + kfree(audio); + return rc; +} + +static int g711_channel_map(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_CS; + } 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_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + } 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_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + lchannel_mapping[5] = PCM_CHANNEL_LFE; + } else if (channels == 7) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + lchannel_mapping[3] = PCM_CHANNEL_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + lchannel_mapping[5] = PCM_CHANNEL_CS; + lchannel_mapping[6] = PCM_CHANNEL_LFE; + } else if (channels == 8) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FLC; + lchannel_mapping[2] = PCM_CHANNEL_FRC; + lchannel_mapping[3] = PCM_CHANNEL_FL; + lchannel_mapping[4] = PCM_CHANNEL_FR; + lchannel_mapping[5] = PCM_CHANNEL_LS; + lchannel_mapping[6] = PCM_CHANNEL_RS; + lchannel_mapping[7] = PCM_CHANNEL_LFE; + } else { + pr_err("%s: ERROR.unsupported num_ch = %u\n", + __func__, channels); + return -EINVAL; + } + return 0; +} + +static const struct file_operations audio_g711_fops = { + .owner = THIS_MODULE, + .open = audio_open, + .release = audio_aio_release, + .unlocked_ioctl = audio_ioctl, + .compat_ioctl = audio_compat_ioctl, + .fsync = audio_aio_fsync, +}; + +static struct miscdevice audio_g711alaw_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "msm_g711alaw", + .fops = &audio_g711_fops, +}; + +static int __init audio_g711alaw_init(void) +{ + int ret = misc_register(&audio_g711alaw_misc); + + if (ret == 0) + device_init_wakeup(audio_g711alaw_misc.this_device, true); + audio_g711_ws_mgr.ref_cnt = 0; + mutex_init(&audio_g711_ws_mgr.ws_lock); + + return ret; +} +static void __exit audio_g711alaw_exit(void) +{ + misc_deregister(&audio_g711alaw_misc); + mutex_destroy(&audio_g711_ws_mgr.ws_lock); +} + +device_initcall(audio_g711alaw_init); +__exitcall(audio_g711alaw_exit); diff --git a/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c b/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c new file mode 100644 index 000000000000..cae2490feb7a --- /dev/null +++ b/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c @@ -0,0 +1,396 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/types.h> +#include <linux/msm_audio_g711_dec.h> +#include <linux/compat.h> +#include "audio_utils_aio.h" + +static struct miscdevice audio_g711mlaw_misc; +static struct ws_mgr audio_g711_ws_mgr; + +static const struct file_operations audio_g711_debug_fops = { + .read = audio_aio_debug_read, + .open = audio_aio_debug_open, +}; + +static struct dentry *config_debugfs_create_file(const char *name, void *data) +{ + return debugfs_create_file(name, S_IFREG | S_IRUGO, + NULL, (void *)data, &audio_g711_debug_fops); +} + +static int g711_channel_map(u8 *channel_mapping, uint32_t channels); + +static long audio_ioctl_shared(struct file *file, unsigned int cmd, + void *arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + struct asm_g711_dec_cfg g711_dec_cfg; + struct msm_audio_g711_dec_config *g711_dec_config; + u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL]; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + memset(&g711_dec_cfg, 0, sizeof(g711_dec_cfg)); + + if (g711_channel_map(channel_mapping, + audio->pcm_cfg.channel_count)) { + pr_err("%s: setting channel map failed %d\n", + __func__, audio->pcm_cfg.channel_count); + } + + pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__, + audio, audio->ac->session); + if (audio->feedback == NON_TUNNEL_MODE) { + /* Configure PCM output block */ + rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count, + 16, /*bits per sample*/ + false, false, channel_mapping); + if (rc < 0) { + pr_err("%s: pcm output block config failed rc=%d\n", + __func__, rc); + break; + } + } + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_cfg.sample_rate = g711_dec_config->sample_rate; + /* Configure Media format block */ + rc = q6asm_media_format_block_g711(audio->ac, &g711_dec_cfg, + audio->ac->stream_id); + if (rc < 0) { + pr_err("%s: cmd media format block failed rc=%d\n", + __func__, rc); + break; + } + rc = audio_aio_enable(audio); + audio->eos_rsp = 0; + audio->eos_flag = 0; + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s: Audio Start procedure failed rc=%d\n", + __func__, rc); + break; + } + pr_debug("%s: AUDIO_START success enable[%d]\n", + __func__, audio->enabled); + if (audio->stopped == 1) + audio->stopped = 0; + break; + } + default: + pr_debug("%s: Unknown ioctl cmd = %d", __func__, cmd); + break; + } + return rc; +} + +static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + rc = audio_ioctl_shared(file, cmd, (void *)arg); + break; + } + case AUDIO_GET_G711_DEC_CONFIG: { + if (copy_to_user((void *)arg, audio->codec_cfg, + sizeof(struct msm_audio_g711_dec_config))) { + pr_err("%s: AUDIO_GET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_DEC_CONFIG: { + if (copy_from_user(audio->codec_cfg, (void *)arg, + sizeof(struct msm_audio_g711_dec_config))) { + pr_err("%s: AUDIO_SET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + } + break; + } + default: { + rc = audio->codec_ioctl(file, cmd, arg); + if (rc) + pr_err("%s: Failed in audio_aio_ioctl: %d cmd=%d\n", + __func__, rc, cmd); + break; + } + } + return rc; +} + +#ifdef CONFIG_COMPAT +struct msm_audio_g711_dec_config_32 { + u32 sample_rate; +}; + +enum { + AUDIO_SET_G711_DEC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config_32), + AUDIO_GET_G711_DEC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config_32) +}; + +static long audio_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct q6audio_aio *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: { + rc = audio_ioctl_shared(file, cmd, (void *)arg); + break; + } + case AUDIO_GET_G711_DEC_CONFIG_32: { + struct msm_audio_g711_dec_config *g711_dec_config; + struct msm_audio_g711_dec_config_32 g711_dec_config_32; + + memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32)); + + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_config_32.sample_rate = g711_dec_config->sample_rate; + + if (copy_to_user((void *)arg, &g711_dec_config_32, + sizeof(g711_dec_config_32))) { + pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_DEC_CONFIG_32: { + struct msm_audio_g711_dec_config *g711_dec_config; + struct msm_audio_g711_dec_config_32 g711_dec_config_32; + + memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32)); + + if (copy_from_user(&g711_dec_config_32, (void *)arg, + sizeof(g711_dec_config_32))) { + pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG failed\n", + __func__); + rc = -EFAULT; + break; + } + g711_dec_config = + (struct msm_audio_g711_dec_config *)audio->codec_cfg; + g711_dec_config->sample_rate = g711_dec_config_32.sample_rate; + + break; + } + default: { + rc = audio->codec_compat_ioctl(file, cmd, arg); + if (rc) + pr_err("%s: Failed in audio_aio_compat_ioctl: %d cmd=%d\n", + __func__, rc, cmd); + break; + } + } + return rc; +} +#else +#define audio_compat_ioctl NULL +#endif + +static int audio_open(struct inode *inode, struct file *file) +{ + struct q6audio_aio *audio = NULL; + int rc = 0; + /* 4 bytes represents decoder number, 1 byte for terminate string */ + char name[sizeof "msm_g711_" + 5]; + + audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL); + + if (!audio) + return -ENOMEM; + audio->codec_cfg = kzalloc(sizeof(struct msm_audio_g711_dec_config), + GFP_KERNEL); + if (!audio->codec_cfg) { + kfree(audio); + return -ENOMEM; + } + + audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN; + audio->miscdevice = &audio_g711mlaw_misc; + audio->wakelock_voted = false; + audio->audio_ws_mgr = &audio_g711_ws_mgr; + + init_waitqueue_head(&audio->event_wait); + + audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb, + (void *)audio); + + if (!audio->ac) { + pr_err("%s: Could not allocate memory for audio client\n", + __func__); + kfree(audio->codec_cfg); + kfree(audio); + return -ENOMEM; + } + rc = audio_aio_open(audio, file); + if (rc < 0) { + pr_err("%s: audio_aio_open rc=%d\n", + __func__, rc); + goto fail; + } + /* open in T/NT mode */ /*foramt:G711_ALAW*/ + if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { + rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM, + FORMAT_G711_MLAW_FS); + if (rc < 0) { + pr_err("%s: NT mode Open failed rc=%d\n", __func__, rc); + goto fail; + } + audio->feedback = NON_TUNNEL_MODE; + /* open G711 decoder, expected frames is always 1*/ + audio->buf_cfg.frames_per_buf = 0x01; + audio->buf_cfg.meta_info_enable = 0x01; + } else if ((file->f_mode & FMODE_WRITE) && + !(file->f_mode & FMODE_READ)) { + rc = q6asm_open_write(audio->ac, FORMAT_G711_MLAW_FS); + if (rc < 0) { + pr_err("%s: T mode Open failed rc=%d\n", __func__, rc); + goto fail; + } + audio->feedback = TUNNEL_MODE; + audio->buf_cfg.meta_info_enable = 0x00; + } else { + pr_err("%s: %d mode is not supported\n", __func__, + file->f_mode); + rc = -EACCES; + goto fail; + } + + snprintf(name, sizeof(name), "msm_g711_%04x", audio->ac->session); + audio->dentry = config_debugfs_create_file(name, (void *)audio); + + if (IS_ERR_OR_NULL(audio->dentry)) + pr_debug("%s: debugfs_create_file failed\n", __func__); + pr_debug("%s: g711dec success mode[%d]session[%d]\n", __func__, + audio->feedback, + audio->ac->session); + return rc; +fail: + q6asm_audio_client_free(audio->ac); + kfree(audio->codec_cfg); + kfree(audio); + return rc; +} + +static int g711_channel_map(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_CS; + } 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_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + } 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_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + lchannel_mapping[5] = PCM_CHANNEL_LFE; + } else if (channels == 7) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FL; + lchannel_mapping[2] = PCM_CHANNEL_FR; + lchannel_mapping[3] = PCM_CHANNEL_LS; + lchannel_mapping[4] = PCM_CHANNEL_RS; + lchannel_mapping[5] = PCM_CHANNEL_CS; + lchannel_mapping[6] = PCM_CHANNEL_LFE; + } else if (channels == 8) { + lchannel_mapping[0] = PCM_CHANNEL_FC; + lchannel_mapping[1] = PCM_CHANNEL_FLC; + lchannel_mapping[2] = PCM_CHANNEL_FRC; + lchannel_mapping[3] = PCM_CHANNEL_FL; + lchannel_mapping[4] = PCM_CHANNEL_FR; + lchannel_mapping[5] = PCM_CHANNEL_LS; + lchannel_mapping[6] = PCM_CHANNEL_RS; + lchannel_mapping[7] = PCM_CHANNEL_LFE; + } else { + pr_err("%s: ERROR.unsupported num_ch = %u\n", + __func__, channels); + return -EINVAL; + } + return 0; +} + +static const struct file_operations audio_g711_fops = { + .owner = THIS_MODULE, + .open = audio_open, + .release = audio_aio_release, + .unlocked_ioctl = audio_ioctl, + .compat_ioctl = audio_compat_ioctl, + .fsync = audio_aio_fsync, +}; + +static struct miscdevice audio_g711mlaw_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "msm_g711mlaw", + .fops = &audio_g711_fops, +}; + +static int __init audio_g711mlaw_init(void) +{ + int ret = misc_register(&audio_g711mlaw_misc); + + if (ret == 0) + device_init_wakeup(audio_g711mlaw_misc.this_device, true); + audio_g711_ws_mgr.ref_cnt = 0; + mutex_init(&audio_g711_ws_mgr.ws_lock); + + return ret; +} + +static void __exit audio_g711mlaw_exit(void) +{ + misc_deregister(&audio_g711mlaw_misc); + mutex_destroy(&audio_g711_ws_mgr.ws_lock); +} + +device_initcall(audio_g711mlaw_init); +__exitcall(audio_g711mlaw_exit); diff --git a/drivers/misc/qcom/qdsp6v2/g711alaw_in.c b/drivers/misc/qcom/qdsp6v2/g711alaw_in.c new file mode 100644 index 000000000000..ac720b53ff5b --- /dev/null +++ b/drivers/misc/qcom/qdsp6v2/g711alaw_in.c @@ -0,0 +1,382 @@ +/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * +*/ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/msm_audio_g711.h> +#include <linux/atomic.h> +#include <linux/compat.h> +#include <asm/ioctls.h> +#include "audio_utils.h" + +/* Buffer with meta*/ +#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in)) + +/* Maximum 10 frames in buffer with meta */ +#define FRAME_SIZE (1 + ((320+sizeof(struct meta_out_dsp)) * 10)) +static long g711_in_ioctl_shared(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + int cnt = 0; + + switch (cmd) { + case AUDIO_START: { + struct msm_audio_g711_enc_config *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg; + pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__, + audio->ac->session, audio->buf_alloc); + if (audio->enabled == 1) { + rc = 0; + break; + } + rc = audio_in_buf_alloc(audio); + if (rc < 0) { + pr_err("%s:session id %d: buffer allocation failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + pr_debug("%s: sample rate %d", __func__, enc_cfg->sample_rate); + rc = q6asm_enc_cfg_blk_g711(audio->ac, + audio->buf_cfg.frames_per_buf, + enc_cfg->sample_rate); + + if (rc < 0) { + pr_err("%s:session id %d: cmd g711 media format block failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + if (audio->feedback == NON_TUNNEL_MODE) { + rc = q6asm_media_format_block_pcm(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count); + + if (rc < 0) { + pr_err("%s:session id %d: media format block failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + } + pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__, + audio->ac->session, audio->enabled); + rc = audio_in_enable(audio); + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + while (cnt++ < audio->str_cfg.buffer_count) + q6asm_read(audio->ac); /* Push buffer to DSP */ + rc = 0; + pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n", + __func__, audio->ac->session, audio->enabled); + break; + } + case AUDIO_STOP: { + pr_debug("%s:session id %d: AUDIO_STOP\n", __func__, + audio->ac->session); + rc = audio_in_disable(audio); + if (rc < 0) { + pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n", + __func__, audio->ac->session, + rc); + break; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG: { + struct msm_audio_g711_enc_config *cfg; + struct msm_audio_g711_enc_config *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg; + + cfg = (struct msm_audio_g711_enc_config *)arg; + if (cfg == NULL) { + pr_err("%s: NULL config pointer\n", __func__); + rc = -EINVAL; + break; + } + if (cfg->sample_rate != 8000 && + cfg->sample_rate != 16000) { + pr_err("%s:session id %d: invalid sample rate\n", + __func__, audio->ac->session); + rc = -EINVAL; + break; + } + enc_cfg->sample_rate = cfg->sample_rate; + pr_debug("%s:session id %d: sample_rate= 0x%x", + __func__, + audio->ac->session, enc_cfg->sample_rate); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} + +static long g711_in_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: + case AUDIO_STOP: { + rc = g711_in_ioctl_shared(file, cmd, arg); + break; + } + case AUDIO_GET_G711_ENC_CONFIG: { + if (copy_to_user((void *)arg, audio->enc_cfg, + sizeof(struct msm_audio_g711_enc_config))) { + pr_err( + "%s: copy_to_user for AUDIO_GET_g711_ENC_CONFIG failed", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG: { + struct msm_audio_g711_enc_config cfg; + + if (copy_from_user(&cfg, (void *) arg, + sizeof(cfg))) { + pr_err( + "%s: copy_from_user for AUDIO_GET_G711_ENC_CONFIG failed", + __func__); + rc = -EFAULT; + break; + } + rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg); + if (rc) + pr_err("%s:AUDIO_GET_G711_ENC_CONFIG failed. Rc= %d\n", + __func__, rc); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} + +#ifdef CONFIG_COMPAT +struct msm_audio_g711_enc_config32 { + uint32_t sample_rate; +}; + +enum { + AUDIO_SET_G711_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config32), + AUDIO_GET_G711_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config32) +}; + +static long g711_in_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: + case AUDIO_STOP: { + rc = g711_in_ioctl_shared(file, cmd, arg); + break; + } + case AUDIO_GET_G711_ENC_CONFIG_32: { + struct msm_audio_g711_enc_config32 cfg_32; + struct msm_audio_g711_enc_config32 *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config32 *)audio->enc_cfg; + cfg_32.sample_rate = enc_cfg->sample_rate; + if (copy_to_user((void *)arg, &cfg_32, + sizeof(cfg_32))) { + pr_err("%s: copy_to_user for AUDIO_GET_G711_ENC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG_32: { + struct msm_audio_g711_enc_config32 cfg_32; + struct msm_audio_g711_enc_config32 cfg; + + if (copy_from_user(&cfg_32, (void *) arg, + sizeof(cfg_32))) { + pr_err("%s: copy_from_user for AUDIO_SET_G711_ENC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + break; + } + cfg.sample_rate = cfg_32.sample_rate; + cmd = AUDIO_SET_G711_ENC_CONFIG; + rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg); + if (rc) + pr_err("%s:AUDIO_SET_G711_ENC_CONFIG failed. rc= %d\n", + __func__, rc); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} +#else +#define g711_in_compat_ioctl NULL +#endif + +static int g711_in_open(struct inode *inode, struct file *file) +{ + struct q6audio_in *audio = NULL; + struct msm_audio_g711_enc_config *enc_cfg; + int rc = 0; + + audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL); + + if (audio == NULL) + return -ENOMEM; + /* Allocate memory for encoder config param */ + audio->enc_cfg = kzalloc(sizeof(struct msm_audio_g711_enc_config), + GFP_KERNEL); + if (audio->enc_cfg == NULL) { + kfree(audio); + return -ENOMEM; + } + enc_cfg = audio->enc_cfg; + + mutex_init(&audio->lock); + mutex_init(&audio->read_lock); + mutex_init(&audio->write_lock); + spin_lock_init(&audio->dsp_lock); + init_waitqueue_head(&audio->read_wait); + init_waitqueue_head(&audio->write_wait); + + /* + * Settings will be re-config at AUDIO_SET_CONFIG, + * but at least we need to have initial config + */ + audio->str_cfg.buffer_size = FRAME_SIZE; + audio->str_cfg.buffer_count = FRAME_NUM; + audio->min_frame_size = 320; + audio->max_frames_per_buf = 10; + audio->pcm_cfg.buffer_size = PCM_BUF_SIZE; + audio->pcm_cfg.buffer_count = PCM_BUF_COUNT; + enc_cfg->sample_rate = 8000; + audio->pcm_cfg.channel_count = 1; + audio->pcm_cfg.sample_rate = 8000; + audio->buf_cfg.meta_info_enable = 0x01; + audio->buf_cfg.frames_per_buf = 0x01; + audio->event_abort = 0; + + audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb, + (void *)audio); + + if (!audio->ac) { + kfree(audio->enc_cfg); + kfree(audio); + return -ENOMEM; + } + + /* open g711 encoder in T/NT mode */ + if ((file->f_mode & FMODE_WRITE) && + (file->f_mode & FMODE_READ)) { + audio->feedback = NON_TUNNEL_MODE; + rc = q6asm_open_read_write(audio->ac, FORMAT_G711_ALAW_FS, + FORMAT_LINEAR_PCM); + if (rc < 0) { + pr_err("%s:session id %d: NT mode Open failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + } else if (!(file->f_mode & FMODE_WRITE) && + (file->f_mode & FMODE_READ)) { + audio->feedback = TUNNEL_MODE; + rc = q6asm_open_read(audio->ac, FORMAT_G711_ALAW_FS); + if (rc < 0) { + pr_err("%s:session id %d: T mode Open failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + /* register for tx overflow (valid for tunnel mode only) */ + rc = q6asm_reg_tx_overflow(audio->ac, 0x01); + if (rc < 0) { + pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + } else { + pr_err("%s:session id %d: Unexpected mode\n", __func__, + audio->ac->session); + rc = -EACCES; + goto fail; + } + + audio->opened = 1; + audio->reset_event = false; + atomic_set(&audio->in_count, PCM_BUF_COUNT); + atomic_set(&audio->out_count, 0x00); + audio->enc_compat_ioctl = g711_in_compat_ioctl; + audio->enc_ioctl = g711_in_ioctl; + file->private_data = audio; + + pr_info("%s:session id %d: success\n", __func__, audio->ac->session); + return 0; +fail: + q6asm_audio_client_free(audio->ac); + kfree(audio->enc_cfg); + kfree(audio); + return rc; +} + +static const struct file_operations audio_in_fops = { + .owner = THIS_MODULE, + .open = g711_in_open, + .release = audio_in_release, + .read = audio_in_read, + .write = audio_in_write, + .unlocked_ioctl = audio_in_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = audio_in_compat_ioctl, +#endif +}; + +struct miscdevice audio_g711alaw_in_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "msm_g711alaw_in", + .fops = &audio_in_fops, +}; + +static int __init g711alaw_in_init(void) +{ + return misc_register(&audio_g711alaw_in_misc); +} + +device_initcall(g711alaw_in_init); diff --git a/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c b/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c new file mode 100644 index 000000000000..6660f83683f8 --- /dev/null +++ b/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c @@ -0,0 +1,385 @@ +/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * +*/ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/msm_audio_g711.h> +#include <linux/atomic.h> +#include <linux/compat.h> +#include <asm/ioctls.h> +#include "audio_utils.h" + +#ifdef CONFIG_COMPAT +#undef PROC_ADD +#endif +/* Buffer with meta*/ +#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in)) + +/* Maximum 10 frames in buffer with meta */ +#define FRAME_SIZE (1 + ((320+sizeof(struct meta_out_dsp)) * 10)) +static long g711_in_ioctl_shared(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + int cnt = 0; + + switch (cmd) { + case AUDIO_START: { + struct msm_audio_g711_enc_config *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg; + pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__, + audio->ac->session, audio->buf_alloc); + if (audio->enabled == 1) { + rc = 0; + break; + } + rc = audio_in_buf_alloc(audio); + if (rc < 0) { + pr_err("%s:session id %d: buffer allocation failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + pr_debug("%s: sample rate %d", __func__, enc_cfg->sample_rate); + rc = q6asm_enc_cfg_blk_g711(audio->ac, + audio->buf_cfg.frames_per_buf, + enc_cfg->sample_rate); + + if (rc < 0) { + pr_err("%s:session id %d: cmd g711 media format block failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + if (audio->feedback == NON_TUNNEL_MODE) { + rc = q6asm_media_format_block_pcm(audio->ac, + audio->pcm_cfg.sample_rate, + audio->pcm_cfg.channel_count); + + if (rc < 0) { + pr_err("%s:session id %d: media format block failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + } + pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__, + audio->ac->session, audio->enabled); + rc = audio_in_enable(audio); + if (!rc) { + audio->enabled = 1; + } else { + audio->enabled = 0; + pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n", + __func__, audio->ac->session, rc); + break; + } + while (cnt++ < audio->str_cfg.buffer_count) + q6asm_read(audio->ac); /* Push buffer to DSP */ + rc = 0; + pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n", + __func__, audio->ac->session, audio->enabled); + break; + } + case AUDIO_STOP: { + pr_debug("%s:session id %d: AUDIO_STOP\n", __func__, + audio->ac->session); + rc = audio_in_disable(audio); + if (rc < 0) { + pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n", + __func__, audio->ac->session, + rc); + break; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG: { + struct msm_audio_g711_enc_config *cfg; + struct msm_audio_g711_enc_config *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg; + + cfg = (struct msm_audio_g711_enc_config *)arg; + if (cfg == NULL) { + pr_err("%s: NULL config pointer\n", __func__); + rc = -EINVAL; + break; + } + if (cfg->sample_rate != 8000 && + cfg->sample_rate != 16000) { + pr_err("%s:session id %d: invalid sample rate\n", + __func__, audio->ac->session); + rc = -EINVAL; + break; + } + enc_cfg->sample_rate = cfg->sample_rate; + pr_debug("%s:session id %d: sample_rate= 0x%x", + __func__, + audio->ac->session, enc_cfg->sample_rate); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} + +static long g711_in_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: + case AUDIO_STOP: { + rc = g711_in_ioctl_shared(file, cmd, arg); + break; + } + case AUDIO_GET_G711_ENC_CONFIG: { + if (copy_to_user((void *)arg, audio->enc_cfg, + sizeof(struct msm_audio_g711_enc_config))) { + pr_err( + "%s: copy_to_user for AUDIO_GET_g711_ENC_CONFIG failed", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG: { + struct msm_audio_g711_enc_config cfg; + + if (copy_from_user(&cfg, (void *) arg, + sizeof(cfg))) { + pr_err( + "%s: copy_from_user for AUDIO_GET_G711_ENC_CONFIG failed", + __func__); + rc = -EFAULT; + break; + } + rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg); + if (rc) + pr_err("%s:AUDIO_GET_G711_ENC_CONFIG failed. Rc= %d\n", + __func__, rc); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} + +#ifdef CONFIG_COMPAT +struct msm_audio_g711_enc_config32 { + uint32_t sample_rate; +}; + +enum { + AUDIO_SET_G711_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config32), + AUDIO_GET_G711_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC, + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config32) +}; + +static long g711_in_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6audio_in *audio = file->private_data; + int rc = 0; + + switch (cmd) { + case AUDIO_START: + case AUDIO_STOP: { + rc = g711_in_ioctl_shared(file, cmd, arg); + break; + } + case AUDIO_GET_G711_ENC_CONFIG_32: { + struct msm_audio_g711_enc_config32 cfg_32; + struct msm_audio_g711_enc_config32 *enc_cfg; + + enc_cfg = (struct msm_audio_g711_enc_config32 *)audio->enc_cfg; + cfg_32.sample_rate = enc_cfg->sample_rate; + if (copy_to_user((void *)arg, &cfg_32, + sizeof(cfg_32))) { + pr_err("%s: copy_to_user for AUDIO_GET_G711_ENC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + } + break; + } + case AUDIO_SET_G711_ENC_CONFIG_32: { + struct msm_audio_g711_enc_config32 cfg_32; + struct msm_audio_g711_enc_config32 cfg; + + if (copy_from_user(&cfg_32, (void *) arg, + sizeof(cfg_32))) { + pr_err("%s: copy_from_user for AUDIO_SET_G711_ENC_CONFIG_32 failed\n", + __func__); + rc = -EFAULT; + break; + } + cfg.sample_rate = cfg_32.sample_rate; + cmd = AUDIO_SET_G711_ENC_CONFIG; + rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg); + if (rc) + pr_err("%s:AUDIO_SET_G711_ENC_CONFIG failed. rc= %d\n", + __func__, rc); + break; + } + default: + pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd); + rc = -ENOIOCTLCMD; + } + return rc; +} +#else +#define g711_in_compat_ioctl NULL +#endif + +static int g711_in_open(struct inode *inode, struct file *file) +{ + struct q6audio_in *audio = NULL; + struct msm_audio_g711_enc_config *enc_cfg; + int rc = 0; + + audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL); + + if (audio == NULL) + return -ENOMEM; + /* Allocate memory for encoder config param */ + audio->enc_cfg = kzalloc(sizeof(struct msm_audio_g711_enc_config), + GFP_KERNEL); + if (audio->enc_cfg == NULL) { + kfree(audio); + return -ENOMEM; + } + enc_cfg = audio->enc_cfg; + + mutex_init(&audio->lock); + mutex_init(&audio->read_lock); + mutex_init(&audio->write_lock); + spin_lock_init(&audio->dsp_lock); + init_waitqueue_head(&audio->read_wait); + init_waitqueue_head(&audio->write_wait); + + /* + * Settings will be re-config at AUDIO_SET_CONFIG, + * but at least we need to have initial config + */ + audio->str_cfg.buffer_size = FRAME_SIZE; + audio->str_cfg.buffer_count = FRAME_NUM; + audio->min_frame_size = 320; + audio->max_frames_per_buf = 10; + audio->pcm_cfg.buffer_size = PCM_BUF_SIZE; + audio->pcm_cfg.buffer_count = PCM_BUF_COUNT; + enc_cfg->sample_rate = 8000; + audio->pcm_cfg.channel_count = 1; + audio->pcm_cfg.sample_rate = 8000; + audio->buf_cfg.meta_info_enable = 0x01; + audio->buf_cfg.frames_per_buf = 0x01; + audio->event_abort = 0; + + audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb, + (void *)audio); + + if (!audio->ac) { + kfree(audio->enc_cfg); + kfree(audio); + return -ENOMEM; + } + + /* open g711 encoder in T/NT mode */ + if ((file->f_mode & FMODE_WRITE) && + (file->f_mode & FMODE_READ)) { + audio->feedback = NON_TUNNEL_MODE; + rc = q6asm_open_read_write(audio->ac, FORMAT_G711_MLAW_FS, + FORMAT_LINEAR_PCM); + if (rc < 0) { + pr_err("%s:session id %d: NT mode Open failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + } else if (!(file->f_mode & FMODE_WRITE) && + (file->f_mode & FMODE_READ)) { + audio->feedback = TUNNEL_MODE; + rc = q6asm_open_read(audio->ac, FORMAT_G711_MLAW_FS); + if (rc < 0) { + pr_err("%s:session id %d: T mode Open failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + /* register for tx overflow (valid for tunnel mode only) */ + rc = q6asm_reg_tx_overflow(audio->ac, 0x01); + if (rc < 0) { + pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n", + __func__, audio->ac->session, rc); + rc = -ENODEV; + goto fail; + } + } else { + pr_err("%s:session id %d: Unexpected mode\n", __func__, + audio->ac->session); + rc = -EACCES; + goto fail; + } + + audio->opened = 1; + audio->reset_event = false; + atomic_set(&audio->in_count, PCM_BUF_COUNT); + atomic_set(&audio->out_count, 0x00); + audio->enc_compat_ioctl = g711_in_compat_ioctl; + audio->enc_ioctl = g711_in_ioctl; + file->private_data = audio; + + pr_info("%s:session id %d: success\n", __func__, audio->ac->session); + return 0; +fail: + q6asm_audio_client_free(audio->ac); + kfree(audio->enc_cfg); + kfree(audio); + return rc; +} + +static const struct file_operations audio_in_fops = { + .owner = THIS_MODULE, + .open = g711_in_open, + .release = audio_in_release, + .read = audio_in_read, + .write = audio_in_write, + .unlocked_ioctl = audio_in_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = audio_in_compat_ioctl, +#endif +}; + +struct miscdevice audio_g711mlaw_in_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "msm_g711mlaw_in", + .fops = &audio_in_fops, +}; + +static int __init g711mlaw_in_init(void) +{ + return misc_register(&audio_g711mlaw_in_misc); +} + +device_initcall(g711mlaw_in_init); diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 6eee4aa0e574..39cb46a5ce11 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3456,7 +3456,8 @@ static void mmc_blk_cmdq_err(struct mmc_queue *mq) struct mmc_request *mrq = host->err_mrq; struct mmc_cmdq_context_info *ctx_info = &host->cmdq_ctx; struct request_queue *q; - int err; + int err, ret; + u32 status = 0; mmc_host_clk_hold(host); host->cmdq_ops->dumpstate(host); @@ -3475,8 +3476,14 @@ static void mmc_blk_cmdq_err(struct mmc_queue *mq) /* RED error - Fatal: requires reset */ if (mrq->cmdq_req->resp_err) { err = mrq->cmdq_req->resp_err; - pr_crit("%s: Response error detected: Device in bad state\n", - mmc_hostname(host)); + if (mmc_host_halt(host) || mmc_host_cq_disable(host)) { + ret = get_card_status(host->card, &status, 0); + if (ret) + pr_err("%s: CMD13 failed with err %d\n", + mmc_hostname(host), ret); + } + pr_err("%s: Response error detected with device status 0x%08x\n", + mmc_hostname(host), status); goto reset; } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 828d2b85f6e4..6ad91042409e 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1552,6 +1552,12 @@ int mmc_cmdq_halt(struct mmc_host *host, bool halt) { int err = 0; + if (mmc_host_cq_disable(host)) { + pr_debug("%s: %s: CQE is already disabled\n", + mmc_hostname(host), __func__); + return 0; + } + if ((halt && mmc_host_halt(host)) || (!halt && !mmc_host_halt(host))) { pr_debug("%s: %s: CQE is already %s\n", mmc_hostname(host), diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 0e0a018f39be..52427815722b 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -863,8 +863,16 @@ skip_cqterri: * If CQE halt fails then, disable CQE * from processing any further requests */ - if (ret) + if (ret) { cmdq_disable_nosync(mmc, true); + /* + * Enable legacy interrupts as CQE halt has failed. + * This is needed to send legacy commands like status + * cmd as part of error handling work. + */ + if (cq_host->ops->clear_set_irqs) + cq_host->ops->clear_set_irqs(mmc, false); + } /* * CQE detected a reponse error from device diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0542ba51445f..886229317fea 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3157,7 +3157,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) do { if (host->mmc->card && mmc_card_cmdq(host->mmc->card) && - !mmc_host_halt(host->mmc)) { + !mmc_host_halt(host->mmc) && !mmc_host_cq_disable(host->mmc)) { pr_debug("*** %s: cmdq intr: 0x%08x\n", mmc_hostname(host->mmc), intmask); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 8676b35914e2..2101147e7d24 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -624,16 +624,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd)); - if (!ipa3_is_ready()) { - IPAERR("IPA not ready, waiting for init completion\n"); - wait_for_completion(&ipa3_ctx->init_completion_obj); - } - if (_IOC_TYPE(cmd) != IPA_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) >= IPA_IOCTL_MAX) return -ENOTTY; + if (!ipa3_is_ready()) { + IPAERR("IPA not ready, waiting for init completion\n"); + wait_for_completion(&ipa3_ctx->init_completion_obj); + } + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); switch (cmd) { diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 9ef57e5d7d64..9d9eed2d5d68 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -178,6 +178,9 @@ config USB_F_RNDIS config USB_F_QCRNDIS tristate +config USB_F_RMNET_BAM + tristate + config USB_F_MASS_STORAGE tristate @@ -345,6 +348,12 @@ config USB_CONFIGFS_RNDIS XP, you'll need to download drivers from Microsoft's website; a URL is given in comments found in that info file. +config USB_CONFIGFS_RMNET_BAM + bool "RMNET" + depends on USB_CONFIGFS + depends on IPA + select USB_F_RMNET_BAM + config USB_CONFIGFS_EEM bool "Ethernet Emulation Model (EEM)" depends on USB_CONFIGFS diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index a213cd4c8377..511909fb78f6 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -62,3 +62,5 @@ usb_f_qdss-y := f_qdss.o u_qdss.o obj-$(CONFIG_USB_F_QDSS) += usb_f_qdss.o usb_f_qcrndis-y := f_qc_rndis.o u_data_ipa.o obj-$(CONFIG_USB_F_QCRNDIS) += usb_f_qcrndis.o +usb_f_rmnet_bam-y := f_rmnet.o u_ctrl_qti.o +obj-$(CONFIG_USB_F_RMNET_BAM) += usb_f_rmnet_bam.o diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h index c4af5ac839cd..e3fe8ae03775 100644 --- a/drivers/usb/gadget/function/f_qdss.h +++ b/drivers/usb/gadget/function/f_qdss.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,6 +21,8 @@ #include <linux/usb/composite.h> #include <linux/usb/usb_qdss.h> +#include "u_rmnet.h" + struct usb_qdss_bam_connect_info { u32 usb_bam_pipe_idx; u32 peer_pipe_idx; @@ -33,8 +35,8 @@ struct gqdss { struct usb_ep *ctrl_out; struct usb_ep *ctrl_in; struct usb_ep *data; - int (*send_encap_cmd)(u8 port_num, void *buf, size_t len); - void (*notify_modem)(void *g, u8 port_num, int cbits); + int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len); + void (*notify_modem)(void *g, enum qti_port_type qport, int cbits); }; /* struct f_qdss - USB qdss function driver private structure */ diff --git a/drivers/usb/gadget/function/f_rmnet.c b/drivers/usb/gadget/function/f_rmnet.c index d84b55cef666..0fd7e213ef99 100644 --- a/drivers/usb/gadget/function/f_rmnet.c +++ b/drivers/usb/gadget/function/f_rmnet.c @@ -17,16 +17,11 @@ #include <linux/netdevice.h> #include <linux/spinlock.h> #include <linux/usb_bam.h> +#include <linux/module.h> -#include "usb_gadget_xport.h" -#include "u_ether.h" #include "u_rmnet.h" -#include "gadget_chips.h" - -static unsigned int rmnet_dl_max_pkt_per_xfer = 7; -module_param(rmnet_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rmnet_dl_max_pkt_per_xfer, - "Maximum packets per transfer for DL aggregation"); +#include "u_data_ipa.h" +#include "configfs.h" #define RMNET_NOTIFY_INTERVAL 5 #define RMNET_MAX_NOTIFY_SIZE sizeof(struct usb_cdc_notification) @@ -38,10 +33,9 @@ MODULE_PARM_DESC(rmnet_dl_max_pkt_per_xfer, * control paths */ struct f_rmnet { - struct gether gether_port; + struct usb_function func; struct grmnet port; int ifc_id; - u8 port_num; atomic_t online; atomic_t ctrl_online; struct usb_composite_dev *cdev; @@ -53,30 +47,11 @@ struct f_rmnet { struct usb_request *notify_req; /* control info */ + struct gadget_ipa_port ipa_port; struct list_head cpkt_resp_q; unsigned long notify_count; unsigned long cpkts_len; - const struct usb_endpoint_descriptor *in_ep_desc_backup; - const struct usb_endpoint_descriptor *out_ep_desc_backup; -}; - -static unsigned int nr_rmnet_ports; -static unsigned int no_ctrl_smd_ports; -static unsigned int no_ctrl_qti_ports; -static unsigned int no_ctrl_hsic_ports; -static unsigned int no_ctrl_hsuart_ports; -static unsigned int no_data_bam_ports; -static unsigned int no_data_bam2bam_ports; -static unsigned int no_data_hsic_ports; -static unsigned int no_data_hsuart_ports; -static struct rmnet_ports { - enum transport_type data_xport; - enum transport_type ctrl_xport; - unsigned data_xport_num; - unsigned ctrl_xport_num; - unsigned port_num; - struct f_rmnet *port; -} rmnet_ports[NR_RMNET_PORTS]; +} *rmnet_port; static struct usb_interface_descriptor rmnet_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, @@ -244,7 +219,7 @@ static void frmnet_ctrl_response_available(struct f_rmnet *dev); static inline struct f_rmnet *func_to_rmnet(struct usb_function *f) { - return container_of(f, struct f_rmnet, gether_port.func); + return container_of(f, struct f_rmnet, func); } static inline struct f_rmnet *port_to_rmnet(struct grmnet *r) @@ -253,8 +228,7 @@ static inline struct f_rmnet *port_to_rmnet(struct grmnet *r) } static struct usb_request * -frmnet_alloc_req(struct usb_ep *ep, unsigned len, size_t extra_buf_alloc, - gfp_t flags) +frmnet_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags) { struct usb_request *req; @@ -262,7 +236,7 @@ frmnet_alloc_req(struct usb_ep *ep, unsigned len, size_t extra_buf_alloc, if (!req) return ERR_PTR(-ENOMEM); - req->buf = kmalloc(len + extra_buf_alloc, flags); + req->buf = kmalloc(len, flags); if (!req->buf) { usb_ep_free_request(ep, req); return ERR_PTR(-ENOMEM); @@ -305,198 +279,42 @@ static void rmnet_free_ctrl_pkt(struct rmnet_ctrl_pkt *pkt) /* -------------------------------------------*/ -static int rmnet_gport_setup(void) -{ - int ret; - int port_idx; - int i; - u8 base; - - pr_debug("%s: bam ports:%u bam2bam ports:%u data hsic ports:%u\n", - __func__, no_data_bam_ports, no_data_bam2bam_ports, - no_data_hsic_ports); - - pr_debug("%s: data hsuart ports:%u smd ports:%u ctrl hsic ports:%u\n", - __func__, no_data_hsuart_ports, no_ctrl_smd_ports, - no_ctrl_hsic_ports); - - pr_debug("%s: ctrl hsuart ports:%u nr_rmnet_ports:%u\n", - __func__, no_ctrl_hsuart_ports, nr_rmnet_ports); - - if (no_data_bam_ports) { - ret = gbam_setup(no_data_bam_ports); - if (ret < 0) - return ret; - } - - if (no_data_bam2bam_ports) { - ret = gbam2bam_setup(no_data_bam2bam_ports); - if (ret < 0) - return ret; - } - - if (no_ctrl_smd_ports) { - ret = gsmd_ctrl_setup(FRMNET_CTRL_CLIENT, - no_ctrl_smd_ports, &base); - if (ret) - return ret; - for (i = 0; i < nr_rmnet_ports; i++) - if (rmnet_ports[i].port) - rmnet_ports[i].port->port_num += base; - } - - if (no_data_hsic_ports) { - port_idx = ghsic_data_setup(no_data_hsic_ports, - USB_GADGET_RMNET); - if (port_idx < 0) - return port_idx; - for (i = 0; i < nr_rmnet_ports; i++) { - if (rmnet_ports[i].data_xport == - USB_GADGET_XPORT_HSIC) { - rmnet_ports[i].data_xport_num = port_idx; - port_idx++; - } - } - } - - if (no_ctrl_hsic_ports) { - port_idx = ghsic_ctrl_setup(no_ctrl_hsic_ports, - USB_GADGET_RMNET); - if (port_idx < 0) - return port_idx; - for (i = 0; i < nr_rmnet_ports; i++) { - if (rmnet_ports[i].ctrl_xport == - USB_GADGET_XPORT_HSIC) { - rmnet_ports[i].ctrl_xport_num = port_idx; - port_idx++; - } - } - } - - return 0; -} - static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf) { int ret; - unsigned port_num; - enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport; - enum transport_type dxport = rmnet_ports[dev->port_num].data_xport; int src_connection_idx = 0, dst_connection_idx = 0; struct usb_gadget *gadget = dev->cdev->gadget; enum usb_ctrl usb_bam_type; - void *net; - - pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n", - __func__, xport_to_str(cxport), xport_to_str(dxport), - dev, dev->port_num); - port_num = rmnet_ports[dev->port_num].ctrl_xport_num; - switch (cxport) { - case USB_GADGET_XPORT_SMD: - ret = gsmd_ctrl_connect(&dev->port, port_num); - if (ret) { - pr_err("%s: gsmd_ctrl_connect failed: err:%d\n", - __func__, ret); - return ret; - } - break; - case USB_GADGET_XPORT_QTI: - ret = gqti_ctrl_connect(&dev->port, port_num, dev->ifc_id, - dxport, USB_GADGET_RMNET); - if (ret) { - pr_err("%s: gqti_ctrl_connect failed: err:%d\n", - __func__, ret); - return ret; - } - break; - case USB_GADGET_XPORT_HSIC: - ret = ghsic_ctrl_connect(&dev->port, port_num); - if (ret) { - pr_err("%s: ghsic_ctrl_connect failed: err:%d\n", - __func__, ret); - return ret; - } - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(cxport)); - return -ENODEV; + ret = gqti_ctrl_connect(&dev->port, QTI_PORT_RMNET, dev->ifc_id); + if (ret) { + pr_err("%s: gqti_ctrl_connect failed: err:%d\n", + __func__, ret); + return ret; } - port_num = rmnet_ports[dev->port_num].data_xport_num; - - switch (dxport) { - case USB_GADGET_XPORT_BAM_DMUX: - ret = gbam_connect(&dev->port, port_num, - dxport, src_connection_idx, dst_connection_idx); - if (ret) { - pr_err("%s: gbam_connect failed: err:%d\n", - __func__, ret); - gsmd_ctrl_disconnect(&dev->port, port_num); - return ret; - } - break; - case USB_GADGET_XPORT_BAM2BAM_IPA: - usb_bam_type = usb_bam_get_bam_type(gadget->name); - src_connection_idx = usb_bam_get_connection_idx(usb_bam_type, - IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, - port_num); - dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type, - IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, - port_num); - if (dst_connection_idx < 0 || src_connection_idx < 0) { - pr_err("%s: usb_bam_get_connection_idx failed\n", - __func__); - gsmd_ctrl_disconnect(&dev->port, port_num); - return -EINVAL; - } - ret = gbam_connect(&dev->port, port_num, - dxport, src_connection_idx, dst_connection_idx); - if (ret) { - pr_err("%s: gbam_connect failed: err:%d\n", - __func__, ret); - if (cxport == USB_GADGET_XPORT_QTI) - gqti_ctrl_disconnect(&dev->port, port_num); - else - gsmd_ctrl_disconnect(&dev->port, port_num); - return ret; - } - break; - case USB_GADGET_XPORT_HSIC: - ret = ghsic_data_connect(&dev->port, port_num); - if (ret) { - pr_err("%s: ghsic_data_connect failed: err:%d\n", - __func__, ret); - ghsic_ctrl_disconnect(&dev->port, port_num); - return ret; - } - break; - case USB_GADGET_XPORT_ETHER: - gether_enable_sg(&dev->gether_port, true); - net = gether_connect(&dev->gether_port); - if (IS_ERR(net)) { - pr_err("%s: gether_connect failed: err:%ld\n", - __func__, PTR_ERR(net)); - if (cxport == USB_GADGET_XPORT_QTI) - gqti_ctrl_disconnect(&dev->port, port_num); - else - gsmd_ctrl_disconnect(&dev->port, port_num); - - return PTR_ERR(net); - } - gether_update_dl_max_pkts_per_xfer(&dev->gether_port, - rmnet_dl_max_pkt_per_xfer); - gether_update_dl_max_xfer_size(&dev->gether_port, 16384); - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(dxport)); - return -ENODEV; + dev->ipa_port.cdev = dev->cdev; + ipa_data_port_select(USB_IPA_FUNC_RMNET); + usb_bam_type = usb_bam_get_bam_type(gadget->name); + src_connection_idx = usb_bam_get_connection_idx(usb_bam_type, + IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, + QTI_PORT_RMNET); + dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type, + IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, + QTI_PORT_RMNET); + if (dst_connection_idx < 0 || src_connection_idx < 0) { + pr_err("%s: usb_bam_get_connection_idx failed\n", + __func__); + gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); + return -EINVAL; + } + ret = ipa_data_connect(&dev->ipa_port, USB_IPA_FUNC_RMNET, + src_connection_idx, dst_connection_idx); + if (ret) { + pr_err("%s: ipa_data_connect failed: err:%d\n", + __func__, ret); + gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); + return ret; } return 0; @@ -504,61 +322,26 @@ static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf) static int gport_rmnet_disconnect(struct f_rmnet *dev) { - unsigned port_num; - enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport; - enum transport_type dxport = rmnet_ports[dev->port_num].data_xport; - - pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n", - __func__, xport_to_str(cxport), xport_to_str(dxport), - dev, dev->port_num); - - port_num = rmnet_ports[dev->port_num].ctrl_xport_num; - switch (cxport) { - case USB_GADGET_XPORT_SMD: - gsmd_ctrl_disconnect(&dev->port, port_num); - break; - case USB_GADGET_XPORT_QTI: - gqti_ctrl_disconnect(&dev->port, port_num); - break; - case USB_GADGET_XPORT_HSIC: - ghsic_ctrl_disconnect(&dev->port, port_num); - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(cxport)); - return -ENODEV; - } + gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); + ipa_data_disconnect(&dev->ipa_port, USB_IPA_FUNC_RMNET); + return 0; +} - port_num = rmnet_ports[dev->port_num].data_xport_num; - switch (dxport) { - case USB_GADGET_XPORT_BAM_DMUX: - case USB_GADGET_XPORT_BAM2BAM_IPA: - gbam_disconnect(&dev->port, port_num, dxport); - break; - case USB_GADGET_XPORT_HSIC: - ghsic_data_disconnect(&dev->port, port_num); - break; - case USB_GADGET_XPORT_ETHER: - gether_disconnect(&dev->gether_port); - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(dxport)); - return -ENODEV; - } +static void frmnet_free(struct usb_function *f) +{ + struct f_rmnet_opts *opts; - return 0; + opts = container_of(f->fi, struct f_rmnet_opts, func_inst); + opts->refcnt--; + kfree(rmnet_port); + rmnet_port = NULL; } static void frmnet_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_rmnet *dev = func_to_rmnet(f); - pr_debug("%s: portno:%d\n", __func__, dev->port_num); + pr_debug("%s: start unbinding\n", __func__); if (gadget_is_superspeed(c->cdev->gadget)) usb_free_descriptors(f->ss_descriptors); if (gadget_is_dualspeed(c->cdev->gadget)) @@ -575,8 +358,7 @@ static void frmnet_purge_responses(struct f_rmnet *dev) unsigned long flags; struct rmnet_ctrl_pkt *cpkt; - pr_debug("%s: port#%d\n", __func__, dev->port_num); - + pr_debug("%s: Purging responses\n", __func__); spin_lock_irqsave(&dev->lock, flags); while (!list_empty(&dev->cpkt_resp_q)) { cpkt = list_first_entry(&dev->cpkt_resp_q, @@ -591,117 +373,46 @@ static void frmnet_purge_responses(struct f_rmnet *dev) static void frmnet_suspend(struct usb_function *f) { - struct f_rmnet *dev = func_to_rmnet(f); - unsigned port_num; - enum transport_type dxport = rmnet_ports[dev->port_num].data_xport; - bool remote_wakeup_allowed; + struct f_rmnet *dev = func_to_rmnet(f); + bool remote_wakeup_allowed; if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; - pr_debug("%s: data xport: %s dev: %p portno: %d remote_wakeup: %d\n", - __func__, xport_to_str(dxport), - dev, dev->port_num, remote_wakeup_allowed); + pr_debug("%s: dev: %p remote_wakeup: %d\n", + __func__, dev, remote_wakeup_allowed); usb_ep_fifo_flush(dev->notify); frmnet_purge_responses(dev); - port_num = rmnet_ports[dev->port_num].data_xport_num; - switch (dxport) { - case USB_GADGET_XPORT_BAM_DMUX: - break; - case USB_GADGET_XPORT_BAM2BAM_IPA: - if (remote_wakeup_allowed) { - gbam_suspend(&dev->port, port_num, dxport); - } else { - /* - * When remote wakeup is disabled, IPA is disconnected - * because it cannot send new data until the USB bus is - * resumed. Endpoint descriptors info is saved before it - * gets reset by the BAM disconnect API. This lets us - * restore this info when the USB bus is resumed. - */ - dev->in_ep_desc_backup = dev->port.in->desc; - dev->out_ep_desc_backup = dev->port.out->desc; - pr_debug("in_ep_desc_bkup = %p, out_ep_desc_bkup = %p", - dev->in_ep_desc_backup, dev->out_ep_desc_backup); - pr_debug("%s(): Disconnecting\n", __func__); - gport_rmnet_disconnect(dev); - } - break; - case USB_GADGET_XPORT_HSIC: - break; - case USB_GADGET_XPORT_HSUART: - break; - case USB_GADGET_XPORT_ETHER: - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(dxport)); - } + ipa_data_suspend(&dev->ipa_port, USB_IPA_FUNC_RMNET, + remote_wakeup_allowed); } static void frmnet_resume(struct usb_function *f) { - struct f_rmnet *dev = func_to_rmnet(f); - unsigned port_num; - enum transport_type dxport = rmnet_ports[dev->port_num].data_xport; - int ret; - bool remote_wakeup_allowed; + struct f_rmnet *dev = func_to_rmnet(f); + bool remote_wakeup_allowed; if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; - pr_debug("%s: data xport: %s dev: %p portno: %d remote_wakeup: %d\n", - __func__, xport_to_str(dxport), - dev, dev->port_num, remote_wakeup_allowed); + pr_debug("%s: dev: %p remote_wakeup: %d\n", + __func__, dev, remote_wakeup_allowed); - port_num = rmnet_ports[dev->port_num].data_xport_num; - switch (dxport) { - case USB_GADGET_XPORT_BAM_DMUX: - break; - case USB_GADGET_XPORT_BAM2BAM_IPA: - if (remote_wakeup_allowed) { - gbam_resume(&dev->port, port_num, dxport); - } else { - dev->port.in->desc = dev->in_ep_desc_backup; - dev->port.out->desc = dev->out_ep_desc_backup; - pr_debug("%s(): Connecting\n", __func__); - ret = gport_rmnet_connect(dev, dev->ifc_id); - if (ret) { - pr_err("%s: gport_rmnet_connect failed: err:%d\n", - __func__, ret); - } - } - break; - case USB_GADGET_XPORT_HSIC: - break; - case USB_GADGET_XPORT_HSUART: - break; - case USB_GADGET_XPORT_ETHER: - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %s\n", __func__, - xport_to_str(dxport)); - } + ipa_data_resume(&dev->ipa_port, USB_IPA_FUNC_RMNET, + remote_wakeup_allowed); } static void frmnet_disable(struct usb_function *f) { - struct f_rmnet *dev = func_to_rmnet(f); - enum transport_type dxport = rmnet_ports[dev->port_num].data_xport; - struct usb_composite_dev *cdev = dev->cdev; - - pr_debug("%s: port#%d\n", __func__, dev->port_num); + struct f_rmnet *dev = func_to_rmnet(f); + pr_debug("%s: Disabling\n", __func__); usb_ep_disable(dev->notify); dev->notify->driver_data = NULL; @@ -709,11 +420,8 @@ static void frmnet_disable(struct usb_function *f) frmnet_purge_responses(dev); - if (dxport == USB_GADGET_XPORT_BAM2BAM_IPA && - gadget_is_dwc3(cdev->gadget)) { - msm_ep_unconfig(dev->port.out); - msm_ep_unconfig(dev->port.in); - } + msm_ep_unconfig(dev->ipa_port.out); + msm_ep_unconfig(dev->ipa_port.in); gport_rmnet_disconnect(dev); } @@ -721,14 +429,14 @@ static int frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_rmnet *dev = func_to_rmnet(f); - struct usb_composite_dev *cdev = dev->cdev; + struct usb_composite_dev *cdev = f->config->cdev; int ret; - struct list_head *cpkt; - - pr_debug("%s:dev:%p port#%d\n", __func__, dev, dev->port_num); + struct list_head *cpkt; + pr_debug("%s: dev: %p\n", __func__, dev); + dev->cdev = cdev; if (dev->notify->driver_data) { - pr_debug("%s: reset port:%d\n", __func__, dev->port_num); + pr_debug("%s: reset port\n", __func__); usb_ep_disable(dev->notify); } @@ -749,14 +457,14 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } dev->notify->driver_data = dev; - if (!dev->port.in->desc || !dev->port.out->desc) { - if (config_ep_by_speed(cdev->gadget, f, dev->port.in) || - config_ep_by_speed(cdev->gadget, f, dev->port.out)) { + if (!dev->ipa_port.in->desc || !dev->ipa_port.out->desc) { + if (config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in) || + config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) { pr_err("%s(): config_ep_by_speed failed.\n", __func__); ret = -EINVAL; goto err_disable_ep; } - dev->port.gadget = dev->cdev->gadget; + dev->ipa_port.cdev = dev->cdev; } ret = gport_rmnet_connect(dev, intf); @@ -777,8 +485,8 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) return ret; err_disable_ep: - dev->port.in->desc = NULL; - dev->port.out->desc = NULL; + dev->ipa_port.in->desc = NULL; + dev->ipa_port.out->desc = NULL; usb_ep_disable(dev->notify); return ret; @@ -790,10 +498,9 @@ static void frmnet_ctrl_response_available(struct f_rmnet *dev) struct usb_cdc_notification *event; unsigned long flags; int ret; - struct rmnet_ctrl_pkt *cpkt; - - pr_debug("%s:dev:%p portno#%d\n", __func__, dev, dev->port_num); + struct rmnet_ctrl_pkt *cpkt; + pr_debug("%s: dev: %p\n", __func__, dev); spin_lock_irqsave(&dev->lock, flags); if (!atomic_read(&dev->online) || !req || !req->buf) { spin_unlock_irqrestore(&dev->lock, flags); @@ -913,8 +620,7 @@ frmnet_send_cpkt_response(void *gr, void *buf, size_t len) dev = port_to_rmnet(gr); - pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num); - + pr_debug("%s: dev: %p\n", __func__, dev); if (!atomic_read(&dev->online) || !atomic_read(&dev->ctrl_online)) { rmnet_free_ctrl_pkt(cpkt); return 0; @@ -934,32 +640,27 @@ frmnet_cmd_complete(struct usb_ep *ep, struct usb_request *req) { struct f_rmnet *dev = req->context; struct usb_composite_dev *cdev; - unsigned port_num; if (!dev) { pr_err("%s: rmnet dev is null\n", __func__); return; } - - pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num); - + pr_debug("%s: dev: %p\n", __func__, dev); cdev = dev->cdev; if (dev->port.send_encap_cmd) { - port_num = rmnet_ports[dev->port_num].ctrl_xport_num; - dev->port.send_encap_cmd(port_num, req->buf, req->actual); + dev->port.send_encap_cmd(QTI_PORT_RMNET, req->buf, req->actual); } } static void frmnet_notify_complete(struct usb_ep *ep, struct usb_request *req) { - struct f_rmnet *dev = req->context; - int status = req->status; + struct f_rmnet *dev = req->context; + int status = req->status; unsigned long flags; struct rmnet_ctrl_pkt *cpkt; - pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num); - + pr_debug("%s: dev: %p\n", __func__, dev); switch (status) { case -ECONNRESET: case -ESHUTDOWN: @@ -1021,14 +722,12 @@ frmnet_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) struct f_rmnet *dev = func_to_rmnet(f); struct usb_composite_dev *cdev = dev->cdev; struct usb_request *req = cdev->req; - unsigned port_num; u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); int ret = -EOPNOTSUPP; - pr_debug("%s:dev:%p port#%d\n", __func__, dev, dev->port_num); - + pr_debug("%s: dev: %p\n", __func__, dev); if (!atomic_read(&dev->online)) { pr_warn("%s: usb cable is not connected\n", __func__); return -ENOTCONN; @@ -1085,8 +784,8 @@ frmnet_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) pr_debug("%s: USB_CDC_REQ_SET_CONTROL_LINE_STATE: DTR:%d\n", __func__, w_value & ACM_CTRL_DTR ? 1 : 0); if (dev->port.notify_modem) { - port_num = rmnet_ports[dev->port_num].ctrl_xport_num; - dev->port.notify_modem(&dev->port, port_num, w_value); + dev->port.notify_modem(&dev->port, + QTI_PORT_RMNET, w_value); } ret = 0; @@ -1121,6 +820,16 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; int ret = -ENODEV; + if (rmnet_string_defs[0].id == 0) { + ret = usb_string_id(c->cdev); + if (ret < 0) { + pr_err("%s: failed to get string id, err:%d\n", + __func__, ret); + return ret; + } + rmnet_string_defs[0].id = ret; + } + pr_debug("%s: start binding\n", __func__); dev->ifc_id = usb_interface_id(c, f); if (dev->ifc_id < 0) { @@ -1135,9 +844,7 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) pr_err("%s: usb epin autoconfig failed\n", __func__); return -ENODEV; } - dev->port.in = ep; - /* Update same for u_ether which uses gether port struct */ - dev->gether_port.in_ep = ep; + dev->ipa_port.in = ep; ep->driver_data = cdev; ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_out_desc); @@ -1146,9 +853,7 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) ret = -ENODEV; goto ep_auto_out_fail; } - dev->port.out = ep; - /* Update same for u_ether which uses gether port struct */ - dev->gether_port.out_ep = ep; + dev->ipa_port.out = ep; ep->driver_data = cdev; ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_notify_desc); @@ -1162,7 +867,6 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) dev->notify_req = frmnet_alloc_req(ep, sizeof(struct usb_cdc_notification), - cdev->gadget->extra_buf_alloc, GFP_KERNEL); if (IS_ERR(dev->notify_req)) { pr_err("%s: unable to allocate memory for notify req\n", @@ -1218,10 +922,9 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) } } - pr_debug("%s: RmNet(%d) %s Speed, IN:%s OUT:%s\n", - __func__, dev->port_num, - gadget_is_dualspeed(cdev->gadget) ? "dual" : "full", - dev->port.in->name, dev->port.out->name); + pr_debug("%s: RmNet %s Speed, IN:%s OUT:%s\n", + __func__, gadget_is_dualspeed(cdev->gadget) ? "dual" : "full", + dev->ipa_port.in->name, dev->ipa_port.out->name); return 0; @@ -1238,67 +941,35 @@ ep_notify_alloc_fail: dev->notify->driver_data = NULL; dev->notify = NULL; ep_auto_notify_fail: - dev->port.out->driver_data = NULL; - dev->port.out = NULL; + dev->ipa_port.out->driver_data = NULL; + dev->ipa_port.out = NULL; ep_auto_out_fail: - dev->port.in->driver_data = NULL; - dev->port.in = NULL; + dev->ipa_port.in->driver_data = NULL; + dev->ipa_port.in = NULL; return ret; } -static int frmnet_bind_config(struct usb_configuration *c, unsigned portno) +static struct usb_function *frmnet_bind_config(struct usb_function_instance *fi) { + struct f_rmnet_opts *opts; int status; struct f_rmnet *dev; struct usb_function *f; unsigned long flags; - pr_debug("%s: usb config:%p\n", __func__, c); - - if (portno >= nr_rmnet_ports) { - pr_err("%s: supporting ports#%u port_id:%u\n", __func__, - nr_rmnet_ports, portno); - return -ENODEV; - } - - dev = rmnet_ports[portno].port; - - if (rmnet_ports[portno].data_xport == USB_GADGET_XPORT_ETHER) { - struct net_device *net = gether_setup_name_default("usb_rmnet"); - - if (IS_ERR(net)) { - pr_err("%s: gether_setup failed\n", __func__); - return PTR_ERR(net); - } - dev->gether_port.ioport = netdev_priv(net); - gether_set_gadget(net, c->cdev->gadget); - status = gether_register_netdev(net); - if (status < 0) { - pr_err("%s: gether_register_netdev failed\n", __func__); - free_netdev(net); - return status; - } - } - - if (rmnet_string_defs[0].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) { - pr_err("%s: failed to get string id, err:%d\n", - __func__, status); - return status; - } - rmnet_string_defs[0].id = status; - } - + /* allocate and initialize one new instance */ + status = -ENOMEM; + opts = container_of(fi, struct f_rmnet_opts, func_inst); + opts->refcnt++; + dev = opts->dev; spin_lock_irqsave(&dev->lock, flags); - dev->cdev = c->cdev; - f = &dev->gether_port.func; - f->name = kasprintf(GFP_ATOMIC, "rmnet%d", portno); + f = &dev->func; + f->name = kasprintf(GFP_ATOMIC, "rmnet%d", 0); spin_unlock_irqrestore(&dev->lock, flags); if (!f->name) { pr_err("%s: cannot allocate memory for name\n", __func__); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } f->strings = rmnet_strings; @@ -1309,166 +980,123 @@ static int frmnet_bind_config(struct usb_configuration *c, unsigned portno) f->setup = frmnet_setup; f->suspend = frmnet_suspend; f->resume = frmnet_resume; + f->free_func = frmnet_free; dev->port.send_cpkt_response = frmnet_send_cpkt_response; dev->port.disconnect = frmnet_disconnect; dev->port.connect = frmnet_connect; - dev->gether_port.cdc_filter = 0; - - status = usb_add_function(c, f); - if (status) { - pr_err("%s: usb add function failed: %d\n", - __func__, status); - kfree(f->name); - return status; - } pr_debug("%s: complete\n", __func__); - return status; + return f; } -static void frmnet_unbind_config(void) +static int rmnet_init(void) { - int i; + return gqti_ctrl_init(); +} - for (i = 0; i < nr_rmnet_ports; i++) - if (rmnet_ports[i].data_xport == USB_GADGET_XPORT_ETHER) { - gether_cleanup(rmnet_ports[i].port->gether_port.ioport); - rmnet_ports[i].port->gether_port.ioport = NULL; - } +static void frmnet_cleanup(void) +{ + gqti_ctrl_cleanup(); } -static int rmnet_init(void) +static void rmnet_free_inst(struct usb_function_instance *f) { - return gqti_ctrl_init(); + struct f_rmnet_opts *opts = container_of(f, struct f_rmnet_opts, + func_inst); + ipa_data_free(USB_IPA_FUNC_RMNET); + kfree(opts); } -static void frmnet_cleanup(void) +static int rmnet_set_inst_name(struct usb_function_instance *fi, + const char *name) { - int i; + int name_len; + int ret; - gqti_ctrl_cleanup(); + name_len = strlen(name) + 1; + if (name_len > MAX_INST_NAME_LEN) + return -ENAMETOOLONG; - for (i = 0; i < nr_rmnet_ports; i++) - kfree(rmnet_ports[i].port); - - gbam_cleanup(); - nr_rmnet_ports = 0; - no_ctrl_smd_ports = 0; - no_ctrl_qti_ports = 0; - no_data_bam_ports = 0; - no_data_bam2bam_ports = 0; - no_ctrl_hsic_ports = 0; - no_data_hsic_ports = 0; - no_ctrl_hsuart_ports = 0; - no_data_hsuart_ports = 0; + ret = ipa_data_setup(USB_IPA_FUNC_RMNET); + return ret; } -static int frmnet_init_port(const char *ctrl_name, const char *data_name, - const char *port_name) +static inline struct f_rmnet_opts *to_f_rmnet_opts(struct config_item *item) { - struct f_rmnet *dev; - struct rmnet_ports *rmnet_port; - int ret; - int i; + return container_of(to_config_group(item), struct f_rmnet_opts, + func_inst.group); +} - if (nr_rmnet_ports >= NR_RMNET_PORTS) { - pr_err("%s: Max-%d instances supported\n", - __func__, NR_RMNET_PORTS); - return -EINVAL; - } +static void rmnet_opts_release(struct config_item *item) +{ + struct f_rmnet_opts *opts = to_f_rmnet_opts(item); - pr_debug("%s: port#:%d, ctrl port: %s data port: %s\n", - __func__, nr_rmnet_ports, ctrl_name, data_name); + usb_put_function_instance(&opts->func_inst); +}; - dev = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL); - if (!dev) - return -ENOMEM; +static struct configfs_item_operations rmnet_item_ops = { + .release = rmnet_opts_release, +}; - dev->port_num = nr_rmnet_ports; - spin_lock_init(&dev->lock); - INIT_LIST_HEAD(&dev->cpkt_resp_q); +static struct config_item_type rmnet_func_type = { + .ct_item_ops = &rmnet_item_ops, + .ct_owner = THIS_MODULE, +}; - rmnet_port = &rmnet_ports[nr_rmnet_ports]; - rmnet_port->port = dev; - rmnet_port->port_num = nr_rmnet_ports; - rmnet_port->ctrl_xport = str_to_xport(ctrl_name); - rmnet_port->data_xport = str_to_xport(data_name); +static struct usb_function_instance *rmnet_alloc_inst(void) +{ + struct f_rmnet_opts *opts; - switch (rmnet_port->ctrl_xport) { - case USB_GADGET_XPORT_SMD: - rmnet_port->ctrl_xport_num = no_ctrl_smd_ports; - no_ctrl_smd_ports++; - break; - case USB_GADGET_XPORT_QTI: - rmnet_port->ctrl_xport_num = no_ctrl_qti_ports; - no_ctrl_qti_ports++; - break; - case USB_GADGET_XPORT_HSIC: - ghsic_ctrl_set_port_name(port_name, ctrl_name); - rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports; - no_ctrl_hsic_ports++; - break; - case USB_GADGET_XPORT_HSUART: - rmnet_port->ctrl_xport_num = no_ctrl_hsuart_ports; - no_ctrl_hsuart_ports++; - break; - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %u\n", __func__, - rmnet_port->ctrl_xport); - ret = -ENODEV; - goto fail_probe; - } + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); - switch (rmnet_port->data_xport) { - case USB_GADGET_XPORT_BAM2BAM: - /* Override BAM2BAM to BAM_DMUX for old ABI compatibility */ - rmnet_port->data_xport = USB_GADGET_XPORT_BAM_DMUX; - /* fall-through */ - case USB_GADGET_XPORT_BAM_DMUX: - rmnet_port->data_xport_num = no_data_bam_ports; - no_data_bam_ports++; - break; - case USB_GADGET_XPORT_BAM2BAM_IPA: - rmnet_port->data_xport_num = no_data_bam2bam_ports; - no_data_bam2bam_ports++; - break; - case USB_GADGET_XPORT_HSIC: - ghsic_data_set_port_name(port_name, data_name); - rmnet_port->data_xport_num = no_data_hsic_ports; - no_data_hsic_ports++; - break; - case USB_GADGET_XPORT_HSUART: - rmnet_port->data_xport_num = no_data_hsuart_ports; - no_data_hsuart_ports++; - break; - case USB_GADGET_XPORT_ETHER: - case USB_GADGET_XPORT_NONE: - break; - default: - pr_err("%s: Un-supported transport: %u\n", __func__, - rmnet_port->data_xport); - ret = -ENODEV; - goto fail_probe; - } - nr_rmnet_ports++; + opts->func_inst.set_inst_name = rmnet_set_inst_name; + opts->func_inst.free_func_inst = rmnet_free_inst; - return 0; + config_group_init_type_name(&opts->func_inst.group, "", + &rmnet_func_type); + return &opts->func_inst; +} + +static struct usb_function *rmnet_alloc(struct usb_function_instance *fi) +{ + struct f_rmnet_opts *opts = container_of(fi, + struct f_rmnet_opts, func_inst); + rmnet_port = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL); + if (!rmnet_port) + return ERR_PTR(-ENOMEM); + opts->dev = rmnet_port; + spin_lock_init(&rmnet_port->lock); + INIT_LIST_HEAD(&rmnet_port->cpkt_resp_q); + return frmnet_bind_config(fi); +} -fail_probe: - for (i = 0; i < nr_rmnet_ports; i++) - kfree(rmnet_ports[i].port); +DECLARE_USB_FUNCTION(rmnet_bam, rmnet_alloc_inst, rmnet_alloc); - nr_rmnet_ports = 0; - no_ctrl_smd_ports = 0; - no_ctrl_qti_ports = 0; - no_data_bam_ports = 0; - no_ctrl_hsic_ports = 0; - no_data_hsic_ports = 0; - no_ctrl_hsuart_ports = 0; - no_data_hsuart_ports = 0; +static int __init usb_rmnet_init(void) +{ + int ret; + ret = rmnet_init(); + if (!ret) { + ret = usb_function_register(&rmnet_bamusb_func); + if (ret) { + pr_err("%s: failed to register rmnet %d\n", + __func__, ret); + return ret; + } + } return ret; } + +static void __exit usb_rmnet_exit(void) +{ + usb_function_unregister(&rmnet_bamusb_func); + frmnet_cleanup(); +} + +module_init(usb_rmnet_init); +module_exit(usb_rmnet_exit); +MODULE_DESCRIPTION("USB RMNET Function Driver"); diff --git a/drivers/usb/gadget/function/u_ctrl_qti.c b/drivers/usb/gadget/function/u_ctrl_qti.c index 7ef56eca20b8..c0650b0abf8c 100644 --- a/drivers/usb/gadget/function/u_ctrl_qti.c +++ b/drivers/usb/gadget/function/u_ctrl_qti.c @@ -14,11 +14,11 @@ #include <linux/wait.h> #include <linux/poll.h> #include <linux/usb/usb_ctrl_qti.h> - -#include <soc/qcom/bam_dmux.h> +#include <linux/miscdevice.h> +#include <linux/debugfs.h> #include "u_rmnet.h" -#include "usb_gadget_xport.h" +#include "f_qdss.h" #define RMNET_CTRL_QTI_NAME "rmnet_ctrl" #define DPL_CTRL_QTI_NAME "dpl_ctrl" @@ -54,18 +54,18 @@ struct qti_ctrl_port { struct list_head cpkt_req_q; spinlock_t lock; - enum gadget_type gtype; + enum qti_port_type port_type; unsigned host_to_modem; unsigned copied_to_modem; unsigned copied_from_modem; unsigned modem_to_host; unsigned drp_cpkt_cnt; }; -static struct qti_ctrl_port *ctrl_port[NR_QTI_PORTS]; +static struct qti_ctrl_port *ctrl_port[QTI_NUM_PORTS]; static inline int qti_ctrl_lock(atomic_t *excl) { - if (atomic_inc_return(excl) == 1) { + if (atomic_inc_return(excl) == 1) return 0; atomic_dec(excl); return -EBUSY; @@ -76,6 +76,32 @@ static inline void qti_ctrl_unlock(atomic_t *excl) atomic_dec(excl); } +static struct rmnet_ctrl_pkt *alloc_rmnet_ctrl_pkt(unsigned len, gfp_t flags) +{ + struct rmnet_ctrl_pkt *pkt; + + pkt = kzalloc(sizeof(struct rmnet_ctrl_pkt), flags); + if (!pkt) + return ERR_PTR(-ENOMEM); + + pkt->buf = kmalloc(len, flags); + if (!pkt->buf) { + kfree(pkt); + return ERR_PTR(-ENOMEM); + } + + pkt->len = len; + + return pkt; +} + +static void free_rmnet_ctrl_pkt(struct rmnet_ctrl_pkt *pkt) +{ + kfree(pkt->buf); + kfree(pkt); +} + + static void qti_ctrl_queue_notify(struct qti_ctrl_port *port) { unsigned long flags; @@ -106,7 +132,8 @@ static void qti_ctrl_queue_notify(struct qti_ctrl_port *port) wake_up(&port->read_wq); } -static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len) +static int gqti_ctrl_send_cpkt_tomodem(enum qti_port_type qport, + void *buf, size_t len) { unsigned long flags; struct qti_ctrl_port *port; @@ -118,12 +145,11 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len) return -EINVAL; } - if (portno >= NR_QTI_PORTS) { - pr_err("%s: Invalid QTI port %d\n", __func__, portno); + if (qport >= QTI_NUM_PORTS) { + pr_err("%s: Invalid QTI port %d\n", __func__, qport); return -ENODEV; } - port = ctrl_port[portno]; - + port = ctrl_port[qport]; cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC); if (IS_ERR(cpkt)) { pr_err("%s: Unable to allocate ctrl pkt\n", __func__); @@ -133,8 +159,8 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len) memcpy(cpkt->buf, buf, len); cpkt->len = len; - pr_debug("%s: gtype:%d: Add to cpkt_req_q packet with len = %zu\n", - __func__, port->gtype, len); + pr_debug("%s: port type:%d: Add to cpkt_req_q packet with len = %zu\n", + __func__, port->port_type, len); spin_lock_irqsave(&port->lock, flags); /* drop cpkt if port is not open */ @@ -159,71 +185,51 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len) } static void -gqti_ctrl_notify_modem(void *gptr, u8 portno, int val) +gqti_ctrl_notify_modem(void *gptr, enum qti_port_type qport, int val) { struct qti_ctrl_port *port; - if (portno >= NR_QTI_PORTS) { - pr_err("%s: Invalid QTI port %d\n", __func__, portno); + if (qport >= QTI_NUM_PORTS) { + pr_err("%s: Invalid QTI port %d\n", __func__, qport); return; } - port = ctrl_port[portno]; - + port = ctrl_port[qport]; atomic_set(&port->line_state, val); /* send 0 len pkt to qti to notify state change */ qti_ctrl_queue_notify(port); } -int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf, - enum transport_type dxport, enum gadget_type gtype) +int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf) { struct qti_ctrl_port *port; struct grmnet *g_rmnet = NULL; struct gqdss *g_dpl = NULL; unsigned long flags; - pr_debug("%s: gtype:%d gadget:%p\n", __func__, gtype, gr); - if (port_num >= NR_QTI_PORTS) { - pr_err("%s: Invalid QTI port %d\n", __func__, port_num); + pr_debug("%s: port type:%d gadget:%p\n", __func__, qport, gr); + if (qport >= QTI_NUM_PORTS) { + pr_err("%s: Invalid QTI port %d\n", __func__, qport); return -ENODEV; } - port = ctrl_port[port_num]; + port = ctrl_port[qport]; if (!port) { pr_err("%s: gadget port is null\n", __func__); return -ENODEV; } spin_lock_irqsave(&port->lock, flags); - port->gtype = gtype; - if (dxport == USB_GADGET_XPORT_BAM_DMUX) { - /* - * BAM-DMUX data transport is used for RMNET and DPL - * on some targets where IPA is not available. - * Set endpoint type as BAM-DMUX and interface - * id as channel number. This information is - * sent to user space via EP_LOOKUP ioctl. - * - */ - - port->ep_type = DATA_EP_TYPE_BAM_DMUX; - port->intf = (gtype == USB_GADGET_RMNET) ? - BAM_DMUX_USB_RMNET_0 : - BAM_DMUX_USB_DPL; - port->ipa_prod_idx = 0; - port->ipa_cons_idx = 0; - } else { - port->ep_type = DATA_EP_TYPE_HSUSB; - port->intf = intf; - } + port->port_type = qport; + port->ep_type = DATA_EP_TYPE_HSUSB; + port->intf = intf; - if (gr && port->gtype == USB_GADGET_RMNET) { + if (gr && port->port_type == QTI_PORT_RMNET) { port->port_usb = gr; g_rmnet = (struct grmnet *)gr; g_rmnet->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem; g_rmnet->notify_modem = gqti_ctrl_notify_modem; - } else if (gr && port->gtype == USB_GADGET_DPL) { + } else if (gr && port->port_type == QTI_PORT_DPL) { port->port_usb = gr; g_dpl = (struct gqdss *)gr; g_dpl->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem; @@ -231,7 +237,7 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf, atomic_set(&port->line_state, 1); } else { spin_unlock_irqrestore(&port->lock, flags); - pr_err("%s(): Port is used without gtype.\n", __func__); + pr_err("%s(): Port is used without port type.\n", __func__); return -ENODEV; } @@ -251,7 +257,7 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf, return 0; } -void gqti_ctrl_disconnect(void *gr, u8 port_num) +void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport) { struct qti_ctrl_port *port; unsigned long flags; @@ -261,13 +267,12 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num) pr_debug("%s: gadget:%p\n", __func__, gr); - if (port_num >= NR_QTI_PORTS) { - pr_err("%s: Invalid QTI port %d\n", __func__, port_num); + if (qport >= QTI_NUM_PORTS) { + pr_err("%s: Invalid QTI port %d\n", __func__, qport); return; } - port = ctrl_port[port_num]; - + port = ctrl_port[qport]; if (!port) { pr_err("%s: gadget port is null\n", __func__); return; @@ -282,17 +287,17 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num) port->ipa_cons_idx = -1; port->port_usb = NULL; - if (gr && port->gtype == USB_GADGET_RMNET) { + if (gr && port->port_type == QTI_PORT_RMNET) { g_rmnet = (struct grmnet *)gr; g_rmnet->send_encap_cmd = NULL; g_rmnet->notify_modem = NULL; - } else if (gr && port->gtype == USB_GADGET_DPL) { + } else if (gr && port->port_type == QTI_PORT_DPL) { g_dpl = (struct gqdss *)gr; g_dpl->send_encap_cmd = NULL; g_dpl->notify_modem = NULL; } else { pr_err("%s(): unrecognized gadget type(%d).\n", - __func__, port->gtype); + __func__, port->port_type); } while (!list_empty(&port->cpkt_req_q)) { @@ -309,18 +314,17 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num) qti_ctrl_queue_notify(port); } -void gqti_ctrl_update_ipa_pipes(void *gr, u8 port_num, u32 ipa_prod, - u32 ipa_cons) +void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport, + u32 ipa_prod, u32 ipa_cons) { struct qti_ctrl_port *port; - if (port_num >= NR_QTI_PORTS) { - pr_err("%s: Invalid QTI port %d\n", __func__, port_num); + if (qport >= QTI_NUM_PORTS) { + pr_err("%s: Invalid QTI port %d\n", __func__, qport); return; } - port = ctrl_port[port_num]; - + port = ctrl_port[qport]; port->ipa_prod_idx = ipa_prod; port->ipa_cons_idx = ipa_cons; @@ -492,12 +496,12 @@ qti_ctrl_write(struct file *fp, const char __user *buf, size_t count, spin_lock_irqsave(&port->lock, flags); if (port && port->port_usb) { - if (port->gtype == USB_GADGET_RMNET) { + if (port->port_type == QTI_PORT_RMNET) { g_rmnet = (struct grmnet *)port->port_usb; } else { spin_unlock_irqrestore(&port->lock, flags); pr_err("%s(): unrecognized gadget type(%d).\n", - __func__, port->gtype); + __func__, port->port_type); return -EINVAL; } @@ -530,15 +534,15 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg) struct ep_info info; int val, ret = 0; - pr_debug("%s: Received command %d for gtype:%d\n", - __func__, cmd, port->gtype); + pr_debug("%s: Received command %d for port type:%d\n", + __func__, cmd, port->port_type); if (qti_ctrl_lock(&port->ioctl_excl)) return -EBUSY; switch (cmd) { case QTI_CTRL_MODEM_OFFLINE: - if (port && (port->gtype == USB_GADGET_DPL)) { + if (port && (port->port_type == QTI_PORT_DPL)) { pr_err("%s(): Modem Offline not handled\n", __func__); goto exit_ioctl; } @@ -550,7 +554,7 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg) gr->disconnect(gr); break; case QTI_CTRL_MODEM_ONLINE: - if (port && (port->gtype == USB_GADGET_DPL)) { + if (port && (port->port_type == QTI_PORT_DPL)) { pr_err("%s(): Modem Online not handled\n", __func__); goto exit_ioctl; } @@ -568,13 +572,13 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg) pr_err("copying to user space failed"); ret = -EFAULT; } - pr_debug("%s: Sent line_state: %d for gtype:%d\n", __func__, - atomic_read(&port->line_state), port->gtype); + pr_debug("%s: Sent line_state: %d for port type:%d\n", __func__, + atomic_read(&port->line_state), port->port_type); break; case QTI_CTRL_EP_LOOKUP: - pr_debug("%s(): EP_LOOKUP for gtype:%d\n", __func__, - port->gtype); + pr_debug("%s(): EP_LOOKUP for port type:%d\n", __func__, + port->port_type); val = atomic_read(&port->connected); if (!val) { pr_err_ratelimited("EP_LOOKUP failed: not connected\n"); @@ -593,9 +597,9 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg) info.ipa_ep_pair.cons_pipe_num = port->ipa_cons_idx; info.ipa_ep_pair.prod_pipe_num = port->ipa_prod_idx; - pr_debug("%s(): gtype:%d ep_type:%d intf:%d\n", - __func__, port->gtype, info.ph_ep_info.ep_type, - info.ph_ep_info.peripheral_iface_id); + pr_debug("%s(): port type:%d ep_type:%d intf:%d\n", + __func__, port->port_type, info.ph_ep_info.ep_type, + info.ph_ep_info.peripheral_iface_id); pr_debug("%s(): ipa_cons_idx:%d ipa_prod_idx:%d\n", __func__, info.ipa_ep_pair.cons_pipe_num, @@ -650,7 +654,7 @@ static int qti_ctrl_read_stats(struct seq_file *s, void *unused) unsigned long flags; int i; - for (i = 0; i < NR_QTI_PORTS; i++) { + for (i = 0; i < QTI_NUM_PORTS; i++) { port = ctrl_port[i]; if (!port) continue; @@ -687,7 +691,7 @@ static ssize_t qti_ctrl_reset_stats(struct file *file, int i; unsigned long flags; - for (i = 0; i < NR_QTI_PORTS; i++) { + for (i = 0; i < QTI_NUM_PORTS; i++) { port = ctrl_port[i]; if (!port) continue; @@ -762,10 +766,9 @@ int gqti_ctrl_init(void) int ret, i, sz = QTI_CTRL_NAME_LEN; struct qti_ctrl_port *port = NULL; - for (i = 0; i < NR_QTI_PORTS; i++) { + for (i = 0; i < QTI_NUM_PORTS; i++) { port = kzalloc(sizeof(struct qti_ctrl_port), GFP_KERNEL); if (!port) { - pr_err("Failed to allocate rmnet control device\n"); ret = -ENOMEM; goto fail_init; } @@ -787,16 +790,16 @@ int gqti_ctrl_init(void) port->ipa_prod_idx = -1; port->ipa_cons_idx = -1; - if (i == 0) + if (i == QTI_PORT_RMNET) strlcat(port->name, RMNET_CTRL_QTI_NAME, sz); - else if (i == DPL_QTI_CTRL_PORT_NO) + else if (i == QTI_PORT_DPL) strlcat(port->name, DPL_CTRL_QTI_NAME, sz); else snprintf(port->name, sz, "%s%d", - RMNET_CTRL_QTI_NAME, i); + RMNET_CTRL_QTI_NAME, i); port->ctrl_device.name = port->name; - if (i == DPL_QTI_CTRL_PORT_NO) + if (i == QTI_PORT_DPL) port->ctrl_device.fops = &dpl_qti_ctrl_fops; else port->ctrl_device.fops = &qti_ctrl_fops; @@ -809,7 +812,6 @@ int gqti_ctrl_init(void) } } qti_ctrl_debugfs_init(); - return ret; fail_init: @@ -825,7 +827,7 @@ void gqti_ctrl_cleanup(void) { int i; - for (i = 0; i < NR_QTI_PORTS; i++) { + for (i = 0; i < QTI_NUM_PORTS; i++) { misc_deregister(&ctrl_port[i]->ctrl_device); kfree(ctrl_port[i]); ctrl_port[i] = NULL; diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c index 56e7dea427ec..2da0c59fdfc2 100644 --- a/drivers/usb/gadget/function/u_data_ipa.c +++ b/drivers/usb/gadget/function/u_data_ipa.c @@ -23,6 +23,7 @@ #include <linux/usb_bam.h> #include "u_data_ipa.h" +#include "u_rmnet.h" struct ipa_data_ch_info { struct usb_request *rx_req; @@ -564,6 +565,11 @@ static void ipa_data_connect_work(struct work_struct *w) atomic_set(&port->pipe_connect_notified, 1); } + if (port->func_type == USB_IPA_FUNC_RMNET) { + gqti_ctrl_update_ipa_pipes(port->port_usb, QTI_PORT_RMNET, + gport->ipa_producer_ep, gport->ipa_consumer_ep); + } + pr_debug("ipa_producer_ep:%d ipa_consumer_ep:%d\n", gport->ipa_producer_ep, gport->ipa_consumer_ep); @@ -1135,7 +1141,7 @@ int ipa_data_setup(enum ipa_func_type func) } if (ipa_data_wq) { pr_debug("ipa_data_wq is already setup."); - goto free_rndis_data; + return 0; } ipa_data_wq = alloc_workqueue("k_usb_ipa_data", diff --git a/drivers/usb/gadget/function/u_data_ipa.h b/drivers/usb/gadget/function/u_data_ipa.h index a1c1055bd8ef..14411575af22 100644 --- a/drivers/usb/gadget/function/u_data_ipa.h +++ b/drivers/usb/gadget/function/u_data_ipa.h @@ -20,6 +20,8 @@ #include <linux/ipa_usb.h> #include <linux/usb_bam.h> +#include "u_rmnet.h" + enum ipa_func_type { USB_IPA_FUNC_ECM, USB_IPA_FUNC_MBIM, @@ -57,6 +59,12 @@ struct f_rndis_qc_opts { int refcnt; }; +struct f_rmnet_opts { + struct usb_function_instance func_inst; + struct f_rmnet *dev; + int refcnt; +}; + void ipa_data_port_select(enum ipa_func_type func); void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func); int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func, @@ -87,4 +95,6 @@ void *rndis_qc_get_ipa_rx_cb(void); bool rndis_qc_get_skip_ep_config(void); void *rndis_qc_get_ipa_tx_cb(void); void rndis_ipa_reset_trigger(void); +void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport, + u32 ipa_prod, u32 ipa_cons); #endif diff --git a/drivers/usb/gadget/function/u_rmnet.h b/drivers/usb/gadget/function/u_rmnet.h index 4336dbf26274..e0843794b594 100644 --- a/drivers/usb/gadget/function/u_rmnet.h +++ b/drivers/usb/gadget/function/u_rmnet.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,18 +19,19 @@ #include <linux/workqueue.h> struct rmnet_ctrl_pkt { - void *buf; - int len; + void *buf; + int len; struct list_head list; }; -struct grmnet { - struct usb_function func; +enum qti_port_type { + QTI_PORT_RMNET, + QTI_PORT_DPL, + QTI_NUM_PORTS +}; - struct usb_gadget *gadget; - struct usb_ep *in; - struct usb_ep *out; +struct grmnet { /* to usb host, aka laptop, windows pc etc. Will * be filled by usb driver of rmnet functionality */ @@ -39,18 +40,13 @@ struct grmnet { /* to modem, and to be filled by driver implementing * control function */ - int (*send_encap_cmd)(u8 port_num, void *buf, size_t len); - - void (*notify_modem)(void *g, u8 port_num, int cbits); + int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len); + void (*notify_modem)(void *g, enum qti_port_type qport, int cbits); void (*disconnect)(struct grmnet *g); void (*connect)(struct grmnet *g); }; -#define NR_QTI_PORTS (NR_RMNET_PORTS + NR_DPL_PORTS) -#define NR_RMNET_PORTS 4 -#define NR_DPL_PORTS 1 - enum ctrl_client { FRMNET_CTRL_CLIENT, GPS_CTRL_CLIENT, @@ -58,22 +54,8 @@ enum ctrl_client { NR_CTRL_CLIENTS }; -int gbam_setup(unsigned int no_bam_port); -int gbam2bam_setup(unsigned int no_bam2bam_port); -void gbam_cleanup(void); -int gbam_connect(struct grmnet *gr, u8 port_num, - enum transport_type trans, u8 src_connection_idx, - u8 dst_connection_idx); -void gbam_disconnect(struct grmnet *gr, u8 port_num, - enum transport_type trans); -void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans); -void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans); -int gbam_mbim_setup(void); -int gbam_mbim_connect(struct usb_gadget *g, struct usb_ep *in, - struct usb_ep *out); -void gbam_mbim_disconnect(void); -int gsmd_ctrl_connect(struct grmnet *gr, int port_num); -void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num); -int gsmd_ctrl_setup(enum ctrl_client client_num, unsigned int count, - u8 *first_port_idx); +int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf); +void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport); +int gqti_ctrl_init(void); +void gqti_ctrl_cleanup(void); #endif /* __U_RMNET_H*/ diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 5a24a1995af9..5a6d7bc3ff78 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -164,6 +164,7 @@ enum mdss_hw_quirk { MDSS_QUIRK_NEED_SECURE_MAP, MDSS_QUIRK_SRC_SPLIT_ALWAYS, MDSS_QUIRK_MMSS_GDSC_COLLAPSE, + MDSS_QUIRK_MDP_CLK_SET_RATE, MDSS_QUIRK_MAX, }; @@ -289,6 +290,7 @@ struct mdss_data_type { bool en_svs_high; u32 max_mdp_clk_rate; struct mdss_util_intf *mdss_util; + unsigned long mdp_clk_rate; struct platform_device *pdev; struct dss_io_data mdss_io; diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 840df3741b21..132dc0e028ae 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -45,6 +45,8 @@ #define VDDA_UA_ON_LOAD 100000 /* uA units */ #define VDDA_UA_OFF_LOAD 100 /* uA units */ +#define DP_CRYPTO_CLK_RATE_KHZ 337500 + struct mdss_dp_attention_node { u32 vdo; struct list_head list; @@ -208,9 +210,9 @@ static int mdss_dp_get_dt_clk_data(struct device *dev, &ctrl_power_data->clk_config[ctrl_clk_index]; strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); ctrl_clk_index++; - if (!strcmp(clk_name, "ctrl_link_clk")) - clk->type = DSS_CLK_PCLK; - else if (!strcmp(clk_name, "ctrl_pixel_clk")) + if (!strcmp(clk_name, "ctrl_link_clk") || + !strcmp(clk_name, "ctrl_pixel_clk") || + !strcmp(clk_name, "ctrl_crypto_clk")) clk->type = DSS_CLK_PCLK; else clk->type = DSS_CLK_AHB; @@ -1089,6 +1091,23 @@ exit: return ret; } +static void mdss_dp_set_clock_rate(struct mdss_dp_drv_pdata *dp, + char *name, u32 rate) +{ + u32 num = dp->power_data[DP_CTRL_PM].num_clk; + struct dss_clk *cfg = dp->power_data[DP_CTRL_PM].clk_config; + + while (num && strcmp(cfg->clk_name, name)) { + num--; + cfg++; + } + + if (num) + cfg->rate = rate; + else + pr_err("%s clock could not be set with rate %d\n", name, rate); +} + /** * mdss_dp_enable_mainlink_clocks() - enables Display Port main link clocks * @dp: Display Port Driver data @@ -1099,12 +1118,14 @@ static int mdss_dp_enable_mainlink_clocks(struct mdss_dp_drv_pdata *dp) { int ret = 0; - dp->power_data[DP_CTRL_PM].clk_config[0].rate = - ((dp->link_rate * DP_LINK_RATE_MULTIPLIER) / 1000);/* KHz */ + mdss_dp_set_clock_rate(dp, "ctrl_link_clk", + (dp->link_rate * DP_LINK_RATE_MULTIPLIER) / DP_KHZ_TO_HZ); + + mdss_dp_set_clock_rate(dp, "ctrl_crypto_clk", DP_CRYPTO_CLK_RATE_KHZ); dp->pixel_rate = dp->panel_data.panel_info.clk_rate; - dp->power_data[DP_CTRL_PM].clk_config[3].rate = - (dp->pixel_rate / 1000);/* KHz */ + mdss_dp_set_clock_rate(dp, "ctrl_pixel_clk", + (dp->pixel_rate / DP_KHZ_TO_HZ)); ret = mdss_dp_clk_ctrl(dp, DP_CTRL_PM, true); if (ret) { @@ -1286,12 +1307,8 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv) link_training: dp_drv->power_on = true; - if (-EAGAIN == mdss_dp_train_main_link(dp_drv)) { - mutex_unlock(&dp_drv->train_mutex); - - mdss_dp_link_retraining(dp_drv); - return 0; - } + while (-EAGAIN == mdss_dp_train_main_link(dp_drv)) + pr_debug("MAIN LINK TRAINING RETRY\n"); dp_drv->cont_splash = 0; @@ -1622,13 +1639,27 @@ static void mdss_dp_hdcp_cb_work(struct work_struct *work) struct mdss_dp_drv_pdata *dp; struct delayed_work *dw = to_delayed_work(work); struct hdcp_ops *ops; + unsigned char *base; int rc = 0; + u32 hdcp_auth_state; dp = container_of(dw, struct mdss_dp_drv_pdata, hdcp_cb_work); + base = dp->base; + + hdcp_auth_state = (dp_read(base + DP_HDCP_STATUS) >> 20) & 0x3; + + pr_debug("hdcp auth state %d\n", hdcp_auth_state); ops = dp->hdcp.ops; switch (dp->hdcp_status) { + case HDCP_STATE_AUTHENTICATING: + pr_debug("start authenticaton\n"); + + if (dp->hdcp.ops && dp->hdcp.ops->authenticate) + rc = dp->hdcp.ops->authenticate(dp->hdcp.data); + + break; case HDCP_STATE_AUTHENTICATED: pr_debug("hdcp authenticated\n"); dp->hdcp.auth_state = true; @@ -1636,7 +1667,7 @@ static void mdss_dp_hdcp_cb_work(struct work_struct *work) case HDCP_STATE_AUTH_FAIL: dp->hdcp.auth_state = false; - if (dp->power_on) { + if (dp->alt_mode.dp_status.hpd_high && dp->power_on) { pr_debug("Reauthenticating\n"); if (ops && ops->reauthenticate) { rc = ops->reauthenticate(dp->hdcp.data); @@ -1664,7 +1695,8 @@ static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status) dp->hdcp_status = status; - queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4); + if (dp->alt_mode.dp_status.hpd_high) + queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4); } static int mdss_dp_hdcp_init(struct mdss_panel_data *pdata) @@ -1927,20 +1959,28 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, rc = mdss_dp_on(pdata); break; case MDSS_EVENT_PANEL_ON: + mdss_dp_ack_state(dp, true); + mdss_dp_update_hdcp_info(dp); - if (dp->hdcp.ops && dp->hdcp.ops->authenticate) - rc = dp->hdcp.ops->authenticate(dp->hdcp.data); + if (dp_is_hdcp_enabled(dp)) { + cancel_delayed_work(&dp->hdcp_cb_work); - mdss_dp_ack_state(dp, true); + dp->hdcp_status = HDCP_STATE_AUTHENTICATING; + queue_delayed_work(dp->workq, + &dp->hdcp_cb_work, HZ / 2); + } break; case MDSS_EVENT_PANEL_OFF: rc = mdss_dp_off(pdata); break; case MDSS_EVENT_BLANK: - if (dp_is_hdcp_enabled(dp) && dp->hdcp.ops->off) { - flush_delayed_work(&dp->hdcp_cb_work); - dp->hdcp.ops->off(dp->hdcp.data); + if (dp_is_hdcp_enabled(dp)) { + dp->hdcp_status = HDCP_STATE_INACTIVE; + + cancel_delayed_work(&dp->hdcp_cb_work); + if (dp->hdcp.ops->off) + dp->hdcp.ops->off(dp->hdcp.data); } mdss_dp_mainlink_push_idle(pdata); @@ -2189,9 +2229,6 @@ irqreturn_t dp_isr(int irq, void *ptr) isr1 &= ~mask1; /* remove masks bit */ - pr_debug("isr=%x mask=%x isr2=%x\n", - isr1, mask1, isr2); - ack = isr1 & EDP_INTR_STATUS1; ack <<= 1; /* ack bits */ ack |= mask1; @@ -2601,8 +2638,7 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) if (dp_drv->alt_mode.dp_status.hpd_irq) { pr_debug("Attention: hpd_irq high\n"); - if (dp_drv->power_on && dp_drv->hdcp.ops && - dp_drv->hdcp.ops->cp_irq) { + if (dp_drv->hdcp.ops && dp_drv->hdcp.ops->cp_irq) { if (!dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data)) return; } @@ -2616,6 +2652,12 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) if (!dp_drv->alt_mode.dp_status.hpd_high) { pr_debug("Attention: HPD low\n"); + + if (dp_is_hdcp_enabled(dp_drv) && dp_drv->hdcp.ops->off) { + cancel_delayed_work(&dp_drv->hdcp_cb_work); + dp_drv->hdcp.ops->off(dp_drv->hdcp.data); + } + mdss_dp_update_cable_status(dp_drv, false); mdss_dp_notify_clients(dp_drv, false); pr_debug("Attention: Notified clients\n"); diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index 04abe9221acc..dc84694f2238 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -228,6 +228,7 @@ struct dp_alt_mode { #define DP_LINK_RATE_MAX DP_LINK_RATE_540 #define DP_LINK_RATE_MULTIPLIER 27000000 +#define DP_KHZ_TO_HZ 1000 #define DP_MAX_PIXEL_CLK_KHZ 675000 struct downstream_port_config { /* Byte 02205h */ diff --git a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c index 695331babf55..73b9ad65482f 100644 --- a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c @@ -23,6 +23,8 @@ #include "mdss_hdcp.h" #include "mdss_dp_util.h" +struct dp_hdcp2p2_ctrl; + enum dp_hdcp2p2_sink_status { SINK_DISCONNECTED, SINK_CONNECTED @@ -33,9 +35,21 @@ enum dp_auth_status { DP_HDCP_AUTH_STATUS_SUCCESS }; +struct dp_hdcp2p2_int_set { + u32 interrupt; + char *name; + void (*func)(struct dp_hdcp2p2_ctrl *ctrl); +}; + +struct dp_hdcp2p2_interrupts { + u32 reg; + struct dp_hdcp2p2_int_set *int_set; +}; + struct dp_hdcp2p2_ctrl { atomic_t auth_state; enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */ + struct dp_hdcp2p2_interrupts *intr; struct hdcp_init_data init_data; struct mutex mutex; /* mutex to protect access to ctrl */ struct mutex msg_lock; /* mutex to protect access to msg buffer */ @@ -172,7 +186,10 @@ static int dp_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) queue_kthread_work(&ctrl->worker, &ctrl->status); break; case HDMI_HDCP_WKUP_CMD_LINK_POLL: - ctrl->polling = true; + if (ctrl->cp_irq_done) + queue_kthread_work(&ctrl->worker, &ctrl->recv_msg); + else + ctrl->polling = true; break; case HDMI_HDCP_WKUP_CMD_AUTHENTICATE: queue_kthread_work(&ctrl->worker, &ctrl->auth); @@ -211,6 +228,31 @@ static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl) atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE); } +static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable) +{ + unsigned char *base = ctrl->init_data.core_io->base; + struct dp_hdcp2p2_interrupts *intr = ctrl->intr; + + while (intr && intr->reg) { + struct dp_hdcp2p2_int_set *int_set = intr->int_set; + u32 interrupts = 0; + + while (int_set && int_set->interrupt) { + interrupts |= int_set->interrupt; + int_set++; + } + + if (enable) + dp_write(base + intr->reg, + dp_read(base + intr->reg) | interrupts); + else + dp_write(base + intr->reg, + dp_read(base + intr->reg) & ~interrupts); + + intr++; + } +} + static void dp_hdcp2p2_off(void *input) { struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; @@ -221,6 +263,13 @@ static void dp_hdcp2p2_off(void *input) return; } + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("hdcp is off\n"); + return; + } + + dp_hdcp2p2_set_interrupts(ctrl, false); + dp_hdcp2p2_reset(ctrl); flush_kthread_worker(&ctrl->worker); @@ -237,6 +286,8 @@ static int dp_hdcp2p2_authenticate(void *input) flush_kthread_worker(&ctrl->worker); + dp_hdcp2p2_set_interrupts(ctrl, true); + ctrl->sink_status = SINK_CONNECTED; atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING); @@ -317,6 +368,8 @@ static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl) return; } + dp_hdcp2p2_set_interrupts(ctrl, false); + /* notify DP about HDCP failure */ ctrl->init_data.notify_status(ctrl->init_data.cb_data, HDCP_STATE_AUTH_FAIL); @@ -640,6 +693,8 @@ static int dp_hdcp2p2_cp_irq(void *input) goto error; } + pr_debug("sink_rx_status=0x%x\n", ctrl->sink_rx_status); + if (!ctrl->sink_rx_status) { pr_debug("not a hdcp 2.2 irq\n"); rc = -EINVAL; @@ -653,6 +708,46 @@ error: return rc; } +static int dp_hdcp2p2_isr(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; + int rc = 0; + struct dss_io_data *io; + struct dp_hdcp2p2_interrupts *intr; + u32 hdcp_int_val; + + if (!ctrl || !ctrl->init_data.core_io) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + io = ctrl->init_data.core_io; + intr = ctrl->intr; + + while (intr && intr->reg) { + struct dp_hdcp2p2_int_set *int_set = intr->int_set; + + hdcp_int_val = dp_read(io->base + intr->reg); + + while (int_set && int_set->interrupt) { + if (hdcp_int_val & (int_set->interrupt >> 2)) { + pr_debug("%s\n", int_set->name); + + if (int_set->func) + int_set->func(ctrl); + + dp_write(io->base + intr->reg, hdcp_int_val | + (int_set->interrupt >> 1)); + } + int_set++; + } + intr++; + } +end: + return rc; +} + void dp_hdcp2p2_deinit(void *input) { struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; @@ -684,6 +779,7 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data) int rc; struct dp_hdcp2p2_ctrl *ctrl; static struct hdcp_ops ops = { + .isr = dp_hdcp2p2_isr, .reauthenticate = dp_hdcp2p2_reauthenticate, .authenticate = dp_hdcp2p2_authenticate, .feature_supported = dp_hdcp2p2_feature_supported, @@ -694,7 +790,22 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data) static struct hdcp_client_ops client_ops = { .wakeup = dp_hdcp2p2_wakeup, }; - + static struct dp_hdcp2p2_int_set int_set1[] = { + {BIT(17), "authentication successful", 0}, + {BIT(20), "authentication failed", 0}, + {BIT(24), "encryption enabled", 0}, + {BIT(27), "encryption disabled", 0}, + {0}, + }; + static struct dp_hdcp2p2_int_set int_set2[] = { + {BIT(2), "key fifo underflow", 0}, + {0}, + }; + static struct dp_hdcp2p2_interrupts intr[] = { + {DP_INTR_STATUS2, int_set1}, + {DP_INTR_STATUS3, int_set2}, + {0} + }; static struct hdcp_txmtr_ops txmtr_ops; struct hdcp_register_data register_data = {0}; @@ -719,6 +830,7 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data) } ctrl->sink_status = SINK_DISCONNECTED; + ctrl->intr = intr; atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE); diff --git a/drivers/video/fbdev/msm/mdss_hdcp_1x.c b/drivers/video/fbdev/msm/mdss_hdcp_1x.c index cefe368ccc9a..44a3ad993909 100644 --- a/drivers/video/fbdev/msm/mdss_hdcp_1x.c +++ b/drivers/video/fbdev/msm/mdss_hdcp_1x.c @@ -10,13 +10,14 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "%s: " fmt, __func__ + #include <linux/io.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/stat.h> #include <linux/iopoll.h> -#include <soc/qcom/scm.h> #include <linux/hdcp_qseecom.h> #include "mdss_hdcp.h" #include "mdss_fb.h" @@ -51,10 +52,6 @@ #define HDCP_POLL_SLEEP_US (20 * 1000) #define HDCP_POLL_TIMEOUT_US (HDCP_POLL_SLEEP_US * 100) -#define reg_set_data(x) \ - (hdcp_ctrl->init_data.sec_access ? reg_set->sec_data##x : \ - reg_set->data##x) - struct hdcp_sink_addr { char *name; u32 addr; @@ -125,25 +122,15 @@ struct hdcp_reg_set { u32 aksv_msb; u32 entropy_ctrl0; u32 entropy_ctrl1; - u32 sha_ctrl; - u32 sha_data; u32 sec_sha_ctrl; u32 sec_sha_data; u32 sha_status; - u32 data0; - u32 data1; u32 data2_0; u32 data3; u32 data4; u32 data5; u32 data6; - u32 data7; - u32 data8; - u32 data9; - u32 data10; - u32 data11; - u32 data12; u32 sec_data0; u32 sec_data1; @@ -164,16 +151,11 @@ struct hdcp_reg_set { {HDMI_HDCP_LINK0_STATUS, 28, 24, 20, HDMI_HDCP_CTRL, \ HDMI_HDCP_SW_LOWER_AKSV, HDMI_HDCP_SW_UPPER_AKSV, \ HDMI_HDCP_ENTROPY_CTRL0, HDMI_HDCP_ENTROPY_CTRL1, \ - HDMI_HDCP_SHA_CTRL, HDMI_HDCP_SHA_DATA, \ HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, \ HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA, \ - HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA0, \ - HDMI_HDCP_RCVPORT_DATA1, HDMI_HDCP_RCVPORT_DATA2_0, \ + HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA2_0, \ HDMI_HDCP_RCVPORT_DATA3, HDMI_HDCP_RCVPORT_DATA4, \ HDMI_HDCP_RCVPORT_DATA5, HDMI_HDCP_RCVPORT_DATA6, \ - HDMI_HDCP_RCVPORT_DATA7, HDMI_HDCP_RCVPORT_DATA8, \ - HDMI_HDCP_RCVPORT_DATA9, HDMI_HDCP_RCVPORT_DATA10, \ - HDMI_HDCP_RCVPORT_DATA11, HDMI_HDCP_RCVPORT_DATA12, \ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \ @@ -188,12 +170,11 @@ struct hdcp_reg_set { {DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \ DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \ DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \ - 0, 0, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA, \ - DP_HDCP_SHA_STATUS, 0, 0, DP_HDCP_RCVPORT_DATA2_0, \ + DP_HDCP_SHA_STATUS, DP_HDCP_RCVPORT_DATA2_0, \ DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \ DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \ - 0, 0, 0, 0, 0, 0, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \ @@ -233,8 +214,8 @@ struct hdcp_reg_set { struct hdcp_1x_ctrl { u32 auth_retries; u32 tp_msgid; - u32 tz_hdcp; bool sink_r0_ready; + bool reauth; enum hdcp_states hdcp_state; struct HDCP_V2V1_MSG_TOPOLOGY cached_tp; struct HDCP_V2V1_MSG_TOPOLOGY current_tp; @@ -280,7 +261,7 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) struct dss_io_data *io; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } @@ -290,8 +271,8 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS); failure = (hdcp_ddc_status >> 16) & 0x1; nack0 = (hdcp_ddc_status >> 14) & 0x1; - DEV_DBG("%s: %s: On Entry: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n", - __func__, HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0); + pr_debug("%s: On Entry: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n", + HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0); if (failure == 0x1) { /* @@ -301,8 +282,8 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) * matches HDCP_DDC_RETRY_CNT. * Failure occured, let's clear it. */ - DEV_DBG("%s: %s: DDC failure detected.HDCP_DDC_STATUS=0x%08x\n", - __func__, HDCP_STATE_NAME, hdcp_ddc_status); + pr_debug("%s: DDC failure detected.HDCP_DDC_STATUS=0x%08x\n", + HDCP_STATE_NAME, hdcp_ddc_status); /* First, Disable DDC */ DSS_REG_W(io, HDMI_HDCP_DDC_CTRL_0, BIT(0)); @@ -316,18 +297,18 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS); hdcp_ddc_status = (hdcp_ddc_status >> 16) & BIT(0); if (hdcp_ddc_status == 0x0) - DEV_DBG("%s: %s: HDCP DDC Failure cleared\n", __func__, + pr_debug("%s: HDCP DDC Failure cleared\n", HDCP_STATE_NAME); else - DEV_WARN("%s: %s: Unable to clear HDCP DDC Failure", - __func__, HDCP_STATE_NAME); + pr_debug("%s: Unable to clear HDCP DDC Failure", + HDCP_STATE_NAME); /* Re-Enable HDCP DDC */ DSS_REG_W(io, HDMI_HDCP_DDC_CTRL_0, 0); } if (nack0 == 0x1) { - DEV_DBG("%s: %s: Before: HDMI_DDC_SW_STATUS=0x%08x\n", __func__, + pr_debug("%s: Before: HDMI_DDC_SW_STATUS=0x%08x\n", HDCP_STATE_NAME, DSS_REG_R(io, HDMI_DDC_SW_STATUS)); /* Reset HDMI DDC software status */ DSS_REG_W_ND(io, HDMI_DDC_CTRL, @@ -342,7 +323,7 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) msleep(20); DSS_REG_W_ND(io, HDMI_DDC_CTRL, DSS_REG_R(io, HDMI_DDC_CTRL) & ~BIT(1)); - DEV_DBG("%s: %s: After: HDMI_DDC_SW_STATUS=0x%08x\n", __func__, + pr_debug("%s: After: HDMI_DDC_SW_STATUS=0x%08x\n", HDCP_STATE_NAME, DSS_REG_R(io, HDMI_DDC_SW_STATUS)); } @@ -350,8 +331,8 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl) failure = (hdcp_ddc_status >> 16) & BIT(0); nack0 = (hdcp_ddc_status >> 14) & BIT(0); - DEV_DBG("%s: %s: On Exit: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n", - __func__, HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0); + pr_debug("%s: On Exit: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n", + HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0); } /* reset_hdcp_ddc_failures */ static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl) @@ -364,14 +345,14 @@ static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl) u32 timeout_count; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } io = hdcp_ctrl->init_data.core_io; if (!io->base) { - DEV_ERR("%s: core io not inititalized\n", __func__); - return; + pr_err("core io not inititalized\n"); + return; } /* Wait to be clean on DDC HW engine */ @@ -393,49 +374,16 @@ static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl) ddc_hw_not_ready = xfer_not_done || hw_not_done; - DEV_DBG("%s: %s: timeout count(%d): ddc hw%sready\n", - __func__, HDCP_STATE_NAME, timeout_count, + pr_debug("%s: timeout count(%d): ddc hw%sready\n", + HDCP_STATE_NAME, timeout_count, ddc_hw_not_ready ? " not " : " "); - DEV_DBG("hdcp_ddc_status[0x%x], ddc_hw_status[0x%x]\n", + pr_debug("hdcp_ddc_status[0x%x], ddc_hw_status[0x%x]\n", hdcp_ddc_status, ddc_hw_status); if (ddc_hw_not_ready) msleep(20); } while (ddc_hw_not_ready && --timeout_count); } /* hdcp_1x_hw_ddc_clean */ -static int hdcp_scm_call(struct scm_hdcp_req *req, u32 *resp) -{ - int ret = 0; - - if (!is_scm_armv8()) { - ret = scm_call(SCM_SVC_HDCP, SCM_CMD_HDCP, (void *) req, - SCM_HDCP_MAX_REG * sizeof(struct scm_hdcp_req), - &resp, sizeof(*resp)); - } else { - struct scm_desc desc; - - desc.args[0] = req[0].addr; - desc.args[1] = req[0].val; - desc.args[2] = req[1].addr; - desc.args[3] = req[1].val; - desc.args[4] = req[2].addr; - desc.args[5] = req[2].val; - desc.args[6] = req[3].addr; - desc.args[7] = req[3].val; - desc.args[8] = req[4].addr; - desc.args[9] = req[4].val; - desc.arginfo = SCM_ARGS(10); - - ret = scm_call2(SCM_SIP_FNID(SCM_SVC_HDCP, SCM_CMD_HDCP), - &desc); - *resp = desc.ret[0]; - if (ret) - return ret; - } - - return ret; -} - static int hdcp_1x_load_keys(void *input) { int rc = 0; @@ -451,14 +399,14 @@ static int hdcp_1x_load_keys(void *input) if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io || !hdcp_ctrl->init_data.qfprom_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); rc = -EINVAL; goto end; } if ((HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) && (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state)) { - DEV_ERR("%s: %s: invalid state. returning\n", __func__, + pr_err("%s: invalid state. returning\n", HDCP_STATE_NAME); rc = -EINVAL; goto end; @@ -481,7 +429,7 @@ static int hdcp_1x_load_keys(void *input) if (use_sw_keys) { if (hdcp1_set_keys(&aksv_msb, &aksv_lsb)) { - pr_err("%s: setting hdcp SW keys failed\n", __func__); + pr_err("setting hdcp SW keys failed\n"); rc = -EINVAL; goto end; } @@ -499,7 +447,7 @@ static int hdcp_1x_load_keys(void *input) aksv_msb = DSS_REG_R(qfprom_io, ksv_msb_addr); } - DEV_DBG("%s: %s: AKSV=%02x%08x\n", __func__, HDCP_STATE_NAME, + pr_debug("%s: AKSV=%02x%08x\n", HDCP_STATE_NAME, aksv_msb, aksv_lsb); aksv[0] = aksv_lsb & 0xFF; @@ -510,7 +458,7 @@ static int hdcp_1x_load_keys(void *input) /* check there are 20 ones in AKSV */ if (hdcp_1x_count_one(aksv, 5) != 20) { - DEV_ERR("%s: AKSV bit count failed\n", __func__); + pr_err("AKSV bit count failed\n"); rc = -EINVAL; goto end; } @@ -558,7 +506,7 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl, rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); if (rc) - DEV_ERR("%s: %s: %s read failed\n", __func__, + pr_err("%s: %s read failed\n", HDCP_STATE_NAME, sink->name); } else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) && hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { @@ -609,7 +557,7 @@ static int hdcp_1x_write(struct hdcp_1x_ctrl *hdcp_ctrl, rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl); if (rc) - DEV_ERR("%s: %s: %s write failed\n", __func__, + pr_err("%s: %s write failed\n", HDCP_STATE_NAME, sink->name); } else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) && hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { @@ -621,7 +569,7 @@ static int hdcp_1x_write(struct hdcp_1x_ctrl *hdcp_ctrl, rc = dp_aux_write(hdcp_ctrl->init_data.cb_data, &cmd); if (rc) - DEV_ERR("%s: %s: %s read failed\n", __func__, + pr_err("%s: %s read failed\n", HDCP_STATE_NAME, sink->name); } @@ -661,14 +609,11 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) u8 bcaps = 0; u32 link0_status = 0; u8 buf[0xFF]; - struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; - u32 ret = 0; - u32 resp = 0; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io || !hdcp_ctrl->init_data.qfprom_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); rc = -EINVAL; goto error; } @@ -680,7 +625,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) reg_set = &hdcp_ctrl->reg_set; if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) { - DEV_ERR("%s: %s: invalid state. returning\n", __func__, + pr_err("%s: invalid state. returning\n", HDCP_STATE_NAME); rc = -EINVAL; goto error; @@ -689,7 +634,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, &bcaps, false); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading bcaps\n", __func__); + pr_err("error reading bcaps\n"); goto error; } @@ -699,24 +644,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) DS_REPEATER : DS_RECEIVER; /* Write BCAPS to the hardware */ - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); - - scm_buf[0].addr = phy_addr + reg_set->data12; - scm_buf[0].val = bcaps; - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W(hdcp_io, reg_set->sec_data12, bcaps); - } else { - DSS_REG_W(io, reg_set->data12, bcaps); - } + DSS_REG_W(hdcp_io, reg_set->sec_data12, bcaps); /* Wait for HDCP keys to be checked and validated */ rc = readl_poll_timeout(io->base + reg_set->status, link0_status, @@ -724,7 +652,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) == HDCP_KEYS_STATE_VALID, HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: key not ready\n", __func__); + pr_err("key not ready\n"); goto error; } @@ -739,7 +667,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) (link0_status & (BIT(8) | BIT(9))), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: An not ready\n", __func__); + pr_err("An not ready\n"); goto error; } @@ -784,16 +712,16 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bksv, bksv, false); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading bksv from sink\n", __func__); + pr_err("error reading bksv from sink\n"); goto error; } /* check there are 20 ones in BKSV */ if (hdcp_1x_count_one(bksv, 5) != 20) { - DEV_ERR("%s: %s: BKSV doesn't have 20 1's and 20 0's\n", - __func__, HDCP_STATE_NAME); - DEV_ERR("%s: %s: BKSV chk fail. BKSV=%02x%02x%02x%02x%02x\n", - __func__, HDCP_STATE_NAME, bksv[4], bksv[3], bksv[2], + pr_err("%s: BKSV doesn't have 20 1's and 20 0's\n", + HDCP_STATE_NAME); + pr_err("%s: BKSV chk fail. BKSV=%02x%02x%02x%02x%02x\n", + HDCP_STATE_NAME, bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]); rc = -EINVAL; goto error; @@ -804,51 +732,30 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1]; link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0]; link0_bksv_1 = bksv[4]; - DEV_DBG("%s: %s: BKSV=%02x%08x\n", __func__, HDCP_STATE_NAME, + pr_debug("%s: BKSV=%02x%08x\n", HDCP_STATE_NAME, link0_bksv_1, link0_bksv_0); - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); - - scm_buf[0].addr = phy_addr + reg_set->data0; - scm_buf[0].val = link0_bksv_0; - scm_buf[1].addr = phy_addr + reg_set->data1; - scm_buf[1].val = link0_bksv_1; - - ret = hdcp_scm_call(scm_buf, &resp); - - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0); - DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1); - } else { - DSS_REG_W(io, reg_set->data0, link0_bksv_0); - DSS_REG_W(io, reg_set->data1, link0_bksv_1); - } + DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0); + DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1); /* Wait for HDCP R0 computation to be completed */ rc = readl_poll_timeout(io->base + reg_set->status, link0_status, link0_status & BIT(reg_set->r0_offset), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: R0 not ready\n", __func__); + pr_err("R0 not ready\n"); goto error; } rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.an, an); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error writing an to sink\n", __func__); + pr_err("error writing an to sink\n"); goto error; } rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.aksv, aksv); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error writing aksv to sink\n", __func__); + pr_err("error writing aksv to sink\n"); goto error; } @@ -864,8 +771,8 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl) timeout_count = wait_for_completion_timeout( &hdcp_ctrl->sink_r0_available, HZ / 2); - if (!timeout_count) { - DEV_ERR("sink R0 not ready\n"); + if (!timeout_count || hdcp_ctrl->reauth) { + pr_err("sink R0 not ready\n"); rc = -EINVAL; goto error; } @@ -875,11 +782,11 @@ r0_read_retry: memset(buf, 0, sizeof(buf)); rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.r0, buf, false); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading R0' from sink\n", __func__); + pr_err("error reading R0' from sink\n"); goto error; } - DEV_DBG("%s: %s: R0'=%02x%02x\n", __func__, HDCP_STATE_NAME, + pr_debug("%s: R0'=%02x%02x\n", HDCP_STATE_NAME, buf[1], buf[0]); /* Write R0' to HDCP registers and check to see if it is a match */ @@ -888,7 +795,7 @@ r0_read_retry: link0_status & BIT(12), r0_read_delay_us, r0_read_timeout_us); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: R0 mismatch\n", __func__); + pr_err("R0 mismatch\n"); if (--r0_retry) goto r0_read_retry; @@ -897,13 +804,13 @@ r0_read_retry: hdcp1_set_enc(true); - DEV_INFO("%s: %s: Authentication Part I successful\n", __func__, + pr_debug("%s: Authentication Part I successful\n", hdcp_ctrl ? HDCP_STATE_NAME : "???"); return 0; error: - DEV_ERR("%s: %s: Authentication Part I failed\n", __func__, + pr_err("%s: Authentication Part I failed\n", hdcp_ctrl ? HDCP_STATE_NAME : "???"); return rc; @@ -915,20 +822,16 @@ static int hdcp_1x_set_v_h(struct hdcp_1x_ctrl *hdcp_ctrl, int rc; struct dss_io_data *io; - if (!hdcp_ctrl->tz_hdcp && hdcp_ctrl->init_data.sec_access) - io = hdcp_ctrl->init_data.hdcp_io; - else - io = hdcp_ctrl->init_data.core_io; + io = hdcp_ctrl->init_data.hdcp_io; rc = hdcp_1x_read(hdcp_ctrl, rd->sink, buf, false); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading %s\n", __func__, rd->sink->name); + pr_err("error reading %s\n", rd->sink->name); goto end; } - if (!hdcp_ctrl->tz_hdcp) - DSS_REG_W(io, rd->reg_id, - (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); + DSS_REG_W(io, rd->reg_id, + (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); end: return rc; } @@ -937,46 +840,27 @@ static int hdcp_1x_transfer_v_h(struct hdcp_1x_ctrl *hdcp_ctrl) { int rc = 0; u8 buf[4]; - struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; struct hdcp_reg_set *reg_set = &hdcp_ctrl->reg_set; struct hdcp_1x_reg_data reg_data[] = { - {reg_set_data(7), &hdcp_ctrl->sink_addr.v_h0}, - {reg_set_data(8), &hdcp_ctrl->sink_addr.v_h1}, - {reg_set_data(9), &hdcp_ctrl->sink_addr.v_h2}, - {reg_set_data(10), &hdcp_ctrl->sink_addr.v_h3}, - {reg_set_data(11), &hdcp_ctrl->sink_addr.v_h4}, + {reg_set->sec_data7, &hdcp_ctrl->sink_addr.v_h0}, + {reg_set->sec_data8, &hdcp_ctrl->sink_addr.v_h1}, + {reg_set->sec_data9, &hdcp_ctrl->sink_addr.v_h2}, + {reg_set->sec_data10, &hdcp_ctrl->sink_addr.v_h3}, + {reg_set->sec_data11, &hdcp_ctrl->sink_addr.v_h4}, }; u32 size = ARRAY_SIZE(reg_data); - u32 iter = 0, ret = 0, resp = 0; + u32 iter = 0; phy_addr = hdcp_ctrl->init_data.phy_addr; - memset(scm_buf, 0x00, sizeof(scm_buf)); - for (iter = 0; iter < size; iter++) { struct hdcp_1x_reg_data *rd = reg_data + iter; memset(buf, 0, sizeof(buf)); hdcp_1x_set_v_h(hdcp_ctrl, rd, buf); - - if (hdcp_ctrl->tz_hdcp) { - u32 reg_val = buf[3] << 24 | buf[2] << 16 | - buf[1] << 8 | buf[0]; - - scm_buf[iter].addr = phy_addr + reg_data[iter].reg_id; - scm_buf[iter].val = reg_val; - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: scm err: ret=%d, resp=%d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } } -error: + return rc; } @@ -993,15 +877,12 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) u32 ksv_bytes; struct dss_io_data *io; struct hdcp_reg_set *reg_set; - struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; - u32 ret = 0; - u32 resp = 0; u32 ksv_read_retry = 20; int v_retry = 3; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); rc = -EINVAL; goto error; } @@ -1010,7 +891,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) reg_set = &hdcp_ctrl->reg_set; if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) { - DEV_DBG("%s: %s: invalid state. returning\n", __func__, + pr_debug("%s: invalid state. returning\n", HDCP_STATE_NAME); rc = -EINVAL; goto error; @@ -1029,7 +910,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) */ rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, &bcaps, true); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading bcaps\n", __func__); + pr_err("error reading bcaps\n"); goto error; } @@ -1040,7 +921,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, &bcaps, true); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading bcaps\n", __func__); + pr_err("error reading bcaps\n"); goto error; } msleep(100); @@ -1050,8 +931,8 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) timeout_count = wait_for_completion_timeout( &hdcp_ctrl->sink_rep_ready, HZ * 5); - if (!timeout_count) { - DEV_ERR("sink not ready with DS KSV list\n"); + if (!timeout_count || hdcp_ctrl->reauth) { + pr_err("sink not ready with DS KSV list\n"); rc = -EINVAL; goto error; } @@ -1060,42 +941,20 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus, buf, true); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: error reading bstatus\n", __func__); + pr_err("error reading bstatus\n"); goto error; } bstatus = buf[1]; bstatus = (bstatus << 8) | buf[0]; - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); - - /* Write BSTATUS and BCAPS to HDCP registers */ - scm_buf[0].addr = phy_addr + reg_set->data12; - scm_buf[0].val = bcaps | (bstatus << 8); - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - reg_set->sec_data12, - bcaps | (bstatus << 8)); - } else { - DSS_REG_W(io, reg_set->data12, bcaps | (bstatus << 8)); - } - down_stream_devices = bstatus & 0x7F; - DEV_DBG("%s: DEVICE_COUNT %d\n", __func__, down_stream_devices); + pr_debug("DEVICE_COUNT %d\n", down_stream_devices); /* Cascaded repeater depth */ repeater_cascade_depth = (bstatus >> 8) & 0x7; - DEV_DBG("%s: DEPTH %d\n", __func__, repeater_cascade_depth); + pr_debug("DEPTH %d\n", repeater_cascade_depth); /* * HDCP Compliance 1B-05: @@ -1103,10 +962,10 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) * exceed max_devices_connected from bit 7 of Bstatus. */ max_devs_exceeded = (bstatus & BIT(7)) >> 7; - DEV_DBG("%s: MAX_DEVS_EXCEEDED %d\n", __func__, max_devs_exceeded); + pr_debug("MAX_DEVS_EXCEEDED %d\n", max_devs_exceeded); if (max_devs_exceeded == 0x01) { - DEV_ERR("%s: %s: no. of devs connected exceeds max allowed", - __func__, HDCP_STATE_NAME); + pr_err("%s: no. of devs connected exceeds max allowed", + HDCP_STATE_NAME); rc = -EINVAL; goto error; } @@ -1117,11 +976,11 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) * exceed max_cascade_connected from bit 11 of Bstatus. */ max_cascade_exceeded = (bstatus & BIT(11)) >> 11; - DEV_DBG("%s: MAX CASCADE_EXCEEDED %d\n", __func__, + pr_debug("MAX CASCADE_EXCEEDED %d\n", max_cascade_exceeded); if (max_cascade_exceeded == 0x01) { - DEV_ERR("%s: %s: no. of cascade conn exceeds max allowed", - __func__, HDCP_STATE_NAME); + pr_err("%s: no. of cascade conn exceeds max allowed", + HDCP_STATE_NAME); rc = -EINVAL; goto error; } @@ -1142,8 +1001,8 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.ksv_fifo, ksv_fifo, false); if (IS_ERR_VALUE(rc)) { - DEV_DBG("%s: could not read ksv fifo (%d)\n", - __func__, ksv_read_retry); + pr_debug("could not read ksv fifo (%d)\n", + ksv_read_retry); /* * HDCP Compliace Test case 1B-01: * Wait here until all the ksv bytes have been @@ -1156,9 +1015,12 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl) } if (rc) { - DEV_ERR("%s: error reading ksv_fifo\n", __func__); + pr_err("error reading ksv_fifo\n"); goto error; } + + DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, + reg_set->sec_data12, bcaps | (bstatus << 8)); v_read_retry: rc = hdcp_1x_transfer_v_h(hdcp_ctrl); if (rc) @@ -1176,55 +1038,15 @@ v_read_retry: /* First, reset SHA engine */ /* Next, enable SHA engine, SEL=DIGA_HDCP */ - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); - - scm_buf[0].addr = phy_addr + reg_set->sha_ctrl; - scm_buf[0].val = HDCP_REG_ENABLE; - scm_buf[1].addr = phy_addr + reg_set->sha_ctrl; - scm_buf[1].val = HDCP_REG_DISABLE; - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - reg_set->sec_sha_ctrl, - HDCP_REG_ENABLE); - DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - reg_set->sec_sha_ctrl, - HDCP_REG_DISABLE); - } else { - DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_ENABLE); - DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_DISABLE); - } + DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, + reg_set->sec_sha_ctrl, HDCP_REG_ENABLE); + DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, + reg_set->sec_sha_ctrl, HDCP_REG_DISABLE); for (i = 0; i < ksv_bytes - 1; i++) { /* Write KSV byte and do not set DONE bit[0] */ - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); - - scm_buf[0].addr = phy_addr + reg_set->sha_data; - scm_buf[0].val = ksv_fifo[i] << 16; - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, - reg_set->sec_sha_data, - ksv_fifo[i] << 16); - } else { - DSS_REG_W_ND(io, reg_set->sha_data, ksv_fifo[i] << 16); - } + DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, + reg_set->sec_sha_data, ksv_fifo[i] << 16); /* * Once 64 bytes have been written, we need to poll for @@ -1236,41 +1058,22 @@ v_read_retry: HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: block not done\n", __func__); + pr_err("block not done\n"); goto error; } } } /* Write l to DONE bit[0] */ - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); - - scm_buf[0].addr = phy_addr + reg_set->sha_data; - scm_buf[0].val = (ksv_fifo[ksv_bytes - 1] << 16) | 0x1; - - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; - } - } else if (hdcp_ctrl->init_data.sec_access) { - DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, - reg_set->sec_sha_data, - (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); - } else { - DSS_REG_W_ND(io, reg_set->sha_data, - (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); - } + DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, + reg_set->sec_sha_data, (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); /* Now wait for HDCP_SHA_COMP_DONE */ rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status, sha_status & BIT(4), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: V computation not done\n", __func__); + pr_err("V computation not done\n"); goto error; } @@ -1279,21 +1082,20 @@ v_read_retry: status & BIT(reg_set->v_offset), HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); if (IS_ERR_VALUE(rc)) { - DEV_ERR("%s: V mismatch\n", __func__); + pr_err("V mismatch\n"); if (--v_retry) goto v_read_retry; } error: if (rc) - DEV_ERR("%s: %s: Authentication Part II failed\n", __func__, + pr_err("%s: Authentication Part II failed\n", hdcp_ctrl ? HDCP_STATE_NAME : "???"); else - DEV_INFO("%s: %s: Authentication Part II successful\n", - __func__, HDCP_STATE_NAME); + pr_debug("%s: Authentication Part II successful\n", + HDCP_STATE_NAME); if (!hdcp_ctrl) { - DEV_ERR("%s: hdcp_ctrl null. Topology not updated\n", - __func__); + pr_err("hdcp_ctrl null. Topology not updated\n"); return rc; } /* Update topology information */ @@ -1308,7 +1110,7 @@ error: static void hdcp_1x_cache_topology(struct hdcp_1x_ctrl *hdcp_ctrl) { if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } @@ -1331,7 +1133,7 @@ static void hdcp_1x_notify_topology(struct hdcp_1x_ctrl *hdcp_ctrl) snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX); kobject_uevent_env(hdcp_ctrl->init_data.sysfs_kobj, KOBJ_CHANGE, envp); - DEV_DBG("%s Event Sent: %s msgID = %s srcID = %s\n", __func__, + pr_debug("Event Sent: %s msgID = %s srcID = %s\n", envp[0], envp[1], envp[2]); } @@ -1341,7 +1143,7 @@ static void hdcp_1x_int_work(struct work_struct *work) struct hdcp_1x_ctrl, hdcp_int_work); if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } @@ -1368,17 +1170,18 @@ static void hdcp_1x_auth_work(struct work_struct *work) struct dss_io_data *io; if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) { - DEV_DBG("%s: %s: invalid state. returning\n", __func__, + pr_debug("%s: invalid state. returning\n", HDCP_STATE_NAME); return; } hdcp_ctrl->sink_r0_ready = false; + hdcp_ctrl->reauth = false; io = hdcp_ctrl->init_data.core_io; /* Enabling Software DDC for HDMI and REF timer for DP */ @@ -1390,7 +1193,7 @@ static void hdcp_1x_auth_work(struct work_struct *work) rc = hdcp_1x_authentication_part1(hdcp_ctrl); if (rc) { - DEV_DBG("%s: %s: HDCP Auth Part I failed\n", __func__, + pr_debug("%s: HDCP Auth Part I failed\n", HDCP_STATE_NAME); goto error; } @@ -1398,12 +1201,12 @@ static void hdcp_1x_auth_work(struct work_struct *work) if (hdcp_ctrl->current_tp.ds_type == DS_REPEATER) { rc = hdcp_1x_authentication_part2(hdcp_ctrl); if (rc) { - DEV_DBG("%s: %s: HDCP Auth Part II failed\n", __func__, + pr_debug("%s: HDCP Auth Part II failed\n", HDCP_STATE_NAME); goto error; } } else { - DEV_INFO("%s: Downstream device is not a repeater\n", __func__); + pr_debug("Downstream device is not a repeater\n"); } /* Disabling software DDC before going into part3 to make sure * there is no Arbitration between software and hardware for DDC */ @@ -1431,16 +1234,16 @@ error: mutex_unlock(hdcp_ctrl->init_data.mutex); /* Notify HDMI Tx controller of the result */ - DEV_DBG("%s: %s: Notifying HDMI Tx of auth result\n", - __func__, HDCP_STATE_NAME); + pr_debug("%s: Notifying HDMI Tx of auth result\n", + HDCP_STATE_NAME); if (hdcp_ctrl->init_data.notify_status) { hdcp_ctrl->init_data.notify_status( hdcp_ctrl->init_data.cb_data, hdcp_ctrl->hdcp_state); } } else { - DEV_DBG("%s: %s: HDCP state changed during authentication\n", - __func__, HDCP_STATE_NAME); + pr_debug("%s: HDCP state changed during authentication\n", + HDCP_STATE_NAME); mutex_unlock(hdcp_ctrl->init_data.mutex); } return; @@ -1451,17 +1254,17 @@ int hdcp_1x_authenticate(void *input) struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input; if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return -EINVAL; } if (HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) { - DEV_DBG("%s: %s: already active or activating. returning\n", - __func__, HDCP_STATE_NAME); + pr_debug("%s: already active or activating. returning\n", + HDCP_STATE_NAME); return 0; } - DEV_DBG("%s: %s: Queuing work to start HDCP authentication", __func__, + pr_debug("%s: Queuing work to start HDCP authentication", HDCP_STATE_NAME); if (!hdcp_1x_load_keys(input)) { @@ -1489,7 +1292,7 @@ int hdcp_1x_reauthenticate(void *input) u32 ret = 0, reg; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return -EINVAL; } @@ -1498,7 +1301,7 @@ int hdcp_1x_reauthenticate(void *input) isr = &hdcp_ctrl->int_set; if (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state) { - DEV_DBG("%s: %s: invalid state. returning\n", __func__, + pr_debug("%s: invalid state. returning\n", HDCP_STATE_NAME); return 0; } @@ -1545,7 +1348,7 @@ void hdcp_1x_off(void *input) u32 reg; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } @@ -1554,7 +1357,7 @@ void hdcp_1x_off(void *input) isr = &hdcp_ctrl->int_set; if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) { - DEV_DBG("%s: %s: inactive. returning\n", __func__, + pr_debug("%s: inactive. returning\n", HDCP_STATE_NAME); return; } @@ -1581,11 +1384,11 @@ void hdcp_1x_off(void *input) */ rc = cancel_delayed_work(&hdcp_ctrl->hdcp_auth_work); if (rc) - DEV_DBG("%s: %s: Deleted hdcp auth work\n", __func__, + pr_debug("%s: Deleted hdcp auth work\n", HDCP_STATE_NAME); rc = cancel_work_sync(&hdcp_ctrl->hdcp_int_work); if (rc) - DEV_DBG("%s: %s: Deleted hdcp int work\n", __func__, + pr_debug("%s: Deleted hdcp int work\n", HDCP_STATE_NAME); @@ -1599,7 +1402,7 @@ void hdcp_1x_off(void *input) hdcp_ctrl->sink_r0_ready = false; - DEV_DBG("%s: %s: HDCP: Off\n", __func__, HDCP_STATE_NAME); + pr_debug("%s: HDCP: Off\n", HDCP_STATE_NAME); } /* hdcp_1x_off */ int hdcp_1x_isr(void *input) @@ -1612,7 +1415,7 @@ int hdcp_1x_isr(void *input) struct hdcp_int_set *isr; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); rc = -EINVAL; goto error; } @@ -1633,7 +1436,7 @@ int hdcp_1x_isr(void *input) /* AUTH_SUCCESS_INT */ DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->auth_success_ack)); - DEV_INFO("%s: %s: AUTH_SUCCESS_INT received\n", __func__, + pr_debug("%s: AUTH_SUCCESS_INT received\n", HDCP_STATE_NAME); if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) complete_all(&hdcp_ctrl->r0_checked); @@ -1645,8 +1448,8 @@ int hdcp_1x_isr(void *input) DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->auth_fail_ack)); - DEV_INFO("%s: %s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n", - __func__, HDCP_STATE_NAME, link_status); + pr_debug("%s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n", + HDCP_STATE_NAME, link_status); if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state) { /* Inform HDMI Tx of the failure */ queue_work(hdcp_ctrl->workq, @@ -1665,7 +1468,7 @@ int hdcp_1x_isr(void *input) /* DDC_XFER_REQ_INT */ DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->tx_req_ack)); - DEV_INFO("%s: %s: DDC_XFER_REQ_INT received\n", __func__, + pr_debug("%s: DDC_XFER_REQ_INT received\n", HDCP_STATE_NAME); } @@ -1673,7 +1476,7 @@ int hdcp_1x_isr(void *input) /* DDC_XFER_DONE_INT */ DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->tx_req_done_ack)); - DEV_INFO("%s: %s: DDC_XFER_DONE received\n", __func__, + pr_debug("%s: DDC_XFER_DONE received\n", HDCP_STATE_NAME); } @@ -1681,7 +1484,7 @@ int hdcp_1x_isr(void *input) /* Encryption enabled */ DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->encryption_ready_ack)); - DEV_INFO("%s: %s: encryption ready received\n", __func__, + pr_debug("%s: encryption ready received\n", HDCP_STATE_NAME); } @@ -1689,7 +1492,7 @@ int hdcp_1x_isr(void *input) /* Encryption enabled */ DSS_REG_W(io, isr->int_reg, (hdcp_int_val | isr->encryption_not_ready_ack)); - DEV_INFO("%s: %s: encryption not ready received\n", __func__, + pr_debug("%s: encryption not ready received\n", HDCP_STATE_NAME); } @@ -1738,13 +1541,13 @@ static ssize_t hdcp_1x_sysfs_rda_status(struct device *dev, struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev); if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return -EINVAL; } mutex_lock(hdcp_ctrl->init_data.mutex); ret = snprintf(buf, PAGE_SIZE, "%d\n", hdcp_ctrl->hdcp_state); - DEV_DBG("%s: '%d'\n", __func__, hdcp_ctrl->hdcp_state); + pr_debug("'%d'\n", hdcp_ctrl->hdcp_state); mutex_unlock(hdcp_ctrl->init_data.mutex); return ret; @@ -1757,7 +1560,7 @@ static ssize_t hdcp_1x_sysfs_rda_tp(struct device *dev, struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev); if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return -EINVAL; } @@ -1791,7 +1594,7 @@ static ssize_t hdcp_1x_sysfs_wta_tp(struct device *dev, struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev); if (!hdcp_ctrl || !buf) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return -EINVAL; } @@ -1831,7 +1634,7 @@ void hdcp_1x_deinit(void *input) struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input; if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); return; } @@ -1872,39 +1675,46 @@ static int hdcp_1x_cp_irq(void *input) int ret = -EINVAL; if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); goto end; } ret = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.cp_irq_status, &buf, false); if (IS_ERR_VALUE(ret)) { - DEV_ERR("%s: error reading cp_irq_status\n", __func__); + pr_err("error reading cp_irq_status\n"); goto end; } if (!buf) { - DEV_DBG("%s: not a hdcp 1.x irq\n", __func__); + pr_debug("not a hdcp 1.x irq\n"); ret = -EINVAL; goto end; } if ((buf & BIT(2)) || (buf & BIT(3))) { - DEV_ERR("%s: REAUTH REQUIRED\n", __func__); + pr_err("%s\n", + buf & BIT(2) ? "LINK_INTEGRITY_FAILURE" : + "REAUTHENTICATION_REQUEST"); + + hdcp_ctrl->reauth = true; + + complete_all(&hdcp_ctrl->sink_rep_ready); + complete_all(&hdcp_ctrl->sink_r0_available); queue_work(hdcp_ctrl->workq, &hdcp_ctrl->hdcp_int_work); goto end; } if (buf & BIT(1)) { - DEV_DBG("%s: R0' AVAILABLE\n", __func__); + pr_debug("R0' AVAILABLE\n"); hdcp_ctrl->sink_r0_ready = true; complete_all(&hdcp_ctrl->sink_r0_available); goto end; } if (buf & BIT(0)) { - DEV_DBG("%s: KSVs READY\n", __func__); + pr_debug("KSVs READY\n"); complete_all(&hdcp_ctrl->sink_rep_ready); goto end; } @@ -1916,7 +1726,6 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data) { struct hdcp_1x_ctrl *hdcp_ctrl = NULL; char name[20]; - int ret; static struct hdcp_ops ops = { .isr = hdcp_1x_isr, .cp_irq = hdcp_1x_cp_irq, @@ -1928,20 +1737,18 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data) if (!init_data || !init_data->core_io || !init_data->qfprom_io || !init_data->mutex || !init_data->notify_status || !init_data->workq || !init_data->cb_data) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("invalid input\n"); goto error; } if (init_data->sec_access && !init_data->hdcp_io) { - DEV_ERR("%s: hdcp_io required\n", __func__); + pr_err("hdcp_io required\n"); goto error; } hdcp_ctrl = kzalloc(sizeof(*hdcp_ctrl), GFP_KERNEL); - if (!hdcp_ctrl) { - DEV_ERR("%s: Out of memory\n", __func__); + if (!hdcp_ctrl) goto error; - } hdcp_ctrl->init_data = *init_data; hdcp_ctrl->ops = &ops; @@ -1951,7 +1758,7 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data) hdcp_ctrl->workq = create_workqueue(name); if (!hdcp_ctrl->workq) { - DEV_ERR("%s: Error creating workqueue\n", __func__); + pr_err("Error creating workqueue\n"); goto error; } @@ -1959,7 +1766,7 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data) if (sysfs_create_group(init_data->sysfs_kobj, &hdcp_1x_fs_attr_group)) { - DEV_ERR("%s: hdcp sysfs group creation failed\n", __func__); + pr_err("hdcp sysfs group creation failed\n"); goto error; } @@ -1971,18 +1778,7 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data) init_completion(&hdcp_ctrl->sink_r0_available); init_completion(&hdcp_ctrl->sink_rep_ready); - if (!hdcp_ctrl->init_data.sec_access) { - ret = scm_is_call_available(SCM_SVC_HDCP, SCM_CMD_HDCP); - if (ret <= 0) { - DEV_ERR("%s: secure hdcp service unavailable, ret = %d", - __func__, ret); - } else { - DEV_DBG("%s: tz_hdcp = 1\n", __func__); - hdcp_ctrl->tz_hdcp = 1; - } - } - - DEV_DBG("%s: HDCP module initialized. HDCP_STATE=%s", __func__, + pr_debug("HDCP module initialized. HDCP_STATE=%s\n", HDCP_STATE_NAME); error: diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index e137a8b050b0..58e0d9676736 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1139,12 +1139,31 @@ static int mdss_mdp_clk_update(u32 clk_idx, u32 enable) { int ret = -ENODEV; struct clk *clk = mdss_mdp_get_clk(clk_idx); + struct mdss_data_type *mdata = mdss_res; if (clk) { pr_debug("clk=%d en=%d\n", clk_idx, enable); if (enable) { if (clk_idx == MDSS_CLK_MDP_VSYNC) clk_set_rate(clk, 19200000); + if (mdss_has_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE) + && (clk_idx == MDSS_CLK_MDP_CORE)) { + + if (WARN_ON(!mdata->mdp_clk_rate)) { + /* + * rate should have been set in probe + * or during clk scaling; but if this + * is not the case, set max clk rate. + */ + pr_warn("set max mdp clk rate:%u\n", + mdata->max_mdp_clk_rate); + mdss_mdp_set_clk_rate( + mdata->max_mdp_clk_rate, true); + } else { + clk_set_rate(clk, mdata->mdp_clk_rate); + } + } + ret = clk_prepare_enable(clk); } else { clk_disable_unprepare(clk); @@ -1172,7 +1191,7 @@ int mdss_mdp_vsync_clk_enable(int enable, bool locked) return ret; } -void mdss_mdp_set_clk_rate(unsigned long rate) +void mdss_mdp_set_clk_rate(unsigned long rate, bool locked) { struct mdss_data_type *mdata = mdss_res; unsigned long clk_rate; @@ -1182,7 +1201,9 @@ void mdss_mdp_set_clk_rate(unsigned long rate) min_clk_rate = max(rate, mdata->perf_tune.min_mdp_clk); if (clk) { - mutex_lock(&mdp_clk_lock); + + if (!locked) + mutex_lock(&mdp_clk_lock); if (min_clk_rate < mdata->max_mdp_clk_rate) clk_rate = clk_round_rate(clk, min_clk_rate); else @@ -1190,12 +1211,15 @@ void mdss_mdp_set_clk_rate(unsigned long 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)) { + + mdata->mdp_clk_rate = clk_rate; 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); + if (!locked) + mutex_unlock(&mdp_clk_lock); } else { pr_err("mdp src clk not setup properly\n"); } @@ -1779,7 +1803,7 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata) mdss_mdp_irq_clk_register(mdata, "mnoc_clk", MDSS_CLK_MNOC_AHB); /* Setting the default clock rate to the max supported.*/ - mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate); + mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate, false); pr_debug("mdp clk rate=%ld\n", mdss_mdp_get_clk_rate(MDSS_CLK_MDP_CORE, false)); @@ -2022,6 +2046,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata) mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU); mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT); mdss_set_quirk(mdata, MDSS_QUIRK_MMSS_GDSC_COLLAPSE); + mdss_set_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE); mdata->has_wb_ubwc = true; set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map); set_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map); diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 623c588ae456..20aeabfdf9a4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -22,6 +22,7 @@ #include <linux/notifier.h> #include <linux/irqreturn.h> #include <linux/kref.h> +#include <linux/kthread.h> #include "mdss.h" #include "mdss_mdp_hwio.h" @@ -550,6 +551,7 @@ struct mdss_mdp_ctl { /* dynamic resolution switch during cont-splash handoff */ bool switch_with_handoff; struct mdss_mdp_avr_info avr_info; + bool commit_in_progress; }; struct mdss_mdp_mixer { @@ -931,7 +933,6 @@ struct mdss_overlay_private { struct sw_sync_timeline *vsync_timeline; struct mdss_mdp_vsync_handler vsync_retire_handler; - struct work_struct retire_work; int retire_cnt; bool kickoff_released; u32 cursor_ndx[2]; @@ -943,6 +944,11 @@ struct mdss_overlay_private { struct mdss_mdp_cwb cwb; wait_queue_head_t wb_waitq; atomic_t wb_busy; + bool allow_kickoff; + + struct kthread_worker worker; + struct kthread_work vsync_work; + struct task_struct *thread; }; struct mdss_mdp_set_ot_params { @@ -1590,7 +1596,7 @@ u32 mdss_mdp_get_irq_mask(u32 intr_type, u32 intf_num); void mdss_mdp_footswitch_ctrl_splash(int on); void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable); -void mdss_mdp_set_clk_rate(unsigned long min_clk_rate); +void mdss_mdp_set_clk_rate(unsigned long min_clk_rate, bool locked); unsigned long mdss_mdp_get_clk_rate(u32 clk_idx, bool locked); int mdss_mdp_vsync_clk_enable(int enable, bool locked); void mdss_mdp_clk_ctrl(int enable); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 9c5c5ea090c3..c80d8f47bbb7 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -2375,7 +2375,7 @@ static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, */ if (update_clk) { ATRACE_INT("mdp_clk", clk_rate); - mdss_mdp_set_clk_rate(clk_rate); + mdss_mdp_set_clk_rate(clk_rate, false); pr_debug("update clk rate = %d HZ\n", clk_rate); } @@ -5788,7 +5788,9 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, } else { sctl_flush_bits = sctl->flush_bits; } + sctl->commit_in_progress = true; } + ctl->commit_in_progress = true; ctl_flush_bits = ctl->flush_bits; ATRACE_END("postproc_programming"); @@ -5916,11 +5918,16 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, ATRACE_BEGIN("flush_kickoff"); mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush_bits); - if (sctl && sctl_flush_bits) { - mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH, - sctl_flush_bits); - sctl->flush_bits = 0; + if (sctl) { + if (sctl_flush_bits) { + mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH, + sctl_flush_bits); + sctl->flush_bits = 0; + } + sctl->commit_in_progress = false; } + ctl->commit_in_progress = false; + MDSS_XLOG(ctl->intf_num, ctl_flush_bits, sctl_flush_bits, split_lm_valid); wmb(); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index a71c7254de7c..4852fc73f040 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -1267,7 +1267,8 @@ static void mdss_mdp_cmd_pingpong_done(void *arg) atomic_read(&ctx->koff_cnt)); if (sync_ppdone) { atomic_inc(&ctx->pp_done_cnt); - schedule_work(&ctx->pp_done_work); + if (!ctl->commit_in_progress) + schedule_work(&ctx->pp_done_work); mdss_mdp_resource_control(ctl, MDP_RSRC_CTL_EVENT_PP_DONE); diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 154b9d86e67c..bf8130b35a57 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -1923,6 +1923,8 @@ static void __restore_pipe(struct mdss_mdp_pipe *pipe) pipe->dst.y = pipe->layer.dst_rect.y; pipe->dst.w = pipe->layer.dst_rect.w; pipe->dst.h = pipe->layer.dst_rect.h; + + pipe->restore_roi = false; } /** @@ -1946,7 +1948,6 @@ static int __crop_adjust_pipe_rect(struct mdss_mdp_pipe *pipe, u32 roi_y_pos; int ret = 0; - pipe->restore_roi = false; if (mdss_rect_overlap_check(&pipe->dst, &dual_roi->first_roi)) { mdss_mdp_crop_rect(&pipe->src, &pipe->dst, &dual_roi->first_roi, false); @@ -2092,6 +2093,13 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd, } list_for_each_entry(pipe, &mdp5_data->pipes_used, list) { + /* + * Restore the pipe src/dst ROI if it was altered + * in the previous kickoff. + */ + if (pipe->restore_roi) + __restore_pipe(pipe); + pr_debug("pipe:%d src:{%d,%d,%d,%d} dst:{%d,%d,%d,%d}\n", pipe->num, pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h, pipe->dst.x, @@ -5580,7 +5588,7 @@ ctl_stop: * retire_signal api checks for retire_cnt with sync_mutex lock. */ - flush_work(&mdp5_data->retire_work); + flush_kthread_work(&mdp5_data->vsync_work); } mutex_lock(&mdp5_data->ov_lock); @@ -5783,13 +5791,13 @@ static void __vsync_retire_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t) } mdp5_data = mfd_to_mdp5_data(mfd); - schedule_work(&mdp5_data->retire_work); + queue_kthread_work(&mdp5_data->worker, &mdp5_data->vsync_work); } -static void __vsync_retire_work_handler(struct work_struct *work) +static void __vsync_retire_work_handler(struct kthread_work *work) { struct mdss_overlay_private *mdp5_data = - container_of(work, typeof(*mdp5_data), retire_work); + container_of(work, typeof(*mdp5_data), vsync_work); if (!mdp5_data->ctl || !mdp5_data->ctl->mfd) return; @@ -5889,6 +5897,7 @@ static int __vsync_retire_setup(struct msm_fb_data_type *mfd) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); char name[24]; + struct sched_param param = { .sched_priority = 5 }; snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index); mdp5_data->vsync_timeline = sw_sync_timeline_create(name); @@ -5896,12 +5905,26 @@ static int __vsync_retire_setup(struct msm_fb_data_type *mfd) pr_err("cannot vsync create time line"); return -ENOMEM; } + + init_kthread_worker(&mdp5_data->worker); + init_kthread_work(&mdp5_data->vsync_work, __vsync_retire_work_handler); + + mdp5_data->thread = kthread_run(kthread_worker_fn, + &mdp5_data->worker, "vsync_retire_work"); + + if (IS_ERR(mdp5_data->thread)) { + pr_err("unable to start vsync thread\n"); + mdp5_data->thread = NULL; + return -ENOMEM; + } + + sched_setscheduler(mdp5_data->thread, SCHED_FIFO, ¶m); + mfd->mdp_sync_pt_data.get_retire_fence = __vsync_retire_get_fence; mdp5_data->vsync_retire_handler.vsync_handler = __vsync_retire_handle_vsync; mdp5_data->vsync_retire_handler.cmd_post_flush = false; - INIT_WORK(&mdp5_data->retire_work, __vsync_retire_work_handler); return 0; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index 94e64dd396d5..4d42e42035c3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -1114,6 +1114,7 @@ static void mdss_mdp_init_pipe_params(struct mdss_mdp_pipe *pipe) pipe->is_right_blend = false; pipe->src_split_req = false; pipe->bwc_mode = 0; + pipe->restore_roi = false; pipe->mfd = NULL; pipe->mixer_left = pipe->mixer_right = NULL; diff --git a/include/linux/clk/msm-clk-provider.h b/include/linux/clk/msm-clk-provider.h index a09ce5c3b156..2fa8916ad356 100644 --- a/include/linux/clk/msm-clk-provider.h +++ b/include/linux/clk/msm-clk-provider.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2007-2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -29,6 +29,7 @@ #include <linux/seq_file.h> #include <linux/clk/msm-clk.h> +#if defined(CONFIG_COMMON_CLK_MSM) /* * Bit manipulation macros */ @@ -265,4 +266,5 @@ static inline const char *clk_name(struct clk *c) return "(null)"; return c->dbg_name; }; +#endif /* CONFIG_COMMON_CLK_MSM */ #endif diff --git a/include/linux/clk/msm-clk.h b/include/linux/clk/msm-clk.h index 964909d25021..8455fd776246 100644 --- a/include/linux/clk/msm-clk.h +++ b/include/linux/clk/msm-clk.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2012-2015 The Linux Foundation. All rights reserved. +/* Copyright (c) 2009, 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,6 +23,9 @@ enum branch_mem_flags { CLKFLAG_PERIPH_OFF_SET, CLKFLAG_PERIPH_OFF_CLEAR, }; + +#include <linux/clk.h> + #elif defined(CONFIG_COMMON_CLK_MSM) #define CLKFLAG_INVERT 0x00000001 #define CLKFLAG_NOINVERT 0x00000002 @@ -42,7 +45,6 @@ enum branch_mem_flags { #define CLKFLAG_EPROBE_DEFER 0x00010000 #define CLKFLAG_PERIPH_OFF_SET 0x00020000 #define CLKFLAG_PERIPH_OFF_CLEAR 0x00040000 -#endif struct clk_lookup; struct clk; @@ -132,4 +134,5 @@ int msm_clk_notif_register(struct clk *clk, struct notifier_block *nb); int msm_clk_notif_unregister(struct clk *clk, struct notifier_block *nb); +#endif /* CONFIG_COMMON_CLK_MSM */ #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index 4f6711f31939..9c3be2d56ac5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2401,6 +2401,8 @@ struct cpu_cycle_counter_cb { u64 (*get_cpu_cycle_counter)(int cpu); }; +#define MAX_NUM_CGROUP_COLOC_ID 20 + #ifdef CONFIG_SCHED_HMP extern void free_task_load_ptrs(struct task_struct *p); extern int sched_set_window(u64 window_start, unsigned int window_size); diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index e713641cc3ec..e01e16e5cebe 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -3609,6 +3609,10 @@ struct asm_alac_cfg { u32 channel_layout_tag; }; +struct asm_g711_dec_cfg { + u32 sample_rate; +}; + struct asm_vorbis_cfg { u32 bit_stream_fmt; }; @@ -4220,6 +4224,22 @@ struct asm_aac_enc_cfg_v2 { } __packed; +#define ASM_MEDIA_FMT_G711_ALAW_FS 0x00010BF7 +#define ASM_MEDIA_FMT_G711_MLAW_FS 0x00010C2E + +struct asm_g711_enc_cfg_v2 { + struct apr_hdr hdr; + struct asm_stream_cmd_set_encdec_param encdec; + struct asm_enc_cfg_blk_param_v2 encblk; + + u32 sample_rate; +/* + * Number of samples per second. + * Supported values: 8000, 16000 Hz + */ + +} __packed; + struct asm_vorbis_fmt_blk_v2 { struct apr_hdr hdr; struct asm_data_cmd_media_fmt_update_v2 fmtblk; @@ -4321,6 +4341,12 @@ struct asm_alac_fmt_blk_v2 { } __packed; +struct asm_g711_dec_fmt_blk_v2 { + struct apr_hdr hdr; + struct asm_data_cmd_media_fmt_update_v2 fmtblk; + u32 sample_rate; +} __packed; + struct asm_ape_fmt_blk_v2 { struct apr_hdr hdr; struct asm_data_cmd_media_fmt_update_v2 fmtblk; @@ -8811,6 +8837,7 @@ struct afe_param_id_clip_bank_sel { /* Supported OSR clock values */ #define Q6AFE_LPASS_OSR_CLK_12_P288_MHZ 0xBB8000 +#define Q6AFE_LPASS_OSR_CLK_11_P2896_MHZ 0xAC4400 #define Q6AFE_LPASS_OSR_CLK_9_P600_MHZ 0x927C00 #define Q6AFE_LPASS_OSR_CLK_8_P192_MHZ 0x7D0000 #define Q6AFE_LPASS_OSR_CLK_6_P144_MHZ 0x5DC000 diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index f08bd73edb59..efa5af8e661c 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -73,6 +73,11 @@ /* bit 4 represents META enable of encoded data buffer */ #define BUFFER_META_ENABLE 0x0010 +/* bit 5 represents timestamp */ +/* bit 5 - 0 -- ASM_DATA_EVENT_READ_DONE will have relative time-stamp*/ +/* bit 5 - 1 -- ASM_DATA_EVENT_READ_DONE will have absolute time-stamp*/ +#define ABSOLUTE_TIMESTAMP_ENABLE 0x0020 + /* Enable Sample_Rate/Channel_Mode notification event from Decoder */ #define SR_CM_NOTIFY_ENABLE 0x0004 @@ -175,6 +180,7 @@ struct audio_aio_read_param { phys_addr_t paddr; uint32_t len; uint32_t uid; + uint32_t flags;/*meta data flags*/ }; struct audio_port_data { @@ -382,6 +388,10 @@ int q6asm_enc_cfg_blk_aac(struct audio_client *ac, uint32_t bit_rate, uint32_t mode, uint32_t format); +int q6asm_enc_cfg_blk_g711(struct audio_client *ac, + uint32_t frames_per_buf, + uint32_t sample_rate); + int q6asm_enc_cfg_blk_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels); @@ -530,6 +540,9 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac, int q6asm_media_format_block_alac(struct audio_client *ac, struct asm_alac_cfg *cfg, int stream_id); +int q6asm_media_format_block_g711(struct audio_client *ac, + struct asm_g711_dec_cfg *cfg, int stream_id); + int q6asm_stream_media_format_block_vorbis(struct audio_client *ac, struct asm_vorbis_cfg *cfg, int stream_id); diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 14bd1e806ad7..748b7c277a3c 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -302,6 +302,8 @@ header-y += msm_audio_wma.h header-y += msm_audio_wmapro.h header-y += msm_audio_alac.h header-y += msm_audio_ape.h +header-y += msm_audio_g711.h +header-y += msm_audio_g711_dec.h header-y += msm_ion.h header-y += msm_kgsl.h header-y += msm_pft.h diff --git a/include/uapi/linux/msm_audio_g711.h b/include/uapi/linux/msm_audio_g711.h new file mode 100644 index 000000000000..48ebd6a1131e --- /dev/null +++ b/include/uapi/linux/msm_audio_g711.h @@ -0,0 +1,17 @@ +#ifndef _UAPI_MSM_AUDIO_G711_H +#define _UAPI_MSM_AUDIO_G711_H + +#include <linux/msm_audio.h> + +struct msm_audio_g711_enc_config { + uint32_t sample_rate; +}; + +#define AUDIO_SET_G711_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config) + +#define AUDIO_GET_G711_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config) + + +#endif /* _UAPI_MSM_AUDIO_G711_H */ diff --git a/include/uapi/linux/msm_audio_g711_dec.h b/include/uapi/linux/msm_audio_g711_dec.h new file mode 100644 index 000000000000..ff7e4ce39fd5 --- /dev/null +++ b/include/uapi/linux/msm_audio_g711_dec.h @@ -0,0 +1,16 @@ +#ifndef _UAPI_MSM_AUDIO_G711_H +#define _UAPI_MSM_AUDIO_G711_H + +#include <linux/msm_audio.h> + +struct msm_audio_g711_dec_config { + uint32_t sample_rate; +}; + +#define AUDIO_SET_G711_DEC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config) + +#define AUDIO_GET_G711_DEC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \ + (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config) + +#endif /* _UAPI_MSM_AUDIO_G711_H */ diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h index e9b5501c697b..50b8fc32b129 100644 --- a/include/uapi/media/msm_media_info.h +++ b/include/uapi/media/msm_media_info.h @@ -2,7 +2,9 @@ #define __MEDIA_INFO_H__ #ifndef MSM_MEDIA_ALIGN -#define MSM_MEDIA_ALIGN(__sz, __align) (((__sz) + (__align-1)) & (~(__align-1))) +#define MSM_MEDIA_ALIGN(__sz, __align) (((__align) & ((__align) - 1)) ?\ + ((((__sz) + (__align) - 1) / (__align)) * (__align)) :\ + (((__sz) + (__align) - 1) & (~((__align) - 1)))) #endif #ifndef MSM_MEDIA_ROUNDUP @@ -399,8 +401,195 @@ enum color_fmts { * Extradata, 4096) */ COLOR_FMT_RGBA8888_UBWC, + /* Venus RGBA1010102 UBWC format: + * Contains 2 planes in the following order - + * (A) Meta plane + * (B) RGBA plane + * + * <--- RGB_Meta_Stride ----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_RGB_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <-------- RGB_Stride --------> + * <------- Width -------> + * R R R R R R R R R R R R . . . . ^ ^ + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . Height | + * R R R R R R R R R R R R . . . . | RGB_Scanlines + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * + * RGB_Stride = align(Width * 4, 256) + * RGB_Scanlines = align(Height, 16) + * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) + * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) + * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) + * RGB_Meta_Plane_size = align(RGB_Meta_Stride * + * RGB_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + + * Extradata, 4096) + */ + COLOR_FMT_RGBA1010102_UBWC, + /* Venus RGB565 UBWC format: + * Contains 2 planes in the following order - + * (A) Meta plane + * (B) RGB plane + * + * <--- RGB_Meta_Stride ----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_RGB_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <-------- RGB_Stride --------> + * <------- Width -------> + * R R R R R R R R R R R R . . . . ^ ^ + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . Height | + * R R R R R R R R R R R R . . . . | RGB_Scanlines + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * + * RGB_Stride = align(Width * 2, 128) + * RGB_Scanlines = align(Height, 16) + * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) + * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) + * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) + * RGB_Meta_Plane_size = align(RGB_Meta_Stride * + * RGB_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + + * Extradata, 4096) + */ + COLOR_FMT_RGB565_UBWC, + /* P010 UBWC: + * Compressed Macro-tile format for NV12. + * Contains 4 planes in the following order - + * (A) Y_Meta_Plane + * (B) Y_UBWC_Plane + * (C) UV_Meta_Plane + * (D) UV_UBWC_Plane + * + * Y_Meta_Plane consists of meta information to decode compressed + * tile data in Y_UBWC_Plane. + * Y_UBWC_Plane consists of Y data in compressed macro-tile format. + * UBWC decoder block will use the Y_Meta_Plane data together with + * Y_UBWC_Plane data to produce loss-less uncompressed 10 bit Y samples. + * + * UV_Meta_Plane consists of meta information to decode compressed + * tile data in UV_UBWC_Plane. + * UV_UBWC_Plane consists of UV data in compressed macro-tile format. + * UBWC decoder block will use UV_Meta_Plane data together with + * UV_UBWC_Plane data to produce loss-less uncompressed 10 bit 2x2 + * subsampled color difference samples. + * + * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable + * and randomly accessible. There is no dependency between tiles. + * + * <----- Y_Meta_Stride -----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_Y_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <--Compressed tile Y Stride---> + * <------- Width -------> + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * <----- UV_Meta_Stride ----> + * M M M M M M M M M M M M . . ^ + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . M_UV_Scanlines + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * <--Compressed tile UV Stride---> + * U* V* U* V* U* V* U* V* . . . . ^ + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * + * + * Y_Stride = align(Width * 2, 256) + * UV_Stride = align(Width * 2, 256) + * Y_Scanlines = align(Height, 16) + * UV_Scanlines = align(Height/2, 16) + * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096) + * UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096) + * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) + * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16) + * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096) + * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) + * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) + * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size + + * Y_Meta_Plane_size + UV_Meta_Plane_size + * + max(Extradata, Y_Stride * 48), 4096) + */ + COLOR_FMT_P010_UBWC, }; +#define COLOR_FMT_RGBA1010102_UBWC COLOR_FMT_RGBA1010102_UBWC +#define COLOR_FMT_RGB565_UBWC COLOR_FMT_RGB565_UBWC +#define COLOR_FMT_P010_UBWC COLOR_FMT_P010_UBWC + static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height) { (void)height; @@ -433,6 +622,10 @@ static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width) stride = MSM_MEDIA_ALIGN(width, 192); stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment); break; + case COLOR_FMT_P010_UBWC: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width * 2, alignment); + break; default: break; } @@ -460,6 +653,10 @@ static inline unsigned int VENUS_UV_STRIDE(int color_fmt, int width) stride = MSM_MEDIA_ALIGN(width, 192); stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment); break; + case COLOR_FMT_P010_UBWC: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width * 2, alignment); + break; default: break; } @@ -482,6 +679,7 @@ static inline unsigned int VENUS_Y_SCANLINES(int color_fmt, int height) alignment = 32; break; case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: alignment = 16; break; default: @@ -504,6 +702,7 @@ static inline unsigned int VENUS_UV_SCANLINES(int color_fmt, int height) case COLOR_FMT_NV12: case COLOR_FMT_NV12_MVTB: case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: alignment = 16; break; case COLOR_FMT_NV12_UBWC: @@ -528,6 +727,7 @@ static inline unsigned int VENUS_Y_META_STRIDE(int color_fmt, int width) switch (color_fmt) { case COLOR_FMT_NV12_UBWC: + case COLOR_FMT_P010_UBWC: y_tile_width = 32; break; case COLOR_FMT_NV12_BPP10_UBWC: @@ -556,6 +756,7 @@ static inline unsigned int VENUS_Y_META_SCANLINES(int color_fmt, int height) y_tile_height = 8; break; case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: y_tile_height = 4; break; default: @@ -578,6 +779,7 @@ static inline unsigned int VENUS_UV_META_STRIDE(int color_fmt, int width) switch (color_fmt) { case COLOR_FMT_NV12_UBWC: + case COLOR_FMT_P010_UBWC: uv_tile_width = 16; break; case COLOR_FMT_NV12_BPP10_UBWC: @@ -606,6 +808,7 @@ static inline unsigned int VENUS_UV_META_SCANLINES(int color_fmt, int height) uv_tile_height = 8; break; case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: uv_tile_height = 4; break; default: @@ -621,7 +824,7 @@ invalid_input: static inline unsigned int VENUS_RGB_STRIDE(int color_fmt, int width) { - unsigned int alignment = 0, stride = 0; + unsigned int alignment = 0, stride = 0, bpp = 4; if (!width) goto invalid_input; @@ -630,14 +833,19 @@ static inline unsigned int VENUS_RGB_STRIDE(int color_fmt, int width) case COLOR_FMT_RGBA8888: alignment = 128; break; + case COLOR_FMT_RGB565_UBWC: + alignment = 128; + bpp = 2; + break; case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: alignment = 256; break; default: goto invalid_input; } - stride = MSM_MEDIA_ALIGN(width * 4, alignment); + stride = MSM_MEDIA_ALIGN(width * bpp, alignment); invalid_input: return stride; @@ -655,6 +863,8 @@ static inline unsigned int VENUS_RGB_SCANLINES(int color_fmt, int height) alignment = 32; break; case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + case COLOR_FMT_RGB565_UBWC: alignment = 16; break; default: @@ -676,6 +886,8 @@ static inline unsigned int VENUS_RGB_META_STRIDE(int color_fmt, int width) switch (color_fmt) { case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + case COLOR_FMT_RGB565_UBWC: rgb_tile_width = 16; break; default: @@ -698,6 +910,8 @@ static inline unsigned int VENUS_RGB_META_SCANLINES(int color_fmt, int height) switch (color_fmt) { case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + case COLOR_FMT_RGB565_UBWC: rgb_tile_height = 4; break; default: diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 47367c663011..ef96966b2bbe 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -70,6 +70,11 @@ #define Q6_DTS 0x00010D88 #define Q6_DTS_LBR 0x00010DBB +/* Timestamp flsg */ +/* Bit-0 - 1 : Enable Timestamp mode */ +/* Bit-0 - 0 : Disable Timestamp mode */ +#define COMPRESSED_TIMESTAMP_FLAG 0x0001 + /* Codecs are listed linearly to allow for extensibility */ #define SND_AUDIOCODEC_PCM ((__u32) 0x00000001) #define SND_AUDIOCODEC_MP3 ((__u32) 0x00000002) @@ -480,7 +485,24 @@ struct snd_codec { __u32 align; __u32 compr_passthr; union snd_codec_options options; - __u32 reserved[3]; + __u32 flags; + __u32 reserved[2]; } __attribute__((packed, aligned(4))); + +/** struct snd_codec_metadata + * @length: Length of the encoded buffer. + * @offset: Offset from the buffer address to the first byte of the first + * encoded frame. All encoded frames are consecutive starting + * from this offset. + * @timestamp: Session time in microseconds of the first sample in the buffer. + * @reserved: Reserved for future use. + */ +struct snd_codec_metadata { + __u32 length; + __u32 offset; + __u64 timestamp; + __u32 reserved[4]; +}; + #endif diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f352d06d7673..d7846edd7a79 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -8071,6 +8071,9 @@ void __init sched_init(void) atomic_set(&rq->nr_iowait, 0); } + i = alloc_related_thread_groups(); + BUG_ON(i); + set_hmp_defaults(); set_load_weight(&init_task); diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index 5ff7a11d043f..6304c5030137 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -788,11 +788,12 @@ __read_mostly unsigned int sched_major_task_runtime = 10000000; static unsigned int sync_cpu; -static LIST_HEAD(related_thread_groups); +struct related_thread_group *related_thread_groups[MAX_NUM_CGROUP_COLOC_ID]; +static LIST_HEAD(active_related_thread_groups); static DEFINE_RWLOCK(related_thread_group_lock); #define for_each_related_thread_group(grp) \ - list_for_each_entry(grp, &related_thread_groups, list) + list_for_each_entry(grp, &active_related_thread_groups, list) /* * Task load is categorized into buckets for the purpose of top task tracking. @@ -3056,7 +3057,7 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size) read_unlock(&tasklist_lock); - list_for_each_entry(grp, &related_thread_groups, list) { + list_for_each_entry(grp, &active_related_thread_groups, list) { int j; for_each_possible_cpu(j) { @@ -3972,47 +3973,54 @@ _group_cpu_time(struct related_thread_group *grp, int cpu) return grp ? per_cpu_ptr(grp->cpu_time, cpu) : NULL; } -struct related_thread_group *alloc_related_thread_group(int group_id) +static inline struct related_thread_group* +lookup_related_thread_group(unsigned int group_id) { - struct related_thread_group *grp; - - grp = kzalloc(sizeof(*grp), GFP_ATOMIC); - if (!grp) - return ERR_PTR(-ENOMEM); - - if (alloc_group_cputime(grp)) { - kfree(grp); - return ERR_PTR(-ENOMEM); - } - - grp->id = group_id; - INIT_LIST_HEAD(&grp->tasks); - INIT_LIST_HEAD(&grp->list); - raw_spin_lock_init(&grp->lock); - - return grp; + return related_thread_groups[group_id]; } -struct related_thread_group *lookup_related_thread_group(unsigned int group_id) +int alloc_related_thread_groups(void) { + int i, ret; struct related_thread_group *grp; - list_for_each_entry(grp, &related_thread_groups, list) { - if (grp->id == group_id) - return grp; + /* groupd_id = 0 is invalid as it's special id to remove group. */ + for (i = 1; i < MAX_NUM_CGROUP_COLOC_ID; i++) { + grp = kzalloc(sizeof(*grp), GFP_NOWAIT); + if (!grp) { + ret = -ENOMEM; + goto err; + } + + if (alloc_group_cputime(grp)) { + kfree(grp); + ret = -ENOMEM; + goto err; + } + + grp->id = i; + INIT_LIST_HEAD(&grp->tasks); + INIT_LIST_HEAD(&grp->list); + raw_spin_lock_init(&grp->lock); + + related_thread_groups[i] = grp; } - return NULL; -} + return 0; -/* See comments before preferred_cluster() */ -static void free_related_thread_group(struct rcu_head *rcu) -{ - struct related_thread_group *grp = container_of(rcu, struct - related_thread_group, rcu); +err: + for (i = 1; i < MAX_NUM_CGROUP_COLOC_ID; i++) { + grp = lookup_related_thread_group(i); + if (grp) { + free_group_cputime(grp); + kfree(grp); + related_thread_groups[i] = NULL; + } else { + break; + } + } - free_group_cputime(grp); - kfree(grp); + return ret; } static void remove_task_from_group(struct task_struct *p) @@ -4037,10 +4045,12 @@ static void remove_task_from_group(struct task_struct *p) raw_spin_unlock(&grp->lock); /* Reserved groups cannot be destroyed */ - if (empty_group && grp->id != DEFAULT_CGROUP_COLOC_ID) { - list_del(&grp->list); - call_rcu(&grp->rcu, free_related_thread_group); - } + if (empty_group && grp->id != DEFAULT_CGROUP_COLOC_ID) + /* + * We test whether grp->list is attached with list_empty() + * hence re-init the list after deletion. + */ + list_del_init(&grp->list); } static int @@ -4112,53 +4122,15 @@ void add_new_task_to_grp(struct task_struct *new) write_unlock_irqrestore(&related_thread_group_lock, flags); } -#if defined(CONFIG_SCHED_TUNE) && defined(CONFIG_CGROUP_SCHEDTUNE) -/* - * We create a default colocation group at boot. There is no need to - * synchronize tasks between cgroups at creation time because the - * correct cgroup hierarchy is not available at boot. Therefore cgroup - * colocation is turned off by default even though the colocation group - * itself has been allocated. Furthermore this colocation group cannot - * be destroyted once it has been created. All of this has been as part - * of runtime optimizations. - * - * The job of synchronizing tasks to the colocation group is done when - * the colocation flag in the cgroup is turned on. - */ -static int __init create_default_coloc_group(void) -{ - struct related_thread_group *grp = NULL; - unsigned long flags; - - grp = alloc_related_thread_group(DEFAULT_CGROUP_COLOC_ID); - if (IS_ERR(grp)) { - WARN_ON(1); - return -ENOMEM; - } - - write_lock_irqsave(&related_thread_group_lock, flags); - list_add(&grp->list, &related_thread_groups); - write_unlock_irqrestore(&related_thread_group_lock, flags); - - update_freq_aggregate_threshold(MAX_FREQ_AGGR_THRESH); - return 0; -} -late_initcall(create_default_coloc_group); - -int sync_cgroup_colocation(struct task_struct *p, bool insert) -{ - unsigned int grp_id = insert ? DEFAULT_CGROUP_COLOC_ID : 0; - - return sched_set_group_id(p, grp_id); -} -#endif - -int sched_set_group_id(struct task_struct *p, unsigned int group_id) +static int __sched_set_group_id(struct task_struct *p, unsigned int group_id) { int rc = 0; unsigned long flags; struct related_thread_group *grp = NULL; + if (group_id >= MAX_NUM_CGROUP_COLOC_ID) + return -EINVAL; + raw_spin_lock_irqsave(&p->pi_lock, flags); write_lock(&related_thread_group_lock); @@ -4174,29 +4146,26 @@ int sched_set_group_id(struct task_struct *p, unsigned int group_id) } grp = lookup_related_thread_group(group_id); - if (!grp) { - /* This is a reserved id */ - if (group_id == DEFAULT_CGROUP_COLOC_ID) { - rc = -EINVAL; - goto done; - } - - grp = alloc_related_thread_group(group_id); - if (IS_ERR(grp)) { - rc = -ENOMEM; - goto done; - } - - list_add(&grp->list, &related_thread_groups); - } + if (list_empty(&grp->list)) + list_add(&grp->list, &active_related_thread_groups); rc = add_task_to_group(p, grp); done: write_unlock(&related_thread_group_lock); raw_spin_unlock_irqrestore(&p->pi_lock, flags); + return rc; } +int sched_set_group_id(struct task_struct *p, unsigned int group_id) +{ + /* DEFAULT_CGROUP_COLOC_ID is a reserved id */ + if (group_id == DEFAULT_CGROUP_COLOC_ID) + return -EINVAL; + + return __sched_set_group_id(p, group_id); +} + unsigned int sched_get_group_id(struct task_struct *p) { unsigned int group_id; @@ -4210,6 +4179,42 @@ unsigned int sched_get_group_id(struct task_struct *p) return group_id; } +#if defined(CONFIG_SCHED_TUNE) && defined(CONFIG_CGROUP_SCHEDTUNE) +/* + * We create a default colocation group at boot. There is no need to + * synchronize tasks between cgroups at creation time because the + * correct cgroup hierarchy is not available at boot. Therefore cgroup + * colocation is turned off by default even though the colocation group + * itself has been allocated. Furthermore this colocation group cannot + * be destroyted once it has been created. All of this has been as part + * of runtime optimizations. + * + * The job of synchronizing tasks to the colocation group is done when + * the colocation flag in the cgroup is turned on. + */ +static int __init create_default_coloc_group(void) +{ + struct related_thread_group *grp = NULL; + unsigned long flags; + + grp = lookup_related_thread_group(DEFAULT_CGROUP_COLOC_ID); + write_lock_irqsave(&related_thread_group_lock, flags); + list_add(&grp->list, &active_related_thread_groups); + write_unlock_irqrestore(&related_thread_group_lock, flags); + + update_freq_aggregate_threshold(MAX_FREQ_AGGR_THRESH); + return 0; +} +late_initcall(create_default_coloc_group); + +int sync_cgroup_colocation(struct task_struct *p, bool insert) +{ + unsigned int grp_id = insert ? DEFAULT_CGROUP_COLOC_ID : 0; + + return __sched_set_group_id(p, grp_id); +} +#endif + static void update_cpu_cluster_capacity(const cpumask_t *cpus) { int i; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 30838bb9b442..f569c6fe3cbb 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1448,6 +1448,8 @@ static inline void update_cgroup_boost_settings(void) { } static inline void restore_cgroup_boost_settings(void) { } #endif +extern int alloc_related_thread_groups(void); + #else /* CONFIG_SCHED_HMP */ struct hmp_sched_stats; @@ -1638,6 +1640,7 @@ static inline void set_hmp_defaults(void) { } static inline void clear_reserved(int cpu) { } static inline void sched_boost_parse_dt(void) {} +static inline int alloc_related_thread_groups(void) { return 0; } #define trace_sched_cpu_load(...) #define trace_sched_cpu_load_lb(...) diff --git a/mm/page_isolation.c b/mm/page_isolation.c index 00c96462cc36..3ecd3807c2c2 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -7,6 +7,7 @@ #include <linux/pageblock-flags.h> #include <linux/memory.h> #include <linux/hugetlb.h> +#include <linux/kasan.h> #include "internal.h" static int set_migratetype_isolate(struct page *page, @@ -105,6 +106,8 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype) if (pfn_valid_within(page_to_pfn(buddy)) && !is_migrate_isolate_page(buddy)) { __isolate_free_page(page, order); + kasan_alloc_pages(page, order); + arch_alloc_page(page, order); kernel_map_pages(page, (1 << order), 1); set_page_refcounted(page); isolated_page = page; diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c index 185b609e637f..35b94e9da0d9 100644 --- a/net/rmnet_data/rmnet_data_handlers.c +++ b/net/rmnet_data/rmnet_data_handlers.c @@ -505,6 +505,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL)) { LOGD("Failed to add headroom of %d bytes", required_headroom); + kfree_skb(skb); return 1; } } @@ -528,6 +529,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, if (!map_header) { LOGD("%s", "Failed to add MAP header to egress packet"); + kfree_skb(skb); return 1; } diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f580a1048d65..5f21eb37eae4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -139,6 +139,10 @@ snd-soc-wcd9xxx-v2-objs := wcd9xxx-common-v2.o wcd9xxx-resmgr-v2.o ifeq ($(CONFIG_COMMON_CLK_MSM), y) audio-ext-clock-objs := audio-ext-clk.o endif + +ifeq ($(CONFIG_COMMON_CLK_QCOM), y) + audio-ext-clock-up-objs := audio-ext-clk-up.o +endif snd-soc-wcd-cpe-objs := wcd_cpe_services.o wcd_cpe_core.o snd-soc-wsa881x-objs := wsa881x.o wsa881x-tables.o wsa881x-regmap.o wsa881x-temp-sensor.o snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o @@ -349,6 +353,9 @@ obj-$(CONFIG_SND_SOC_WCD934X) += wcd934x/ ifeq ($(CONFIG_COMMON_CLK_MSM), y) obj-$(CONFIG_AUDIO_EXT_CLK) += audio-ext-clock.o endif +ifeq ($(CONFIG_COMMON_CLK_QCOM), y) + obj-$(CONFIG_AUDIO_EXT_CLK) += audio-ext-clock-up.o +endif obj-$(CONFIG_SND_SOC_WCD9XXX) += snd-soc-wcd9xxx.o obj-$(CONFIG_SND_SOC_WCD9XXX_V2) += snd-soc-wcd9xxx-v2.o obj-$(CONFIG_SND_SOC_WCD_CPE) += snd-soc-wcd-cpe.o diff --git a/sound/soc/codecs/audio-ext-clk-up.c b/sound/soc/codecs/audio-ext-clk-up.c new file mode 100644 index 000000000000..f989498e9c32 --- /dev/null +++ b/sound/soc/codecs/audio-ext-clk-up.c @@ -0,0 +1,577 @@ +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include "../../../drivers/clk/qcom/common.h" +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <dt-bindings/clock/audio-ext-clk.h> +#include <sound/q6afe-v2.h> + +enum audio_clk_mux { + AP_CLK2, + LPASS_MCLK, + LPASS_MCLK2, +}; + +struct pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *sleep; + struct pinctrl_state *active; +}; + +struct audio_ext_ap_clk { + bool enabled; + int gpio; + struct clk_fixed_factor fact; +}; + +struct audio_ext_pmi_clk { + int gpio; + struct clk_fixed_factor fact; +}; + +struct audio_ext_ap_clk2 { + bool enabled; + struct pinctrl_info pnctrl_info; + struct clk_fixed_factor fact; +}; + +struct audio_ext_lpass_mclk { + struct pinctrl_info pnctrl_info; + struct clk_fixed_factor fact; +}; + +static struct afe_clk_set clk2_config = { + Q6AFE_LPASS_CLK_CONFIG_API_VERSION, + Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR, + Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static struct afe_clk_set lpass_default = { + Q6AFE_LPASS_CLK_CONFIG_API_VERSION, + Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR, + Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static struct afe_clk_set lpass_mclk = { + Q6AFE_LPASS_CLK_CONFIG_API_VERSION, + Q6AFE_LPASS_CLK_ID_MCLK_1, + Q6AFE_LPASS_OSR_CLK_11_P2896_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static inline struct audio_ext_ap_clk *to_audio_ap_clk(struct clk_hw *hw) +{ + return container_of(hw, struct audio_ext_ap_clk, fact.hw); +} + +static int audio_ext_clk_prepare(struct clk_hw *hw) +{ + struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(hw); + + pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio); + if (gpio_is_valid(audio_clk->gpio)) + return gpio_direction_output(audio_clk->gpio, 1); + return 0; +} + +static void audio_ext_clk_unprepare(struct clk_hw *hw) +{ + struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(hw); + + pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio); + if (gpio_is_valid(audio_clk->gpio)) + gpio_direction_output(audio_clk->gpio, 0); +} + +static inline struct audio_ext_ap_clk2 *to_audio_ap_clk2(struct clk_hw *hw) +{ + return container_of(hw, struct audio_ext_ap_clk2, fact.hw); +} + +static int audio_ext_clk2_prepare(struct clk_hw *hw) +{ + struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(hw); + struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info; + int ret; + + + if (!pnctrl_info->pinctrl || !pnctrl_info->active) + return 0; + + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->active); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return -EIO; + } + + clk2_config.enable = 1; + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config); + if (ret < 0) { + pr_err("%s: failed to set clock, ret = %d\n", __func__, ret); + return -EINVAL; + } + + return 0; +} + +static void audio_ext_clk2_unprepare(struct clk_hw *hw) +{ + struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(hw); + struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info; + int ret; + + if (!pnctrl_info->pinctrl || !pnctrl_info->sleep) + return; + + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) + pr_err("%s: sleep state select failed with %d\n", + __func__, ret); + + clk2_config.enable = 0; + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config); + if (ret < 0) + pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret); +} + +static inline struct audio_ext_lpass_mclk *to_audio_lpass_mclk( + struct clk_hw *hw) +{ + return container_of(hw, struct audio_ext_lpass_mclk, fact.hw); +} + +static int audio_ext_lpass_mclk_prepare(struct clk_hw *hw) +{ + struct audio_ext_lpass_mclk *audio_lpass_mclk = to_audio_lpass_mclk(hw); + struct pinctrl_info *pnctrl_info = &audio_lpass_mclk->pnctrl_info; + int ret; + + if (pnctrl_info->pinctrl) { + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->active); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return -EIO; + } + } + + lpass_mclk.enable = 1; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, + &lpass_mclk); + if (ret < 0) { + pr_err("%s afe_set_digital_codec_core_clock failed\n", + __func__); + return ret; + } + + return 0; +} + +static void audio_ext_lpass_mclk_unprepare(struct clk_hw *hw) +{ + struct audio_ext_lpass_mclk *audio_lpass_mclk = to_audio_lpass_mclk(hw); + struct pinctrl_info *pnctrl_info = &audio_lpass_mclk->pnctrl_info; + int ret; + + if (pnctrl_info->pinctrl) { + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return; + } + } + + lpass_mclk.enable = 0; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, + &lpass_mclk); + if (ret < 0) + pr_err("%s: afe_set_digital_codec_core_clock failed, ret = %d\n", + __func__, ret); +} + +static int audio_ext_lpass_mclk2_prepare(struct clk_hw *hw) +{ + struct audio_ext_lpass_mclk *audio_lpass_mclk2 = + to_audio_lpass_mclk(hw); + struct pinctrl_info *pnctrl_info = &audio_lpass_mclk2->pnctrl_info; + int ret; + + if (pnctrl_info->pinctrl) { + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->active); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return -EIO; + } + } + + lpass_default.enable = 1; + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &lpass_default); + if (ret < 0) { + pr_err("%s: failed to set clock, ret = %d\n", __func__, ret); + return -EINVAL; + } + + return 0; +} + +static void audio_ext_lpass_mclk2_unprepare(struct clk_hw *hw) +{ + struct audio_ext_lpass_mclk *audio_lpass_mclk2 = + to_audio_lpass_mclk(hw); + struct pinctrl_info *pnctrl_info = &audio_lpass_mclk2->pnctrl_info; + int ret; + + if (pnctrl_info->pinctrl) { + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) + pr_err("%s: sleep state select failed with %d\n", + __func__, ret); + } + + lpass_default.enable = 0; + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &lpass_default); + if (ret < 0) + pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret); +} + +static struct clk_ops audio_ext_ap_clk_ops = { + .prepare = audio_ext_clk_prepare, + .unprepare = audio_ext_clk_unprepare, +}; + +static struct clk_ops audio_ext_ap_clk2_ops = { + .prepare = audio_ext_clk2_prepare, + .unprepare = audio_ext_clk2_unprepare, +}; + +static struct clk_ops audio_ext_lpass_mclk_ops = { + .prepare = audio_ext_lpass_mclk_prepare, + .unprepare = audio_ext_lpass_mclk_unprepare, +}; + +static struct clk_ops audio_ext_lpass_mclk2_ops = { + .prepare = audio_ext_lpass_mclk2_prepare, + .unprepare = audio_ext_lpass_mclk2_unprepare, +}; + +static struct audio_ext_pmi_clk audio_pmi_clk = { + .gpio = -EINVAL, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_ext_pmi_clk", + .ops = &clk_dummy_ops, + }, + }, +}; + +static struct audio_ext_pmi_clk audio_pmi_lnbb_clk = { + .gpio = -EINVAL, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_ext_pmi_lnbb_clk", + .ops = &clk_dummy_ops, + }, + }, +}; + +static struct audio_ext_ap_clk audio_ap_clk = { + .gpio = -EINVAL, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_ap_clk", + .ops = &audio_ext_ap_clk_ops, + }, + }, +}; + +static struct audio_ext_ap_clk2 audio_ap_clk2 = { + .enabled = false, + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_ap_clk2", + .ops = &audio_ext_ap_clk2_ops, + }, + }, +}; + +static struct audio_ext_lpass_mclk audio_lpass_mclk = { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk", + .ops = &audio_ext_lpass_mclk_ops, + }, + }, +}; + +static struct audio_ext_lpass_mclk audio_lpass_mclk2 = { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk2", + .ops = &audio_ext_lpass_mclk2_ops, + }, + }, +}; + +static struct clk_hw *audio_msm_hws[] = { + &audio_pmi_clk.fact.hw, + &audio_pmi_lnbb_clk.fact.hw, + &audio_ap_clk.fact.hw, + &audio_ap_clk2.fact.hw, + &audio_lpass_mclk.fact.hw, + &audio_lpass_mclk2.fact.hw, +}; + +static int audio_get_pinctrl(struct platform_device *pdev, + enum audio_clk_mux mux) +{ + struct pinctrl_info *pnctrl_info; + struct pinctrl *pinctrl; + int ret; + + switch (mux) { + case AP_CLK2: + pnctrl_info = &audio_ap_clk2.pnctrl_info; + break; + case LPASS_MCLK: + pnctrl_info = &audio_lpass_mclk.pnctrl_info; + break; + case LPASS_MCLK2: + pnctrl_info = &audio_lpass_mclk2.pnctrl_info; + break; + default: + dev_err(&pdev->dev, "%s Not a valid MUX ID: %d\n", + __func__, mux); + return -EINVAL; + } + pnctrl_info = &audio_ap_clk2.pnctrl_info; + + if (pnctrl_info->pinctrl) { + dev_dbg(&pdev->dev, "%s: already requested before\n", + __func__); + return -EINVAL; + } + + pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n", + __func__); + return -EINVAL; + } + pnctrl_info->pinctrl = pinctrl; + /* get all state handles from Device Tree */ + pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep"); + if (IS_ERR(pnctrl_info->sleep)) { + dev_err(&pdev->dev, "%s: could not get sleep pinstate\n", + __func__); + goto err; + } + pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active"); + if (IS_ERR(pnctrl_info->active)) { + dev_err(&pdev->dev, "%s: could not get active pinstate\n", + __func__); + goto err; + } + /* Reset the TLMM pins to a default state */ + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) { + dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n", + __func__, ret); + goto err; + } + return 0; + +err: + devm_pinctrl_put(pnctrl_info->pinctrl); + return -EINVAL; +} + +static int audio_ref_clk_probe(struct platform_device *pdev) +{ + int clk_gpio; + int ret; + u32 mclk_freq; + struct clk *audio_clk; + struct device *dev = &pdev->dev; + int i; + struct clk_onecell_data *clk_data; + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,codec-mclk-clk-freq", + &mclk_freq); + if (!ret) { + lpass_mclk.clk_freq_in_hz = mclk_freq; + + ret = audio_get_pinctrl(pdev, LPASS_MCLK); + if (ret) + dev_err(&pdev->dev, "%s: Parsing pinctrl %s failed\n", + __func__, "LPASS_MCLK"); + ret = audio_get_pinctrl(pdev, LPASS_MCLK2); + if (ret) + dev_dbg(&pdev->dev, "%s: Parsing pinctrl %s failed\n", + __func__, "LPASS_MCLK2"); + } + + clk_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,audio-ref-clk-gpio", 0); + if (clk_gpio > 0) { + ret = gpio_request(clk_gpio, "EXT_CLK"); + if (ret) { + dev_err(&pdev->dev, + "Request ext clk gpio failed %d, err:%d\n", + clk_gpio, ret); + goto err; + } + if (of_property_read_bool(pdev->dev.of_node, + "qcom,node_has_rpm_clock")) { + audio_pmi_clk.gpio = clk_gpio; + } else + audio_ap_clk.gpio = clk_gpio; + + } + + ret = audio_get_pinctrl(pdev, AP_CLK2); + if (ret) + dev_dbg(&pdev->dev, "%s: Parsing pinctrl failed\n", + __func__); + + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + goto err_gpio; + + clk_data->clk_num = ARRAY_SIZE(audio_msm_hws); + clk_data->clks = devm_kzalloc(&pdev->dev, + clk_data->clk_num * sizeof(struct clk *), + GFP_KERNEL); + if (!clk_data->clks) + goto err_clk; + + for (i = 0; i < ARRAY_SIZE(audio_msm_hws); i++) { + audio_clk = devm_clk_register(dev, audio_msm_hws[i]); + if (IS_ERR(audio_clk)) { + dev_err(&pdev->dev, + "%s: audio ref clock i = %d register failed\n", + __func__, i); + return PTR_ERR(audio_clk); + } + clk_data->clks[i] = audio_clk; + } + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + if (ret) { + dev_err(&pdev->dev, "%s: audio ref clock register failed\n", + __func__); + goto err_gpio; + } + + return 0; + +err_clk: + if (clk_data) + devm_kfree(&pdev->dev, clk_data->clks); + devm_kfree(&pdev->dev, clk_data); +err_gpio: + gpio_free(clk_gpio); + +err: + return ret; +} + +static int audio_ref_clk_remove(struct platform_device *pdev) +{ + struct pinctrl_info *pnctrl_info = &audio_ap_clk2.pnctrl_info; + + if (audio_pmi_clk.gpio > 0) + gpio_free(audio_pmi_clk.gpio); + else if (audio_ap_clk.gpio > 0) + gpio_free(audio_ap_clk.gpio); + + if (pnctrl_info->pinctrl) { + devm_pinctrl_put(pnctrl_info->pinctrl); + pnctrl_info->pinctrl = NULL; + } + + return 0; +} + +static const struct of_device_id audio_ref_clk_match[] = { + {.compatible = "qcom,audio-ref-clk"}, + {} +}; +MODULE_DEVICE_TABLE(of, audio_ref_clk_match); + +static struct platform_driver audio_ref_clk_driver = { + .driver = { + .name = "audio-ref-clk", + .owner = THIS_MODULE, + .of_match_table = audio_ref_clk_match, + }, + .probe = audio_ref_clk_probe, + .remove = audio_ref_clk_remove, +}; + +static int __init audio_ref_clk_platform_init(void) +{ + return platform_driver_register(&audio_ref_clk_driver); +} +module_init(audio_ref_clk_platform_init); + +static void __exit audio_ref_clk_platform_exit(void) +{ + platform_driver_unregister(&audio_ref_clk_driver); +} +module_exit(audio_ref_clk_platform_exit); + +MODULE_DESCRIPTION("Audio Ref Up Clock module platform driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index b0bb89c8d9c2..1fdf81a3a45f 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -1879,6 +1879,7 @@ static void tavil_codec_override(struct snd_soc_codec *codec, int mode, { if (mode == CLS_AB || mode == CLS_AB_HIFI) { switch (event) { + case SND_SOC_DAPM_PRE_PMU: case SND_SOC_DAPM_POST_PMU: if (!(snd_soc_read(codec, WCD934X_CDC_RX2_RX_PATH_CTL) & 0x10) && @@ -2088,6 +2089,9 @@ static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, } switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil_codec_override(codec, CLS_AB, event); + break; case SND_SOC_DAPM_POST_PMU: /* * 5ms sleep is required after PA is enabled as per @@ -2102,6 +2106,13 @@ static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, lineout_mix_vol_reg, 0x10, 0x00); break; + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + tavil_codec_override(codec, CLS_AB, event); default: break; }; @@ -7039,10 +7050,12 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = { SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD934X_ANA_LO_1_2, 7, 0, NULL, 0, tavil_codec_enable_lineout_pa, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0, tavil_codec_enable_lineout_pa, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0, tavil_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), @@ -8156,6 +8169,8 @@ static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = { {WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_COMPANDER8_CTL7, 0x1E, 0x18}, @@ -8189,6 +8204,8 @@ static const struct tavil_reg_mask_val tavil_codec_reg_init_1_1_val[] = { {WCD934X_CDC_COMPANDER2_CTL7, 0x1E, 0x06}, {WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0xFF, 0x84}, {WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0xFF, 0x84}, + {WCD934X_CDC_RX3_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD934X_CDC_RX4_RX_PATH_SEC0, 0xFC, 0xF4}, }; static const struct tavil_cpr_reg_defaults cpr_defaults[] = { diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c index 94a529acaff7..1df839333d09 100644 --- a/sound/soc/msm/msm8998.c +++ b/sound/soc/msm/msm8998.c @@ -398,7 +398,8 @@ static char const *ch_text[] = {"Two", "Three", "Four", "Five", static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_16", "KHZ_22P05", "KHZ_32", "KHZ_44P1", "KHZ_48", - "KHZ_96", "KHZ_192", "KHZ_384"}; + "KHZ_88P2", "KHZ_96", "KHZ_176P4", + "KHZ_192", "KHZ_352P8", "KHZ_384"}; static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96", "KHZ_192"}; static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four", @@ -1031,12 +1032,21 @@ static int usb_audio_rx_sample_rate_get(struct snd_kcontrol *kcontrol, switch (usb_rx_cfg.sample_rate) { case SAMPLING_RATE_384KHZ: - sample_rate_val = 9; + sample_rate_val = 12; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 11; break; case SAMPLING_RATE_192KHZ: - sample_rate_val = 8; + sample_rate_val = 10; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 9; break; case SAMPLING_RATE_96KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_88P2KHZ: sample_rate_val = 7; break; case SAMPLING_RATE_48KHZ: @@ -1073,15 +1083,24 @@ static int usb_audio_rx_sample_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { switch (ucontrol->value.integer.value[0]) { - case 9: + case 12: usb_rx_cfg.sample_rate = SAMPLING_RATE_384KHZ; break; - case 8: + case 11: + usb_rx_cfg.sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 10: usb_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ; break; - case 7: + case 9: + usb_rx_cfg.sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 8: usb_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ; break; + case 7: + usb_rx_cfg.sample_rate = SAMPLING_RATE_88P2KHZ; + break; case 6: usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; break; @@ -1191,12 +1210,21 @@ static int usb_audio_tx_sample_rate_get(struct snd_kcontrol *kcontrol, switch (usb_tx_cfg.sample_rate) { case SAMPLING_RATE_384KHZ: - sample_rate_val = 9; + sample_rate_val = 12; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 11; break; case SAMPLING_RATE_192KHZ: - sample_rate_val = 8; + sample_rate_val = 10; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 9; break; case SAMPLING_RATE_96KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_88P2KHZ: sample_rate_val = 7; break; case SAMPLING_RATE_48KHZ: @@ -1235,15 +1263,24 @@ static int usb_audio_tx_sample_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { switch (ucontrol->value.integer.value[0]) { - case 9: + case 12: usb_tx_cfg.sample_rate = SAMPLING_RATE_384KHZ; break; - case 8: + case 11: + usb_tx_cfg.sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 10: usb_tx_cfg.sample_rate = SAMPLING_RATE_192KHZ; break; - case 7: + case 9: + usb_tx_cfg.sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 8: usb_tx_cfg.sample_rate = SAMPLING_RATE_96KHZ; break; + case 7: + usb_tx_cfg.sample_rate = SAMPLING_RATE_88P2KHZ; + break; case 6: usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ; break; diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 90371b8e27f4..d3c0850d8de2 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -55,6 +55,10 @@ #define DSP_NUM_OUTPUT_FRAME_BUFFERED 2 #define FLAC_BLK_SIZE_LIMIT 65535 +/* Timestamp mode payload offsets */ +#define TS_LSW_OFFSET 6 +#define TS_MSW_OFFSET 7 + /* decoder parameter length */ #define DDP_DEC_MAX_NUM_PARAM 18 @@ -130,7 +134,9 @@ struct msm_compr_audio { uint64_t received_total; /* bytes received from DSP */ uint64_t bytes_copied; /* to userspace */ uint64_t bytes_read; /* from DSP */ - uint32_t bytes_read_offset; /* bytes read offset*/ + uint32_t bytes_read_offset; /* bytes read offset */ + + uint32_t ts_header_offset; /* holds the timestamp header offset */ int32_t first_buffer; int32_t last_buffer; @@ -380,19 +386,23 @@ static int msm_compr_read_buffer(struct msm_compr_audio *prtd) return -EINVAL; } - buffer_length = prtd->codec_param.buffer.fragment_size; + buffer_length = prtd->codec_param.buffer.fragment_size - + prtd->ts_header_offset; bytes_available = prtd->received_total - prtd->bytes_copied; buffer_sent = prtd->bytes_read - prtd->bytes_copied; - if (buffer_sent + buffer_length > prtd->buffer_size) { + if (buffer_sent + buffer_length + prtd->ts_header_offset + > prtd->buffer_size) { pr_debug(" %s : Buffer is Full bytes_available: %llu\n", __func__, bytes_available); return 0; } memset(¶m, 0x0, sizeof(struct audio_aio_read_param)); - param.paddr = prtd->buffer_paddr + prtd->bytes_read_offset; + param.paddr = prtd->buffer_paddr + prtd->bytes_read_offset + + prtd->ts_header_offset; param.len = buffer_length; param.uid = buffer_length; + param.flags = prtd->codec_param.codec.flags; pr_debug("%s: reading %d bytes from DSP byte_offset = %llu\n", __func__, buffer_length, prtd->bytes_read); @@ -423,6 +433,7 @@ static void compr_event_handler(uint32_t opcode, uint32_t stream_index; unsigned long flags; uint64_t read_size; + uint32_t *buff_addr; if (!prtd) { pr_err("%s: prtd is NULL\n", __func__); @@ -514,6 +525,23 @@ static void compr_event_handler(uint32_t opcode, pr_debug("ASM_DATA_EVENT_READ_DONE_V2 offset %d, length %d\n", prtd->byte_offset, payload[4]); + + if (prtd->ts_header_offset) { + /* Update the header for received buffer */ + buff_addr = prtd->buffer + prtd->byte_offset; + /* Write the length of the buffer */ + *buff_addr = prtd->codec_param.buffer.fragment_size + - prtd->ts_header_offset; + buff_addr++; + /* Write the offset */ + *buff_addr = prtd->ts_header_offset; + buff_addr++; + /* Write the TS LSW */ + *buff_addr = payload[TS_LSW_OFFSET]; + buff_addr++; + /* Write the TS MSW */ + *buff_addr = payload[TS_MSW_OFFSET]; + } /* Always assume read_size is same as fragment_size */ read_size = prtd->codec_param.buffer.fragment_size; prtd->byte_offset += read_size; @@ -1214,7 +1242,7 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream) pr_debug("%s: stream_id %d bits_per_sample %d\n", __func__, ac->stream_id, bits_per_sample); - ret = q6asm_open_read_v3(prtd->audio_client, FORMAT_LINEAR_PCM, + ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, bits_per_sample); if (ret < 0) { pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret); @@ -1265,6 +1293,11 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream) prtd->buffer_paddr = ac->port[dir].buf[0].phys; prtd->buffer_size = runtime->fragments * runtime->fragment_size; + /* Bit-0 of flags represent timestamp mode */ + if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) + prtd->ts_header_offset = sizeof(struct snd_codec_metadata); + else + prtd->ts_header_offset = 0; pr_debug("%s: sample_rate = %d channels = %d bps = %d sample_word_size = %d\n", __func__, prtd->sample_rate, prtd->num_channels, @@ -3146,7 +3179,7 @@ static int msm_compr_dec_params_get(struct snd_kcontrol *kcontrol, return 0; } -static int msm_compr_app_type_cfg_put(struct snd_kcontrol *kcontrol, +static int msm_compr_playback_app_type_cfg_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { u64 fe_id = kcontrol->private_value; @@ -3173,7 +3206,7 @@ static int msm_compr_app_type_cfg_put(struct snd_kcontrol *kcontrol, return 0; } -static int msm_compr_app_type_cfg_get(struct snd_kcontrol *kcontrol, +static int msm_compr_playback_app_type_cfg_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { u64 fe_id = kcontrol->private_value; @@ -3208,6 +3241,68 @@ done: return ret; } +static int msm_compr_capture_app_type_cfg_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int app_type; + int acdb_dev_id; + int sample_rate = 48000; + + pr_debug("%s: fe_id- %llu\n", __func__, fe_id); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds fe_id %llu\n", + __func__, fe_id); + return -EINVAL; + } + + app_type = ucontrol->value.integer.value[0]; + acdb_dev_id = ucontrol->value.integer.value[1]; + if (ucontrol->value.integer.value[2] != 0) + sample_rate = ucontrol->value.integer.value[2]; + pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n", + __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX); + msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type, + acdb_dev_id, sample_rate, SESSION_TYPE_TX); + + return 0; +} + +static int msm_compr_capture_app_type_cfg_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate; + + pr_debug("%s: fe_id- %llu\n", __func__, fe_id); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds fe_id %llu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX, + &app_type, &acdb_dev_id, &sample_rate); + if (ret < 0) { + pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n", + __func__, ret); + goto done; + } + + ucontrol->value.integer.value[0] = app_type; + ucontrol->value.integer.value[1] = acdb_dev_id; + ucontrol->value.integer.value[2] = sample_rate; + pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n", + __func__, fe_id, SESSION_TYPE_TX, + app_type, acdb_dev_id, sample_rate); +done: + return ret; +} + static int msm_compr_channel_map_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -3595,7 +3690,8 @@ static int msm_compr_add_dec_runtime_params_control( static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) { - const char *mixer_ctl_name = "Audio Stream"; + const char *playback_mixer_ctl_name = "Audio Stream"; + const char *capture_mixer_ctl_name = "Audio Stream Capture"; const char *deviceNo = "NN"; const char *suffix = "App Type Cfg"; char *mixer_str = NULL; @@ -3606,8 +3702,8 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) .name = "?", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_compr_app_type_cfg_info, - .put = msm_compr_app_type_cfg_put, - .get = msm_compr_app_type_cfg_get, + .put = msm_compr_playback_app_type_cfg_put, + .get = msm_compr_playback_app_type_cfg_get, .private_value = 0, } }; @@ -3618,11 +3714,15 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) } pr_debug("%s: added new compr FE ctl with name %s, id %d, cpu dai %s, device no %d\n", - __func__, rtd->dai_link->name, rtd->dai_link->be_id, - rtd->dai_link->cpu_dai_name, rtd->pcm->device); + __func__, rtd->dai_link->name, rtd->dai_link->be_id, + rtd->dai_link->cpu_dai_name, rtd->pcm->device); + if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) + ctl_len = strlen(playback_mixer_ctl_name) + 1 + strlen(deviceNo) + + 1 + strlen(suffix) + 1; + else + ctl_len = strlen(capture_mixer_ctl_name) + 1 + strlen(deviceNo) + + 1 + strlen(suffix) + 1; - ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + - strlen(suffix) + 1; mixer_str = kzalloc(ctl_len, GFP_KERNEL); if (!mixer_str) { @@ -3630,14 +3730,31 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) return 0; } - snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name, - rtd->pcm->device, suffix); + if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) + snprintf(mixer_str, ctl_len, "%s %d %s", + playback_mixer_ctl_name, rtd->pcm->device, suffix); + else + snprintf(mixer_str, ctl_len, "%s %d %s", + capture_mixer_ctl_name, rtd->pcm->device, suffix); + fe_app_type_cfg_control[0].name = mixer_str; fe_app_type_cfg_control[0].private_value = rtd->dai_link->be_id; + + if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) { + fe_app_type_cfg_control[0].put = + msm_compr_playback_app_type_cfg_put; + fe_app_type_cfg_control[0].get = + msm_compr_playback_app_type_cfg_get; + } else { + fe_app_type_cfg_control[0].put = + msm_compr_capture_app_type_cfg_put; + fe_app_type_cfg_control[0].get = + msm_compr_capture_app_type_cfg_get; + } pr_debug("Registering new mixer ctl %s", mixer_str); snd_soc_add_platform_controls(rtd->platform, - fe_app_type_cfg_control, - ARRAY_SIZE(fe_app_type_cfg_control)); + fe_app_type_cfg_control, + ARRAY_SIZE(fe_app_type_cfg_control)); kfree(mixer_str); return 0; } diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index c75f7214db1a..75dc7cf059e3 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -4595,7 +4595,7 @@ static ssize_t afe_debug_write(struct file *filp, lbuf[cnt] = '\0'; - if (!strncmp(lb_str, "afe_loopback", 12)) { + if (!strcmp(lb_str, "afe_loopback")) { rc = afe_get_parameters(lbuf, param, 3); if (!rc) { pr_info("%s: %lu %lu %lu\n", lb_str, param[0], param[1], @@ -4624,7 +4624,7 @@ static ssize_t afe_debug_write(struct file *filp, rc = -EINVAL; } - } else if (!strncmp(lb_str, "afe_loopback_gain", 17)) { + } else if (!strcmp(lb_str, "afe_loopback_gain")) { rc = afe_get_parameters(lbuf, param, 2); if (!rc) { pr_info("%s: %s %lu %lu\n", diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index e3545405f61d..38c51eb32f4d 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1639,7 +1639,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) asm_token.token = data->token; if (q6asm_get_flag_from_token(&asm_token, ASM_CMD_NO_WAIT_OFFSET)) { pr_debug("%s: No wait command opcode[0x%x] cmd_opcode:%x\n", - __func__, data->opcode, payload[0]); + __func__, data->opcode, payload ? payload[0] : 0); wakeup_flag = 0; } @@ -1673,9 +1673,14 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) data->dest_port); if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) && (data->opcode != ASM_DATA_EVENT_EOS) && - (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) + (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) { + if (payload == NULL) { + pr_err("%s: payload is null\n", __func__); + return -EINVAL; + } dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n", __func__, payload[0], payload[1], data->opcode); + } if (data->opcode == APR_BASIC_RSP_RESULT) { switch (payload[0]) { case ASM_STREAM_CMD_SET_PP_PARAMS_V2: @@ -2285,7 +2290,8 @@ static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr, static int __q6asm_open_read(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, - uint32_t pcm_format_block_ver) + uint32_t pcm_format_block_ver, + bool ts_mode) { int rc = 0x00; struct asm_stream_cmd_open_read_v3 open; @@ -2329,11 +2335,21 @@ static int __q6asm_open_read(struct audio_client *ac, case FORMAT_LINEAR_PCM: open.mode_flags |= 0x00; open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver); + if (ts_mode) + open.mode_flags |= ABSOLUTE_TIMESTAMP_ENABLE; break; case FORMAT_MPEG4_AAC: open.mode_flags |= BUFFER_META_ENABLE; open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2; break; + case FORMAT_G711_ALAW_FS: + open.mode_flags |= BUFFER_META_ENABLE; + open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS; + break; + case FORMAT_G711_MLAW_FS: + open.mode_flags |= BUFFER_META_ENABLE; + open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS; + break; case FORMAT_V13K: open.mode_flags |= BUFFER_META_ENABLE; open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS; @@ -2391,14 +2407,16 @@ int q6asm_open_read(struct audio_client *ac, uint32_t format) { return __q6asm_open_read(ac, format, 16, - PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/); + PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/, + false/*ts_mode*/); } int q6asm_open_read_v2(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/); + PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/, + false/*ts_mode*/); } /* @@ -2412,7 +2430,8 @@ int q6asm_open_read_v3(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - PCM_MEDIA_FORMAT_V3/*media fmt block ver*/); + PCM_MEDIA_FORMAT_V3/*media fmt block ver*/, + false/*ts_mode*/); } EXPORT_SYMBOL(q6asm_open_read_v3); @@ -2427,7 +2446,8 @@ int q6asm_open_read_v4(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/); + PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/, + true/*ts_mode*/); } EXPORT_SYMBOL(q6asm_open_read_v4); @@ -2857,6 +2877,11 @@ static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format, break; case FORMAT_DSD: open.dec_fmt_id = ASM_MEDIA_FMT_DSD; + case FORMAT_G711_ALAW_FS: + open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS; + break; + case FORMAT_G711_MLAW_FS: + open.dec_fmt_id = ASM_MEDIA_FMT_G711_MLAW_FS; break; default: pr_err("%s: Invalid format 0x%x\n", @@ -2873,6 +2898,12 @@ static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format, case FORMAT_MPEG4_AAC: open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2; break; + case FORMAT_G711_ALAW_FS: + open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS; + break; + case FORMAT_G711_MLAW_FS: + open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS; + break; case FORMAT_V13K: open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS; break; @@ -3540,6 +3571,57 @@ fail_cmd: return rc; } +int q6asm_enc_cfg_blk_g711(struct audio_client *ac, + uint32_t frames_per_buf, + uint32_t sample_rate) +{ + struct asm_g711_enc_cfg_v2 enc_cfg; + int rc = 0; + + pr_debug("%s: session[%d]frames[%d]SR[%d]\n", + __func__, ac->session, frames_per_buf, + sample_rate); + + q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE); + atomic_set(&ac->cmd_state, -1); + + 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(struct asm_g711_enc_cfg_v2) - + sizeof(struct asm_stream_cmd_set_encdec_param); + 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.sample_rate = sample_rate; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg); + if (rc < 0) { + pr_err("%s: Comamnd %d failed %d\n", + __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc); + rc = -EINVAL; + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout. waited for FORMAT_UPDATE\n", + __func__); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} + int q6asm_set_encdec_chan_map(struct audio_client *ac, uint32_t num_channels) { @@ -5424,6 +5506,75 @@ fail_cmd: return rc; } +/* + * q6asm_media_format_block_g711 - sends g711 decoder configuration + * parameters + * @ac: Client session handle + * @cfg: Audio stream manager configuration parameters + * @stream_id: Stream id + */ +int q6asm_media_format_block_g711(struct audio_client *ac, + struct asm_g711_dec_cfg *cfg, int stream_id) +{ + struct asm_g711_dec_fmt_blk_v2 fmt; + int rc = 0; + + if (!ac) { + pr_err("%s: audio client is null\n", __func__); + return -EINVAL; + } + if (!cfg) { + pr_err("%s: Invalid ASM config\n", __func__); + return -EINVAL; + } + + if (stream_id <= 0) { + pr_err("%s: Invalid stream id\n", __func__); + return -EINVAL; + } + + pr_debug("%s :session[%d]rate[%d]\n", __func__, + ac->session, cfg->sample_rate); + + memset(&fmt, 0, sizeof(struct asm_g711_dec_fmt_blk_v2)); + + q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id); + atomic_set(&ac->cmd_state, -1); + + fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) - + sizeof(fmt.fmtblk); + + fmt.sample_rate = cfg->sample_rate; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt); + if (rc < 0) { + pr_err("%s :Command media format update failed %d\n", + __func__, rc); + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__); + rc = -ETIMEDOUT; + goto fail_cmd; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} +EXPORT_SYMBOL(q6asm_media_format_block_g711); + int q6asm_stream_media_format_block_vorbis(struct audio_client *ac, struct asm_vorbis_cfg *cfg, int stream_id) { @@ -7150,7 +7301,11 @@ int q6asm_async_read(struct audio_client *ac, lbuf_phys_addr = (param->paddr - 64); dir = OUT; } else { - lbuf_phys_addr = param->paddr; + if (param->flags & COMPRESSED_TIMESTAMP_FLAG) + lbuf_phys_addr = param->paddr - + sizeof(struct snd_codec_metadata); + else + lbuf_phys_addr = param->paddr; dir = OUT; } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 4c66eeaeeb03..b1980df07dce 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2623,8 +2623,7 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, dapm_mark_dirty(widgets[dir], "Route added"); } - if (dapm->card->instantiated && path->connect) - dapm_path_invalidate(path); + dapm_path_invalidate(path); return 0; err: |
