diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-11-26 17:46:55 -0700 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-11-26 17:46:56 -0700 |
| commit | a6fff3c86ee7b4fa4e33384634f4ea73b44ffb23 (patch) | |
| tree | 34deda2952363839768405ddc71d879ca6d9a970 | |
| parent | 9811ea8f33b639a3a2e11661be50c19f2fec9927 (diff) | |
| parent | b23cd82dba85b13ace45d0c638452f1b641039cd (diff) | |
Promotion of kernel.lnx.4.4-161126.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
1086894 I78770eea7fdd57f12d92ff40ed8043987e742024 msm: mdss: refine the calculation of tmds clock rate
1086976 Iae12fa648df17dddd48f3a71e94d06c2c3b03277 soc: qcom: socinfo: Change offset of image OEM attribute
1056661 If225dc4ec2c2e3eb8996f49f4fdf6acd31a50680 Revert "msm: kgsl: Enable limits management on A540v2"
1093546 I8f1cba6e1efa65ae41e674b14bd7598b4b521f05 soc: qcom: msm_bus: Set current index to default value
1092875 I53f89cf6b7c11f32c5e8e5a51a5986fa31424b92 qpnp-smb2: force UFP mode before shutdown
1084600 I53cd6ed709263669edbc34f096a21cddffcf4489 smb-lib: fix null ptr access while handling src change i
1081033 I6fc8323cbcf395a2c24e49e65cc7012709d031a2 input: synaptics_dsx: add checks of user input data
1086894 Ia3ea67cc7658098928a442460198b2dccc8ff8e1 msm: mdss: update vic info when powering on HDMI
1091972 I36ca125143cf9929fb0bd781990bdd8ab1dbeebf ARM: dts: msm: Add thermal mitigation properties to msmf
1091972 Ie564c181db61f6229479a49917cdb9e6c1887fc5 ARM: dts: msm: Add thermal sensor info for msmfalcon
1091566 Ic68cd12cc861d04e107b70e2b96200483f13da26 qpnp-smb2: add support to configure auto recharge
1072067 I7c6ab8bc0e88010eb221788cf8ce4c182e3128d9 ASoc: msm: qdsp6v2: Add support for compress capture
1060631 Icb48ac2624d489ff054dca3158f52c45cc85cce7 msm: camera: Enable secure camera feature
1087473 I09fbda8eb92c81acf24d0ff07ca9c040141680e1 msm: mdss: fix to handle multi-rect configuration in err
1082636 I3db0c20ac5fa47ed278f3d60368c406f472430c1 msm: crypto: fix issues on digest buf and copy_from_user
1090500 Ie592d06d2e09c2e263a2e9485a42eafb368e49cc include: clock: Add audio external clock of_index extrie
1084152 I48b5fc1c9e98994c8a7d92d462138cbacb246005 ASoC: wcd9335: Add dapm ignore suspend for codec dai
Change-Id: I0cc98bd7e0978cccd6a24fd1ead5e80d66e76a30
CRs-Fixed: 1056661, 1086894, 1087473, 1081033, 1091566, 1086976, 1093546, 1092875, 1060631, 1072067, 1084152, 1084600, 1090500, 1091972, 1082636
26 files changed, 2097 insertions, 302 deletions
diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt index 9d8670c7594b..382587ea5922 100644 --- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt @@ -138,6 +138,14 @@ Charger specific properties: then charge inhibit will be disabled by default. Allowed values are: 50, 100, 200, 300. +- qcom,auto-recharge-soc + Usage: optional + Value type: <empty> + Definition: Specifies if automatic recharge needs to be based off battery + SOC. If this property is not specified, then auto recharge will + be based off battery voltage. For both SOC and battery voltage, + charger receives the signal from FG to resume charging. + ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index f85a40007d3f..ed8bee03b4d0 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -47,6 +47,7 @@ compatible = "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile0>; }; CPU1: cpu@1 { @@ -54,6 +55,7 @@ compatible = "arm,armv8"; reg = <0x0 0x1>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile0>; }; CPU2: cpu@2 { @@ -61,6 +63,7 @@ compatible = "arm,armv8"; reg = <0x0 0x2>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile0>; }; CPU3: cpu@3 { @@ -68,6 +71,7 @@ compatible = "arm,armv8"; reg = <0x0 0x3>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile0>; }; CPU4: cpu@100 { @@ -75,6 +79,7 @@ compatible = "arm,armv8"; reg = <0x0 0x100>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile1>; }; CPU5: cpu@101 { @@ -82,6 +87,7 @@ compatible = "arm,armv8"; reg = <0x0 0x101>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile2>; }; CPU6: cpu@102 { @@ -89,6 +95,7 @@ compatible = "arm,armv8"; reg = <0x0 0x102>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile3>; }; CPU7: cpu@103 { @@ -96,6 +103,7 @@ compatible = "arm,armv8"; reg = <0x0 0x103>; enable-method = "psci"; + qcom,limits-info = <&mitigation_profile4>; }; cpu-map { @@ -358,6 +366,180 @@ clock-names = "core", "iface"; }; + qcom,sensor-information { + compatible = "qcom,sensor-information"; + sensor_information0: qcom,sensor-information-0 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor0"; + qcom,scaling-factor = <10>; + }; + sensor_information1: qcom,sensor-information-1 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor1"; + qcom,scaling-factor = <10>; + }; + sensor_information2: qcom,sensor-information-2 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor2"; + qcom,scaling-factor = <10>; + }; + sensor_information3: qcom,sensor-information-3 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor3"; + qcom,scaling-factor = <10>; + }; + sensor_information4: qcom,sensor-information-4 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor4"; + qcom,scaling-factor = <10>; + }; + sensor_information5: qcom,sensor-information-5 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor5"; + qcom,scaling-factor = <10>; + }; + sensor_information6: qcom,sensor-information-6 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor6"; + qcom,scaling-factor = <10>; + }; + sensor_information7: qcom,sensor-information-7 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor7"; + qcom,scaling-factor = <10>; + }; + sensor_information8: qcom,sensor-information-8 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor8"; + qcom,scaling-factor = <10>; + qcom,alias-name = "gpu"; + }; + sensor_information9: qcom,sensor-information-9 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor9"; + qcom,scaling-factor = <10>; + }; + sensor_information10: qcom,sensor-information-10 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor10"; + qcom,scaling-factor = <10>; + }; + sensor_information11: qcom,sensor-information-11 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor11"; + qcom,scaling-factor = <10>; + }; + sensor_information12: qcom,sensor-information-12 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor12"; + qcom,scaling-factor = <10>; + }; + sensor_information13: qcom,sensor-information-13 { + qcom,sensor-type = "tsens"; + qcom,sensor-name = "tsens_tz_sensor13"; + qcom,scaling-factor = <10>; + }; + sensor_information14: qcom,sensor-information-14 { + qcom,sensor-type = "alarm"; + qcom,sensor-name = "pmfalcon_tz"; + qcom,scaling-factor = <1000>; + }; + sensor_information15: qcom,sensor-information-15 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "msm_therm"; + }; + sensor_information16: qcom,sensor-information-16 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "xo_therm"; + }; + sensor_information17: qcom,sensor-information-17 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "pa_therm0"; + }; + sensor_information18: qcom,sensor-information-18 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "pa_therm1"; + }; + sensor_information19: qcom,sensor-information-19 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "quiet_therm"; + }; + sensor_information20: qcom,sensor-information-20 { + qcom,sensor-type = "llm"; + qcom,sensor-name = "limits_sensor-00"; + }; + sensor_information21: qcom,sensor-information-21 { + qcom,sensor-type = "llm"; + qcom,sensor-name = "limits_sensor-01"; + }; + }; + + mitigation_profile0: qcom,limit_info-0 { + qcom,temperature-sensor = <&sensor_information1>; + qcom,hotplug-mitigation-enable; + }; + + mitigation_profile1: qcom,limit_info-1 { + qcom,temperature-sensor = <&sensor_information3>; + qcom,hotplug-mitigation-enable; + }; + + mitigation_profile2: qcom,limit_info-2 { + qcom,temperature-sensor = <&sensor_information4>; + qcom,hotplug-mitigation-enable; + }; + + mitigation_profile3: qcom,limit_info-3 { + qcom,temperature-sensor = <&sensor_information5>; + qcom,hotplug-mitigation-enable; + }; + + mitigation_profile4: qcom,limit_info-4 { + qcom,temperature-sensor = <&sensor_information6>; + qcom,hotplug-mitigation-enable; + }; + + qcom,msm-thermal { + compatible = "qcom,msm-thermal"; + qcom,sensor-id = <1>; + qcom,poll-ms = <100>; + qcom,therm-reset-temp = <115>; + qcom,core-limit-temp = <70>; + qcom,core-temp-hysteresis = <10>; + qcom,hotplug-temp = <105>; + qcom,hotplug-temp-hysteresis = <20>; + qcom,online-hotplug-core; + qcom,synchronous-cluster-id = <0 1>; + qcom,synchronous-cluster-map = <0 4 &CPU0 &CPU1 &CPU2 &CPU3>, + <1 4 &CPU4 &CPU5 &CPU6 &CPU7>; + + qcom,vdd-restriction-temp = <5>; + qcom,vdd-restriction-temp-hysteresis = <10>; + + vdd-dig-supply = <&pm2falcon_s3_floor_level>; + vdd-gfx-supply = <&gfx_vreg_corner>; + + qcom,vdd-dig-rstr{ + qcom,vdd-rstr-reg = "vdd-dig"; + qcom,levels = <RPM_SMD_REGULATOR_LEVEL_NOM + RPM_SMD_REGULATOR_LEVEL_TURBO + RPM_SMD_REGULATOR_LEVEL_TURBO>; + qcom,min-level = <RPM_SMD_REGULATOR_LEVEL_NONE>; + }; + + qcom,vdd-gfx-rstr{ + qcom,vdd-rstr-reg = "vdd-gfx"; + qcom,levels = <5 6 6>; /* Nominal, Turbo, Turbo */ + qcom,min-level = <1>; /* No Request */ + }; + + msm_thermal_freq: qcom,vdd-apps-rstr{ + qcom,vdd-rstr-reg = "vdd-apps"; + qcom,levels = <1248000>; + qcom,freq-req; + }; + }; + uartblsp2dm1: serial@0c1b0000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0xc1b0000 0x1000>; diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index e2099c4e7877..433e4783d1d1 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -603,7 +603,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq, while (len > 0) { user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr; - if (user_src && __copy_from_user(k_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[i].len)) return -EFAULT; @@ -639,7 +639,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq, /* Copy data from user src(s) */ user_src = (void __user *)qcedev_areq->sha_op_req.data[0].vaddr; - if (user_src && __copy_from_user(k_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[0].len)) { kzfree(k_buf_src); @@ -648,7 +648,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq, k_src += qcedev_areq->sha_op_req.data[0].len; for (i = 1; i < qcedev_areq->sha_op_req.entries; i++) { user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr; - if (user_src && __copy_from_user(k_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[i].len)) { kzfree(k_buf_src); @@ -702,13 +702,6 @@ static int qcedev_sha_update(struct qcedev_async_req *qcedev_areq, return -EINVAL; } - /* verify address src(s) */ - for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) - if (!access_ok(VERIFY_READ, - (void __user *)qcedev_areq->sha_op_req.data[i].vaddr, - qcedev_areq->sha_op_req.data[i].len)) - return -EFAULT; - if (qcedev_areq->sha_op_req.data_len > QCE_MAX_OPER_DATA) { struct qcedev_sha_op_req *saved_req; @@ -868,19 +861,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq, total = qcedev_areq->sha_op_req.data_len; - /* verify address src(s) */ - for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) - if (!access_ok(VERIFY_READ, - (void __user *)qcedev_areq->sha_op_req.data[i].vaddr, - qcedev_areq->sha_op_req.data[i].len)) - return -EFAULT; - - /* Verify Source Address */ - if (!access_ok(VERIFY_READ, - (void __user *)qcedev_areq->sha_op_req.authkey, - qcedev_areq->sha_op_req.authklen)) - return -EFAULT; - if (__copy_from_user(&handle->sha_ctxt.authkey[0], + if (copy_from_user(&handle->sha_ctxt.authkey[0], (void __user *)qcedev_areq->sha_op_req.authkey, qcedev_areq->sha_op_req.authklen)) return -EFAULT; @@ -900,7 +881,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq, for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) { user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr; - if (user_src && __copy_from_user(k_src, (void __user *)user_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[i].len)) { kzfree(k_buf_src); return -EFAULT; @@ -928,12 +909,7 @@ static int qcedev_set_hmac_auth_key(struct qcedev_async_req *areq, if (areq->sha_op_req.authklen <= QCEDEV_MAX_KEY_SIZE) { qcedev_sha_init(areq, handle); - /* Verify Source Address */ - if (!access_ok(VERIFY_READ, - (void __user *)areq->sha_op_req.authkey, - areq->sha_op_req.authklen)) - return -EFAULT; - if (__copy_from_user(&handle->sha_ctxt.authkey[0], + if (copy_from_user(&handle->sha_ctxt.authkey[0], (void __user *)areq->sha_op_req.authkey, areq->sha_op_req.authklen)) return -EFAULT; @@ -1146,7 +1122,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, byteoffset = areq->cipher_op_req.byteoffset; user_src = (void __user *)areq->cipher_op_req.vbuf.src[0].vaddr; - if (user_src && __copy_from_user((k_align_src + byteoffset), + if (user_src && copy_from_user((k_align_src + byteoffset), (void __user *)user_src, areq->cipher_op_req.vbuf.src[0].len)) return -EFAULT; @@ -1156,7 +1132,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, for (i = 1; i < areq->cipher_op_req.entries; i++) { user_src = (void __user *)areq->cipher_op_req.vbuf.src[i].vaddr; - if (user_src && __copy_from_user(k_align_src, + if (user_src && copy_from_user(k_align_src, (void __user *)user_src, areq->cipher_op_req.vbuf.src[i].len)) { return -EFAULT; @@ -1188,7 +1164,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, while (creq->data_len > 0) { if (creq->vbuf.dst[dst_i].len <= creq->data_len) { - if (err == 0 && __copy_to_user( + if (err == 0 && copy_to_user( (void __user *)creq->vbuf.dst[dst_i].vaddr, (k_align_dst + byteoffset), creq->vbuf.dst[dst_i].len)) @@ -1199,7 +1175,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, creq->data_len -= creq->vbuf.dst[dst_i].len; dst_i++; } else { - if (err == 0 && __copy_to_user( + if (err == 0 && copy_to_user( (void __user *)creq->vbuf.dst[dst_i].vaddr, (k_align_dst + byteoffset), creq->data_len)) @@ -1531,36 +1507,6 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req, __func__, total, req->data_len); goto error; } - /* Verify Source Address's */ - for (i = 0, total = 0; i < req->entries; i++) { - if (total < req->data_len) { - if (!access_ok(VERIFY_READ, - (void __user *)req->vbuf.src[i].vaddr, - req->vbuf.src[i].len)) { - pr_err("%s:SRC RD_VERIFY err %d=0x%lx\n", - __func__, i, (uintptr_t) - req->vbuf.src[i].vaddr); - goto error; - } - total += req->vbuf.src[i].len; - } - } - - /* Verify Destination Address's */ - for (i = 0, total = 0; i < QCEDEV_MAX_BUFFERS; i++) { - if ((req->vbuf.dst[i].vaddr != 0) && - (total < req->data_len)) { - if (!access_ok(VERIFY_WRITE, - (void __user *)req->vbuf.dst[i].vaddr, - req->vbuf.dst[i].len)) { - pr_err("%s:DST WR_VERIFY err %d=0x%lx\n", - __func__, i, (uintptr_t) - req->vbuf.dst[i].vaddr); - goto error; - } - total += req->vbuf.dst[i].len; - } - } return 0; error: return -EINVAL; @@ -1656,11 +1602,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) switch (cmd) { case QCEDEV_IOCTL_ENC_REQ: case QCEDEV_IOCTL_DEC_REQ: - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_cipher_op_req))) - return -EFAULT; - - if (__copy_from_user(&qcedev_areq.cipher_op_req, + if (copy_from_user(&qcedev_areq.cipher_op_req, (void __user *)arg, sizeof(struct qcedev_cipher_op_req))) return -EFAULT; @@ -1673,20 +1615,17 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle); if (err) return err; - if (__copy_to_user((void __user *)arg, + if (copy_to_user((void __user *)arg, &qcedev_areq.cipher_op_req, sizeof(struct qcedev_cipher_op_req))) - return -EFAULT; + return -EFAULT; break; case QCEDEV_IOCTL_SHA_INIT_REQ: { struct scatterlist sg_src; - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1696,9 +1635,9 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) err = qcedev_hash_init(&qcedev_areq, handle, &sg_src); if (err) return err; - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) - return -EFAULT; + return -EFAULT; } handle->sha_ctxt.init_done = true; break; @@ -1708,11 +1647,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case QCEDEV_IOCTL_SHA_UPDATE_REQ: { struct scatterlist sg_src; - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1734,10 +1670,15 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) return err; } + if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { + pr_err("Invalid sha_ctxt.diglen %d\n", + handle->sha_ctxt.diglen); + return -EINVAL; + } memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; } @@ -1749,11 +1690,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) pr_err("%s Init was not called\n", __func__); return -EINVAL; } - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1767,7 +1704,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; handle->sha_ctxt.init_done = false; @@ -1776,11 +1713,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case QCEDEV_IOCTL_GET_SHA_REQ: { struct scatterlist sg_src; - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1798,7 +1732,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; } diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index d07e6b36dc8f..e6163384f9c1 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -269,7 +269,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .patchid = ANY_ID, .features = ADRENO_PREEMPTION | ADRENO_64BIT | ADRENO_CONTENT_PROTECTION | - ADRENO_GPMU | ADRENO_SPTP_PC | ADRENO_LM, + ADRENO_GPMU | ADRENO_SPTP_PC, .pm4fw_name = "a530_pm4.fw", .pfpfw_name = "a530_pfp.fw", .zap_name = "a540_zap", 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 2282fe005bc7..f001706236ab 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c @@ -1606,6 +1606,13 @@ 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) { + 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; + } + memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]), (const void *)buf, count); diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c index feede3a14e07..d6b32036f31c 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/dma-buf.h> #include <asm/dma-iommu.h> +#include <asm/cacheflush.h> #include <linux/dma-direction.h> #include <linux/dma-attrs.h> #include <linux/of_platform.h> @@ -23,6 +24,8 @@ #include <linux/dma-mapping.h> #include <linux/msm_dma_iommu_mapping.h> #include <linux/workqueue.h> +#include <soc/qcom/scm.h> +#include <soc/qcom/secure_buffer.h> #include "cam_smmu_api.h" #define SCRATCH_ALLOC_START SZ_128K @@ -35,10 +38,15 @@ #define COOKIE_MASK ((1<<COOKIE_SIZE)-1) #define HANDLE_INIT (-1) #define CAM_SMMU_CB_MAX 2 +#define CAM_SMMU_SID_MAX 4 + #define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK)) #define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK) +#define CAMERA_DEVICE_ID 0x16 +#define SECURE_SYSCALL_ID 0x18 + #ifdef CONFIG_CAM_SMMU_DBG #define CDBG(fmt, args...) pr_err(fmt, ##args) #else @@ -104,6 +112,8 @@ struct cam_context_bank_info { int, void*); void *token[CAM_SMMU_CB_MAX]; int cb_count; + int ref_cnt; + int sids[CAM_SMMU_SID_MAX]; }; struct cam_iommu_cb_set { @@ -136,6 +146,17 @@ struct cam_dma_buff_info { size_t phys_len; }; +struct cam_sec_buff_info { + struct ion_handle *i_hdl; + struct ion_client *i_client; + enum dma_data_direction dir; + int ref_count; + dma_addr_t paddr; + struct list_head list; + int ion_fd; + size_t len; +}; + static struct cam_iommu_cb_set iommu_cb_set; static enum dma_data_direction cam_smmu_translate_dir( @@ -151,6 +172,9 @@ static int cam_smmu_create_add_handle_in_table(char *name, static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx, int ion_fd); +static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx, + int ion_fd); + static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map, dma_addr_t base, size_t size, int order); @@ -477,10 +501,14 @@ void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops) iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH; iommu_cb_set.cb_info[i].dev = NULL; iommu_cb_set.cb_info[i].cb_count = 0; + iommu_cb_set.cb_info[i].ref_cnt = 0; for (j = 0; j < CAM_SMMU_CB_MAX; j++) { iommu_cb_set.cb_info[i].token[j] = NULL; iommu_cb_set.cb_info[i].handler[j] = NULL; } + for (j = 0; j < CAM_SMMU_SID_MAX; j++) + iommu_cb_set.cb_info[i].sids[j] = -1; + if (ops == CAM_SMMU_TABLE_INIT) mutex_init(&iommu_cb_set.cb_info[i].lock); else @@ -549,6 +577,8 @@ static int cam_smmu_create_add_handle_in_table(char *name, pr_err("Error: %s already got handle 0x%x\n", name, iommu_cb_set.cb_info[i].handle); + *hdl = iommu_cb_set.cb_info[i].handle; + iommu_cb_set.cb_info[i].ref_cnt++; mutex_unlock(&iommu_cb_set.cb_info[i].lock); return -EINVAL; } @@ -561,6 +591,7 @@ static int cam_smmu_create_add_handle_in_table(char *name, /* put handle in the table */ iommu_cb_set.cb_info[i].handle = handle; iommu_cb_set.cb_info[i].cb_count = 0; + iommu_cb_set.cb_info[i].ref_cnt++; *hdl = handle; CDBG("%s creates handle 0x%x\n", name, handle); mutex_unlock(&iommu_cb_set.cb_info[i].lock); @@ -698,6 +729,23 @@ static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx, return NULL; } +static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx, + int ion_fd) +{ + struct cam_sec_buff_info *mapping; + + list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->ion_fd == ion_fd) { + CDBG("[sec_cam] find ion_fd %d\n", ion_fd); + return mapping; + } + } + pr_err("Error: Cannot find fd %d by index %d\n", + ion_fd, idx); + return NULL; +} + static void cam_smmu_clean_buffer_list(int idx) { int ret; @@ -754,6 +802,148 @@ static int cam_smmu_attach(int idx) return ret; } +static int cam_smmu_send_syscall_cpp_intf(int vmid, int idx) +{ + int rc = 0; + struct scm_desc desc = {0}; + struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + uint32_t sid_info; + + + sid_info = cb->sids[0]; /* CPP SID */ + + desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL); + desc.args[0] = CAMERA_DEVICE_ID; + desc.args[1] = SCM_BUFFER_PHYS(&sid_info); + desc.args[2] = sizeof(uint32_t); + desc.args[3] = vmid; + /* + * Syscall to hypervisor to switch CPP SID's + * between secure and non-secure contexts + */ + dmac_flush_range(&sid_info, &sid_info + 1); + if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID), + &desc)){ + pr_err("call to hypervisor failed\n"); + return -EINVAL; + } + return rc; +} + +static int cam_smmu_send_syscall_pix_intf(int vmid, int idx) +{ + int rc = 0; + struct scm_desc desc = {0}; + uint32_t *sid_info = NULL; + struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + + sid_info = kzalloc(sizeof(uint32_t) * 2, GFP_KERNEL); + if (!sid_info) + return -ENOMEM; + + sid_info[0] = cb->sids[0]; /* VFE 0 Image SID */ + sid_info[1] = cb->sids[2]; /* VFE 1 Image SID */ + + desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL); + desc.args[0] = CAMERA_DEVICE_ID; + desc.args[1] = SCM_BUFFER_PHYS(sid_info); + desc.args[2] = sizeof(uint32_t) * 2; + desc.args[3] = vmid; + /* + * Syscall to hypervisor to switch VFE SID's + * between secure and non-secure contexts + */ + dmac_flush_range(sid_info, sid_info + 2); + if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID), + &desc)){ + pr_err("call to hypervisor failed\n"); + kfree(sid_info); + return -EINVAL; + } + + kfree(sid_info); + return rc; +} + +static int cam_smmu_detach_device(int idx) +{ + struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + + /* detach the mapping to device */ + arm_iommu_detach_device(cb->dev); + iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH; + return 0; +} + +static int cam_smmu_attach_sec_cpp(int idx) +{ + /* + * When switching to secure, detach CPP NS, do scm call + * with CPP SID and no need of attach again, because + * all cpp sids are shared in SCM call. so no need of + * attach again. + */ + + if (cam_smmu_send_syscall_cpp_intf(VMID_CP_CAMERA, idx)) { + pr_err("error: syscall failed\n"); + return -EINVAL; + } + return 0; +} + +static int cam_smmu_detach_sec_cpp(int idx) +{ + /* + * When exiting secure, do scm call to attach + * with CPP SID in NS mode. + */ + if (cam_smmu_send_syscall_cpp_intf(VMID_HLOS, idx)) { + pr_err("error: syscall failed\n"); + return -EINVAL; + } + return 0; +} + +static int cam_smmu_attach_sec_vfe_ns_stats(int idx) +{ + /* + *When switching to secure, for secure pixel and non-secure stats + *localizing scm/attach of non-secure SID's in attach secure + */ + if (cam_smmu_send_syscall_pix_intf(VMID_CP_CAMERA, idx)) { + pr_err("error: syscall failed\n"); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + if (cam_smmu_attach(idx)) { + pr_err("error: failed to attach\n"); + return -EINVAL; + } + } + return 0; +} + +static int cam_smmu_detach_sec_vfe_ns_stats(int idx) +{ + /* + *While exiting from secure mode for secure pixel and non-secure stats, + *localizing detach/scm of non-secure SID's to detach secure + */ + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_DETACH) { + if (cam_smmu_detach_device(idx) < 0) { + pr_err("Error: ARM IOMMU detach failed\n"); + return -ENODEV; + } + } + + if (cam_smmu_send_syscall_pix_intf(VMID_HLOS, idx)) { + pr_err("error: syscall failed\n"); + return -EINVAL; + } + return 0; +} + static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, size_t *len_ptr) @@ -805,7 +995,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, } else { rc = -EINVAL; pr_err("Error: table sgl is null\n"); - goto err_unmap_sg; + goto err_map_addr; } /* fill up mapping_info */ @@ -813,7 +1003,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, if (!mapping_info) { pr_err("Error: No enough space!\n"); rc = -ENOSPC; - goto err_unmap_sg; + goto err_map_addr; } mapping_info->ion_fd = ion_fd; mapping_info->buf = buf; @@ -831,7 +1021,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, if (!*paddr_ptr || !*len_ptr) { pr_err("Error: Space Allocation failed!\n"); rc = -ENOSPC; - goto err_unmap_sg; + goto err_mapping_info; } CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd, (void *)iommu_cb_set.cb_info[idx].dev, @@ -841,6 +1031,12 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); return 0; +err_mapping_info: + kzfree(mapping_info); +err_map_addr: + msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev, + table->sgl, table->nents, + dma_dir, buf); err_unmap_sg: dma_buf_unmap_attachment(attach, table, dma_dir); err_detach: @@ -851,6 +1047,98 @@ err_out: return rc; } +static int cam_smmu_map_secure_buffer_and_add_to_list(int idx, + struct dma_buf *buf, + enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int rc = -1; + struct cam_dma_buff_info *mapping_info; + struct dma_buf_attachment *attach = NULL; + struct sg_table *table = NULL; + + attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev); + if (IS_ERR_OR_NULL(attach)) { + rc = PTR_ERR(attach); + pr_err("Error: dma buf attach failed\n"); + goto err_put; + } + + table = dma_buf_map_attachment(attach, dma_dir); + if (IS_ERR_OR_NULL(table)) { + rc = PTR_ERR(table); + pr_err("Error: dma buf map attachment failed\n"); + goto err_detach; + } + + rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev, table->sgl, + table->nents, dma_dir, buf); + if (!rc) { + pr_err("Error: msm_dma_map_sg_lazy failed\n"); + goto err_unmap_sg; + } + + if (table->sgl) { + CDBG("DMA buf: %p, device: %p, attach: %p, table: %p\n", + (void *)buf, + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)attach, (void *)table); + CDBG("table sgl: %p, rc: %d, dma_address: 0x%x\n", + (void *)table->sgl, rc, + (unsigned int)table->sgl->dma_address); + } else { + rc = -EINVAL; + pr_err("Error: table sgl is null\n"); + goto err_map_addr; + } + + /* fill up mapping_info */ + mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL); + if (!mapping_info) { + rc = -ENOSPC; + goto err_map_addr; + } + mapping_info->ion_fd = 0; + mapping_info->buf = buf; + mapping_info->attach = attach; + mapping_info->table = table; + mapping_info->paddr = sg_dma_address(table->sgl); + mapping_info->len = (size_t)sg_dma_len(table->sgl); + mapping_info->dir = dma_dir; + mapping_info->ref_count = 1; + + /* return paddr and len to client */ + *paddr_ptr = sg_dma_address(table->sgl); + *len_ptr = (size_t)sg_dma_len(table->sgl); + + if (!*paddr_ptr || !*len_ptr) { + pr_err("Error: Invalid dma address/length\n"); + rc = -ENOSPC; + goto err_mapping_info; + } + CDBG("dev = %p, paddr= %p, len = %u\n", + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)*paddr_ptr, (unsigned int)*len_ptr); + + /* add to the list */ + list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); + + return 0; + +err_mapping_info: + kzfree(mapping_info); +err_map_addr: + msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev, + table->sgl, table->nents, + dma_dir, buf); +err_unmap_sg: + dma_buf_unmap_attachment(attach, table, dma_dir); +err_detach: + dma_buf_detach(buf, attach); +err_put: + return rc; +} + static int cam_smmu_unmap_buf_and_remove_from_list( struct cam_dma_buff_info *mapping_info, int idx) @@ -951,7 +1239,23 @@ int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops) break; } case CAM_SMMU_DETACH: { - ret = 0; + ret = cam_smmu_detach_device(idx); + break; + } + case CAM_SMMU_ATTACH_SEC_VFE_NS_STATS: { + ret = cam_smmu_attach_sec_vfe_ns_stats(idx); + break; + } + case CAM_SMMU_DETACH_SEC_VFE_NS_STATS: { + ret = cam_smmu_detach_sec_vfe_ns_stats(idx); + break; + } + case CAM_SMMU_ATTACH_SEC_CPP: { + ret = cam_smmu_attach_sec_cpp(idx); + break; + } + case CAM_SMMU_DETACH_SEC_CPP: { + ret = cam_smmu_detach_sec_cpp(idx); break; } case CAM_SMMU_VOTE: @@ -1126,7 +1430,7 @@ int cam_smmu_get_phy_addr_scratch(int handle, size_t virt_len, size_t phys_len) { - int idx, rc; + int idx, rc = 0; unsigned int iommu_dir; if (!paddr_ptr || !virt_len || !phys_len) { @@ -1250,12 +1554,384 @@ int cam_smmu_put_phy_addr_scratch(int handle, pr_err("Error: unmap or remove list fail\n"); goto handle_err; } +handle_err: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} + +int cam_smmu_get_phy_addr_secure_scratch(int handle, + enum cam_smmu_map_dir dir, + struct dma_buf *scratch_buf, + dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int idx, rc; + enum dma_data_direction dma_dir; + + if (!paddr_ptr || !len_ptr) { + pr_err("Error: Input pointer or lengths invalid\n"); + return -EINVAL; + } + + dma_dir = cam_smmu_translate_dir(dir); + if (dma_dir == DMA_NONE) { + pr_err("Error: translate direction failed. dir = %d\n", dir); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto error; + } + + CDBG("%s: smmu handle = %x, idx = %d, dir = %d\n", + __func__, handle, idx, dir); + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + pr_err("Error: Device %s should call SMMU attach before map buffer\n", + iommu_cb_set.cb_info[idx].name); + rc = -EINVAL; + goto error; + } + + rc = cam_smmu_map_secure_buffer_and_add_to_list(idx, + scratch_buf, + dma_dir, + paddr_ptr, + len_ptr); + if (rc < 0) { + pr_err("Error: mapping or add list fail\n"); + goto error; + } + + CDBG("Mapped scratch buffer physical address is %lx\n", + (unsigned long)*paddr_ptr); +error: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} + +int cam_smmu_put_phy_addr_secure_scratch(int handle, + dma_addr_t paddr) +{ + int idx; + int rc = -1; + struct cam_dma_buff_info *mapping_info; + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto handle_err; + } + + /* Based on virtual address and index, we can find mapping info + * of the scratch buffer + */ + mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr); + if (!mapping_info) { + pr_err("Error: Invalid params\n"); + rc = -EINVAL; + goto handle_err; + } + + /* unmapping one buffer from device */ + rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx); + if (rc < 0) { + pr_err("Error: unmap or remove list fail\n"); + goto handle_err; + } + CDBG("Unmap secure scratch buffer %lx success fully\n", + (unsigned long)paddr); handle_err: mutex_unlock(&iommu_cb_set.cb_info[idx].lock); return rc; } +int cam_smmu_alloc_get_stage2_scratch_mem(int handle, + enum cam_smmu_map_dir dir, struct ion_client *client, + struct ion_handle **sc_handle, ion_phys_addr_t *addr, + size_t *len_ptr) +{ + int idx, rc = 0; + enum dma_data_direction dma_dir; + + dma_dir = cam_smmu_translate_dir(dir); + if (dma_dir == DMA_NONE) { + pr_err("Error: translate direction failed. dir = %d\n", dir); + return -EINVAL; + } + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + pr_err("Error: Device %s should call SMMU attach before map buffer\n", + iommu_cb_set.cb_info[idx].name); + return -EINVAL; + } + *sc_handle = ion_alloc(client, SZ_2M, SZ_2M, + ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID), + ION_FLAG_SECURE | ION_FLAG_CP_CAMERA); + if (IS_ERR_OR_NULL((void *) (*sc_handle))) { + rc = -ENOMEM; + goto err_ion_handle; + } + + /* return addr and len to client */ + rc = ion_phys(client, *sc_handle, addr, len_ptr); + if (rc) { + pr_err("%s: ION Get Physical failed, rc = %d\n", + __func__, rc); + rc = -EINVAL; + goto err_ion_phys; + } + + CDBG("dev = %pK, paddr= %pK, len = %u\n", + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)*addr, (unsigned int)*len_ptr); + return rc; + +err_ion_phys: + ion_free(client, *sc_handle); + +err_ion_handle: + *sc_handle = NULL; + return rc; +} + +int cam_smmu_free_stage2_scratch_mem(int handle, + struct ion_client *client, struct ion_handle *sc_handle) +{ + int idx = 0; + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + ion_free(client, sc_handle); + return 0; +} + +static int cam_smmu_secure_unmap_buf_and_remove_from_list( + struct cam_sec_buff_info *mapping_info, + int idx) +{ + if (!mapping_info) { + pr_err("Error: List doesn't exist\n"); + return -EINVAL; + } + ion_free(mapping_info->i_client, mapping_info->i_hdl); + list_del_init(&mapping_info->list); + + /* free one buffer */ + kfree(mapping_info); + return 0; +} + +int cam_smmu_put_stage2_phy_addr(int handle, int ion_fd) +{ + int idx, rc; + struct cam_sec_buff_info *mapping_info; + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto put_addr_end; + } + + /* based on ion fd and index, we can find mapping info of buffer */ + mapping_info = cam_smmu_find_mapping_by_sec_buf_idx(idx, ion_fd); + if (!mapping_info) { + pr_err("Error: Invalid params! idx = %d, fd = %d\n", + idx, ion_fd); + rc = -EINVAL; + goto put_addr_end; + } + + mapping_info->ref_count--; + if (mapping_info->ref_count > 0) { + CDBG("There are still %u buffer(s) with same fd %d", + mapping_info->ref_count, mapping_info->ion_fd); + rc = 0; + goto put_addr_end; + } + + /* unmapping one buffer from device */ + rc = cam_smmu_secure_unmap_buf_and_remove_from_list(mapping_info, idx); + if (rc < 0) { + pr_err("Error: unmap or remove list fail\n"); + goto put_addr_end; + } + +put_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_put_stage2_phy_addr); + +static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd, + enum dma_data_direction dma_dir, struct ion_client *client, + dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int rc = 0; + struct ion_handle *i_handle = NULL; + struct cam_sec_buff_info *mapping_info; + + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + pr_err("Error: Device %s should call SMMU attach before map buffer\n", + iommu_cb_set.cb_info[idx].name); + return -EINVAL; + } + + i_handle = ion_import_dma_buf(client, ion_fd); + if (IS_ERR_OR_NULL((void *)(i_handle))) { + pr_err("%s: ion import dma buffer failed\n", __func__); + return -EINVAL; + } + + /* return addr and len to client */ + rc = ion_phys(client, i_handle, paddr_ptr, len_ptr); + if (rc) { + pr_err("%s: ION Get Physical failed, rc = %d\n", + __func__, rc); + return -EINVAL; + } + + /* fill up mapping_info */ + mapping_info = kzalloc(sizeof(struct cam_sec_buff_info), GFP_KERNEL); + if (!mapping_info) + return -ENOSPC; + + mapping_info->ion_fd = ion_fd; + mapping_info->paddr = *paddr_ptr; + mapping_info->len = *len_ptr; + mapping_info->dir = dma_dir; + mapping_info->ref_count = 1; + mapping_info->i_hdl = i_handle; + mapping_info->i_client = client; + + CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd, + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)*paddr_ptr, (unsigned int)*len_ptr); + + /* add to the list */ + list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); + + return rc; +} + +int cam_smmu_get_stage2_phy_addr(int handle, + int ion_fd, enum cam_smmu_map_dir dir, + struct ion_client *client, ion_phys_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int idx, rc; + enum dma_data_direction dma_dir; + enum cam_smmu_buf_state buf_state; + + if (!paddr_ptr || !len_ptr) { + pr_err("Error: Input pointers are invalid\n"); + return -EINVAL; + } + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + dma_dir = cam_smmu_translate_dir(dir); + if (dma_dir == DMA_NONE) { + pr_err("Error: translate direction failed. dir = %d\n", dir); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { + pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + pr_err("Error: Device %s should call SMMU attach before map buffer\n", + iommu_cb_set.cb_info[idx].name); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); + if (buf_state == CAM_SMMU_BUFF_EXIST) { + CDBG("ion_fd:%d already in the list, give same addr back", + ion_fd); + rc = 0; + goto get_addr_end; + } + rc = cam_smmu_map_stage2_buffer_and_add_to_list(idx, ion_fd, dma_dir, + client, paddr_ptr, len_ptr); + if (rc < 0) { + pr_err("Error: mapping or add list fail\n"); + goto get_addr_end; + } + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} + + int cam_smmu_get_phy_addr(int handle, int ion_fd, enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr, size_t *len_ptr) @@ -1383,6 +2059,11 @@ int cam_smmu_destroy_handle(int handle) } mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (--iommu_cb_set.cb_info[idx].ref_cnt != 0) { + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return 0; + } + if (iommu_cb_set.cb_info[idx].handle != handle) { pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", iommu_cb_set.cb_info[idx].handle, handle); @@ -1469,6 +2150,28 @@ end: return rc; } +static int cam_smmu_populate_sids(struct device *dev, + struct cam_context_bank_info *cb) +{ + int i, j, rc = 0; + unsigned int cnt = 0; + const void *property; + + /* set the name of the context bank */ + property = of_get_property(dev->of_node, "iommus", &cnt); + cnt /= 4; + for (i = 0, j = 0; i < cnt; i = i + 2, j++) { + rc = of_property_read_u32_index(dev->of_node, + "iommus", i + 1, &cb->sids[j]); + if (rc < 0) + pr_err("misconfiguration, can't fetch SID\n"); + + pr_err("__debug cnt = %d, cb->name: :%s sid [%d] = %d\n,", + cnt, cb->name, j, cb->sids[j]); + } + return rc; +} + static int cam_alloc_smmu_context_banks(struct device *dev) { struct device_node *domains_child_node = NULL; @@ -1541,6 +2244,11 @@ static int cam_populate_smmu_context_banks(struct device *dev, goto cb_init_fail; } + /* populate SID's for each cb */ + rc = cam_smmu_populate_sids(dev, cb); + if (rc < 0) + pr_err("Error: failed to populate sids : %s\n", cb->name); + /* Check if context bank supports scratch buffers */ if (of_property_read_bool(dev->of_node, "qcom,scratch-buf-support")) cb->scratch_buf_support = 1; @@ -1549,9 +2257,9 @@ static int cam_populate_smmu_context_banks(struct device *dev, /* set the secure/non secure domain type */ if (of_property_read_bool(dev->of_node, "qcom,secure-context")) - cb->is_secure = CAM_SECURE; + cb->is_secure = true; else - cb->is_secure = CAM_NON_SECURE; + cb->is_secure = false; CDBG("cb->name :%s, cb->is_secure :%d, cb->scratch_support :%d\n", cb->name, cb->is_secure, cb->scratch_buf_support); diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h index 59d085989a9c..3b8481f8bf7e 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h +++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h @@ -23,6 +23,8 @@ #include <linux/random.h> #include <linux/spinlock_types.h> #include <linux/mutex.h> +#include <linux/msm_ion.h> + /* * Enum for possible CAM SMMU operations @@ -31,6 +33,10 @@ enum cam_smmu_ops_param { CAM_SMMU_ATTACH, CAM_SMMU_DETACH, + CAM_SMMU_ATTACH_SEC_VFE_NS_STATS, + CAM_SMMU_DETACH_SEC_VFE_NS_STATS, + CAM_SMMU_ATTACH_SEC_CPP, + CAM_SMMU_DETACH_SEC_CPP, CAM_SMMU_VOTE, CAM_SMMU_DEVOTE, CAM_SMMU_OPS_INVALID @@ -87,6 +93,59 @@ int cam_smmu_get_phy_addr(int handle, int cam_smmu_put_phy_addr(int handle, int ion_fd); /** + * @param handle: Client has to pass back the smmu handle provided. + * @param ion_fd: ION handle identifying the memory buffer. + * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, + * DMA_TO_DEVICE or DMA_FROM_DEVICE + * @client : Client has to pass the ion_client pointer created by the client. + * @phys_addr : Pointer to physical address where mapped address will be + * returned. + * @len : Length of buffer mapped returned by CAM SMMU driver. + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_stage2_phy_addr(int handle, + int ion_fd, enum cam_smmu_map_dir dir, + struct ion_client *client, ion_phys_addr_t *addr, + size_t *len_ptr); + +/** + * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) + * @param ion_fd: ION handle identifying the memory buffer. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_put_stage2_phy_addr(int handle, int ion_fd); + +/** + * @param handle: Client has to pass back the smmu handle provided. + * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, + * DMA_TO_DEVICE or DMA_FROM_DEVICE, client has to pass. + * @client : Client has to pass the ion_client pointer created by the client. + * @ion_handle : handle to the buffer returned by CAM SMMU driver. + * @phys_addr : Pointer to physical address where mapped address will be + * returned. + * @len : Length of buffer mapped returned by CAM SMMU driver. + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_alloc_get_stage2_scratch_mem(int handle, + enum cam_smmu_map_dir dir, struct ion_client *client, + struct ion_handle **sc_handle, ion_phys_addr_t *addr, + size_t *len_ptr); + + +/** + * @param handle: Client has to pass back the smmu handle provided. + * @client : Client has to pass the ion_client pointer provided by SMMU + * driver. + * @ion_handle : Client has to pass the ion_handle provided by SMMU + * driver. + * @return Status of operation. Negative in case of error. Zero otherwise. + */ + +int cam_smmu_free_stage2_scratch_mem(int handle, + struct ion_client *client, struct ion_handle *sc_handle); + +/** * @brief : Allocates a scratch buffer * * This function allocates a scratch virtual buffer of length virt_len in the diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index 7accaa3a1673..039ffcc24c23 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -214,7 +214,6 @@ static struct smb_params v1_params = { #define STEP_CHARGING_MAX_STEPS 5 struct smb_dt_props { - bool no_battery; int fcc_ua; int usb_icl_ua; int otg_cl_ua; @@ -226,7 +225,9 @@ struct smb_dt_props { struct device_node *revid_dev_node; int float_option; int chg_inhibit_thr_mv; + bool no_battery; bool hvdcp_disable; + bool auto_recharge_soc; }; struct smb2 { @@ -344,6 +345,8 @@ static int smb2_parse_dt(struct smb2 *chip) return -EINVAL; } + chip->dt.auto_recharge_soc = of_property_read_bool(node, + "qcom,auto-recharge-soc"); return 0; } @@ -1295,6 +1298,28 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } + if (chip->dt.auto_recharge_soc) { + rc = smblib_masked_write(chg, FG_UPDATE_CFG_2_SEL_REG, + SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT | + VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT, + VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n", + rc); + return rc; + } + } else { + rc = smblib_masked_write(chg, FG_UPDATE_CFG_2_SEL_REG, + SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT | + VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT, + SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n", + rc); + return rc; + } + } + return rc; } @@ -1837,8 +1862,13 @@ static void smb2_shutdown(struct platform_device *pdev) struct smb2 *chip = platform_get_drvdata(pdev); struct smb_charger *chg = &chip->chg; + /* configure power role for UFP */ + smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_POWER_ROLE_CMD_MASK, UFP_EN_CMD_BIT); + + /* force HVDCP to 5V */ smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, - HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0); + HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0); smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT); } diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 3403474565be..52805357ef92 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -505,15 +505,14 @@ static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg) static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg) { - const struct apsd_result *apsd_result; + const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* if PD is active, APSD is disabled so won't have a valid result */ if (chg->pd_active) { chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD; - return 0; + return apsd_result; } - apsd_result = smblib_get_apsd_result(chg); chg->usb_psy_desc.type = apsd_result->pst; return apsd_result; } diff --git a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c index deb7231a4ed1..10fb4cc8ebff 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c @@ -869,7 +869,7 @@ static void unregister_client_adhoc(uint32_t cl) } curr = client->curr; - if (curr >= pdata->num_usecases) { + if ((curr < 0) || (curr >= pdata->num_usecases)) { MSM_BUS_ERR("Invalid index Defaulting curr to 0"); curr = 0; } diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 826a22355429..f93ee29123fe 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -42,8 +42,8 @@ #define SMEM_IMAGE_VERSION_NAME_SIZE 75 #define SMEM_IMAGE_VERSION_VARIANT_SIZE 20 #define SMEM_IMAGE_VERSION_VARIANT_OFFSET 75 -#define SMEM_IMAGE_VERSION_OEM_SIZE 32 -#define SMEM_IMAGE_VERSION_OEM_OFFSET 96 +#define SMEM_IMAGE_VERSION_OEM_SIZE 33 +#define SMEM_IMAGE_VERSION_OEM_OFFSET 95 #define SMEM_IMAGE_VERSION_PARTITION_APPS 10 enum { @@ -974,7 +974,7 @@ msm_get_image_crm_version(struct device *dev, } string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; string_address += SMEM_IMAGE_VERSION_OEM_OFFSET; - return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s\n", + return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.33s\n", string_address); } @@ -995,7 +995,7 @@ msm_set_image_crm_version(struct device *dev, } store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; store_address += SMEM_IMAGE_VERSION_OEM_OFFSET; - snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s", buf); + snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.33s", buf); return count; } @@ -1049,7 +1049,8 @@ msm_get_images(struct device *dev, image_address); pos += snprintf(buf + pos, PAGE_SIZE - pos, "\tVariant:\t%-.20s\n", image_address + SMEM_IMAGE_VERSION_VARIANT_OFFSET); - pos += snprintf(buf + pos, PAGE_SIZE - pos, "\tVersion:\t%-.32s\n\n", + pos += snprintf(buf + pos, PAGE_SIZE - pos, + "\tVersion:\t%-.33s\n", image_address + SMEM_IMAGE_VERSION_OEM_OFFSET); image_address += SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index b90ac82049c6..0a316fa19909 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -134,6 +134,7 @@ struct hdmi_edid_ctrl { u8 it_scan_info; u8 ce_scan_info; u8 cea_blks; + /* DC: MSB -> LSB: Y420_48|Y420_36|Y420_30|RGB48|RGB36|RGB30|Y444 */ u8 deep_color; u16 physical_address; u32 video_resolution; /* selected by user */ @@ -858,6 +859,43 @@ static const u8 *hdmi_edid_find_block(const u8 *in_buf, u32 start_offset, return NULL; } /* hdmi_edid_find_block */ +static const u8 *hdmi_edid_find_hfvsdb(const u8 *in_buf) +{ + u8 len = 0, i = 0; + const u8 *vsd = NULL; + u32 vsd_offset = DBC_START_OFFSET; + u32 hf_ieee_oui = 0; + + /* Find HF-VSDB with HF-OUI */ + do { + vsd = hdmi_edid_find_block(in_buf, vsd_offset, + VENDOR_SPECIFIC_DATA_BLOCK, &len); + + if (!vsd || !len || len > MAX_DATA_BLOCK_SIZE) { + if (i == 0) + pr_debug("%s: VSDB not found\n", __func__); + else + pr_debug("%s: no more VSDB found\n", __func__); + + return NULL; + } + + hf_ieee_oui = (vsd[1] << 16) | (vsd[2] << 8) | vsd[3]; + + if (hf_ieee_oui == HDMI_FORUM_IEEE_OUI) { + pr_debug("%s: found HF-VSDB\n", __func__); + break; + } + + pr_debug("%s: Not a HF OUI 0x%x\n", __func__, hf_ieee_oui); + + i++; + vsd_offset = vsd - in_buf + len + 1; + } while (1); + + return vsd; +} + static void hdmi_edid_set_y420_support(struct hdmi_edid_ctrl *edid_ctrl, u32 video_format) { @@ -1251,62 +1289,32 @@ static void hdmi_edid_extract_speaker_allocation_data( static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf) { - u8 len = 0, i = 0; const u8 *vsd = NULL; - u32 vsd_offset = DBC_START_OFFSET; - u32 hf_ieee_oui = 0; if (!edid_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + pr_err("%s: invalid input\n", __func__); return; } - /* Find HF-VSDB with HF-OUI */ - do { - vsd = hdmi_edid_find_block(in_buf, vsd_offset, - VENDOR_SPECIFIC_DATA_BLOCK, &len); - - if (!vsd || !len || len > MAX_DATA_BLOCK_SIZE) { - if (i == 0) - DEV_ERR("%s: VSDB not found\n", __func__); - else - DEV_DBG("%s: no more VSDB found\n", __func__); - break; - } - - hf_ieee_oui = (vsd[1] << 16) | (vsd[2] << 8) | vsd[3]; - - if (hf_ieee_oui == HDMI_FORUM_IEEE_OUI) { - DEV_DBG("%s: found HF-VSDB\n", __func__); - break; - } - - DEV_DBG("%s: Not a HF OUI 0x%x\n", __func__, hf_ieee_oui); - - i++; - vsd_offset = vsd - in_buf + len + 1; - } while (1); - - if (!vsd) { - DEV_DBG("%s: HF-VSDB not found\n", __func__); - return; + vsd = hdmi_edid_find_hfvsdb(in_buf); + + if (vsd) { + /* Max pixel clock is in multiples of 5Mhz. */ + edid_ctrl->sink_caps.max_pclk_in_hz = + vsd[5]*5000000; + edid_ctrl->sink_caps.scdc_present = + (vsd[6] & 0x80) ? true : false; + edid_ctrl->sink_caps.scramble_support = + (vsd[6] & 0x08) ? true : false; + edid_ctrl->sink_caps.read_req_support = + (vsd[6] & 0x40) ? true : false; + edid_ctrl->sink_caps.osd_disparity = + (vsd[6] & 0x01) ? true : false; + edid_ctrl->sink_caps.dual_view_support = + (vsd[6] & 0x02) ? true : false; + edid_ctrl->sink_caps.ind_view_support = + (vsd[6] & 0x04) ? true : false; } - - /* Max pixel clock is in multiples of 5Mhz. */ - edid_ctrl->sink_caps.max_pclk_in_hz = - vsd[5]*5000000; - edid_ctrl->sink_caps.scdc_present = - (vsd[6] & 0x80) ? true : false; - edid_ctrl->sink_caps.scramble_support = - (vsd[6] & 0x08) ? true : false; - edid_ctrl->sink_caps.read_req_support = - (vsd[6] & 0x40) ? true : false; - edid_ctrl->sink_caps.osd_disparity = - (vsd[6] & 0x01) ? true : false; - edid_ctrl->sink_caps.dual_view_support = - (vsd[6] & 0x02) ? true : false; - edid_ctrl->sink_caps.ind_view_support = - (vsd[6] & 0x04) ? true : false; } static void hdmi_edid_extract_latency_fields(struct hdmi_edid_ctrl *edid_ctrl, @@ -1404,12 +1412,19 @@ static void hdmi_edid_extract_dc(struct hdmi_edid_ctrl *edid_ctrl, edid_ctrl->deep_color = (vsd[6] >> 0x3) & 0xF; - DEV_DBG("%s: deep color: Y444|RGB30|RGB36|RGB48: (%d|%d|%d|%d)\n", - __func__, + vsd = hdmi_edid_find_hfvsdb(in_buf); + + if (vsd) + edid_ctrl->deep_color |= (vsd[7] & 0x07) << 4; + + pr_debug("deep color: Y444|RGB30|RGB36|RGB48|Y420_30|Y420_36|Y420_48: (%d|%d|%d|%d|%d|%d|%d)\n", (int) (edid_ctrl->deep_color & BIT(0)) >> 0, (int) (edid_ctrl->deep_color & BIT(1)) >> 1, (int) (edid_ctrl->deep_color & BIT(2)) >> 2, - (int) (edid_ctrl->deep_color & BIT(3)) >> 3); + (int) (edid_ctrl->deep_color & BIT(3)) >> 3, + (int) (edid_ctrl->deep_color & BIT(4)) >> 4, + (int) (edid_ctrl->deep_color & BIT(5)) >> 5, + (int) (edid_ctrl->deep_color & BIT(6)) >> 6); } static u32 hdmi_edid_check_header(const u8 *edid_buf) @@ -2398,8 +2413,8 @@ u32 hdmi_edid_get_sink_mode(void *input) * * This API returns deep color for different formats supported by sink. * Deep color support for Y444 (BIT(0)), RGB30 (BIT(1)), RGB36 (BIT(2), - * RGB 48 (BIT(3)) is provided in a 8 bit integer. The MSB 8 bits are - * not used. + * RGB 48 (BIT(3)), Y420_30 (BIT(4)), Y420_36 (BIT(5)), Y420_48 (BIT(6)) + * is provided in a 8 bit integer. The MSB 8 bits are not used. * * Return: deep color data. */ @@ -2416,6 +2431,25 @@ u8 hdmi_edid_get_deep_color(void *input) } /** + * hdmi_edid_get_max_pclk() - get max pclk supported. Sink side's limitation + * should be concerned as well. + * @input: edid parser data + * + * Return: max pclk rate + */ +u32 hdmi_edid_get_max_pclk(void *input) +{ + struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; + + if (!edid_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return 0; + } + + return edid_ctrl->init_data.max_pclk_khz; +} + +/** * hdmi_edid_get_hdr_data() - get the HDR capabiliies of the sink * @input: edid parser data * diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index ce6cecbb2e03..43e1adb1f139 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -60,6 +60,7 @@ void *hdmi_edid_init(struct hdmi_edid_init_data *init_data); bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode); u8 hdmi_edid_get_deep_color(void *edid_ctrl); +u32 hdmi_edid_get_max_pclk(void *edid_ctrl); void hdmi_edid_get_hdr_data(void *edid_ctrl, struct hdmi_edid_hdr_data **hdr_data); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.c b/drivers/video/fbdev/msm/mdss_hdmi_panel.c index 522debfba8ce..a8a56e3a8745 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_panel.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.c @@ -602,14 +602,51 @@ end: return rc; } +static int hdmi_panel_setup_dc(struct hdmi_panel *panel) +{ + u32 hdmi_ctrl_reg; + u32 vbi_pkt_reg; + int rc = 0; + + pr_debug("Deep Color: %s\n", panel->data->dc_enable ? "ON" : "OFF"); + + /* enable deep color if supported */ + if (panel->data->dc_enable) { + hdmi_ctrl_reg = DSS_REG_R(panel->io, HDMI_CTRL); + + /* GC CD override */ + hdmi_ctrl_reg |= BIT(27); + + /* enable deep color for RGB888 30 bits */ + hdmi_ctrl_reg |= BIT(24); + DSS_REG_W(panel->io, HDMI_CTRL, hdmi_ctrl_reg); + + /* Enable GC_CONT and GC_SEND in General Control Packet + * (GCP) register so that deep color data is + * transmitted to the sink on every frame, allowing + * the sink to decode the data correctly. + * + * GC_CONT: 0x1 - Send GCP on every frame + * GC_SEND: 0x1 - Enable GCP Transmission + */ + vbi_pkt_reg = DSS_REG_R(panel->io, HDMI_VBI_PKT_CTRL); + vbi_pkt_reg |= BIT(5) | BIT(4); + DSS_REG_W(panel->io, HDMI_VBI_PKT_CTRL, vbi_pkt_reg); + } + + return rc; +} + static int hdmi_panel_setup_scrambler(struct hdmi_panel *panel) { int rc = 0; int timeout_hsync; u32 reg_val = 0; u32 tmds_clock_ratio = 0; + u32 tmds_clock = 0; bool scrambler_on = false; struct msm_hdmi_mode_timing_info *timing = NULL; + struct mdss_panel_info *pinfo = NULL; if (!panel) { pr_err("invalid input\n"); @@ -622,13 +659,22 @@ static int hdmi_panel_setup_scrambler(struct hdmi_panel *panel) return -EINVAL; } + pinfo = panel->data->pinfo; + if (!pinfo) { + pr_err("invalid panel data\n"); + return -EINVAL; + } + /* Scrambling is supported from HDMI TX 4.0 */ if (panel->version < HDMI_TX_SCRAMBLER_MIN_TX_VERSION) { pr_debug("scrambling not supported by tx\n"); return 0; } - if (timing->pixel_freq > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) { + tmds_clock = hdmi_tx_setup_tmds_clk_rate(timing->pixel_freq, + pinfo->out_format, panel->data->dc_enable); + + if (tmds_clock > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) { scrambler_on = true; tmds_clock_ratio = 1; } else { @@ -798,6 +844,12 @@ static int hdmi_panel_power_on(void *input) pr_err("scrambler setup failed. rc=%d\n", rc); goto err; } + + rc = hdmi_panel_setup_dc(panel); + if (rc) { + pr_err("Deep Color setup failed. rc=%d\n", rc); + goto err; + } end: panel->on = true; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.h b/drivers/video/fbdev/msm/mdss_hdmi_panel.h index 6fa9af13d46e..cb40f0cad55e 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_panel.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.h @@ -28,6 +28,7 @@ * @infoframe: set to true if infoframes should be sent to sink * @is_it_content: set to true if content is IT * @scrambler: set to true if scrambler needs to be enabled + * @dc_enable: set to true if deep color is enabled */ struct hdmi_panel_data { struct mdss_panel_info *pinfo; @@ -39,6 +40,7 @@ struct hdmi_panel_data { bool infoframe; bool is_it_content; bool scrambler; + bool dc_enable; }; /** diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index d01d163af5fa..ff44d0ae4ac5 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -35,6 +35,7 @@ #include "mdss.h" #include "mdss_panel.h" #include "mdss_hdmi_mhl.h" +#include "mdss_hdmi_util.h" #define DRV_NAME "hdmi-tx" #define COMPATIBLE_NAME "qcom,hdmi-tx" @@ -58,13 +59,6 @@ #define AUDIO_POLL_SLEEP_US (5 * 1000) #define AUDIO_POLL_TIMEOUT_US (AUDIO_POLL_SLEEP_US * 1000) -#define HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2 -#define HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 -#define HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 - -#define HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ 340000 -#define HDMI_TX_SCRAMBLER_TIMEOUT_MSEC 200 - /* Maximum pixel clock rates for hdmi tx */ #define HDMI_DEFAULT_MAX_PCLK_RATE 148500 #define HDMI_TX_3_MAX_PCLK_RATE 297000 @@ -111,7 +105,6 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data); static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl); static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, int enable); -static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl); static void hdmi_tx_fps_work(struct work_struct *work); static int hdmi_tx_pinctrl_set_state(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, bool active); @@ -318,11 +311,29 @@ static inline bool hdmi_tx_metadata_type_one(struct hdmi_tx_ctrl *hdmi_ctrl) return hdr_data->metadata_type_one; } +static inline bool hdmix_tx_sink_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + void *edid_fd = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); + + if (hdmi_ctrl->panel_data.panel_info.out_format == MDP_Y_CBCR_H2V2) + return (hdmi_edid_get_deep_color(edid_fd) & BIT(4)); + else + return (hdmi_edid_get_deep_color(edid_fd) & BIT(1)); +} + static inline bool hdmi_tx_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl) { - return hdmi_ctrl->dc_feature_on && hdmi_ctrl->dc_support && - (hdmi_edid_get_deep_color( - hdmi_tx_get_fd(HDMI_TX_FEAT_EDID)) & BIT(1)); + /* actual pixel clock if deep color is enabled */ + void *edid_fd = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); + u32 tmds_clk_with_dc = hdmi_tx_setup_tmds_clk_rate( + hdmi_ctrl->timing.pixel_freq, + hdmi_ctrl->panel.pinfo->out_format, + true); + + return hdmi_ctrl->dc_feature_on && + hdmi_ctrl->dc_support && + hdmix_tx_sink_dc_support(hdmi_ctrl) && + (tmds_clk_with_dc <= hdmi_edid_get_max_pclk(edid_fd)); } static const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module) @@ -349,7 +360,10 @@ static const char *hdmi_tx_io_name(u32 type) static void hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl) { if (hdmi_ctrl && hdmi_ctrl->audio_ops.on) { - u32 pclk = hdmi_tx_setup_tmds_clk_rate(hdmi_ctrl); + u32 pclk = hdmi_tx_setup_tmds_clk_rate( + hdmi_ctrl->timing.pixel_freq, + hdmi_ctrl->panel.pinfo->out_format, + hdmi_ctrl->panel.dc_enable); hdmi_ctrl->audio_ops.on(hdmi_ctrl->audio_data, pclk, &hdmi_ctrl->audio_params); @@ -2345,7 +2359,6 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) struct dss_io_data *io = NULL; /* Defaults: Disable block, HDMI mode */ u32 hdmi_ctrl_reg = BIT(1); - u32 vbi_pkt_reg; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); @@ -2383,27 +2396,6 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) * longer be used */ hdmi_ctrl_reg |= BIT(31); - - /* enable deep color if supported */ - if (hdmi_tx_dc_support(hdmi_ctrl)) { - /* GC CD override */ - hdmi_ctrl_reg |= BIT(27); - - /* enable deep color for RGB888 30 bits */ - hdmi_ctrl_reg |= BIT(24); - - /* Enable GC_CONT and GC_SEND in General Control Packet - * (GCP) register so that deep color data is - * transmitted to the sink on every frame, allowing - * the sink to decode the data correctly. - * - * GC_CONT: 0x1 - Send GCP on every frame - * GC_SEND: 0x1 - Enable GCP Transmission - */ - vbi_pkt_reg = DSS_REG_R(io, HDMI_VBI_PKT_CTRL); - vbi_pkt_reg |= BIT(5) | BIT(4); - DSS_REG_W(io, HDMI_VBI_PKT_CTRL, vbi_pkt_reg); - } } DSS_REG_W(io, HDMI_CTRL, hdmi_ctrl_reg); @@ -2973,44 +2965,6 @@ static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote) return hpd; } -static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl) -{ - u32 rate = 0; - struct msm_hdmi_mode_timing_info *timing = NULL; - u32 rate_ratio; - - if (!hdmi_ctrl) { - DEV_ERR("%s: Bad input parameters\n", __func__); - goto end; - } - - timing = &hdmi_ctrl->timing; - if (!timing) { - DEV_ERR("%s: Invalid timing info\n", __func__); - goto end; - } - - switch (hdmi_ctrl->panel_data.panel_info.out_format) { - case MDP_Y_CBCR_H2V2: - rate_ratio = HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO; - break; - case MDP_Y_CBCR_H2V1: - rate_ratio = HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO; - break; - default: - rate_ratio = HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO; - break; - } - - rate = timing->pixel_freq / rate_ratio; - - if (hdmi_tx_dc_support(hdmi_ctrl)) - rate += rate >> 2; - -end: - return rate; -} - static inline bool hdmi_tx_hw_is_cable_connected(struct hdmi_tx_ctrl *hdmi_ctrl) { return DSS_REG_R(&hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO], @@ -3117,7 +3071,7 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl) void *pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL); void *edata = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); - hdmi_panel_get_vic(&panel_data->panel_info, + hdmi_ctrl->vic = hdmi_panel_get_vic(&panel_data->panel_info, &hdmi_ctrl->ds_data); if (hdmi_ctrl->vic <= 0) { @@ -3144,16 +3098,14 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->vic); hdmi_ctrl->panel.scrambler = hdmi_edid_get_sink_scrambler_support( edata); + hdmi_ctrl->panel.dc_enable = hdmi_tx_dc_support(hdmi_ctrl); if (hdmi_ctrl->panel_ops.on) hdmi_ctrl->panel_ops.on(pdata); - pixel_clk = hdmi_ctrl->timing.pixel_freq * 1000; - - if (panel_data->panel_info.out_format == MDP_Y_CBCR_H2V2) - pixel_clk >>= 1; - else if (hdmi_tx_dc_support(hdmi_ctrl)) - pixel_clk += pixel_clk >> 2; + pixel_clk = hdmi_tx_setup_tmds_clk_rate(hdmi_ctrl->timing.pixel_freq, + hdmi_ctrl->panel.pinfo->out_format, + hdmi_ctrl->panel.dc_enable) * 1000; DEV_DBG("%s: setting pixel clk %d\n", __func__, pixel_clk); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c index c9fc8ba8bfdb..89890bcf68df 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -15,6 +15,7 @@ #include <linux/io.h> #include <linux/delay.h> +#include <linux/msm_mdp.h> #include "mdss_hdmi_util.h" #define RESOLUTION_NAME_STR_LEN 30 @@ -26,6 +27,10 @@ #define HDMI_SCDC_UNKNOWN_REGISTER "Unknown register" +#define HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2 +#define HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 +#define HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 + static char res_buf[RESOLUTION_NAME_STR_LEN]; enum trigger_mode { @@ -738,6 +743,30 @@ ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf, u32 size) return len; } /* hdmi_get_video_3d_fmt_2string */ +int hdmi_tx_setup_tmds_clk_rate(u32 pixel_freq, u32 out_format, bool dc_enable) +{ + u32 rate_ratio; + + switch (out_format) { + case MDP_Y_CBCR_H2V2: + rate_ratio = HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO; + break; + case MDP_Y_CBCR_H2V1: + rate_ratio = HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO; + break; + default: + rate_ratio = HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO; + break; + } + + pixel_freq /= rate_ratio; + + if (dc_enable) + pixel_freq += pixel_freq >> 2; + + return pixel_freq; +} + static void hdmi_ddc_trigger(struct hdmi_tx_ddc_ctrl *ddc_ctrl, enum trigger_mode mode, bool seg) { diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h index 8a7e4d1ebafc..4fd659616bcc 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h @@ -16,6 +16,7 @@ #include "video/msm_hdmi_modes.h" #include "mdss_panel.h" +#include "mdss_hdmi_panel.h" /* HDMI_TX Registers */ #define HDMI_CTRL (0x00000000) @@ -495,6 +496,7 @@ bool hdmi_is_valid_resv_timing(int mode); void hdmi_reset_resv_timing_info(void); int hdmi_panel_get_vic(struct mdss_panel_info *pinfo, struct hdmi_util_ds_data *ds_data); +int hdmi_tx_setup_tmds_clk_rate(u32 pixel_freq, u32 out_format, bool dc_enable); /* todo: Fix this. Right now this is defined in mdss_hdmi_tx.c */ void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, u32 type); diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 298b8743f0a6..6ba5828479f5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -1453,6 +1453,21 @@ static void mdss_mdp_overlay_update_pm(struct mdss_overlay_private *mdp5_data) activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time); } +static void __unstage_pipe_and_clean_buf(struct msm_fb_data_type *mfd, + struct mdss_mdp_pipe *pipe, struct mdss_mdp_data *buf) +{ + + pr_debug("unstaging pipe:%d rect:%d buf:%d\n", + pipe->num, pipe->multirect.num, !buf); + MDSS_XLOG(pipe->num, pipe->multirect.num, !buf); + mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left); + mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right); + pipe->dirty = true; + + if (buf) + __pipe_buf_mark_cleanup(mfd, buf); +} + static int __overlay_queue_pipes(struct msm_fb_data_type *mfd) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); @@ -1573,14 +1588,36 @@ static int __overlay_queue_pipes(struct msm_fb_data_type *mfd) ret = mdss_mdp_pipe_queue_data(pipe, buf); if (IS_ERR_VALUE(ret)) { - pr_warn("Unable to queue data for pnum=%d\n", - pipe->num); - mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left); - mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right); - pipe->dirty = true; + pr_warn("Unable to queue data for pnum=%d rect=%d\n", + pipe->num, pipe->multirect.num); + + /* + * If we fail for a multi-rect pipe, unstage both rects + * so we don't leave the pipe configured in multi-rect + * mode with only one rectangle staged. + */ + if (pipe->multirect.mode != + MDSS_MDP_PIPE_MULTIRECT_NONE) { + struct mdss_mdp_pipe *next_pipe = + (struct mdss_mdp_pipe *) + pipe->multirect.next; + + if (next_pipe) { + struct mdss_mdp_data *next_buf = + list_first_entry_or_null( + &next_pipe->buf_queue, + struct mdss_mdp_data, + pipe_list); + + __unstage_pipe_and_clean_buf(mfd, + next_pipe, next_buf); + } else { + pr_warn("cannot find rect pnum=%d\n", + pipe->num); + } + } - if (buf) - __pipe_buf_mark_cleanup(mfd, buf); + __unstage_pipe_and_clean_buf(mfd, pipe, buf); } } diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index bcf5309993b9..d7678e4d2ae5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -2702,8 +2702,8 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, if (ret) { pr_err("pipe pp setup error for pnum=%d\n", pipe->num); - MDSS_XLOG(pipe->num, pipe->mixer_left->num, - pipe->play_cnt, 0xbad); + MDSS_XLOG(pipe->num, pipe->multirect.num, + pipe->mixer_left->num, pipe->play_cnt, 0xbad); goto done; } @@ -2714,13 +2714,14 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, pipe->params_changed = 0; mdss_mdp_pipe_solidfill_setup(pipe); - MDSS_XLOG(pipe->num, pipe->mixer_left->num, pipe->play_cnt, - 0x111); + MDSS_XLOG(pipe->num, pipe->multirect.num, pipe->mixer_left->num, + pipe->play_cnt, 0x111); goto update_nobuf; } - MDSS_XLOG(pipe->num, pipe->mixer_left->num, pipe->play_cnt, 0x222); + MDSS_XLOG(pipe->num, pipe->multirect.num, pipe->mixer_left->num, + pipe->play_cnt, 0x222); if (params_changed) { pipe->params_changed = 0; diff --git a/include/dt-bindings/clock/audio-ext-clk.h b/include/dt-bindings/clock/audio-ext-clk.h index 6e4932342751..c9a8286d7c7f 100644 --- a/include/dt-bindings/clock/audio-ext-clk.h +++ b/include/dt-bindings/clock/audio-ext-clk.h @@ -14,9 +14,19 @@ #define __AUDIO_EXT_CLK_H /* Audio External Clocks */ +#ifdef CONFIG_COMMON_CLK_QCOM +#define AUDIO_PMI_CLK 0 +#define AUDIO_PMIC_LNBB_CLK 1 +#define AUDIO_AP_CLK 2 +#define AUDIO_AP_CLK2 3 +#define AUDIO_LPASS_MCLK 4 +#define AUDIO_LPASS_MCLK2 5 +#else #define clk_audio_ap_clk 0x9b5727cb #define clk_audio_pmi_clk 0xcbfe416d #define clk_audio_ap_clk2 0x454d1e91 #define clk_audio_lpass_mclk 0xf0f2a284 #define clk_audio_pmi_lnbb_clk 0x57312343 #endif + +#endif diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 06e00fdfe6a1..71858e268232 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -13681,6 +13681,7 @@ static int tasha_codec_probe(struct snd_soc_codec *codec) snd_soc_dapm_ignore_suspend(dapm, "AIF Mix Playback"); snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX"); snd_soc_dapm_ignore_suspend(dapm, "VIfeed"); + snd_soc_dapm_ignore_suspend(dapm, "AIF5 CPE TX"); } snd_soc_dapm_sync(dapm); diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c index aa036d352f40..9c720acf8ef8 100644 --- a/sound/soc/msm/msm-dai-fe.c +++ b/sound/soc/msm/msm-dai-fe.c @@ -2449,6 +2449,63 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .name = "VoiceMMode2", .probe = fe_dai_probe, }, + { + .capture = { + .stream_name = "MultiMedia17 Capture", + .aif_name = "MM_UL17", + .rates = (SNDRV_PCM_RATE_8000_48000| + SNDRV_PCM_RATE_KNOT), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE), + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 48000, + }, + .ops = &msm_fe_Multimedia_dai_ops, + .compress_new = snd_soc_new_compress, + .name = "MultiMedia17", + .probe = fe_dai_probe, + }, + { + .capture = { + .stream_name = "MultiMedia18 Capture", + .aif_name = "MM_UL18", + .rates = (SNDRV_PCM_RATE_8000_48000| + SNDRV_PCM_RATE_KNOT), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE), + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 48000, + }, + .ops = &msm_fe_Multimedia_dai_ops, + .compress_new = snd_soc_new_compress, + .name = "MultiMedia18", + .probe = fe_dai_probe, + }, + { + .capture = { + .stream_name = "MultiMedia19 Capture", + .aif_name = "MM_UL19", + .rates = (SNDRV_PCM_RATE_8000_48000| + SNDRV_PCM_RATE_KNOT), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE), + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 48000, + }, + .ops = &msm_fe_Multimedia_dai_ops, + .compress_new = snd_soc_new_compress, + .name = "MultiMedia19", + .probe = fe_dai_probe, + }, }; static int msm_fe_dai_dev_probe(struct platform_device *pdev) diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index a2cd6c6f98db..90371b8e27f4 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -127,6 +127,11 @@ struct msm_compr_audio { uint64_t bytes_received; /* from userspace */ uint64_t bytes_sent; /* to DSP */ + 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*/ + int32_t first_buffer; int32_t last_buffer; int32_t partial_drain_delay; @@ -362,6 +367,49 @@ static int msm_compr_send_buffer(struct msm_compr_audio *prtd) return 0; } +static int msm_compr_read_buffer(struct msm_compr_audio *prtd) +{ + int buffer_length; + uint64_t bytes_available; + uint64_t buffer_sent; + struct audio_aio_read_param param; + int ret; + + if (!atomic_read(&prtd->start)) { + pr_err("%s: stream is not in started state\n", __func__); + return -EINVAL; + } + + buffer_length = prtd->codec_param.buffer.fragment_size; + bytes_available = prtd->received_total - prtd->bytes_copied; + buffer_sent = prtd->bytes_read - prtd->bytes_copied; + if (buffer_sent + buffer_length > 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.len = buffer_length; + param.uid = buffer_length; + + pr_debug("%s: reading %d bytes from DSP byte_offset = %llu\n", + __func__, buffer_length, prtd->bytes_read); + ret = q6asm_async_read(prtd->audio_client, ¶m); + if (ret < 0) { + pr_err("%s: q6asm_async_read failed - %d\n", + __func__, ret); + return ret; + } + prtd->bytes_read += buffer_length; + prtd->bytes_read_offset += buffer_length; + if (prtd->bytes_read_offset >= prtd->buffer_size) + prtd->bytes_read_offset -= prtd->buffer_size; + + return 0; +} + static void compr_event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) { @@ -374,6 +422,7 @@ static void compr_event_handler(uint32_t opcode, int stream_id; uint32_t stream_index; unsigned long flags; + uint64_t read_size; if (!prtd) { pr_err("%s: prtd is NULL\n", __func__); @@ -459,6 +508,32 @@ static void compr_event_handler(uint32_t opcode, spin_unlock_irqrestore(&prtd->lock, flags); break; + + case ASM_DATA_EVENT_READ_DONE_V2: + spin_lock_irqsave(&prtd->lock, flags); + + pr_debug("ASM_DATA_EVENT_READ_DONE_V2 offset %d, length %d\n", + prtd->byte_offset, payload[4]); + /* Always assume read_size is same as fragment_size */ + read_size = prtd->codec_param.buffer.fragment_size; + prtd->byte_offset += read_size; + prtd->received_total += read_size; + if (prtd->byte_offset >= prtd->buffer_size) + prtd->byte_offset -= prtd->buffer_size; + + snd_compr_fragment_elapsed(cstream); + + if (!atomic_read(&prtd->start)) { + pr_debug("read_done received while not started, treat as xrun"); + atomic_set(&prtd->xrun, 1); + spin_unlock_irqrestore(&prtd->lock, flags); + break; + } + msm_compr_read_buffer(prtd); + + spin_unlock_irqrestore(&prtd->lock, flags); + break; + case ASM_DATA_EVENT_RENDERED_EOS: spin_lock_irqsave(&prtd->lock, flags); pr_debug("%s: ASM_DATA_CMDRSP_EOS token 0x%x,stream id %d\n", @@ -511,6 +586,14 @@ static void compr_event_handler(uint32_t opcode, /* FIXME: A state is a better way, dealing with this*/ spin_lock_irqsave(&prtd->lock, flags); + + if (cstream->direction == SND_COMPRESS_CAPTURE) { + atomic_set(&prtd->start, 1); + msm_compr_read_buffer(prtd); + spin_unlock_irqrestore(&prtd->lock, flags); + break; + } + if (!prtd->bytes_sent) { bytes_available = prtd->bytes_received - prtd->copied_total; if (bytes_available < cstream->runtime->fragment_size) { @@ -958,7 +1041,8 @@ static int msm_compr_init_pp_params(struct snd_compr_stream *cstream, return ret; } -static int msm_compr_configure_dsp(struct snd_compr_stream *cstream) +static int msm_compr_configure_dsp_for_playback + (struct snd_compr_stream *cstream) { struct snd_compr_runtime *runtime = cstream->runtime; struct msm_compr_audio *prtd = runtime->private_data; @@ -1096,7 +1180,103 @@ static int msm_compr_configure_dsp(struct snd_compr_stream *cstream) return ret; } -static int msm_compr_open(struct snd_compr_stream *cstream) +static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream) +{ + struct snd_compr_runtime *runtime = cstream->runtime; + struct msm_compr_audio *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data; + uint16_t bits_per_sample; + uint16_t sample_word_size; + int dir = OUT, ret = 0; + struct audio_client *ac = prtd->audio_client; + uint32_t stream_index; + + switch (prtd->codec_param.codec.format) { + case SNDRV_PCM_FORMAT_S24_LE: + bits_per_sample = 24; + sample_word_size = 32; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + bits_per_sample = 24; + sample_word_size = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + bits_per_sample = 32; + sample_word_size = 32; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + bits_per_sample = 16; + sample_word_size = 16; + break; + } + + 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, + bits_per_sample); + if (ret < 0) { + pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret); + return ret; + } + + ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id, + ac->perf_mode, + prtd->session_id, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) { + pr_err("%s: stream reg failed:%d\n", __func__, ret); + return ret; + } + + ret = q6asm_set_io_mode(ac, (COMPRESSED_STREAM_IO | ASYNC_IO_MODE)); + if (ret < 0) { + pr_err("%s: Set IO mode failed\n", __func__); + return -EINVAL; + } + + stream_index = STREAM_ARRAY_INDEX(ac->stream_id); + if (stream_index >= MAX_NUMBER_OF_STREAMS || stream_index < 0) { + pr_err("%s: Invalid stream index:%d", __func__, stream_index); + return -EINVAL; + } + + runtime->fragments = prtd->codec_param.buffer.fragments; + runtime->fragment_size = prtd->codec_param.buffer.fragment_size; + pr_debug("%s: allocate %d buffers each of size %d\n", + __func__, runtime->fragments, + runtime->fragment_size); + ret = q6asm_audio_client_buf_alloc_contiguous(dir, ac, + runtime->fragment_size, + runtime->fragments); + if (ret < 0) { + pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret); + return -ENOMEM; + } + + prtd->byte_offset = 0; + prtd->received_total = 0; + prtd->app_pointer = 0; + prtd->bytes_copied = 0; + prtd->bytes_read = 0; + prtd->bytes_read_offset = 0; + prtd->buffer = ac->port[dir].buf[0].data; + prtd->buffer_paddr = ac->port[dir].buf[0].phys; + prtd->buffer_size = runtime->fragments * runtime->fragment_size; + + + pr_debug("%s: sample_rate = %d channels = %d bps = %d sample_word_size = %d\n", + __func__, prtd->sample_rate, prtd->num_channels, + bits_per_sample, sample_word_size); + ret = q6asm_enc_cfg_blk_pcm_format_support_v3(prtd->audio_client, + prtd->sample_rate, prtd->num_channels, + bits_per_sample, sample_word_size); + + return ret; +} + +static int msm_compr_playback_open(struct snd_compr_stream *cstream) { struct snd_compr_runtime *runtime = cstream->runtime; struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -1181,15 +1361,80 @@ static int msm_compr_open(struct snd_compr_stream *cstream) kfree(prtd); return -ENOMEM; } + pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session); + prtd->audio_client->perf_mode = false; + prtd->session_id = prtd->audio_client->session; + + return 0; +} +static int msm_compr_capture_open(struct snd_compr_stream *cstream) +{ + struct snd_compr_runtime *runtime = cstream->runtime; + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct msm_compr_audio *prtd; + struct msm_compr_pdata *pdata = + snd_soc_platform_get_drvdata(rtd->platform); + + pr_debug("%s\n", __func__); + prtd = kzalloc(sizeof(struct msm_compr_audio), GFP_KERNEL); + if (prtd == NULL) { + pr_err("Failed to allocate memory for msm_compr_audio\n"); + return -ENOMEM; + } + + runtime->private_data = NULL; + prtd->cstream = cstream; + pdata->cstream[rtd->dai_link->be_id] = cstream; + + prtd->audio_client = q6asm_audio_client_alloc( + (app_cb)compr_event_handler, prtd); + if (!prtd->audio_client) { + pr_err("%s: Could not allocate memory for client\n", __func__); + pdata->cstream[rtd->dai_link->be_id] = NULL; + kfree(prtd); + return -ENOMEM; + } pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session); prtd->audio_client->perf_mode = false; prtd->session_id = prtd->audio_client->session; + prtd->codec = FORMAT_LINEAR_PCM; + prtd->bytes_copied = 0; + prtd->bytes_read = 0; + prtd->bytes_read_offset = 0; + prtd->received_total = 0; + prtd->byte_offset = 0; + prtd->sample_rate = 48000; + prtd->num_channels = 2; + prtd->first_buffer = 0; + + spin_lock_init(&prtd->lock); + + atomic_set(&prtd->eos, 0); + atomic_set(&prtd->start, 0); + atomic_set(&prtd->drain, 0); + atomic_set(&prtd->xrun, 0); + atomic_set(&prtd->close, 0); + atomic_set(&prtd->wait_on_close, 0); + atomic_set(&prtd->error, 0); + + runtime->private_data = prtd; return 0; } -static int msm_compr_free(struct snd_compr_stream *cstream) +static int msm_compr_open(struct snd_compr_stream *cstream) +{ + int ret = 0; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) + ret = msm_compr_playback_open(cstream); + else if (cstream->direction == SND_COMPRESS_CAPTURE) + ret = msm_compr_capture_open(cstream); + return ret; +} + +static int msm_compr_playback_free(struct snd_compr_stream *cstream) { struct snd_compr_runtime *runtime; struct msm_compr_audio *prtd; @@ -1284,6 +1529,76 @@ static int msm_compr_free(struct snd_compr_stream *cstream) return 0; } +static int msm_compr_capture_free(struct snd_compr_stream *cstream) +{ + struct snd_compr_runtime *runtime; + struct msm_compr_audio *prtd; + struct snd_soc_pcm_runtime *soc_prtd; + struct msm_compr_pdata *pdata; + struct audio_client *ac; + int dir = OUT, stream_id; + unsigned long flags; + uint32_t stream_index; + + if (!cstream) { + pr_err("%s cstream is null\n", __func__); + return 0; + } + runtime = cstream->runtime; + soc_prtd = cstream->private_data; + if (!runtime || !soc_prtd || !(soc_prtd->platform)) { + pr_err("%s runtime or soc_prtd or platform is null\n", + __func__); + return 0; + } + prtd = runtime->private_data; + if (!prtd) { + pr_err("%s prtd is null\n", __func__); + return 0; + } + pdata = snd_soc_platform_get_drvdata(soc_prtd->platform); + ac = prtd->audio_client; + if (!pdata || !ac) { + pr_err("%s pdata or ac is null\n", __func__); + return 0; + } + + spin_lock_irqsave(&prtd->lock, flags); + stream_id = ac->stream_id; + + stream_index = STREAM_ARRAY_INDEX(stream_id); + if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0)) { + spin_unlock_irqrestore(&prtd->lock, flags); + pr_debug("close stream %d", stream_id); + q6asm_stream_cmd(ac, CMD_CLOSE, stream_id); + spin_lock_irqsave(&prtd->lock, flags); + } + spin_unlock_irqrestore(&prtd->lock, flags); + + pdata->cstream[soc_prtd->dai_link->be_id] = NULL; + msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, + SNDRV_PCM_STREAM_CAPTURE); + + q6asm_audio_client_buf_free_contiguous(dir, ac); + + q6asm_audio_client_free(ac); + + kfree(prtd); + + return 0; +} + +static int msm_compr_free(struct snd_compr_stream *cstream) +{ + int ret = 0; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) + ret = msm_compr_playback_free(cstream); + else if (cstream->direction == SND_COMPRESS_CAPTURE) + ret = msm_compr_capture_free(cstream); + return ret; +} + static bool msm_compr_validate_codec_compr(__u32 codec_id) { int32_t i; @@ -1449,7 +1764,10 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream, prtd->partial_drain_delay = msm_compr_get_partial_drain_delay(frame_sz, prtd->sample_rate); - ret = msm_compr_configure_dsp(cstream); + if (cstream->direction == SND_COMPRESS_PLAYBACK) + ret = msm_compr_configure_dsp_for_playback(cstream); + else if (cstream->direction == SND_COMPRESS_CAPTURE) + ret = msm_compr_configure_dsp_for_capture(cstream); return ret; } @@ -1539,11 +1857,6 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) uint32_t stream_index; uint16_t bits_per_sample = 16; - if (cstream->direction != SND_COMPRESS_PLAYBACK) { - pr_err("%s: Unsupported stream type\n", __func__); - return -EINVAL; - } - spin_lock_irqsave(&prtd->lock, flags); if (atomic_read(&prtd->error)) { pr_err("%s Got RESET EVENTS notification, return immediately", @@ -1566,7 +1879,8 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) * compress passthrough volume is controlled in * ADM by adm_send_compressed_device_mute() */ - if (prtd->compr_passthr == LEGACY_PCM) { + if (prtd->compr_passthr == LEGACY_PCM && + cstream->direction == SND_COMPRESS_PLAYBACK) { /* set volume for the stream before RUN */ rc = msm_compr_set_volume(cstream, volume[0], volume[1]); @@ -1578,8 +1892,9 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) if (rc) pr_err("%s : init PP params failed : %d\n", __func__, rc); + } else { + msm_compr_read_buffer(prtd); } - /* issue RUN command for the stream */ q6asm_run_nowait(prtd->audio_client, 0, 0, 0); break; @@ -1589,6 +1904,18 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) prtd->gapless_state.gapless_transition); stream_id = ac->stream_id; atomic_set(&prtd->start, 0); + if (cstream->direction == SND_COMPRESS_CAPTURE) { + q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE); + atomic_set(&prtd->xrun, 0); + prtd->received_total = 0; + prtd->bytes_copied = 0; + prtd->bytes_read = 0; + prtd->bytes_read_offset = 0; + prtd->byte_offset = 0; + prtd->app_pointer = 0; + spin_unlock_irqrestore(&prtd->lock, flags); + break; + } if (prtd->next_stream) { pr_debug("%s: interrupt next track wait queues\n", __func__); @@ -1979,7 +2306,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) } static int msm_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *arg) + struct snd_compr_tstamp *arg) { struct snd_compr_runtime *runtime = cstream->runtime; struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -1998,7 +2325,10 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream, spin_lock_irqsave(&prtd->lock, flags); tstamp.sampling_rate = prtd->sample_rate; tstamp.byte_offset = prtd->byte_offset; - tstamp.copied_total = prtd->copied_total; + if (cstream->direction == SND_COMPRESS_PLAYBACK) + tstamp.copied_total = prtd->copied_total; + else if (cstream->direction == SND_COMPRESS_CAPTURE) + tstamp.copied_total = prtd->received_total; first_buffer = prtd->first_buffer; if (atomic_read(&prtd->error)) { pr_err("%s Got RESET EVENTS notification, return error\n", @@ -2012,37 +2342,39 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream, spin_unlock_irqrestore(&prtd->lock, flags); return -ENETRESET; } + if (cstream->direction == SND_COMPRESS_PLAYBACK) { - gapless_transition = prtd->gapless_state.gapless_transition; - spin_unlock_irqrestore(&prtd->lock, flags); - - if (gapless_transition) - pr_debug("%s session time in gapless transition", - __func__); - - /* - - Do not query if no buffer has been given. - - Do not query on a gapless transition. - Playback for the 2nd stream can start (thus returning time - starting from 0) before the driver knows about EOS of first stream. - */ - - if (!first_buffer && !gapless_transition) { - if (pdata->use_legacy_api) - rc = q6asm_get_session_time_legacy(prtd->audio_client, - &prtd->marker_timestamp); - else - rc = q6asm_get_session_time(prtd->audio_client, - &prtd->marker_timestamp); + gapless_transition = prtd->gapless_state.gapless_transition; + spin_unlock_irqrestore(&prtd->lock, flags); + if (gapless_transition) + pr_debug("%s session time in gapless transition", + __func__); + /* + *- Do not query if no buffer has been given. + *- Do not query on a gapless transition. + * Playback for the 2nd stream can start (thus returning time + * starting from 0) before the driver knows about EOS of first + * stream. + */ + if (!first_buffer || gapless_transition) { - if (rc < 0) { - pr_err("%s: Get Session Time return value =%lld\n", - __func__, timestamp); - if (atomic_read(&prtd->error)) - return -ENETRESET; + if (pdata->use_legacy_api) + rc = q6asm_get_session_time_legacy( + prtd->audio_client, &prtd->marker_timestamp); else - return -EAGAIN; + rc = q6asm_get_session_time( + prtd->audio_client, &prtd->marker_timestamp); + if (rc < 0) { + pr_err("%s: Get Session Time return =%lld\n", + __func__, timestamp); + if (atomic_read(&prtd->error)) + return -ENETRESET; + else + return -EAGAIN; + } } + } else { + spin_unlock_irqrestore(&prtd->lock, flags); } timestamp = prtd->marker_timestamp; @@ -2103,8 +2435,8 @@ static int msm_compr_ack(struct snd_compr_stream *cstream, return 0; } -static int msm_compr_copy(struct snd_compr_stream *cstream, - char __user *buf, size_t count) +static int msm_compr_playback_copy(struct snd_compr_stream *cstream, + char __user *buf, size_t count) { struct snd_compr_runtime *runtime = cstream->runtime; struct msm_compr_audio *prtd = runtime->private_data; @@ -2166,6 +2498,60 @@ static int msm_compr_copy(struct snd_compr_stream *cstream, return count; } +static int msm_compr_capture_copy(struct snd_compr_stream *cstream, + char __user *buf, size_t count) +{ + struct snd_compr_runtime *runtime = cstream->runtime; + struct msm_compr_audio *prtd = runtime->private_data; + void *source; + unsigned long flags; + + pr_debug("%s: count = %zd\n", __func__, count); + if (!prtd->buffer) { + pr_err("%s: Buffer is not allocated yet ??", __func__); + return 0; + } + + spin_lock_irqsave(&prtd->lock, flags); + if (atomic_read(&prtd->error)) { + pr_err("%s Got RESET EVENTS notification", __func__); + spin_unlock_irqrestore(&prtd->lock, flags); + return -ENETRESET; + } + + source = prtd->buffer + prtd->app_pointer; + /* check if we have requested amount of data to copy to user*/ + if (count <= prtd->received_total - prtd->bytes_copied) { + spin_unlock_irqrestore(&prtd->lock, flags); + if (copy_to_user(buf, source, count)) { + pr_err("copy_to_user failed"); + return -EFAULT; + } + spin_lock_irqsave(&prtd->lock, flags); + prtd->app_pointer += count; + if (prtd->app_pointer >= prtd->buffer_size) + prtd->app_pointer -= prtd->buffer_size; + prtd->bytes_copied += count; + } + msm_compr_read_buffer(prtd); + + spin_unlock_irqrestore(&prtd->lock, flags); + return count; +} + +static int msm_compr_copy(struct snd_compr_stream *cstream, + char __user *buf, size_t count) +{ + int ret = 0; + + pr_debug(" In %s\n", __func__); + if (cstream->direction == SND_COMPRESS_PLAYBACK) + ret = msm_compr_playback_copy(cstream, buf, count); + else if (cstream->direction == SND_COMPRESS_CAPTURE) + ret = msm_compr_capture_copy(cstream, buf, count); + return ret; +} + static int msm_compr_get_caps(struct snd_compr_stream *cstream, struct snd_compr_caps *arg) { diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 9164475386ff..a456cc2ab857 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -548,6 +548,15 @@ static struct msm_pcm_routing_fdai_data /* MULTIMEDIA16 */ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA17 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA18 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, + /* MULTIMEDIA19 */ + {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, + {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, }; static unsigned long session_copp_map[MSM_FRONTEND_DAI_MM_SIZE][2] @@ -2288,6 +2297,21 @@ static const struct snd_kcontrol_new ext_ec_ref_mux_ul9 = msm_route_ec_ref_rx_enum[0], msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); +static const struct snd_kcontrol_new ext_ec_ref_mux_ul17 = + SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL17 MUX Mux", + msm_route_ec_ref_rx_enum[0], + msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); + +static const struct snd_kcontrol_new ext_ec_ref_mux_ul18 = + SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL18 MUX Mux", + msm_route_ec_ref_rx_enum[0], + msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); + +static const struct snd_kcontrol_new ext_ec_ref_mux_ul19 = + SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL19 MUX Mux", + msm_route_ec_ref_rx_enum[0], + msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); + static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2417,6 +2441,15 @@ static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = { @@ -2468,6 +2501,15 @@ static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_I2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = { @@ -2519,6 +2561,16 @@ static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + }; static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = { @@ -2621,6 +2673,15 @@ static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_5_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_5_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_5_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = { @@ -2672,6 +2733,15 @@ static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_0_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_0_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_0_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = { @@ -2723,6 +2793,15 @@ static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { @@ -2774,6 +2853,15 @@ static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { @@ -2825,6 +2913,15 @@ static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { @@ -2870,6 +2967,15 @@ static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new secondary_mi2s_rx2_mixer_controls[] = { @@ -2927,6 +3033,15 @@ static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { @@ -2978,6 +3093,15 @@ static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = { @@ -3131,6 +3255,15 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new display_port_mixer_controls[] = { @@ -3432,6 +3565,15 @@ static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_BT_SCO_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_BT_SCO_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_BT_SCO_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_bt_a2dp_rx_mixer_controls[] = { @@ -3534,6 +3676,15 @@ static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_FM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_FM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_FM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = { @@ -3585,6 +3736,15 @@ static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AFE_PCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AFE_PCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AFE_PCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = { @@ -3636,6 +3796,15 @@ static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = { @@ -3687,6 +3856,15 @@ static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_auxpcm_rx_mixer_controls[] = { @@ -5018,6 +5196,77 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = { msm_routing_put_audio_mixer), }; +static const struct snd_kcontrol_new mmul17_mixer_controls[] = { + SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul18_mixer_controls[] = { + SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul19_mixer_controls[] = { + SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = { SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, @@ -8098,6 +8347,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0), @@ -8796,6 +9048,12 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0, mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0, + mmul17_mixer_controls, ARRAY_SIZE(mmul17_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia18 Mixer", SND_SOC_NOPM, 0, 0, + mmul18_mixer_controls, ARRAY_SIZE(mmul18_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia19 Mixer", SND_SOC_NOPM, 0, 0, + mmul19_mixer_controls, ARRAY_SIZE(mmul19_mixer_controls)), SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0, auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)), SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0, @@ -9060,6 +9318,12 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { &ext_ec_ref_mux_ul8), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul9), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL17 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul17), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL18 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul18), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL19 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul19), }; static const struct snd_soc_dapm_route intercon[] = { @@ -9287,9 +9551,15 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia8 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"}, {"MultiMedia8 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"}, {"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"MultiMedia17 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"MultiMedia18 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"MultiMedia19 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia8 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia2 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia17 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia18 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia19 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, @@ -9884,10 +10154,16 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia3 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia4 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, + {"MultiMedia17 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, + {"MultiMedia18 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, + {"MultiMedia19 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia8 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, + {"MultiMedia17 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, + {"MultiMedia18 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, + {"MultiMedia19 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, @@ -9895,6 +10171,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia3 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"}, + {"MultiMedia17 Mixer", "AFE_PCM_TX", "PCM_TX"}, + {"MultiMedia18 Mixer", "AFE_PCM_TX", "PCM_TX"}, + {"MultiMedia19 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia8 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MM_UL1", NULL, "MultiMedia1 Mixer"}, @@ -9905,6 +10184,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"MM_UL5", NULL, "MultiMedia5 Mixer"}, {"MM_UL6", NULL, "MultiMedia6 Mixer"}, {"MM_UL8", NULL, "MultiMedia8 Mixer"}, + {"MM_UL17", NULL, "MultiMedia17 Mixer"}, + {"MM_UL18", NULL, "MultiMedia18 Mixer"}, + {"MM_UL19", NULL, "MultiMedia19 Mixer"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, @@ -10284,6 +10566,21 @@ static const struct snd_soc_dapm_route intercon[] = { {"AUDIO_REF_EC_UL9 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"}, {"AUDIO_REF_EC_UL9 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"}, + {"AUDIO_REF_EC_UL17 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"AUDIO_REF_EC_UL17 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"AUDIO_REF_EC_UL17 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + {"AUDIO_REF_EC_UL17 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + + {"AUDIO_REF_EC_UL18 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"AUDIO_REF_EC_UL18 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"AUDIO_REF_EC_UL18 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + {"AUDIO_REF_EC_UL18 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + + {"AUDIO_REF_EC_UL19 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"AUDIO_REF_EC_UL19 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"AUDIO_REF_EC_UL19 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + {"AUDIO_REF_EC_UL19 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MM_UL1", NULL, "AUDIO_REF_EC_UL1 MUX"}, {"MM_UL2", NULL, "AUDIO_REF_EC_UL2 MUX"}, {"MM_UL3", NULL, "AUDIO_REF_EC_UL3 MUX"}, @@ -10292,6 +10589,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"}, {"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"}, {"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"}, + {"MM_UL17", NULL, "AUDIO_REF_EC_UL17 MUX"}, + {"MM_UL18", NULL, "AUDIO_REF_EC_UL18 MUX"}, + {"MM_UL19", NULL, "AUDIO_REF_EC_UL19 MUX"}, {"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"}, {"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"}, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index 4fdfd6bb936d..d64fd640618e 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -182,6 +182,9 @@ enum { MSM_FRONTEND_DAI_MULTIMEDIA14, MSM_FRONTEND_DAI_MULTIMEDIA15, MSM_FRONTEND_DAI_MULTIMEDIA16, + MSM_FRONTEND_DAI_MULTIMEDIA17, + MSM_FRONTEND_DAI_MULTIMEDIA18, + MSM_FRONTEND_DAI_MULTIMEDIA19, MSM_FRONTEND_DAI_CS_VOICE, MSM_FRONTEND_DAI_VOIP, MSM_FRONTEND_DAI_AFE_RX, @@ -207,8 +210,8 @@ enum { MSM_FRONTEND_DAI_MAX, }; -#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA16 + 1) -#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA16 +#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA19 + 1) +#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA19 enum { MSM_BACKEND_DAI_PRI_I2S_RX = 0, |
