summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-12-27 21:28:55 -0700
committerLinux Build Service Account <lnxbuild@localhost>2016-12-27 21:28:56 -0700
commitaa36bb38fc87f49921c9e07fdb4a1a74482f26af (patch)
tree896eb2e151d70632bb4f04ff0a2a1f7f0dd7b694 /drivers
parent7aa1be414789d169eba3bce5345c4d009e989b6a (diff)
parent55e8426a192811d7567f19d7e781727f46b0406d (diff)
Promotion of kernel.lnx.4.4-161227.
CRs Change ID Subject -------------------------------------------------------------------------------------------------------------- 1104858 I482bbf480d4129cdc6a1dfe08f37a1ec56c3131e clk: qcom: Add FORCE_ENABLE_RCGR & CLK_ENABLE_HAND_OFF f 1104679 I53ac153ba9f7ae81bb0657b17e0e798fd3fe4f48 power_supply: Add SOC_REPORTING_READY property 1104679 I415e322e99bacd61c4e9ac921643d87d3eec4b3e power: qpnp-fg-gen3: add SOC_REPORTING_READY property 1068294 I779074d0aba35827e1a8264385149967cb9973f3 regulator: cpr4-mmss: Add mmss CPR platform specific dri 1105323 I073ab59cc4ef1b71545a9e77b76d94f09d659aac msm_11ad: Add option to enable SMMU fastmap 1102641 I39a1266f4158e71238f374b6cba49e1a8c2b1a3b leds: qpnp-wled: Update WLED config 1104760 I2f9b4e9d45f95066ec93bb5fab179a14bc2c62ee power: reset: Store KASLR offset in IMEM 986540 I711354941b4168f3f6ffe2d29185597bdad4da89 spi: spi_qsd: Fix the register peek/poke debug feature 1102726 I806456737485dfcbca8a71d59db0927bbd843708 clk: qcom: add MDSS PLL support for msmfalcon 1093863 I47cfe2cd7d93ba5db57365cf250c600dac22bab1 i2c-msm-v2:Synchronise runtime PM callback operations 1102841 I2661a639c19dd451f22c9a29d7d75d9b3fb98114 msm: mdss: Initialize mdss v3 pp driver ops for msmfalco 1101084 I334fd782a2c5d604cafb94f44832d9c700891ba2 msm: thermal: Update error handling of device offline 1105169 Ib089e7ddd38d0d15285ed65c8a29039451cfc3c5 ARM: dts: msm: Add initial support for msm8998 QRD SKUK 1104865 Ib1291524c53c4ec757a494a1e08cb0925720e1a6 msm: rtb: record counter timestamp for every log record 1081961 I5680dc5333c9664e1316c29a91e29231f15eb4f1 defconfig: msm: Add support for CPU OSM clock 1094763 Ifd41990058f8bbce8ba488770ffbfcd9b6067ad6 ASoC: msm: add support for WCD interrupt config via LPI 1103739 Ie5474c42ccdd88df4c101b2113ca8d924eddf037 usb: phy: qusb2: Switch to SE clk from diff clk upon sus 1068294 I2111fe55c9335d57ac91f18f4a4fb3689d80660d defconfig: Compile GFX LDO regulator driver for msmfalco 1046799 I47db9f66c95846dbff882f631b915655c33c3d55 spi: spi_qsd: Don't restrict first transfer in FIFO mode 1104607 Ie85f7ede2d91767d0d5d20c90a481e6365ad7189 ARM: dts: msm: Add thermal mitigation properties to msmt 1104981 I476397d88e0f9d2b32ae375afc6f15eca4b9ec95 ARM: dts: msm: Add initial support for msm8998 QRD SKUK 1098662 I214bb19385f855af61da628fdf1cf7efc5dd08d6 msm: mdss: dp: fix calculation of link rate 1102900 Ide652165711eec23644d36837f3847d896293709 msm: mdss: Add mdss capabilities for msmfalcon 1104876 I9a707d953a85c16c9c5be82fd36960b49da36e3c smcinvoke: support listener service request 1104976 Ic8c9657752271026d796ecd6c3b9f9f46f831f37 ARM: dts: msm: update icnss device node for msm8998-inte 1052835 I7f1419c8f7fd7c371767f6921afe0cd8cfaad18f msm: camera: Change %p into %pK 1081961 I0aca021e51ef9ae59dedce855430a63937eb98c6 ARM: dts: msm: Add support for CPU clocks for msmfalcon 1076516 I290ec786bbe5c45873265ea74290eefcd3d16cb1 msm: mdss: dp: add support for PHY compliance tests 1100632 Iab69062336966e61683117a17974f46cd8f513aa ARM: dts: msm: Allocate memory for diag client for msmfa 1103405 Iaaa69a56f13db9304640f115863bb882c72551a8 ARM: dts: msm: Update VA range for venus_ns and modify c 1083444 Ie2702223379b9c77ce4fe30376d446c63223dbc8 diag: dci: Fix possible dangling reference 1102776 I77f8e6de6f1b5c447a3516380c51db9c7129d2f3 spcom: abort any read() operation on SSR 1094456 Ib5247f6bceb1f555c03103f061af089755b2de62 clk: introduce CLK_ENABLE_HAND_OFF flag 1094763 Ib17d8bbd5894be5fbf3fa0cafdbec958abc42649 ARM: dts: msm: Enable audio internal codec nodes for msm 1103891 Iec6247a69c3258660eae398d6e3fe8215e3f254a ARM: dts: msm: Add TP device node into msm8998 interpose 1104880 868394 I885ae66be2d8cca17bcc0b87b7635a71c734e4b2 usb/xhci: Add support for EHSET tests for host complianc 1094456 I7d527571c2eb4d53d58d82126989bd673de12e2d clk: move check for CLK_ENABLE_HAND_OFF at unused tree 1093271 I472449c52bff40d48f7d65b05e145cc47cba9357 msm: crypto: fix AEAD issues for HW crypto driver on msm 1105038 I45d13b40fab9bf6686277c0c26a07668410cdfb2 usb: gadget: u_data_ipa: Fix condition check for IPA pip 1081961 I389cc9e93a26a434be752cf74444d6c0985ff36d clk: qcom: Support CPU clock for OSM for common clock fr 1104001 Ib4cc69afb32a7654bbdd98f2efff901729c4d3da clk: qcom: Add voltage voting for MSM8996 GCC driver 1104876 Ifeed957b99d2becd986629f60e145d6fdb717244 qseecom: support listener request for smcinvoke 1105100 Ic64d89b960c5effada93118d67a30cc051640be2 ARM: dts: msm: set rcu_expedited for msmfalcon and msmtr 1104853 If624bf14e8588e50fa6a97d29b528d7d02ef64dc ARM: dts: msm: disable soft hot JEITA for 8998 QRD SKUK 1099484 I58c30a50c7834e7897daa2849b9885b3e797cf07 ARM: dts: msm: enable vdd and vdd-io for sdhc_2 on msm89 1099101 I41ab0baf1bbe6ccda6b8da2ecd077bea2a388e56 ASoC: msm: Check prepare state to avoid duplicate channe 1104977 I575aecb616a56974ec2680e5888190adb40c969a ARM: dts: msm: set wled string/full scale current for QR 1092969 I6e315eec256f01c143ffc8b463279f2b30e64610 input: qpnp-power-on: Set ship mode in system_pwr_off 1104886 Ic44359e224e0f9070238748bd9b16eed35974ba6 ARM: dts: msm: add support of PM3FALCON based MSMFALCON 1097878 I3f895deaae3acf329088cf8135859cc41e781763 drivers: soc: qcom: Add error handling in function avtim 1104880 I88f2748f0c8cf96fe7f6ab9ebaa82d51ec97f4fd defconfig: msmcortex: Enable EHSET Test Fixture device d 1104760 I456c62764c88149b785ecf1d65691ea5a775c1db ARM: dts: msm: Add kaslr offset IMEM entry for msm8998 1104607 I780f9187256596d6f5d93b3847dc98a3c410a51e ARM: dts: msm: Configure lmh hardware for msmtriton 1104928 I6aad9916c92d2f775632406374dbb803063148de input: misc: fix heap overflow issue in hbtp_input.c 1101260 I6d59c7804d0dac5087e9b0e6c4a0cdacb5ddf3db ARM: dts: msm: Add support for new flash mode on msm8998 1100528 I1fd7b7e7324b79544608a9d9ce73aa53608d1f3e RM: dts: Update SD card Detect GPIO for msmfalcon 1104880 I638ca552f6dae735147378f3e6f6068e0003094b usb: xhci: Add support for SINGLE_STEP_SET_FEATURE test 1103468 I547d792b38649aa1d60525b0dc335791b37989fd msm: kgsl: Do a midframe sampling of power stats if enab 1104607 Id65a720d20fb34b9b5dccf8626af00a1d0519ce3 ARM: dts: msm: Add thermal sensor info for msmtriton 1100213 I29572841624c1cb96d85e2dcfe620b455867d41e ARM: dts: msm: add devfreq nodes to msmfalcon target 1100018 I8e7c4be090107618cd6cbac394a57f109f8a1ced usb: gadget: f_qc_rndis: Fix double-free in qcrndis_free 1084177 I2bbe7be3daedef45a5990c23168df5185e72e82f msm: sensor: correcting return value for get actuator in 1102137 I2fce80cec72e3bd8b1561fd46fa1a1520cddd294 msm: mdss: dp: fix handling of link training mutex 1102584 Idd40a0b471293048833b34dda3ac5044a87fc3c9 ASoC: wcd934x: Fix headset TX mode setting 1103939 I03e4a8e10452ef53d8e35e7cee44bdf51f53483b ARM: dts: msm: Add support for home hard key at QRD8998H 1098041 I8cc22af138a343cd387f4400cff487faa66b3da0 ASoC: wcd934x: Update class-H parameters based on headph 1095411 Ie639a26543e2f20b61d6dfc73b3bcbd6a43b24be msm: mdss: Move PP programming after mdp wait for ping p 1093271 I406a41ac961757d31209ae0a0a4b4d9cc4d31a1e defconfig: msm: disable CRYPTO_DEC_QCE device on msm8998 1104183 I58e19def0042022046e730dd97008a9e1c25b6d6 icnss: Add EXEC permission when assigning the MSA0 back 1104001 Ie596ddee60aac3e6fc996f9a3e8dc988b0f4aa88 clk: qcom: Add smd-rpm voter & voter branch clocks for M 1102726 I49efddea0228e3129d36eabc102d6df0fcd53d12 ARM: dts: msm: add mdss node for msmfalcon target 1099101 I1e76eb2e1c575b433e3899ae2471719bf68ab1c1 ASoC: msm: decrement slim channel ref to set the propert 1105246 I4de26881620dde4230d0a907bd0fd39bebe2bb3d wil6210: missing reinit_completion in wmi_call Change-Id: I0c6d90c668b09a08de714b3bcd03e1e513f1853a CRs-Fixed: 1102584, 986540, 1104976, 1076516, 1104977, 1100018, 1102841, 1105100, 1104880, 1102900, 1081961, 1103939, 1104865, 1104679, 1105169, 1084177, 1105038, 1102641, 1099484, 1046799, 1052835, 1102137, 1098662, 1104853, 1098041, 1095411, 1083444, 1100632, 1104981, 1104858, 1100213, 1104607, 1093271, 1104928, 1102726, 1104876, 1093863, 1099101, 1103891, 1092969, 868394, 1094763, 1105246, 1103739, 1105323, 1094456, 1104760, 1101260, 1100528, 1097878, 1104886, 1104001, 1103468, 1102776, 1068294, 1101084, 1104183, 1103405
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/diag/diag_dci.c26
-rw-r--r--drivers/clk/clk.c63
-rw-r--r--drivers/clk/qcom/Kconfig12
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clk-cpu-osm.c1139
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c93
-rw-r--r--drivers/clk/qcom/common.h1
-rw-r--r--drivers/clk/qcom/gcc-msm8996.c191
-rw-r--r--drivers/clk/qcom/gcc-msmfalcon.c6
-rw-r--r--drivers/clk/qcom/mdss/mdss-pll.c5
-rw-r--r--drivers/clk/qcom/mdss/mdss-pll.h1
-rw-r--r--drivers/clk/qcom/mmcc-msmfalcon.c11
-rw-r--r--drivers/clk/qcom/vdd-level-8996.h95
-rw-r--r--drivers/crypto/msm/qce50.c20
-rw-r--r--drivers/crypto/msm/qcrypto.c53
-rw-r--r--drivers/gpu/msm/adreno_dispatch.c10
-rw-r--r--drivers/gpu/msm/kgsl_pwrctrl.c5
-rw-r--r--drivers/gpu/msm/kgsl_pwrscale.c79
-rw-r--r--drivers/gpu/msm/kgsl_pwrscale.h3
-rw-r--r--drivers/i2c/busses/i2c-msm-v2.c12
-rw-r--r--drivers/input/misc/hbtp_input.c8
-rw-r--r--drivers/input/qpnp-power-on.c21
-rw-r--r--drivers/leds/leds-qpnp-wled.c20
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c6
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp40.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c1
-rw-r--r--drivers/misc/qseecom.c34
-rw-r--r--drivers/misc/qseecom_kernel.h2
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c1
-rw-r--r--drivers/platform/msm/msm_11ad/msm_11ad.c37
-rw-r--r--drivers/power/power_supply_sysfs.c1
-rw-r--r--drivers/power/qcom-charger/fg-core.h1
-rw-r--r--drivers/power/qcom-charger/qpnp-fg-gen3.c11
-rw-r--r--drivers/power/reset/msm-poweroff.c31
-rw-r--r--drivers/regulator/Kconfig11
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/cpr4-mmss-ldo-regulator.c722
-rw-r--r--drivers/soc/qcom/avtimer.c14
-rw-r--r--drivers/soc/qcom/icnss.c2
-rw-r--r--drivers/soc/qcom/smcinvoke.c8
-rw-r--r--drivers/soc/qcom/spcom.c15
-rw-r--r--drivers/spi/spi_qsd.c23
-rw-r--r--drivers/spi/spi_qsd.h78
-rw-r--r--drivers/thermal/msm_thermal.c13
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/gadget/function/f_qc_rndis.c13
-rw-r--r--drivers/usb/gadget/function/u_data_ipa.c32
-rw-r--r--drivers/usb/host/xhci-hub.c178
-rw-r--r--drivers/usb/host/xhci-ring.c150
-rw-r--r--drivers/usb/host/xhci.h4
-rw-r--r--drivers/usb/phy/phy-msm-qusb-v2.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_debug.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c72
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.h55
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_aux.c131
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.c84
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.h6
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c42
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c20
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c4
63 files changed, 2897 insertions, 800 deletions
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 7af9d8184f97..f47b390375c4 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -771,6 +771,7 @@ static int diag_dci_remove_req_entry(unsigned char *buf, int len,
if (*buf != 0x80) {
list_del(&entry->track);
kfree(entry);
+ entry = NULL;
return 1;
}
@@ -788,6 +789,7 @@ static int diag_dci_remove_req_entry(unsigned char *buf, int len,
if (delayed_rsp_id == 0) {
list_del(&entry->track);
kfree(entry);
+ entry = NULL;
return 1;
}
@@ -801,6 +803,7 @@ static int diag_dci_remove_req_entry(unsigned char *buf, int len,
if (rsp_count > 0 && rsp_count < 0x1000) {
list_del(&entry->track);
kfree(entry);
+ entry = NULL;
return 1;
}
@@ -2682,10 +2685,12 @@ int diag_dci_init(void)
err:
pr_err("diag: Could not initialize diag DCI buffers");
kfree(driver->apps_dci_buf);
+ driver->apps_dci_buf = NULL;
if (driver->diag_dci_wq)
destroy_workqueue(driver->diag_dci_wq);
kfree(partial_pkt.data);
+ partial_pkt.data = NULL;
mutex_destroy(&driver->dci_mutex);
mutex_destroy(&dci_log_mask_mutex);
mutex_destroy(&dci_event_mask_mutex);
@@ -2705,7 +2710,9 @@ void diag_dci_channel_init(void)
void diag_dci_exit(void)
{
kfree(partial_pkt.data);
+ partial_pkt.data = NULL;
kfree(driver->apps_dci_buf);
+ driver->apps_dci_buf = NULL;
mutex_destroy(&driver->dci_mutex);
mutex_destroy(&dci_log_mask_mutex);
mutex_destroy(&dci_event_mask_mutex);
@@ -2917,22 +2924,30 @@ fail_alloc:
mutex_destroy(&proc_buf->health_mutex);
if (proc_buf->buf_primary) {
kfree(proc_buf->buf_primary->data);
+ proc_buf->buf_primary->data = NULL;
mutex_destroy(
&proc_buf->buf_primary->data_mutex);
}
kfree(proc_buf->buf_primary);
+ proc_buf->buf_primary = NULL;
if (proc_buf->buf_cmd) {
kfree(proc_buf->buf_cmd->data);
+ proc_buf->buf_cmd->data = NULL;
mutex_destroy(
&proc_buf->buf_cmd->data_mutex);
}
kfree(proc_buf->buf_cmd);
+ proc_buf->buf_cmd = NULL;
}
}
kfree(new_entry->dci_event_mask);
+ new_entry->dci_event_mask = NULL;
kfree(new_entry->dci_log_mask);
+ new_entry->dci_log_mask = NULL;
kfree(new_entry->buffers);
+ new_entry->buffers = NULL;
kfree(new_entry);
+ new_entry = NULL;
}
mutex_unlock(&driver->dci_mutex);
return DIAG_DCI_NO_REG;
@@ -2963,6 +2978,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry)
* masks and send the masks to peripherals
*/
kfree(entry->dci_log_mask);
+ entry->dci_log_mask = NULL;
diag_dci_invalidate_cumulative_log_mask(token);
if (token == DCI_LOCAL_PROC)
diag_update_userspace_clients(DCI_LOG_MASKS_TYPE);
@@ -2971,6 +2987,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry)
return ret;
}
kfree(entry->dci_event_mask);
+ entry->dci_event_mask = NULL;
diag_dci_invalidate_cumulative_event_mask(token);
if (token == DCI_LOCAL_PROC)
diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE);
@@ -2986,6 +3003,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry)
if (!list_empty(&req_entry->track))
list_del(&req_entry->track);
kfree(req_entry);
+ req_entry = NULL;
}
}
@@ -3001,6 +3019,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry)
buf_entry->data = NULL;
mutex_unlock(&buf_entry->data_mutex);
kfree(buf_entry);
+ buf_entry = NULL;
} else if (buf_entry->buf_type == DCI_BUF_CMD) {
peripheral = buf_entry->data_source;
if (peripheral == APPS_DATA)
@@ -3027,14 +3046,17 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry)
mutex_unlock(&buf_entry->data_mutex);
mutex_destroy(&buf_entry->data_mutex);
kfree(buf_entry);
+ buf_entry = NULL;
}
mutex_lock(&proc_buf->buf_primary->data_mutex);
kfree(proc_buf->buf_primary->data);
+ proc_buf->buf_primary->data = NULL;
mutex_unlock(&proc_buf->buf_primary->data_mutex);
mutex_lock(&proc_buf->buf_cmd->data_mutex);
kfree(proc_buf->buf_cmd->data);
+ proc_buf->buf_cmd->data = NULL;
mutex_unlock(&proc_buf->buf_cmd->data_mutex);
mutex_destroy(&proc_buf->health_mutex);
@@ -3042,13 +3064,17 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry)
mutex_destroy(&proc_buf->buf_cmd->data_mutex);
kfree(proc_buf->buf_primary);
+ proc_buf->buf_primary = NULL;
kfree(proc_buf->buf_cmd);
+ proc_buf->buf_cmd = NULL;
mutex_unlock(&proc_buf->buf_mutex);
}
mutex_destroy(&entry->write_buf_mutex);
kfree(entry->buffers);
+ entry->buffers = NULL;
kfree(entry);
+ entry = NULL;
if (driver->num_dci_client == 0) {
diag_update_proc_vote(DIAG_PROC_DCI, VOTE_DOWN, token);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index c4aec62d1014..ac815c6dbac0 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -71,6 +71,8 @@ struct clk_core {
bool orphan;
unsigned int enable_count;
unsigned int prepare_count;
+ bool need_handoff_enable;
+ bool need_handoff_prepare;
unsigned long min_rate;
unsigned long max_rate;
unsigned long accuracy;
@@ -195,6 +197,19 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
hlist_for_each_entry(child, &core->children, child_node)
clk_unprepare_unused_subtree(child);
+ /*
+ * setting CLK_ENABLE_HAND_OFF flag triggers this conditional
+ *
+ * need_handoff_prepare implies this clk was already prepared by
+ * __clk_init. now we have a proper user, so unset the flag in our
+ * internal bookkeeping. See CLK_ENABLE_HAND_OFF flag in clk-provider.h
+ * for details.
+ */
+ if (core->need_handoff_prepare) {
+ core->need_handoff_prepare = false;
+ core->prepare_count--;
+ }
+
if (core->prepare_count)
return;
@@ -221,6 +236,19 @@ static void clk_disable_unused_subtree(struct clk_core *core)
hlist_for_each_entry(child, &core->children, child_node)
clk_disable_unused_subtree(child);
+ /*
+ * setting CLK_ENABLE_HAND_OFF flag triggers this conditional
+ *
+ * need_handoff_enable implies this clk was already enabled by
+ * __clk_init. now we have a proper user, so unset the flag in our
+ * internal bookkeeping. See CLK_ENABLE_HAND_OFF flag in clk-provider.h
+ * for details.
+ */
+ if (core->need_handoff_enable) {
+ core->need_handoff_enable = false;
+ core->enable_count--;
+ }
+
flags = clk_enable_lock();
if (core->enable_count)
@@ -925,7 +953,7 @@ static int clk_core_prepare(struct clk_core *core)
*/
int clk_prepare(struct clk *clk)
{
- int ret;
+ int ret = 0;
if (!clk)
return 0;
@@ -1040,7 +1068,7 @@ static int clk_core_enable(struct clk_core *core)
int clk_enable(struct clk *clk)
{
unsigned long flags;
- int ret;
+ int ret = 0;
if (!clk)
return 0;
@@ -3146,6 +3174,37 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
clk_enable_unlock(flags);
}
+ /*
+ * enable clocks with the CLK_ENABLE_HAND_OFF flag set
+ *
+ * This flag causes the framework to enable the clock at registration
+ * time, which is sometimes necessary for clocks that would cause a
+ * system crash when gated (e.g. cpu, memory, etc). The prepare_count
+ * is migrated over to the first clk consumer to call clk_prepare().
+ * Similarly the clk's enable_count is migrated to the first consumer
+ * to call clk_enable().
+ */
+ if (core->flags & CLK_ENABLE_HAND_OFF) {
+ unsigned long flags;
+
+ /*
+ * Few clocks might have hardware gating which would be required
+ * to be ON before prepare/enabling the clocks. So check if the
+ * clock has been turned ON earlier and we should
+ * prepare/enable those clocks.
+ */
+ if (clk_core_is_enabled(core)) {
+ core->need_handoff_prepare = true;
+ core->need_handoff_enable = true;
+ ret = clk_core_prepare(core);
+ if (ret)
+ goto out;
+ flags = clk_enable_lock();
+ clk_core_enable(core);
+ clk_enable_unlock(flags);
+ }
+ }
+
kref_init(&core->ref);
out:
clk_prepare_unlock();
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 2148dad33e87..b5dd556b3f96 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -219,4 +219,16 @@ config QCOM_A53
Say Y if you want to support CPU frequency scaling on devices
such as MSM8916.
+config CLOCK_CPU_OSM
+ tristate "OSM CPU Clock Controller"
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the osm clock controller.
+ Operating State Manager (OSM) is a hardware engine used by some
+ Qualcomm Technologies, Inc. (QTI) SoCs to manage frequency and
+ voltage scaling in hardware. OSM is capable of controlling
+ frequency and voltage requests for multiple clusters via the
+ existence of multiple OSM domains.
+ Say Y if you want to support osm clocks.
+
source "drivers/clk/qcom/mdss/Kconfig"
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 176dc3103cdb..a63065c97319 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -37,5 +37,6 @@ obj-$(CONFIG_KRAITCC) += krait-cc.o
obj-$(CONFIG_QCOM_A53) += clk-a53.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
+obj-$(CONFIG_CLOCK_CPU_OSM) += clk-cpu-osm.o
obj-y += mdss/
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index f97cd1b03c81..ab6a1384ffbd 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -22,9 +22,7 @@
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/clk.h>
-#include <linux/clk/msm-clk-provider.h>
-#include <linux/clk/msm-clk.h>
-#include <linux/clk/msm-clock-generic.h>
+#include <linux/clk-provider.h>
#include <linux/cpu.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
@@ -32,18 +30,20 @@
#include <linux/pm_qos.h>
#include <linux/interrupt.h>
#include <linux/regulator/driver.h>
+#include <linux/regmap.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
-
#include <soc/qcom/scm.h>
-#include <soc/qcom/clock-pll.h>
-#include <soc/qcom/clock-local2.h>
-#include <soc/qcom/clock-alpha-pll.h>
+#include <dt-bindings/clock/qcom,cpu-osm.h>
-#include <dt-bindings/clock/msm-clocks-hwio-cobalt.h>
-#include <dt-bindings/clock/msm-clocks-cobalt.h>
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-rcg.h"
-#include "clock.h"
+enum {
+ LMH_LITE_CLK_SRC,
+ P_XO,
+};
enum clk_osm_bases {
OSM_BASE,
@@ -74,210 +74,192 @@ enum clk_osm_trace_packet_id {
TRACE_PACKET3,
};
-#define SEQ_REG(n) (0x300 + (n) * 4)
-#define MEM_ACC_SEQ_REG_CFG_START(n) (SEQ_REG(12 + (n)))
-#define MEM_ACC_SEQ_CONST(n) (n)
-#define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40))
-#define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n)))
-#define SEQ_REG1_MSMCOBALT_V2 0x1048
-#define VERSION_REG 0x0
-#define VERSION_1P1 0x00010100
-
-#define OSM_TABLE_SIZE 40
-#define MAX_CLUSTER_CNT 2
-#define MAX_CONFIG 4
-#define LLM_SW_OVERRIDE_CNT 3
-
-#define ENABLE_REG 0x1004
-#define INDEX_REG 0x1150
-#define FREQ_REG 0x1154
-#define VOLT_REG 0x1158
-#define OVERRIDE_REG 0x115C
-#define SPARE_REG 0x1164
-
-#define OSM_CYCLE_COUNTER_CTRL_REG 0x1F00
-#define OSM_CYCLE_COUNTER_STATUS_REG 0x1F04
-#define DCVS_PERF_STATE_DESIRED_REG 0x1F10
-#define DCVS_PERF_STATE_DEVIATION_INTR_STAT 0x1F14
-#define DCVS_PERF_STATE_DEVIATION_INTR_EN 0x1F18
-#define DCVS_PERF_STATE_DEVIATION_INTR_CLEAR 0x1F1C
-#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_STAT 0x1F20
-#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN 0x1F24
-#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_CLEAR 0x1F28
-#define DCVS_PERF_STATE_MET_INTR_STAT 0x1F2C
-#define DCVS_PERF_STATE_MET_INTR_EN 0x1F30
-#define DCVS_PERF_STATE_MET_INTR_CLR 0x1F34
-#define OSM_CORE_TABLE_SIZE 8192
-#define OSM_REG_SIZE 32
-
-#define WDOG_DOMAIN_PSTATE_STATUS 0x1c00
-#define WDOG_PROGRAM_COUNTER 0x1c74
-
-#define OSM_CYCLE_COUNTER_USE_XO_EDGE_EN BIT(8)
-#define PLL_MODE 0x0
-#define PLL_L_VAL 0x4
-#define PLL_USER_CTRL 0xC
-#define PLL_CONFIG_CTL_LO 0x10
-#define PLL_TEST_CTL_HI 0x1C
-#define PLL_STATUS 0x2C
-#define PLL_LOCK_DET_MASK BIT(16)
-#define PLL_WAIT_LOCK_TIME_US 10
-#define PLL_WAIT_LOCK_TIME_NS (PLL_WAIT_LOCK_TIME_US * 1000)
-#define PLL_MIN_LVAL 43
-
-#define CC_ZERO_BEHAV_CTRL 0x100C
-#define SPM_CC_DCVS_DISABLE 0x1020
-#define SPM_CC_CTRL 0x1028
-#define SPM_CC_HYSTERESIS 0x101C
-#define SPM_CORE_RET_MAPPING 0x1024
-#define CFG_DELAY_VAL_3 0x12C
-
-#define LLM_FREQ_VOTE_HYSTERESIS 0x102C
-#define LLM_VOLT_VOTE_HYSTERESIS 0x1030
-#define LLM_INTF_DCVS_DISABLE 0x1034
-
-#define ENABLE_OVERRIDE BIT(0)
-
-#define ITM_CL0_DISABLE_CL1_ENABLED 0x2
-#define ITM_CL0_ENABLED_CL1_DISABLE 0x1
-
-#define APM_MX_MODE 0
-#define APM_APC_MODE BIT(1)
-#define APM_MODE_SWITCH_MASK (BVAL(4, 2, 7) | BVAL(1, 0, 3))
-#define APM_MX_MODE_VAL 0
-#define APM_APC_MODE_VAL 0x3
-
-#define GPLL_SEL 0x400
-#define PLL_EARLY_SEL 0x500
-#define PLL_MAIN_SEL 0x300
-#define RCG_UPDATE 0x3
-#define RCG_UPDATE_SUCCESS 0x2
-#define PLL_POST_DIV1 0x1F
-#define PLL_POST_DIV2 0x11F
-
-#define LLM_SW_OVERRIDE_REG 0x1038
-#define VMIN_REDUC_ENABLE_REG 0x103C
-#define VMIN_REDUC_TIMER_REG 0x1040
-#define PDN_FSM_CTRL_REG 0x1070
-#define CC_BOOST_TIMER_REG0 0x1074
-#define CC_BOOST_TIMER_REG1 0x1078
-#define CC_BOOST_TIMER_REG2 0x107C
-#define CC_BOOST_EN_MASK BIT(0)
-#define PS_BOOST_EN_MASK BIT(1)
-#define DCVS_BOOST_EN_MASK BIT(2)
-#define PC_RET_EXIT_DROOP_EN_MASK BIT(3)
-#define WFX_DROOP_EN_MASK BIT(4)
-#define DCVS_DROOP_EN_MASK BIT(5)
-#define LMH_PS_EN_MASK BIT(6)
-#define IGNORE_PLL_LOCK_MASK BIT(15)
-#define SAFE_FREQ_WAIT_NS 5000
-#define DEXT_DECREMENT_WAIT_NS 1000
-#define DCVS_BOOST_TIMER_REG0 0x1084
-#define DCVS_BOOST_TIMER_REG1 0x1088
-#define DCVS_BOOST_TIMER_REG2 0x108C
-#define PS_BOOST_TIMER_REG0 0x1094
-#define PS_BOOST_TIMER_REG1 0x1098
-#define PS_BOOST_TIMER_REG2 0x109C
-#define BOOST_PROG_SYNC_DELAY_REG 0x10A0
-#define DROOP_CTRL_REG 0x10A4
-#define DROOP_RELEASE_TIMER_CTRL 0x10A8
-#define DROOP_PROG_SYNC_DELAY_REG 0x10BC
-#define DROOP_UNSTALL_TIMER_CTRL_REG 0x10AC
-#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG 0x10B0
-#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL1_REG 0x10B4
-#define OSM_PLL_SW_OVERRIDE_EN 0x10C0
-
-#define PLL_SW_OVERRIDE_DROOP_EN BIT(0)
-#define DCVS_DROOP_TIMER_CTRL 0x10B8
-#define SEQ_MEM_ADDR 0x500
-#define SEQ_CFG_BR_ADDR 0x170
-#define MAX_INSTRUCTIONS 256
-#define MAX_BR_INSTRUCTIONS 49
-
-#define MAX_MEM_ACC_LEVELS 3
-#define MAX_MEM_ACC_VAL_PER_LEVEL 3
-#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \
- MAX_MEM_ACC_VAL_PER_LEVEL)
-#define MEM_ACC_APM_READ_MASK 0xff
-
-#define TRACE_CTRL 0x1F38
-#define TRACE_CTRL_EN_MASK BIT(0)
-#define TRACE_CTRL_ENABLE 1
-#define TRACE_CTRL_DISABLE 0
-#define TRACE_CTRL_ENABLE_WDOG_STATUS BIT(30)
-#define TRACE_CTRL_PACKET_TYPE_MASK BVAL(2, 1, 3)
-#define TRACE_CTRL_PACKET_TYPE_SHIFT 1
-#define TRACE_CTRL_PERIODIC_TRACE_EN_MASK BIT(3)
-#define TRACE_CTRL_PERIODIC_TRACE_ENABLE BIT(3)
-#define PERIODIC_TRACE_TIMER_CTRL 0x1F3C
-#define PERIODIC_TRACE_MIN_NS 1000
-#define PERIODIC_TRACE_MAX_NS 21474836475
-#define PERIODIC_TRACE_DEFAULT_NS 1000000
-
-#define PLL_DD_USER_CTL_LO_ENABLE 0x0f04c408
-#define PLL_DD_USER_CTL_LO_DISABLE 0x1f04c41f
-#define PLL_DD_D0_USER_CTL_LO 0x17916208
-#define PLL_DD_D1_USER_CTL_LO 0x17816208
-
-#define PWRCL_EFUSE_SHIFT 0
-#define PWRCL_EFUSE_MASK 0
-#define PERFCL_EFUSE_SHIFT 29
-#define PERFCL_EFUSE_MASK 0x7
-
-#define MSMCOBALTV1_PWRCL_BOOT_RATE 1478400000
-#define MSMCOBALTV1_PERFCL_BOOT_RATE 1536000000
-#define MSMCOBALTV2_PWRCL_BOOT_RATE 1555200000
-#define MSMCOBALTV2_PERFCL_BOOT_RATE 1728000000
+#define SEQ_REG(n) (0x300 + (n) * 4)
+#define MEM_ACC_SEQ_REG_CFG_START(n) (SEQ_REG(12 + (n)))
+#define MEM_ACC_SEQ_CONST(n) (n)
+#define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40))
+#define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n)))
+#define SEQ_REG1_OFFSET 0x1048
+#define VERSION_REG 0x0
+
+#define OSM_TABLE_SIZE 40
+#define MAX_CLUSTER_CNT 2
+#define LLM_SW_OVERRIDE_CNT 3
+#define CORE_COUNT_VAL(val) ((val & GENMASK(18, 16)) >> 16)
+#define SINGLE_CORE 1
+#define MAX_CORE_COUNT 4
+
+#define ENABLE_REG 0x1004
+#define INDEX_REG 0x1150
+#define FREQ_REG 0x1154
+#define VOLT_REG 0x1158
+#define OVERRIDE_REG 0x115C
+#define SPARE_REG 0x1164
+
+#define OSM_CYCLE_COUNTER_CTRL_REG 0x1F00
+#define OSM_CYCLE_COUNTER_STATUS_REG 0x1F04
+#define DCVS_PERF_STATE_DESIRED_REG 0x1F10
+#define DCVS_PERF_STATE_DEVIATION_INTR_STAT 0x1F14
+#define DCVS_PERF_STATE_DEVIATION_INTR_EN 0x1F18
+#define DCVS_PERF_STATE_DEVIATION_INTR_CLEAR 0x1F1C
+#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_STAT 0x1F20
+#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN 0x1F24
+#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_CLEAR 0x1F28
+#define DCVS_PERF_STATE_MET_INTR_STAT 0x1F2C
+#define DCVS_PERF_STATE_MET_INTR_EN 0x1F30
+#define DCVS_PERF_STATE_MET_INTR_CLR 0x1F34
+#define OSM_CORE_TABLE_SIZE 8192
+#define OSM_REG_SIZE 32
+
+#define WDOG_DOMAIN_PSTATE_STATUS 0x1c00
+#define WDOG_PROGRAM_COUNTER 0x1c74
+
+#define OSM_CYCLE_COUNTER_USE_XO_EDGE_EN BIT(8)
+
+#define PLL_MODE 0x0
+#define PLL_L_VAL 0x4
+#define PLL_USER_CTRL 0xC
+#define PLL_CONFIG_CTL_LO 0x10
+#define PLL_TEST_CTL_HI 0x1C
+#define PLL_STATUS 0x2C
+#define PLL_LOCK_DET_MASK BIT(16)
+#define PLL_WAIT_LOCK_TIME_US 10
+#define PLL_WAIT_LOCK_TIME_NS (PLL_WAIT_LOCK_TIME_US * 1000)
+#define PLL_MIN_LVAL 43
+#define L_VAL(freq_data) ((freq_data) & GENMASK(7, 0))
+
+#define CC_ZERO_BEHAV_CTRL 0x100C
+#define SPM_CC_DCVS_DISABLE 0x1020
+#define SPM_CC_CTRL 0x1028
+#define SPM_CC_HYSTERESIS 0x101C
+#define SPM_CORE_RET_MAPPING 0x1024
+#define CFG_DELAY_VAL_3 0x12C
+
+#define LLM_FREQ_VOTE_HYSTERESIS 0x102C
+#define LLM_VOLT_VOTE_HYSTERESIS 0x1030
+#define LLM_INTF_DCVS_DISABLE 0x1034
+
+#define ENABLE_OVERRIDE BIT(0)
+
+#define ITM_CL0_DISABLE_CL1_ENABLED 0x2
+#define ITM_CL0_ENABLED_CL1_DISABLE 0x1
+
+#define APM_MX_MODE 0
+#define APM_APC_MODE BIT(1)
+#define APM_MODE_SWITCH_MASK (BVAL(4, 2, 7) | BVAL(1, 0, 3))
+#define APM_MX_MODE_VAL 0
+#define APM_APC_MODE_VAL 0x3
+
+#define GPLL_SEL 0x400
+#define PLL_EARLY_SEL 0x500
+#define PLL_MAIN_SEL 0x300
+#define RCG_UPDATE 0x3
+#define RCG_UPDATE_SUCCESS 0x2
+#define PLL_POST_DIV1 0x1F
+#define PLL_POST_DIV2 0x11F
+
+#define LLM_SW_OVERRIDE_REG 0x1038
+#define VMIN_REDUC_ENABLE_REG 0x103C
+#define VMIN_REDUC_TIMER_REG 0x1040
+#define PDN_FSM_CTRL_REG 0x1070
+#define CC_BOOST_TIMER_REG0 0x1074
+#define CC_BOOST_TIMER_REG1 0x1078
+#define CC_BOOST_TIMER_REG2 0x107C
+#define CC_BOOST_EN_MASK BIT(0)
+#define PS_BOOST_EN_MASK BIT(1)
+#define DCVS_BOOST_EN_MASK BIT(2)
+#define PC_RET_EXIT_DROOP_EN_MASK BIT(3)
+#define WFX_DROOP_EN_MASK BIT(4)
+#define DCVS_DROOP_EN_MASK BIT(5)
+#define LMH_PS_EN_MASK BIT(6)
+#define IGNORE_PLL_LOCK_MASK BIT(15)
+#define SAFE_FREQ_WAIT_NS 5000
+#define DEXT_DECREMENT_WAIT_NS 1000
+#define DCVS_BOOST_TIMER_REG0 0x1084
+#define DCVS_BOOST_TIMER_REG1 0x1088
+#define DCVS_BOOST_TIMER_REG2 0x108C
+#define PS_BOOST_TIMER_REG0 0x1094
+#define PS_BOOST_TIMER_REG1 0x1098
+#define PS_BOOST_TIMER_REG2 0x109C
+#define BOOST_PROG_SYNC_DELAY_REG 0x10A0
+#define DROOP_CTRL_REG 0x10A4
+#define DROOP_RELEASE_TIMER_CTRL 0x10A8
+#define DROOP_PROG_SYNC_DELAY_REG 0x10BC
+#define DROOP_UNSTALL_TIMER_CTRL_REG 0x10AC
+#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG 0x10B0
+#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL1_REG 0x10B4
+#define OSM_PLL_SW_OVERRIDE_EN 0x10C0
+
+#define PLL_SW_OVERRIDE_DROOP_EN BIT(0)
+#define DCVS_DROOP_TIMER_CTRL 0x10B8
+#define SEQ_MEM_ADDR 0x500
+#define SEQ_CFG_BR_ADDR 0x170
+#define MAX_INSTRUCTIONS 256
+#define MAX_BR_INSTRUCTIONS 49
+
+#define MAX_MEM_ACC_LEVELS 3
+#define MAX_MEM_ACC_VAL_PER_LEVEL 3
+#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \
+ MAX_MEM_ACC_VAL_PER_LEVEL)
+#define MEM_ACC_APM_READ_MASK 0xff
+
+#define TRACE_CTRL 0x1F38
+#define TRACE_CTRL_EN_MASK BIT(0)
+#define TRACE_CTRL_ENABLE 1
+#define TRACE_CTRL_DISABLE 0
+#define TRACE_CTRL_ENABLE_WDOG_STATUS BIT(30)
+#define TRACE_CTRL_PACKET_TYPE_MASK BVAL(2, 1, 3)
+#define TRACE_CTRL_PACKET_TYPE_SHIFT 1
+#define TRACE_CTRL_PERIODIC_TRACE_EN_MASK BIT(3)
+#define TRACE_CTRL_PERIODIC_TRACE_ENABLE BIT(3)
+#define PERIODIC_TRACE_TIMER_CTRL 0x1F3C
+#define PERIODIC_TRACE_MIN_NS 1000
+#define PERIODIC_TRACE_MAX_NS 21474836475ULL
+#define PERIODIC_TRACE_DEFAULT_NS 1000000
+
+#define PLL_DD_USER_CTL_LO_ENABLE 0x0f04c408
+#define PLL_DD_USER_CTL_LO_DISABLE 0x1f04c41f
+#define PLL_DD_D0_USER_CTL_LO 0x17916208
+#define PLL_DD_D1_USER_CTL_LO 0x17816208
+
+#define PWRCL_EFUSE_SHIFT 0
+#define PWRCL_EFUSE_MASK 0
+#define PERFCL_EFUSE_SHIFT 29
+#define PERFCL_EFUSE_MASK 0x7
/* ACD registers */
-#define ACD_HW_VERSION 0x0
-#define ACDCR 0x4
-#define ACDTD 0x8
-#define ACDSSCR 0x28
-#define ACD_EXTINT_CFG 0x30
-#define ACD_DCVS_SW 0x34
-#define ACD_GFMUX_CFG 0x3c
-#define ACD_READOUT_CFG 0x48
-#define ACD_AUTOXFER_CFG 0x80
-#define ACD_AUTOXFER 0x84
-#define ACD_AUTOXFER_CTL 0x88
-#define ACD_AUTOXFER_STATUS 0x8c
-#define ACD_WRITE_CTL 0x90
-#define ACD_WRITE_STATUS 0x94
-#define ACD_READOUT 0x98
-
-#define ACD_MASTER_ONLY_REG_ADDR 0x80
-#define ACD_WRITE_CTL_UPDATE_EN BIT(0)
-#define ACD_WRITE_CTL_SELECT_SHIFT 1
-#define ACD_GFMUX_CFG_SELECT BIT(0)
-#define ACD_AUTOXFER_START_CLEAR 0
-#define ACD_AUTOXFER_START_SET BIT(0)
-#define AUTO_XFER_DONE_MASK BIT(0)
-#define ACD_DCVS_SW_DCVS_IN_PRGR_SET BIT(0)
-#define ACD_DCVS_SW_DCVS_IN_PRGR_CLEAR 0
-#define ACD_LOCAL_TRANSFER_TIMEOUT_NS 500
-
-static void __iomem *virt_base;
-static void __iomem *debug_base;
-
-#define lmh_lite_clk_src_source_val 1
-
-#define ACD_REG_RELATIVE_ADDR(addr) (addr / 4)
+#define ACD_HW_VERSION 0x0
+#define ACDCR 0x4
+#define ACDTD 0x8
+#define ACDSSCR 0x28
+#define ACD_EXTINT_CFG 0x30
+#define ACD_DCVS_SW 0x34
+#define ACD_GFMUX_CFG 0x3c
+#define ACD_READOUT_CFG 0x48
+#define ACD_AUTOXFER_CFG 0x80
+#define ACD_AUTOXFER 0x84
+#define ACD_AUTOXFER_CTL 0x88
+#define ACD_AUTOXFER_STATUS 0x8c
+#define ACD_WRITE_CTL 0x90
+#define ACD_WRITE_STATUS 0x94
+#define ACD_READOUT 0x98
+
+#define ACD_MASTER_ONLY_REG_ADDR 0x80
+#define ACD_WRITE_CTL_UPDATE_EN BIT(0)
+#define ACD_WRITE_CTL_SELECT_SHIFT 1
+#define ACD_GFMUX_CFG_SELECT BIT(0)
+#define ACD_AUTOXFER_START_CLEAR 0
+#define ACD_AUTOXFER_START_SET BIT(0)
+#define AUTO_XFER_DONE_MASK BIT(0)
+#define ACD_DCVS_SW_DCVS_IN_PRGR_SET BIT(0)
+#define ACD_DCVS_SW_DCVS_IN_PRGR_CLEAR 0
+#define ACD_LOCAL_TRANSFER_TIMEOUT_NS 500
+
+#define ACD_REG_RELATIVE_ADDR(addr) (addr / 4)
#define ACD_REG_RELATIVE_ADDR_BITMASK(addr) \
- (1 << (ACD_REG_RELATIVE_ADDR(addr)))
-
-#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
+ (1 << (ACD_REG_RELATIVE_ADDR(addr)))
-#define F(f, s, div, m, n) \
- { \
- .freq_hz = (f), \
- .src_clk = &s.c, \
- .m_val = (m), \
- .n_val = ~((n)-(m)) * !!(n), \
- .d_val = ~(n),\
- .div_src_val = BVAL(4, 0, (int)FIXDIV(div)) \
- | BVAL(10, 8, s##_source_val), \
- }
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static u32 seq_instr[] = {
0xc2005000, 0x2c9e3b21, 0xc0ab2cdc, 0xc2882525, 0x359dc491,
@@ -325,10 +307,6 @@ static u32 seq_br_instr[] = {
0x20c,
};
-DEFINE_EXT_CLK(xo_ao, NULL);
-DEFINE_EXT_CLK(sys_apcsaux_clk_gcc, NULL);
-DEFINE_EXT_CLK(lmh_lite_clk_src, NULL);
-
struct osm_entry {
u16 virtual_corner;
u16 open_loop_volt;
@@ -338,10 +316,20 @@ struct osm_entry {
long frequency;
};
+static void __iomem *virt_base;
static struct dentry *osm_debugfs_base;
+static struct regulator *vdd_pwrcl;
+static struct regulator *vdd_perfcl;
+
+static const struct regmap_config osm_qcom_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+};
struct clk_osm {
- struct clk c;
+ struct clk_hw hw;
struct osm_entry osm_table[OSM_TABLE_SIZE];
struct dentry *debugfs;
struct regulator *vdd_reg;
@@ -350,13 +338,14 @@ struct clk_osm {
unsigned long pbases[NUM_BASES];
spinlock_t lock;
- u32 version;
u32 cpu_reg_mask;
u32 num_entries;
u32 cluster_num;
u32 irq;
u32 apm_crossover_vc;
u32 apm_threshold_vc;
+ u32 mem_acc_crossover_vc;
+ u32 mem_acc_threshold_vc;
u32 cycle_counter_reads;
u32 cycle_counter_delay;
u32 cycle_counter_factor;
@@ -399,9 +388,6 @@ struct clk_osm {
bool wdog_trace_en;
};
-static bool msmcobalt_v1;
-static bool msmcobalt_v2;
-
static inline void clk_osm_masked_write_reg(struct clk_osm *c, u32 val,
u32 offset, u32 mask)
{
@@ -600,63 +586,86 @@ static inline int clk_osm_count_ns(struct clk_osm *c, u64 nsec)
return temp;
}
-static inline struct clk_osm *to_clk_osm(struct clk *c)
+static inline struct clk_osm *to_clk_osm(struct clk_hw *_hw)
{
- return container_of(c, struct clk_osm, c);
+ return container_of(_hw, struct clk_osm, hw);
}
-static enum handoff clk_osm_handoff(struct clk *c)
+static long clk_osm_list_rate(struct clk_hw *hw, unsigned n,
+ unsigned long rate_max)
{
- return HANDOFF_DISABLED_CLK;
+ if (n >= hw->init->num_rate_max)
+ return -ENXIO;
+ return hw->init->rate_max[n];
}
-static long clk_osm_list_rate(struct clk *c, unsigned n)
+static inline bool is_better_rate(unsigned long req, unsigned long best,
+ unsigned long new)
{
- if (n >= c->num_fmax)
- return -ENXIO;
- return c->fmax[n];
+ if (IS_ERR_VALUE(new))
+ return false;
+
+ return (req <= new && new < best) || (best < req && best < new);
}
-static long clk_osm_round_rate(struct clk *c, unsigned long rate)
+static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
{
int i;
unsigned long rrate = 0;
/*
- * If the rate passed in is 0, return the first frequency in
- * the FMAX table.
+ * If the rate passed in is 0, return the first frequency in the
+ * FMAX table.
*/
if (!rate)
- return c->fmax[0];
+ return hw->init->rate_max[0];
- for (i = 0; i < c->num_fmax; i++) {
- if (is_better_rate(rate, rrate, c->fmax[i])) {
- rrate = c->fmax[i];
- if (rrate == rate)
+ for (i = 0; i < hw->init->num_rate_max; i++) {
+ if (is_better_rate(rate, rrate, hw->init->rate_max[i])) {
+ rrate = hw->init->rate_max[i];
+ if (rate == rrate)
break;
}
}
+ pr_debug("%s: rate %lu, rrate %ld, Rate max %ld\n", __func__, rate,
+ rrate, hw->init->rate_max[i]);
+
return rrate;
}
static int clk_osm_search_table(struct osm_entry *table, int entries, long rate)
{
- int i;
+ int quad_core_index, single_core_index = 0;
+ int core_count;
+
+ for (quad_core_index = 0; quad_core_index < entries;
+ quad_core_index++) {
+ core_count = CORE_COUNT_VAL(table[quad_core_index].freq_data);
+ if (rate == table[quad_core_index].frequency &&
+ core_count == SINGLE_CORE) {
+ single_core_index = quad_core_index;
+ continue;
+ }
+ if (rate == table[quad_core_index].frequency &&
+ core_count == MAX_CORE_COUNT)
+ return quad_core_index;
+ }
+ if (single_core_index)
+ return single_core_index;
- for (i = 0; i < entries; i++)
- if (rate == table[i].frequency)
- return i;
return -EINVAL;
}
-static int clk_osm_set_rate(struct clk *c, unsigned long rate)
+static int clk_osm_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
{
- struct clk_osm *cpuclk = to_clk_osm(c);
+ struct clk_osm *cpuclk = to_clk_osm(hw);
int index = 0;
unsigned long r_rate;
- r_rate = clk_osm_round_rate(c, rate);
+ r_rate = clk_osm_round_rate(hw, rate, NULL);
if (rate != r_rate) {
pr_err("invalid rate requested rate=%ld\n", rate);
@@ -675,9 +684,9 @@ static int clk_osm_set_rate(struct clk *c, unsigned long rate)
if (cpuclk->llm_sw_overr[0]) {
clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[0],
- LLM_SW_OVERRIDE_REG);
+ LLM_SW_OVERRIDE_REG);
clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[1],
- LLM_SW_OVERRIDE_REG);
+ LLM_SW_OVERRIDE_REG);
udelay(1);
}
@@ -687,7 +696,7 @@ static int clk_osm_set_rate(struct clk *c, unsigned long rate)
if (cpuclk->llm_sw_overr[0]) {
udelay(1);
clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[2],
- LLM_SW_OVERRIDE_REG);
+ LLM_SW_OVERRIDE_REG);
}
/* Make sure the write goes through before proceeding */
@@ -696,9 +705,9 @@ static int clk_osm_set_rate(struct clk *c, unsigned long rate)
return 0;
}
-static int clk_osm_enable(struct clk *c)
+static int clk_osm_enable(struct clk_hw *hw)
{
- struct clk_osm *cpuclk = to_clk_osm(c);
+ struct clk_osm *cpuclk = to_clk_osm(hw);
clk_osm_write_reg(cpuclk, 1, ENABLE_REG);
@@ -713,95 +722,108 @@ static int clk_osm_enable(struct clk *c)
return 0;
}
+static unsigned long clk_osm_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_osm *cpuclk = to_clk_osm(hw);
+ int index = 0;
+
+ index = clk_osm_read_reg(cpuclk, DCVS_PERF_STATE_DESIRED_REG);
+
+ pr_debug("%s: Index %d, freq %ld\n", __func__, index,
+ cpuclk->osm_table[index].frequency);
+
+ /* Convert index to frequency.
+ * The frequency corresponding to the index requested might not
+ * be what the clock is actually running at.
+ * There are other inputs into OSM(acd, LMH, sequencer)
+ * which might decide the final rate.
+ */
+ return cpuclk->osm_table[index].frequency;
+}
+
static struct clk_ops clk_ops_cpu_osm = {
.enable = clk_osm_enable,
.set_rate = clk_osm_set_rate,
.round_rate = clk_osm_round_rate,
.list_rate = clk_osm_list_rate,
- .handoff = clk_osm_handoff,
+ .recalc_rate = clk_osm_recalc_rate,
};
-static struct regulator *vdd_pwrcl;
-static struct regulator *vdd_perfcl;
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_XO, 0 },
+ { LMH_LITE_CLK_SRC, 1 },
+};
-static struct clk_freq_tbl ftbl_osm_clk_src[] = {
- F( 200000000, lmh_lite_clk_src, 1.5, 0, 0),
- F_END
+static const char * const gcc_parent_names_1[] = {
+ "xo",
+ "hmss_gpll0_clk_src",
};
-static struct rcg_clk osm_clk_src = {
- .cmd_rcgr_reg = APCS_COMMON_LMH_CMD_RCGR,
- .set_rate = set_rate_hid,
+static struct freq_tbl ftbl_osm_clk_src[] = {
+ F(200000000, LMH_LITE_CLK_SRC, 3, 0, 0),
+ { }
+};
+
+/* APCS_COMMON_LMH_CMD_RCGR */
+static struct clk_rcg2 osm_clk_src = {
+ .cmd_rcgr = 0x0012c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
.freq_tbl = ftbl_osm_clk_src,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_base,
- .c = {
- .dbg_name = "osm_clk_src",
- .ops = &clk_ops_rcg,
- CLK_INIT(osm_clk_src.c),
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "osm_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
},
};
-static struct clk_osm pwrcl_clk = {
- .cluster_num = 0,
- .cpu_reg_mask = 0x3,
- .c = {
- .dbg_name = "pwrcl_clk",
- .ops = &clk_ops_cpu_osm,
- .parent = &xo_ao.c,
- CLK_INIT(pwrcl_clk.c),
+static struct clk_fixed_factor sys_apcsaux_clk_gcc = {
+ .div = 1,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "sys_apcsaux_clk_gcc",
+ .parent_names = (const char *[]){ "hmss_gpll0_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
},
};
-static struct clk_osm perfcl_clk = {
- .cluster_num = 1,
- .cpu_reg_mask = 0x103,
- .c = {
- .dbg_name = "perfcl_clk",
+static struct clk_init_data osm_clks_init[] = {
+ [0] = {
+ .name = "pwrcl_clk",
+ .parent_names = (const char *[]){ "cxo_a" },
+ .num_parents = 1,
+ .ops = &clk_ops_cpu_osm,
+ },
+ [1] = {
+ .name = "perfcl_clk",
+ .parent_names = (const char *[]){ "cxo_a" },
+ .num_parents = 1,
.ops = &clk_ops_cpu_osm,
- .parent = &xo_ao.c,
- CLK_INIT(perfcl_clk.c),
},
};
-static struct clk_ops clk_ops_cpu_dbg_mux;
-
-static struct mux_clk cpu_debug_mux = {
- .offset = 0x0,
- .mask = 0x3,
- .shift = 8,
- .ops = &mux_reg_ops,
- MUX_SRC_LIST(
- { &pwrcl_clk.c, 0x00 },
- { &perfcl_clk.c, 0x01 },
- ),
- .base = &debug_base,
- .c = {
- .dbg_name = "cpu_debug_mux",
- .ops = &clk_ops_cpu_dbg_mux,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(cpu_debug_mux.c),
- },
+static struct clk_osm pwrcl_clk = {
+ .cluster_num = 0,
+ .cpu_reg_mask = 0x3,
+ .hw.init = &osm_clks_init[0],
};
-static struct clk_lookup cpu_clocks_osm[] = {
- CLK_LIST(pwrcl_clk),
- CLK_LIST(perfcl_clk),
- CLK_LIST(sys_apcsaux_clk_gcc),
- CLK_LIST(xo_ao),
- CLK_LIST(osm_clk_src),
- CLK_LIST(cpu_debug_mux),
+static struct clk_osm perfcl_clk = {
+ .cluster_num = 1,
+ .cpu_reg_mask = 0x103,
+ .hw.init = &osm_clks_init[1],
};
-static unsigned long cpu_dbg_mux_get_rate(struct clk *clk)
-{
- /* Account for the divider between the clock and the debug mux */
- if (!strcmp(clk->parent->dbg_name, "pwrcl_clk"))
- return clk->rate/4;
- else if (!strcmp(clk->parent->dbg_name, "perfcl_clk"))
- return clk->rate/8;
- return clk->rate;
-}
+static struct clk_hw *osm_qcom_clk_hws[] = {
+ [SYS_APCSAUX_CLK_GCC] = &sys_apcsaux_clk_gcc.hw,
+ [PWRCL_CLK] = &pwrcl_clk.hw,
+ [PERFCL_CLK] = &perfcl_clk.hw,
+ [OSM_CLK_SRC] = &osm_clk_src.clkr.hw,
+};
static void clk_osm_print_osm_table(struct clk_osm *c)
{
@@ -813,7 +835,7 @@ static void clk_osm_print_osm_table(struct clk_osm *c)
for (i = 0; i < c->num_entries; i++) {
pll_src = (table[i].freq_data & GENMASK(27, 26)) >> 26;
pll_div = (table[i].freq_data & GENMASK(25, 24)) >> 24;
- lval = table[i].freq_data & GENMASK(7, 0);
+ lval = L_VAL(table[i].freq_data);
core_count = (table[i].freq_data & GENMASK(18, 16)) >> 16;
pr_debug("%3d, %11lu, %2u, %5u, %2u, %6u, %8u, %7u, %5u\n",
@@ -828,18 +850,21 @@ static void clk_osm_print_osm_table(struct clk_osm *c)
table[i].spare_data);
}
pr_debug("APM threshold corner=%d, crossover corner=%d\n",
- c->apm_threshold_vc, c->apm_crossover_vc);
+ c->apm_threshold_vc, c->apm_crossover_vc);
+ pr_debug("MEM-ACC threshold corner=%d, crossover corner=%d\n",
+ c->mem_acc_threshold_vc, c->mem_acc_crossover_vc);
}
static int clk_osm_get_lut(struct platform_device *pdev,
struct clk_osm *c, char *prop_name)
{
- struct clk *clk = &c->c;
struct device_node *of = pdev->dev.of_node;
int prop_len, total_elems, num_rows, i, j, k;
int rc = 0;
u32 *array;
+ u32 *fmax_temp;
u32 data;
+ unsigned long abs_fmax = 0;
bool last_entry = false;
if (!of_find_property(of, prop_name, &prop_len)) {
@@ -855,9 +880,9 @@ static int clk_osm_get_lut(struct platform_device *pdev,
num_rows = total_elems / NUM_FIELDS;
- clk->fmax = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long),
- GFP_KERNEL);
- if (!clk->fmax)
+ fmax_temp = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!fmax_temp)
return -ENOMEM;
array = devm_kzalloc(&pdev->dev, prop_len, GFP_KERNEL);
@@ -893,18 +918,34 @@ static int clk_osm_get_lut(struct platform_device *pdev,
c->osm_table[j].spare_data);
data = (array[i + FREQ_DATA] & GENMASK(18, 16)) >> 16;
- if (!last_entry) {
- clk->fmax[k] = array[i];
+ if (!last_entry && data == MAX_CORE_COUNT) {
+ fmax_temp[k] = array[i];
k++;
}
if (i < total_elems - NUM_FIELDS)
i += NUM_FIELDS;
- else
+ else {
+ abs_fmax = array[i];
last_entry = true;
+ }
+ }
+ fmax_temp[k] = abs_fmax;
+
+ osm_clks_init[c->cluster_num].rate_max = devm_kzalloc(&pdev->dev,
+ k * sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!osm_clks_init[c->cluster_num].rate_max) {
+ rc = -ENOMEM;
+ goto exit;
}
- clk->num_fmax = k;
+
+ for (i = 0; i < k; i++)
+ osm_clks_init[c->cluster_num].rate_max[i] = fmax_temp[i];
+
+ osm_clks_init[c->cluster_num].num_rate_max = k;
exit:
+ devm_kfree(&pdev->dev, fmax_temp);
devm_kfree(&pdev->dev, array);
return rc;
}
@@ -1192,7 +1233,6 @@ static int clk_osm_resources_init(struct platform_device *pdev)
{
struct device_node *node;
struct resource *res;
- struct clk *c;
unsigned long pbase;
int i, rc = 0;
void *vbase;
@@ -1213,9 +1253,9 @@ static int clk_osm_resources_init(struct platform_device *pdev)
}
perfcl_clk.pbases[OSM_BASE] = pwrcl_clk.pbases[OSM_BASE] +
- perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE;
+ perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE;
perfcl_clk.vbases[OSM_BASE] = pwrcl_clk.vbases[OSM_BASE] +
- perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE;
+ perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE;
for (i = 0; i < MAX_CLUSTER_CNT; i++) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -1244,22 +1284,6 @@ static int clk_osm_resources_init(struct platform_device *pdev)
}
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug");
- if (!res) {
- dev_err(&pdev->dev, "Failed to get debug mux base\n");
- return -EINVAL;
- }
-
- debug_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!debug_base) {
- dev_err(&pdev->dev, "Unable to map in debug mux base\n");
- return -ENOMEM;
- }
-
- clk_ops_cpu_dbg_mux = clk_ops_gen_mux;
- clk_ops_cpu_dbg_mux.get_rate = cpu_dbg_mux_get_rate;
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_common");
if (!res) {
dev_err(&pdev->dev, "Failed to get apcs common base\n");
@@ -1272,6 +1296,13 @@ static int clk_osm_resources_init(struct platform_device *pdev)
return -ENOMEM;
}
+ osm_clk_src.clkr.regmap = devm_regmap_init_mmio(&pdev->dev, virt_base,
+ &osm_qcom_regmap_config);
+ if (IS_ERR(osm_clk_src.clkr.regmap)) {
+ dev_err(&pdev->dev, "Couldn't get regmap OSM clock\n");
+ return PTR_ERR(osm_clk_src.clkr.regmap);
+ }
+
/* efuse speed bin fuses are optional */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"pwrcl_efuse");
@@ -1381,26 +1412,6 @@ static int clk_osm_resources_init(struct platform_device *pdev)
return -EINVAL;
}
- c = devm_clk_get(&pdev->dev, "aux_clk");
- if (IS_ERR(c)) {
- rc = PTR_ERR(c);
- if (rc != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Unable to get aux_clk, rc=%d\n",
- rc);
- return rc;
- }
- sys_apcsaux_clk_gcc.c.parent = c;
-
- c = devm_clk_get(&pdev->dev, "xo_ao");
- if (IS_ERR(c)) {
- rc = PTR_ERR(c);
- if (rc != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Unable to get xo_ao clk, rc=%d\n",
- rc);
- return rc;
- }
- xo_ao.c.parent = c;
-
return 0;
}
@@ -1490,20 +1501,27 @@ static int clk_osm_resolve_open_loop_voltages(struct clk_osm *c)
}
static int clk_osm_resolve_crossover_corners(struct clk_osm *c,
- struct platform_device *pdev)
+ struct platform_device *pdev,
+ const char *mem_acc_prop)
{
struct regulator *regulator = c->vdd_reg;
- int count, vc, i, threshold, rc = 0;
+ int count, vc, i, apm_threshold;
+ int mem_acc_threshold = 0;
+ int rc = 0;
u32 corner_volt;
rc = of_property_read_u32(pdev->dev.of_node,
"qcom,apm-threshold-voltage",
- &threshold);
+ &apm_threshold);
if (rc) {
pr_info("qcom,apm-threshold-voltage property not specified\n");
return rc;
}
+ if (mem_acc_prop)
+ of_property_read_u32(pdev->dev.of_node, mem_acc_prop,
+ &mem_acc_threshold);
+
/* Determine crossover virtual corner */
count = regulator_count_voltages(regulator);
if (count < 0) {
@@ -1511,19 +1529,49 @@ static int clk_osm_resolve_crossover_corners(struct clk_osm *c,
return count;
}
- c->apm_crossover_vc = count - 1;
+ /*
+ * CPRh corners (in hardware) are ordered:
+ * 0 - n-1 - for n functional corners
+ * APM crossover - required for OSM
+ * [MEM ACC Crossover] - optional
+ *
+ * 'count' corresponds to the total number of corners including n
+ * functional corners, the APM crossover corner, and potentially the
+ * MEM ACC cross over corner.
+ */
+ if (mem_acc_threshold) {
+ c->apm_crossover_vc = count - 2;
+ c->mem_acc_crossover_vc = count - 1;
+ } else {
+ c->apm_crossover_vc = count - 1;
+ }
- /* Determine threshold virtual corner */
+ /* Determine APM threshold virtual corner */
for (i = 0; i < OSM_TABLE_SIZE; i++) {
vc = c->osm_table[i].virtual_corner + 1;
corner_volt = regulator_list_corner_voltage(regulator, vc);
- if (corner_volt >= threshold) {
+ if (corner_volt >= apm_threshold) {
c->apm_threshold_vc = c->osm_table[i].virtual_corner;
break;
}
}
+ /* Determine MEM ACC threshold virtual corner */
+ if (mem_acc_threshold) {
+ for (i = 0; i < OSM_TABLE_SIZE; i++) {
+ vc = c->osm_table[i].virtual_corner + 1;
+ corner_volt =
+ regulator_list_corner_voltage(regulator, vc);
+
+ if (corner_volt >= mem_acc_threshold) {
+ c->mem_acc_threshold_vc
+ = c->osm_table[i].virtual_corner;
+ break;
+ }
+ }
+ }
+
return 0;
}
@@ -1777,9 +1825,9 @@ static int clk_osm_set_llm_volt_policy(struct platform_device *pdev)
/* Enable or disable LLM VOLT DVCS */
regval = val | clk_osm_read_reg(&pwrcl_clk, LLM_INTF_DCVS_DISABLE);
- clk_osm_write_reg(&pwrcl_clk, val, LLM_INTF_DCVS_DISABLE);
+ clk_osm_write_reg(&pwrcl_clk, regval, LLM_INTF_DCVS_DISABLE);
regval = val | clk_osm_read_reg(&perfcl_clk, LLM_INTF_DCVS_DISABLE);
- clk_osm_write_reg(&perfcl_clk, val, LLM_INTF_DCVS_DISABLE);
+ clk_osm_write_reg(&perfcl_clk, regval, LLM_INTF_DCVS_DISABLE);
/* Wait for the writes to complete */
clk_osm_mb(&perfcl_clk, OSM_BASE);
@@ -1820,8 +1868,10 @@ static void clk_osm_program_apm_regs(struct clk_osm *c)
static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
{
+ struct osm_entry *table = c->osm_table;
int i, curr_level, j = 0;
int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {0, 0, 0};
+ int threshold_vc[4];
curr_level = c->osm_table[0].spare_data;
for (i = 0; i < c->num_entries; i++) {
@@ -1829,7 +1879,8 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
break;
if (c->osm_table[i].spare_data != curr_level) {
- mem_acc_level_map[j++] = i - 1;
+ mem_acc_level_map[j++] =
+ c->osm_table[i].virtual_corner - 1;
curr_level = c->osm_table[i].spare_data;
}
}
@@ -1855,16 +1906,49 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i],
MEM_ACC_SEQ_REG_CFG_START(i));
} else {
+ if (c->mem_acc_crossover_vc)
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(88),
+ c->mem_acc_crossover_vc);
+
+ threshold_vc[0] = mem_acc_level_map[0];
+ threshold_vc[1] = mem_acc_level_map[0] + 1;
+ threshold_vc[2] = mem_acc_level_map[1];
+ threshold_vc[3] = mem_acc_level_map[1] + 1;
+
+ /*
+ * Use dynamic MEM ACC threshold voltage based value for the
+ * highest MEM ACC threshold if it is specified instead of the
+ * fixed mapping in the LUT.
+ */
+ if (c->mem_acc_threshold_vc) {
+ threshold_vc[2] = c->mem_acc_threshold_vc - 1;
+ threshold_vc[3] = c->mem_acc_threshold_vc;
+ if (threshold_vc[1] >= threshold_vc[2])
+ threshold_vc[1] = threshold_vc[2] - 1;
+ if (threshold_vc[0] >= threshold_vc[1])
+ threshold_vc[0] = threshold_vc[1] - 1;
+ }
+
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(55),
- mem_acc_level_map[0]);
+ threshold_vc[0]);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(56),
- mem_acc_level_map[0] + 1);
+ threshold_vc[1]);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(57),
- mem_acc_level_map[1]);
+ threshold_vc[2]);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(58),
- mem_acc_level_map[1] + 1);
+ threshold_vc[3]);
/* SEQ_REG(49) = SEQ_REG(28) init by TZ */
}
+
+ /*
+ * Program L_VAL corresponding to the first virtual
+ * corner with MEM ACC level 3.
+ */
+ if (c->mem_acc_threshold_vc)
+ for (i = 0; i < c->num_entries; i++)
+ if (c->mem_acc_threshold_vc == table[i].virtual_corner)
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(32),
+ L_VAL(table[i].freq_data));
}
void clk_osm_setup_sequencer(struct clk_osm *c)
@@ -1895,93 +1979,13 @@ static void clk_osm_setup_cycle_counters(struct clk_osm *c)
/* Setup OSM clock to XO ratio */
do_div(ratio, c->xo_clk_rate);
val |= BVAL(5, 1, ratio - 1) | OSM_CYCLE_COUNTER_USE_XO_EDGE_EN;
+
clk_osm_write_reg(c, val, OSM_CYCLE_COUNTER_CTRL_REG);
+
c->total_cycle_counter = 0;
c->prev_cycle_counter = 0;
- pr_debug("OSM to XO clock ratio: %d\n", ratio);
-}
-
-static void clk_osm_setup_osm_was(struct clk_osm *c)
-{
- u32 cc_hyst;
- u32 val;
-
- if (msmcobalt_v2)
- return;
-
- val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
- val |= IGNORE_PLL_LOCK_MASK;
- cc_hyst = clk_osm_read_reg(c, SPM_CC_HYSTERESIS);
-
- if (c->secure_init) {
- clk_osm_write_reg(c, val, SEQ_REG(47));
- val &= ~IGNORE_PLL_LOCK_MASK;
- clk_osm_write_reg(c, val, SEQ_REG(48));
-
- clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(42),
- SEQ_REG(40));
- clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(43),
- SEQ_REG(41));
- clk_osm_write_reg(c, 0x1, SEQ_REG(44));
- clk_osm_write_reg(c, 0x0, SEQ_REG(45));
- clk_osm_write_reg(c, c->pbases[OSM_BASE] + PDN_FSM_CTRL_REG,
- SEQ_REG(46));
-
- /* C2D/C3 + D2D workaround */
- clk_osm_write_reg(c, c->pbases[OSM_BASE] + SPM_CC_HYSTERESIS,
- SEQ_REG(6));
- clk_osm_write_reg(c, cc_hyst, SEQ_REG(7));
-
- /* Droop detector PLL lock detect workaround */
- clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_ENABLE, SEQ_REG(4));
- clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_DISABLE, SEQ_REG(5));
- clk_osm_write_reg(c, c->cluster_num == 0 ? PLL_DD_D0_USER_CTL_LO
- : PLL_DD_D1_USER_CTL_LO, SEQ_REG(21));
-
- /* PLL lock detect and HMSS AHB clock workaround */
- clk_osm_write_reg(c, 0x640, CFG_DELAY_VAL_3);
-
- /* DxFSM workaround */
- clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911200 :
- 0x17811200, SEQ_REG(22));
- clk_osm_write_reg(c, 0x80800, SEQ_REG(23));
- clk_osm_write_reg(c, 0x179D1100, SEQ_REG(24));
- clk_osm_write_reg(c, 0x11f, SEQ_REG(25));
- clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17912000 :
- 0x17811290, SEQ_REG(26));
- clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911290 :
- 0x17811290, SEQ_REG(20));
- clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17811290 :
- 0x17911290, SEQ_REG(32));
- clk_osm_write_reg(c, 0x179D4020, SEQ_REG(35));
- clk_osm_write_reg(c, 0x11f, SEQ_REG(25));
- clk_osm_write_reg(c, 0xa, SEQ_REG(86));
- clk_osm_write_reg(c, 0xe, SEQ_REG(87));
- clk_osm_write_reg(c, 0x00400000, SEQ_REG(88));
- clk_osm_write_reg(c, 0x00700000, SEQ_REG(89));
- } else {
- scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(47), val);
- val &= ~IGNORE_PLL_LOCK_MASK;
- scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(48), val);
-
- /* C2D/C3 + D2D workaround */
- scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(7),
- cc_hyst);
-
- /* Droop detector PLL lock detect workaround */
- scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(4),
- PLL_DD_USER_CTL_LO_ENABLE);
- }
-
- if (c->cluster_num == 0) {
- val = readl_relaxed(c->vbases[PLL_BASE] + PLL_TEST_CTL_HI)
- | BIT(13);
- writel_relaxed(val, c->vbases[PLL_BASE] +
- PLL_TEST_CTL_HI);
- }
- /* Ensure writes complete before returning */
- clk_osm_mb(c, OSM_BASE);
+ pr_debug("OSM to XO clock ratio: %d\n", ratio);
}
static void clk_osm_setup_fsms(struct clk_osm *c)
@@ -2128,7 +2132,7 @@ static void clk_osm_do_additional_setup(struct clk_osm *c,
return;
dev_info(&pdev->dev, "Performing additional OSM setup due to lack of TZ for cluster=%d\n",
- c->cluster_num);
+ c->cluster_num);
clk_osm_write_reg(c, BVAL(23, 16, 0xF), SPM_CC_CTRL);
@@ -2157,7 +2161,7 @@ static void clk_osm_do_additional_setup(struct clk_osm *c,
/* ITM to OSM handoff */
clk_osm_setup_itm_to_osm_handoff();
- pr_debug("seq_size: %lu, seqbr_size: %lu\n", ARRAY_SIZE(seq_instr),
+ pr_debug("seq_size: %zu, seqbr_size: %zu\n", ARRAY_SIZE(seq_instr),
ARRAY_SIZE(seq_br_instr));
clk_osm_setup_sequencer(&pwrcl_clk);
clk_osm_setup_sequencer(&perfcl_clk);
@@ -2175,38 +2179,31 @@ static void clk_osm_apm_vc_setup(struct clk_osm *c)
clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(1));
clk_osm_write_reg(c, c->apm_crossover_vc, SEQ_REG(72));
clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(1),
- SEQ_REG(8));
- clk_osm_write_reg(c, c->apm_threshold_vc,
- SEQ_REG(15));
+ SEQ_REG(8));
+ clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(15));
clk_osm_write_reg(c, c->apm_threshold_vc != 0 ?
- c->apm_threshold_vc - 1 : 0xff,
- SEQ_REG(31));
+ c->apm_threshold_vc - 1 : 0xff,
+ SEQ_REG(31));
clk_osm_write_reg(c, 0x3b | c->apm_threshold_vc << 6,
- SEQ_REG(73));
+ SEQ_REG(73));
clk_osm_write_reg(c, 0x39 | c->apm_threshold_vc << 6,
- SEQ_REG(76));
+ SEQ_REG(76));
/* Ensure writes complete before returning */
clk_osm_mb(c, OSM_BASE);
} else {
- if (msmcobalt_v1) {
- scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(1),
- c->apm_threshold_vc);
- scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(73),
- 0x3b | c->apm_threshold_vc << 6);
- } else if (msmcobalt_v2) {
+ if (c->apm_threshold_vc)
clk_osm_write_reg(c, c->apm_threshold_vc,
- SEQ_REG1_MSMCOBALT_V2);
- }
+ SEQ_REG1_OFFSET);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(72),
- c->apm_crossover_vc);
+ c->apm_crossover_vc);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(15),
- c->apm_threshold_vc);
+ c->apm_threshold_vc);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(31),
- c->apm_threshold_vc != 0 ?
- c->apm_threshold_vc - 1 : 0xff);
+ c->apm_threshold_vc != 0 ?
+ c->apm_threshold_vc - 1 : 0xff);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(76),
- 0x39 | c->apm_threshold_vc << 6);
+ 0x39 | c->apm_threshold_vc << 6);
}
}
@@ -2298,11 +2295,12 @@ static int add_opp(struct clk_osm *c, struct device *dev)
u32 uv;
long rc;
int j = 0;
- unsigned long min_rate = c->c.fmax[0];
- unsigned long max_rate = c->c.fmax[c->c.num_fmax - 1];
+ unsigned long min_rate = c->hw.init->rate_max[0];
+ unsigned long max_rate =
+ c->hw.init->rate_max[c->hw.init->num_rate_max - 1];
while (1) {
- rate = c->c.fmax[j++];
+ rate = c->hw.init->rate_max[j++];
uv = find_voltage(c, rate);
if (uv <= 0) {
pr_warn("No voltage for %lu.\n", rate);
@@ -2360,12 +2358,12 @@ static struct clk *logical_cpu_to_clk(int cpu)
hwid = of_read_number(cell, of_n_addr_cells(cpu_node));
if ((hwid | pwrcl_clk.cpu_reg_mask) == pwrcl_clk.cpu_reg_mask) {
- cpu_clk_map[cpu] = &pwrcl_clk.c;
- return &pwrcl_clk.c;
+ cpu_clk_map[cpu] = pwrcl_clk.hw.clk;
+ return pwrcl_clk.hw.clk;
}
if ((hwid | perfcl_clk.cpu_reg_mask) == perfcl_clk.cpu_reg_mask) {
- cpu_clk_map[cpu] = &perfcl_clk.c;
- return &perfcl_clk.c;
+ cpu_clk_map[cpu] = perfcl_clk.hw.clk;
+ return perfcl_clk.hw.clk;
}
fail:
@@ -2378,9 +2376,9 @@ static u64 clk_osm_get_cpu_cycle_counter(int cpu)
u32 val;
unsigned long flags;
- if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c)
+ if (logical_cpu_to_clk(cpu) == pwrcl_clk.hw.clk)
c = &pwrcl_clk;
- else if (logical_cpu_to_clk(cpu) == &perfcl_clk.c)
+ else if (logical_cpu_to_clk(cpu) == perfcl_clk.hw.clk)
c = &perfcl_clk;
else {
pr_err("no clock device for CPU=%d\n", cpu);
@@ -2409,11 +2407,11 @@ static void populate_opp_table(struct platform_device *pdev)
int cpu;
for_each_possible_cpu(cpu) {
- if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c) {
+ if (logical_cpu_to_clk(cpu) == pwrcl_clk.hw.clk) {
WARN(add_opp(&pwrcl_clk, get_cpu_device(cpu)),
"Failed to add OPP levels for power cluster\n");
}
- if (logical_cpu_to_clk(cpu) == &perfcl_clk.c) {
+ if (logical_cpu_to_clk(cpu) == perfcl_clk.hw.clk) {
WARN(add_opp(&perfcl_clk, get_cpu_device(cpu)),
"Failed to add OPP levels for perf cluster\n");
}
@@ -2456,15 +2454,11 @@ static int debugfs_set_wdog_trace(void *data, u64 val)
struct clk_osm *c = data;
int regval;
- if (c->version >= VERSION_1P1) {
- regval = clk_osm_read_reg(c, TRACE_CTRL);
- regval = val ? regval | TRACE_CTRL_ENABLE_WDOG_STATUS :
+ regval = clk_osm_read_reg(c, TRACE_CTRL);
+ regval = val ? regval | TRACE_CTRL_ENABLE_WDOG_STATUS :
regval & ~TRACE_CTRL_ENABLE_WDOG_STATUS;
- clk_osm_write_reg(c, regval, TRACE_CTRL);
- c->wdog_trace_en = val ? true : false;
- } else {
- pr_info("wdog status registers enabled by default\n");
- }
+ clk_osm_write_reg(c, regval, TRACE_CTRL);
+ c->wdog_trace_en = val ? true : false;
return 0;
}
@@ -2618,7 +2612,7 @@ static int debugfs_set_trace_periodic_timer(void *data, u64 val)
struct clk_osm *c = data;
if (val < PERIODIC_TRACE_MIN_NS || val > PERIODIC_TRACE_MAX_NS) {
- pr_err("supported periodic trace periods=%d-%ld ns\n",
+ pr_err("supported periodic trace periods=%d-%lld ns\n",
PERIODIC_TRACE_MIN_NS, PERIODIC_TRACE_MAX_NS);
return 0;
}
@@ -2760,7 +2754,7 @@ static void populate_debugfs_dir(struct clk_osm *c)
}
}
- c->debugfs = debugfs_create_dir(c->c.dbg_name, osm_debugfs_base);
+ c->debugfs = debugfs_create_dir(c->hw.init->name, osm_debugfs_base);
if (IS_ERR_OR_NULL(c->debugfs)) {
pr_err("osm debugfs directory creation failed\n");
return;
@@ -2977,31 +2971,60 @@ static int clk_osm_acd_init(struct clk_osm *c)
static unsigned long init_rate = 300000000;
static unsigned long osm_clk_init_rate = 200000000;
+static unsigned long pwrcl_boot_rate = 1401600000;
+static unsigned long perfcl_boot_rate = 1747200000;
-static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
+static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
{
- int rc, cpu;
+ int rc, cpu, i;
int speedbin = 0, pvs_ver = 0;
u32 pte_efuse;
- char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0";
+ int num_clks = ARRAY_SIZE(osm_qcom_clk_hws);
+ struct clk *clk;
+ struct clk *ext_xo_clk, *ext_hmss_gpll0_clk_src;
+ struct device *dev = &pdev->dev;
+ struct clk_onecell_data *clk_data;
char perfclspeedbinstr[] = "qcom,perfcl-speedbin0-v0";
+ char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0";
struct cpu_cycle_counter_cb cb = {
.get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter,
};
- if (of_find_compatible_node(NULL, NULL,
- "qcom,cpu-clock-osm-msmcobalt-v1")) {
- msmcobalt_v1 = true;
- } else if (of_find_compatible_node(NULL, NULL,
- "qcom,cpu-clock-osm-msmcobalt-v2")) {
- msmcobalt_v2 = true;
+ /*
+ * Require the RPM-XO clock and GCC-HMSS-GPLL0 clocks to be registererd
+ * before OSM.
+ */
+ ext_xo_clk = devm_clk_get(dev, "xo_a");
+ if (IS_ERR(ext_xo_clk)) {
+ if (PTR_ERR(ext_xo_clk) != -EPROBE_DEFER)
+ dev_err(dev, "Unable to get xo clock\n");
+ return PTR_ERR(ext_xo_clk);
+ }
+
+ ext_hmss_gpll0_clk_src = devm_clk_get(dev, "aux_clk");
+ if (IS_ERR(ext_hmss_gpll0_clk_src)) {
+ if (PTR_ERR(ext_hmss_gpll0_clk_src) != -EPROBE_DEFER)
+ dev_err(dev, "Unable to get aux_clk clock\n");
+ return PTR_ERR(ext_hmss_gpll0_clk_src);
}
+ clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
+ GFP_KERNEL);
+ if (!clk_data)
+ goto exit;
+
+ clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks *
+ sizeof(struct clk *)), GFP_KERNEL);
+ if (!clk_data->clks)
+ goto clk_err;
+
+ clk_data->clk_num = num_clks;
+
rc = clk_osm_resources_init(pdev);
if (rc) {
if (rc != -EPROBE_DEFER)
dev_err(&pdev->dev, "resources init failed, rc=%d\n",
- rc);
+ rc);
return rc;
}
@@ -3011,17 +3034,11 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
return rc;
}
- if ((pwrcl_clk.secure_init || perfcl_clk.secure_init) &&
- msmcobalt_v2) {
- pr_err("unsupported configuration for msmcobalt v2\n");
- return -EINVAL;
- }
-
if (pwrcl_clk.vbases[EFUSE_BASE]) {
/* Multiple speed-bins are supported */
pte_efuse = readl_relaxed(pwrcl_clk.vbases[EFUSE_BASE]);
speedbin = ((pte_efuse >> PWRCL_EFUSE_SHIFT) &
- PWRCL_EFUSE_MASK);
+ PWRCL_EFUSE_MASK);
snprintf(pwrclspeedbinstr, ARRAY_SIZE(pwrclspeedbinstr),
"qcom,pwrcl-speedbin%d-v%d", speedbin, pvs_ver);
}
@@ -3029,8 +3046,7 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "using pwrcl speed bin %u and pvs_ver %d\n",
speedbin, pvs_ver);
- rc = clk_osm_get_lut(pdev, &pwrcl_clk,
- pwrclspeedbinstr);
+ rc = clk_osm_get_lut(pdev, &pwrcl_clk, pwrclspeedbinstr);
if (rc) {
dev_err(&pdev->dev, "Unable to get OSM LUT for power cluster, rc=%d\n",
rc);
@@ -3041,7 +3057,7 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
/* Multiple speed-bins are supported */
pte_efuse = readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]);
speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT) &
- PERFCL_EFUSE_MASK);
+ PERFCL_EFUSE_MASK);
snprintf(perfclspeedbinstr, ARRAY_SIZE(perfclspeedbinstr),
"qcom,perfcl-speedbin%d-v%d", speedbin, pvs_ver);
}
@@ -3074,13 +3090,14 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
return rc;
}
- rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev);
+ rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev, NULL);
if (rc)
dev_info(&pdev->dev, "No APM crossover corner programmed\n");
- rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev);
+ rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev,
+ "qcom,perfcl-apcs-mem-acc-threshold-voltage");
if (rc)
- dev_info(&pdev->dev, "No APM crossover corner programmed\n");
+ dev_info(&pdev->dev, "No MEM-ACC crossover corner programmed\n");
clk_osm_setup_cycle_counters(&pwrcl_clk);
clk_osm_setup_cycle_counters(&perfcl_clk);
@@ -3146,11 +3163,7 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
if (rc)
pr_err("Debug IRQ not set for perfcl\n");
- clk_osm_setup_osm_was(&pwrcl_clk);
- clk_osm_setup_osm_was(&perfcl_clk);
-
- if (of_property_read_bool(pdev->dev.of_node,
- "qcom,osm-pll-setup")) {
+ if (of_property_read_bool(pdev->dev.of_node, "qcom,osm-pll-setup")) {
clk_osm_setup_cluster_pll(&pwrcl_clk);
clk_osm_setup_cluster_pll(&perfcl_clk);
}
@@ -3176,12 +3189,22 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
atomic_notifier_chain_register(&panic_notifier_list,
&perfcl_clk.panic_notifier);
- rc = of_msm_clock_register(pdev->dev.of_node, cpu_clocks_osm,
- ARRAY_SIZE(cpu_clocks_osm));
+ /* Register OSM pwr and perf clocks with Clock Framework */
+ for (i = 0; i < num_clks; i++) {
+ clk = devm_clk_register(&pdev->dev, osm_qcom_clk_hws[i]);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Unable to register CPU clock at index %d\n",
+ i);
+ return PTR_ERR(clk);
+ }
+ clk_data->clks[i] = clk;
+ }
+
+ rc = of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get,
+ clk_data);
if (rc) {
- dev_err(&pdev->dev, "Unable to register CPU clocks, rc=%d\n",
- rc);
- return rc;
+ dev_err(&pdev->dev, "Unable to register CPU clocks\n");
+ goto provider_err;
}
/*
@@ -3189,15 +3212,15 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
* frequency before enabling OSM. LUT index 0 is always sourced from
* this clock.
*/
- rc = clk_set_rate(&sys_apcsaux_clk_gcc.c, init_rate);
+ rc = clk_set_rate(sys_apcsaux_clk_gcc.hw.clk, init_rate);
if (rc) {
dev_err(&pdev->dev, "Unable to set init rate on hmss_gpll0, rc=%d\n",
rc);
return rc;
}
- clk_prepare_enable(&sys_apcsaux_clk_gcc.c);
+ clk_prepare_enable(sys_apcsaux_clk_gcc.hw.clk);
- rc = clk_set_rate(&osm_clk_src.c, osm_clk_init_rate);
+ rc = clk_set_rate(osm_clk_src.clkr.hw.clk, osm_clk_init_rate);
if (rc) {
dev_err(&pdev->dev, "Unable to set init rate on osm_clk, rc=%d\n",
rc);
@@ -3205,14 +3228,14 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
}
/* Make sure index zero is selected */
- rc = clk_set_rate(&pwrcl_clk.c, init_rate);
+ rc = clk_set_rate(pwrcl_clk.hw.clk, init_rate);
if (rc) {
dev_err(&pdev->dev, "Unable to set init rate on pwr cluster, rc=%d\n",
rc);
goto exit2;
}
- rc = clk_set_rate(&perfcl_clk.c, init_rate);
+ rc = clk_set_rate(perfcl_clk.hw.clk, init_rate);
if (rc) {
dev_err(&pdev->dev, "Unable to set init rate on perf cluster, rc=%d\n",
rc);
@@ -3228,27 +3251,20 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
}
/* Set final boot rate */
- rc = clk_set_rate(&pwrcl_clk.c, msmcobalt_v1 ?
- MSMCOBALTV1_PWRCL_BOOT_RATE :
- MSMCOBALTV2_PWRCL_BOOT_RATE);
+ rc = clk_set_rate(pwrcl_clk.hw.clk, pwrcl_boot_rate);
if (rc) {
dev_err(&pdev->dev, "Unable to set boot rate on pwr cluster, rc=%d\n",
rc);
goto exit2;
}
- rc = clk_set_rate(&perfcl_clk.c, msmcobalt_v1 ?
- MSMCOBALTV1_PERFCL_BOOT_RATE :
- MSMCOBALTV2_PERFCL_BOOT_RATE);
+ rc = clk_set_rate(perfcl_clk.hw.clk, perfcl_boot_rate);
if (rc) {
dev_err(&pdev->dev, "Unable to set boot rate on perf cluster, rc=%d\n",
rc);
goto exit2;
}
- pwrcl_clk.version = clk_osm_read_reg(&pwrcl_clk, VERSION_REG);
- perfcl_clk.version = clk_osm_read_reg(&perfcl_clk, VERSION_REG);
-
populate_opp_table(pdev);
populate_debugfs_dir(&pwrcl_clk);
populate_debugfs_dir(&perfcl_clk);
@@ -3263,39 +3279,42 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
return 0;
exit2:
- clk_disable_unprepare(&sys_apcsaux_clk_gcc.c);
+ clk_disable_unprepare(sys_apcsaux_clk_gcc.hw.clk);
+provider_err:
+ if (clk_data)
+ devm_kfree(&pdev->dev, clk_data->clks);
+clk_err:
+ devm_kfree(&pdev->dev, clk_data);
exit:
- dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n",
- rc);
+ dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n", rc);
panic("Unable to Setup OSM");
}
static const struct of_device_id match_table[] = {
- { .compatible = "qcom,cpu-clock-osm-msmcobalt-v1" },
- { .compatible = "qcom,cpu-clock-osm-msmcobalt-v2" },
+ { .compatible = "qcom,clk-cpu-osm" },
{}
};
-static struct platform_driver cpu_clock_osm_driver = {
- .probe = cpu_clock_osm_driver_probe,
+static struct platform_driver clk_cpu_osm_driver = {
+ .probe = clk_cpu_osm_driver_probe,
.driver = {
- .name = "cpu-clock-osm",
+ .name = "clk-cpu-osm",
.of_match_table = match_table,
.owner = THIS_MODULE,
},
};
-static int __init cpu_clock_osm_init(void)
+static int __init clk_cpu_osm_init(void)
{
- return platform_driver_register(&cpu_clock_osm_driver);
+ return platform_driver_register(&clk_cpu_osm_driver);
}
-arch_initcall(cpu_clock_osm_init);
+arch_initcall(clk_cpu_osm_init);
-static void __exit cpu_clock_osm_exit(void)
+static void __exit clk_cpu_osm_exit(void)
{
- platform_driver_unregister(&cpu_clock_osm_driver);
+ platform_driver_unregister(&clk_cpu_osm_driver);
}
-module_exit(cpu_clock_osm_exit);
+module_exit(clk_cpu_osm_exit);
MODULE_DESCRIPTION("CPU clock driver for OSM");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index c6ea293a8df3..d14c32bffe14 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -551,6 +551,39 @@ DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk2_pin, bb_clk2_a_pin, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk1_pin, rf_clk1_a_pin, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk2_pin, rf_clk2_a_pin, 5);
+/* Voter clocks */
+static DEFINE_CLK_VOTER(mmssnoc_axi_clk, mmssnoc_axi_rpm_clk, 0);
+static DEFINE_CLK_VOTER(mmssnoc_axi_a_clk, mmssnoc_axi_rpm_a_clk, 0);
+static DEFINE_CLK_VOTER(mmssnoc_gds_clk, mmssnoc_axi_rpm_clk, 40000000);
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, bimc_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, bimc_a_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_clk, cnoc_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, cnoc_a_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, snoc_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, snoc_a_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_periph_keepalive_a_clk, cnoc_periph_a_clk,
+ LONG_MAX);
+static DEFINE_CLK_VOTER(mcd_ce1_clk, ce1_clk, 85710000);
+static DEFINE_CLK_VOTER(qcedev_ce1_clk, ce1_clk, 85710000);
+static DEFINE_CLK_VOTER(qcrypto_ce1_clk, ce1_clk, 85710000);
+static DEFINE_CLK_VOTER(qseecom_ce1_clk, ce1_clk, 85710000);
+static DEFINE_CLK_VOTER(scm_ce1_clk, ce1_clk, 85710000);
+static DEFINE_CLK_VOTER(pnoc_keepalive_a_clk, pnoc_a_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_msmbus_clk, pnoc_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, pnoc_a_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_pm_clk, pnoc_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_sps_clk, pnoc_clk, 0);
+static DEFINE_CLK_VOTER(mmssnoc_a_clk_cpu_vote, mmssnoc_axi_rpm_a_clk,
+ 19200000);
+
+/* Voter Branch clocks */
+static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, cxo);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, cxo);
+static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, cxo);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_lpass_clk, cxo);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_ssc_clk, cxo);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_cdsp_clk, cxo);
+
static struct clk_hw *msm8996_clks[] = {
[RPM_XO_CLK_SRC] = &msm8996_cxo.hw,
[RPM_XO_A_CLK_SRC] = &msm8996_cxo_a.hw,
@@ -590,6 +623,31 @@ static struct clk_hw *msm8996_clks[] = {
[RPM_DIV_CLK3_AO] = &msm8996_div_clk3_ao.hw,
[RPM_LN_BB_CLK] = &msm8996_ln_bb_clk.hw,
[RPM_LN_BB_A_CLK] = &msm8996_ln_bb_a_clk.hw,
+ [MMSSNOC_AXI_CLK] = &mmssnoc_axi_clk.hw,
+ [MMSSNOC_AXI_A_CLK] = &mmssnoc_axi_a_clk.hw,
+ [MMSSNOC_GDS_CLK] = &mmssnoc_gds_clk.hw,
+ [BIMC_MSMBUS_CLK] = &bimc_msmbus_clk.hw,
+ [BIMC_MSMBUS_A_CLK] = &bimc_msmbus_a_clk.hw,
+ [CNOC_MSMBUS_CLK] = &cnoc_msmbus_clk.hw,
+ [CNOC_MSMBUS_A_CLK] = &cnoc_msmbus_a_clk.hw,
+ [PNOC_KEEPALIVE_A_CLK] = &pnoc_keepalive_a_clk.hw,
+ [PNOC_MSMBUS_CLK] = &pnoc_msmbus_clk.hw,
+ [PNOC_MSMBUS_A_CLK] = &pnoc_msmbus_a_clk.hw,
+ [PNOC_PM_CLK] = &pnoc_pm_clk.hw,
+ [PNOC_SPS_CLK] = &pnoc_sps_clk.hw,
+ [MCD_CE1_CLK] = &mcd_ce1_clk.hw,
+ [QCEDEV_CE1_CLK] = &qcedev_ce1_clk.hw,
+ [QCRYPTO_CE1_CLK] = &qcrypto_ce1_clk.hw,
+ [QSEECOM_CE1_CLK] = &qseecom_ce1_clk.hw,
+ [SCM_CE1_CLK] = &scm_ce1_clk.hw,
+ [SNOC_MSMBUS_CLK] = &snoc_msmbus_clk.hw,
+ [SNOC_MSMBUS_A_CLK] = &snoc_msmbus_a_clk.hw,
+ [CXO_DWC3_CLK] = &cxo_dwc3_clk.hw,
+ [CXO_LPM_CLK] = &cxo_lpm_clk.hw,
+ [CXO_OTG_CLK] = &cxo_otg_clk.hw,
+ [CXO_PIL_LPASS_CLK] = &cxo_pil_lpass_clk.hw,
+ [CXO_PIL_SSC_CLK] = &cxo_pil_ssc_clk.hw,
+ [MMSSNOC_A_CLK_CPU_VOTE] = &mmssnoc_a_clk_cpu_vote.hw
};
static const struct rpm_smd_clk_desc rpm_clk_msm8996 = {
@@ -627,26 +685,6 @@ DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, ln_bb_clk2_pin,
ln_bb_clk2_pin_ao, 0x2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, ln_bb_clk3_pin,
ln_bb_clk3_pin_ao, 0x3);
-/* Voter clocks */
-static DEFINE_CLK_VOTER(bimc_msmbus_clk, bimc_clk, LONG_MAX);
-static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, bimc_a_clk, LONG_MAX);
-static DEFINE_CLK_VOTER(cnoc_msmbus_clk, cnoc_clk, LONG_MAX);
-static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, cnoc_a_clk, LONG_MAX);
-static DEFINE_CLK_VOTER(snoc_msmbus_clk, snoc_clk, LONG_MAX);
-static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, snoc_a_clk, LONG_MAX);
-static DEFINE_CLK_VOTER(cnoc_periph_keepalive_a_clk, cnoc_periph_a_clk,
- LONG_MAX);
-static DEFINE_CLK_VOTER(mcd_ce1_clk, ce1_clk, 85710000);
-static DEFINE_CLK_VOTER(qcedev_ce1_clk, ce1_clk, 85710000);
-static DEFINE_CLK_VOTER(qcrypto_ce1_clk, ce1_clk, 85710000);
-static DEFINE_CLK_VOTER(qseecom_ce1_clk, ce1_clk, 85710000);
-static DEFINE_CLK_VOTER(scm_ce1_clk, ce1_clk, 85710000);
-
-static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, cxo);
-static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, cxo);
-static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, cxo);
-static DEFINE_CLK_BRANCH_VOTER(cxo_pil_lpass_clk, cxo);
-static DEFINE_CLK_BRANCH_VOTER(cxo_pil_cdsp_clk, cxo);
static struct clk_hw *msmfalcon_clks[] = {
[RPM_XO_CLK_SRC] = &msmfalcon_cxo.hw,
@@ -799,10 +837,19 @@ static int rpm_smd_clk_probe(struct platform_device *pdev)
if (ret)
goto err;
- /* Keep an active vote on CXO in case no other driver votes for it */
- if (is_8996)
+ if (is_8996) {
+ /*
+ * Keep an active vote on CXO in case no other driver
+ * votes for it.
+ */
clk_prepare_enable(msm8996_cxo_a.hw.clk);
- else if (is_falcon) {
+
+ /* Hold an active set vote for the pnoc_keepalive_a_clk */
+ clk_set_rate(pnoc_keepalive_a_clk.hw.clk, 19200000);
+ clk_prepare_enable(pnoc_keepalive_a_clk.hw.clk);
+
+ clk_prepare_enable(mmssnoc_a_clk_cpu_vote.hw.clk);
+ } else if (is_falcon) {
clk_prepare_enable(msmfalcon_cxo_a.hw.clk);
/* Hold an active set vote for the cnoc_periph resource */
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index 841367eb21ff..76c010970b51 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -137,6 +137,7 @@ struct clk_debug_mux {
};
#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
+#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb))
#define to_clk_measure(_hw) container_of((_hw), struct clk_debug_mux, hw)
diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c
index 0f39bf278cd4..51c85e08372c 100644
--- a/drivers/clk/qcom/gcc-msm8996.c
+++ b/drivers/clk/qcom/gcc-msm8996.c
@@ -31,9 +31,12 @@
#include "clk-rcg.h"
#include "clk-branch.h"
#include "reset.h"
+#include "vdd-level-8996.h"
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+
enum {
P_XO,
P_GPLL0,
@@ -89,7 +92,7 @@ static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
static const char * const gcc_xo_gpll0_gpll4[] = {
"xo",
"gpll0",
- "gpll4"
+ "gpll4_early"
};
static const struct parent_map gcc_xo_gpll0_aud_ref_clk_map[] = {
@@ -128,7 +131,7 @@ static const struct parent_map gcc_xo_gpll0_gpll4_gpll0_early_div_map[] = {
static const char * const gcc_xo_gpll0_gpll4_gpll0_early_div[] = {
"xo",
"gpll0",
- "gpll4",
+ "gpll4_early",
"gpll0_early_div"
};
@@ -162,7 +165,7 @@ static const char * const gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_d
"gpll0",
"gpll1_early_div",
"gpll1",
- "gpll4",
+ "gpll4_early",
"gpll0_early_div"
};
@@ -202,10 +205,24 @@ static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div[]
"gpll2",
"gpll3",
"gpll1",
- "gpll4",
+ "gpll4_early",
"gpll0_early_div"
};
+static struct clk_fixed_factor gcc_ce1_ahb_m_clk = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ce1_ahb_m_clk",
+ .ops = &clk_dummy_ops,
+ },
+};
+
+static struct clk_fixed_factor gcc_ce1_axi_m_clk = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ce1_axi_m_clk",
+ .ops = &clk_dummy_ops,
+ },
+};
+
static struct clk_fixed_factor xo = {
.mult = 1,
.div = 1,
@@ -294,6 +311,8 @@ static struct clk_rcg2 usb30_master_clk_src = {
.parent_names = gcc_xo_gpll0_gpll0_early_div,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 60000000, LOW, 120000000,
+ NOMINAL, 150000000),
},
};
@@ -312,6 +331,7 @@ static struct clk_rcg2 usb30_mock_utmi_clk_src = {
.parent_names = gcc_xo_gpll0_gpll0_early_div,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 40000000, LOW, 60000000),
},
};
@@ -330,6 +350,7 @@ static struct clk_rcg2 usb3_phy_aux_clk_src = {
.parent_names = gcc_xo_sleep_clk,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(LOWER, 1200000),
},
};
@@ -349,6 +370,8 @@ static struct clk_rcg2 usb20_master_clk_src = {
.parent_names = gcc_xo_gpll0_gpll0_early_div,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 60000000,
+ NOMINAL, 120000000),
},
};
@@ -362,6 +385,7 @@ static struct clk_rcg2 usb20_mock_utmi_clk_src = {
.parent_names = gcc_xo_gpll0_gpll0_early_div,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 60000000),
},
};
@@ -388,6 +412,8 @@ static struct clk_rcg2 sdcc1_apps_clk_src = {
.parent_names = gcc_xo_gpll0_gpll4_gpll0_early_div,
.num_parents = 4,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 200000000,
+ NOMINAL, 400000000),
},
};
@@ -408,6 +434,8 @@ static struct clk_rcg2 sdcc1_ice_core_clk_src = {
.parent_names = gcc_xo_gpll0_gpll4_gpll0_early_div,
.num_parents = 4,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 150000000,
+ NOMINAL, 300000000),
},
};
@@ -433,6 +461,8 @@ static struct clk_rcg2 sdcc2_apps_clk_src = {
.parent_names = gcc_xo_gpll0_gpll4,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 100000000,
+ NOMINAL, 200000000),
},
};
@@ -447,6 +477,8 @@ static struct clk_rcg2 sdcc3_apps_clk_src = {
.parent_names = gcc_xo_gpll0_gpll4,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 100000000,
+ NOMINAL, 200000000),
},
};
@@ -471,6 +503,8 @@ static struct clk_rcg2 sdcc4_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 50000000,
+ NOMINAL, 100000000),
},
};
@@ -496,6 +530,8 @@ static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -515,6 +551,7 @@ static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -548,6 +585,8 @@ static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -562,6 +601,8 @@ static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -575,6 +616,7 @@ static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -589,6 +631,8 @@ static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -603,6 +647,8 @@ static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -616,6 +662,7 @@ static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -630,6 +677,8 @@ static struct clk_rcg2 blsp1_uart3_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -644,6 +693,8 @@ static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -657,6 +708,7 @@ static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -671,6 +723,8 @@ static struct clk_rcg2 blsp1_uart4_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -685,6 +739,8 @@ static struct clk_rcg2 blsp1_qup5_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -698,6 +754,7 @@ static struct clk_rcg2 blsp1_qup5_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -712,6 +769,8 @@ static struct clk_rcg2 blsp1_uart5_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -726,6 +785,8 @@ static struct clk_rcg2 blsp1_qup6_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -739,6 +800,7 @@ static struct clk_rcg2 blsp1_qup6_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -753,6 +815,8 @@ static struct clk_rcg2 blsp1_uart6_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -767,6 +831,8 @@ static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -780,6 +846,7 @@ static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -794,6 +861,8 @@ static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -808,6 +877,8 @@ static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -821,6 +892,7 @@ static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -835,6 +907,8 @@ static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -849,6 +923,8 @@ static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -862,6 +938,7 @@ static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -876,6 +953,8 @@ static struct clk_rcg2 blsp2_uart3_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -890,6 +969,8 @@ static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -903,6 +984,7 @@ static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -917,6 +999,8 @@ static struct clk_rcg2 blsp2_uart4_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -931,6 +1015,8 @@ static struct clk_rcg2 blsp2_qup5_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -944,6 +1030,7 @@ static struct clk_rcg2 blsp2_qup5_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -958,6 +1045,8 @@ static struct clk_rcg2 blsp2_uart5_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -972,6 +1061,8 @@ static struct clk_rcg2 blsp2_qup6_spi_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 25000000,
+ NOMINAL, 50000000),
},
};
@@ -985,6 +1076,7 @@ static struct clk_rcg2 blsp2_qup6_i2c_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
},
};
@@ -999,6 +1091,8 @@ static struct clk_rcg2 blsp2_uart6_apps_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 31580000,
+ NOMINAL, 63160000),
},
};
@@ -1017,6 +1111,7 @@ static struct clk_rcg2 pdm2_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 60000000),
},
};
@@ -1036,6 +1131,7 @@ static struct clk_rcg2 tsif_ref_clk_src = {
.parent_names = gcc_xo_gpll0_aud_ref_clk,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
},
};
@@ -1082,6 +1178,8 @@ static struct clk_rcg2 gp1_clk_src = {
.parent_names = gcc_xo_gpll0_sleep_clk_gpll0_early_div,
.num_parents = 4,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+ NOMINAL, 200000000),
},
};
@@ -1096,6 +1194,8 @@ static struct clk_rcg2 gp2_clk_src = {
.parent_names = gcc_xo_gpll0_sleep_clk_gpll0_early_div,
.num_parents = 4,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+ NOMINAL, 200000000),
},
};
@@ -1110,6 +1210,8 @@ static struct clk_rcg2 gp3_clk_src = {
.parent_names = gcc_xo_gpll0_sleep_clk_gpll0_early_div,
.num_parents = 4,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+ NOMINAL, 200000000),
},
};
@@ -1129,6 +1231,7 @@ static struct clk_rcg2 pcie_aux_clk_src = {
.parent_names = gcc_xo_sleep_clk,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(LOWER, 1011000),
},
};
@@ -1150,6 +1253,8 @@ static struct clk_rcg2 ufs_axi_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 19200000, LOW, 100000000,
+ NOMINAL, 200000000, HIGH, 240000000),
},
};
@@ -1170,6 +1275,8 @@ static struct clk_rcg2 ufs_ice_core_clk_src = {
.parent_names = gcc_xo_gpll0,
.num_parents = 2,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 150000000,
+ NOMINAL, 300000000),
},
};
@@ -1191,6 +1298,8 @@ static struct clk_rcg2 qspi_ser_clk_src = {
.parent_names = gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div,
.num_parents = 6,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 80200000, LOW, 160400000,
+ NOMINAL, 320000000),
},
};
@@ -1321,25 +1430,25 @@ static struct clk_branch gcc_usb3_phy_aux_clk = {
},
};
-static struct clk_gate2 gcc_usb3_phy_pipe_clk = {
- .udelay = 50,
+static struct clk_gate2 gpll0_out_msscc_clk = {
+ .udelay = 1,
.clkr = {
- .enable_reg = 0x50004,
- .enable_mask = BIT(0),
+ .enable_reg = 0x5200c,
+ .enable_mask = BIT(2),
.hw.init = &(struct clk_init_data){
- .name = "gcc_usb3_phy_pipe_clk",
+ .name = "gpll0_out_msscc_clk",
.ops = &clk_gate2_ops,
},
},
};
-static struct clk_gate2 gpll0_out_msscc = {
- .udelay = 1,
+static struct clk_gate2 gcc_usb3_phy_pipe_clk = {
+ .udelay = 50,
.clkr = {
- .enable_reg = 0x5200c,
- .enable_mask = BIT(2),
+ .enable_reg = 0x50004,
+ .enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
- .name = "gpll0_out_msscc",
+ .name = "gcc_usb3_phy_pipe_clk",
.ops = &clk_gate2_ops,
},
},
@@ -1826,6 +1935,7 @@ static struct clk_branch gcc_blsp2_ahb_clk = {
.enable_mask = BIT(15),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_ahb_clk",
+ .flags = CLK_ENABLE_HAND_OFF,
.ops = &clk_branch2_ops,
},
},
@@ -2728,18 +2838,6 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = {
},
};
-static struct clk_branch gcc_aggre1_pnoc_ahb_clk = {
- .halt_reg = 0x82014,
- .clkr = {
- .enable_reg = 0x82014,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "gcc_aggre1_pnoc_ahb_clk",
- .ops = &clk_branch2_ops,
- },
- },
-};
-
static struct clk_branch gcc_aggre2_ufs_axi_clk = {
.halt_reg = 0x83014,
.clkr = {
@@ -2995,11 +3093,13 @@ static struct clk_branch gcc_mmss_gpll0_div_clk = {
};
static struct clk_hw *gcc_msm8996_hws[] = {
- &xo.hw,
- &gpll0_early_div.hw,
- &ufs_tx_cfg_clk_src.hw,
- &ufs_rx_cfg_clk_src.hw,
- &ufs_ice_core_postdiv_clk_src.hw,
+ [GCC_XO] = &xo.hw,
+ [GCC_CE1_AHB_M_CLK] = &gcc_ce1_ahb_m_clk.hw,
+ [GCC_CE1_AXI_M_CLK] = &gcc_ce1_axi_m_clk.hw,
+ [GCC_GPLL0_EARLY_DIV] = &gpll0_early_div.hw,
+ [GCC_UFS_TX_CFG_CLK_SRC] = &ufs_tx_cfg_clk_src.hw,
+ [GCC_UFS_RX_CFG_CLK_SRC] = &ufs_rx_cfg_clk_src.hw,
+ [GCC_UFS_ICE_CORE_PDIV_CLK_SRC] = &ufs_ice_core_postdiv_clk_src.hw,
};
static struct clk_regmap *gcc_msm8996_clocks[] = {
@@ -3170,7 +3270,6 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
[GCC_AGGRE0_CNOC_AHB_CLK] = &gcc_aggre0_cnoc_ahb_clk.clkr,
[GCC_SMMU_AGGRE0_AXI_CLK] = &gcc_smmu_aggre0_axi_clk.clkr,
[GCC_SMMU_AGGRE0_AHB_CLK] = &gcc_smmu_aggre0_ahb_clk.clkr,
- [GCC_AGGRE1_PNOC_AHB_CLK] = &gcc_aggre1_pnoc_ahb_clk.clkr,
[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
@@ -3192,10 +3291,10 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
[GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr,
[GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
[GCC_MSS_MNOC_BIMC_AXI_CLK] = &gcc_mss_mnoc_bimc_axi_clk.clkr,
- [GCC_DCC_AHB_ALK] = &gcc_dcc_ahb_clk.clkr,
+ [GCC_DCC_AHB_CLK] = &gcc_dcc_ahb_clk.clkr,
[GCC_AGGRE0_NOC_MPU_CFG_AHB_CLK] = &gcc_aggre0_noc_mpu_cfg_ahb_clk.clkr,
[GCC_MMSS_GPLL0_DIV_CLK] = &gcc_mmss_gpll0_div_clk.clkr,
- [GPLL0_OUT_MSSCC] = &gpll0_out_msscc.clkr,
+ [GPLL0_OUT_MSSCC_CLK] = &gpll0_out_msscc_clk.clkr,
};
static const struct qcom_reset_map gcc_msm8996_resets[] = {
@@ -3317,6 +3416,8 @@ static const struct regmap_config gcc_msm8996_regmap_config = {
static const struct qcom_cc_desc gcc_msm8996_desc = {
.config = &gcc_msm8996_regmap_config,
.clks = gcc_msm8996_clocks,
+ .hwclks = gcc_msm8996_hws,
+ .num_hwclks = ARRAY_SIZE(gcc_msm8996_hws),
.num_clks = ARRAY_SIZE(gcc_msm8996_clocks),
.resets = gcc_msm8996_resets,
.num_resets = ARRAY_SIZE(gcc_msm8996_resets),
@@ -3330,9 +3431,7 @@ MODULE_DEVICE_TABLE(of, gcc_msm8996_match_table);
static int gcc_msm8996_probe(struct platform_device *pdev)
{
- struct clk *clk;
- struct device *dev = &pdev->dev;
- int i, ret = 0;
+ int ret = 0;
struct regmap *regmap;
regmap = qcom_cc_map(pdev, &gcc_msm8996_desc);
@@ -3342,10 +3441,14 @@ static int gcc_msm8996_probe(struct platform_device *pdev)
/* Set the HMSS_AHB_CLK_ENA bit to enable the hmss_ahb_clk */
regmap_update_bits(regmap, 0x52004, BIT(21), BIT(21));
- for (i = 0; i < ARRAY_SIZE(gcc_msm8996_hws); i++) {
- clk = devm_clk_register(dev, gcc_msm8996_hws[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ vdd_dig.vdd_uv[1] = RPM_REGULATOR_CORNER_SVS_KRAIT;
+
+ vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
+ if (IS_ERR(vdd_dig.regulator[0])) {
+ if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_dig regulator!");
+ return PTR_ERR(vdd_dig.regulator[0]);
}
ret = qcom_cc_really_probe(pdev, &gcc_msm8996_desc, regmap);
@@ -3358,6 +3461,12 @@ static int gcc_msm8996_probe(struct platform_device *pdev)
/* This clock is used for all MMSS register access */
clk_prepare_enable(gcc_mmss_noc_cfg_ahb_clk.clkr.hw.clk);
+ /*
+ * Keep the core memory settings enabled at all times for
+ * gcc_mmss_bimc_gfx_clk.
+ */
+ clk_set_flags(gcc_mmss_bimc_gfx_clk.clkr.hw.clk, CLKFLAG_RETAIN_MEM);
+
dev_info(&pdev->dev, "Registered GCC clocks\n");
return ret;
diff --git a/drivers/clk/qcom/gcc-msmfalcon.c b/drivers/clk/qcom/gcc-msmfalcon.c
index dfcd55ab2c26..1e1c871ef22c 100644
--- a/drivers/clk/qcom/gcc-msmfalcon.c
+++ b/drivers/clk/qcom/gcc-msmfalcon.c
@@ -1229,6 +1229,7 @@ static struct clk_branch gcc_blsp1_ahb_clk = {
.enable_mask = BIT(17),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_ahb_clk",
+ .flags = CLK_ENABLE_HAND_OFF,
.ops = &clk_branch2_ops,
},
},
@@ -1422,6 +1423,7 @@ static struct clk_branch gcc_blsp2_ahb_clk = {
.enable_mask = BIT(15),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_ahb_clk",
+ .flags = CLK_ENABLE_HAND_OFF,
.ops = &clk_branch2_ops,
},
},
@@ -2844,7 +2846,7 @@ static struct measure_clk_data debug_mux_priv = {
static const char *const debug_mux_parent_names[] = {
"snoc_clk",
"cnoc_clk",
- "cnoc_periph",
+ "cnoc_periph_clk",
"bimc_clk",
"ce1_clk",
"ipa_clk",
@@ -2924,6 +2926,7 @@ static const char *const debug_mux_parent_names[] = {
"gcc_ufs_rx_symbol_1_clk",
"gcc_ufs_tx_symbol_0_clk",
"gcc_usb3_phy_pipe_clk",
+ "mmssnoc_axi_clk",
"mmss_bimc_smmu_ahb_clk",
"mmss_bimc_smmu_axi_clk",
"mmss_camss_ahb_clk",
@@ -3104,6 +3107,7 @@ static struct clk_debug_mux gcc_debug_mux = {
{ "gcc_ufs_rx_symbol_1_clk", 0x162 },
{ "gcc_ufs_tx_symbol_0_clk", 0x0EC },
{ "gcc_usb3_phy_pipe_clk", 0x040 },
+ { "mmssnoc_axi_clk", 0x22, MMCC, 0x004 },
{ "mmss_bimc_smmu_ahb_clk", 0x22, MMCC, 0x00C },
{ "mmss_bimc_smmu_axi_clk", 0x22, MMCC, 0x00D },
{ "mmss_camss_ahb_clk", 0x22, MMCC, 0x037 },
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index b4b73ea4211a..b51ab4f21561 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -133,6 +133,10 @@ static int mdss_pll_resource_parse(struct platform_device *pdev,
pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
pll_res->target_id = MDSS_PLL_TARGET_8996;
pll_res->revision = 2;
+ } else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_msmfalcon")) {
+ pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
+ pll_res->target_id = MDSS_PLL_TARGET_MSMFALCON;
+ pll_res->revision = 2;
} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8998")) {
pll_res->pll_interface_type = MDSS_DSI_PLL_8998;
} else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_8998")) {
@@ -378,6 +382,7 @@ static const struct of_device_id mdss_pll_dt_match[] = {
{.compatible = "qcom,mdss_hdmi_pll_8996_v3_1p8"},
{.compatible = "qcom,mdss_dp_pll_8998"},
{.compatible = "qcom,mdss_hdmi_pll_8998"},
+ {.compatible = "qcom,mdss_dsi_pll_msmfalcon"},
{}
};
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index 3528dcfd0cb5..01664eaa815c 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -51,6 +51,7 @@ enum {
enum {
MDSS_PLL_TARGET_8996,
+ MDSS_PLL_TARGET_MSMFALCON,
};
#define DFPS_MAX_NUM_OF_FRAME_RATES 20
diff --git a/drivers/clk/qcom/mmcc-msmfalcon.c b/drivers/clk/qcom/mmcc-msmfalcon.c
index 44611bfce0d1..59dbebd825fd 100644
--- a/drivers/clk/qcom/mmcc-msmfalcon.c
+++ b/drivers/clk/qcom/mmcc-msmfalcon.c
@@ -529,6 +529,7 @@ static struct clk_rcg2 ahb_clk_src = {
.hid_width = 5,
.parent_map = mmcc_parent_map_10,
.freq_tbl = ftbl_ahb_clk_src,
+ .flags = FORCE_ENABLE_RCGR,
.clkr.hw.init = &(struct clk_init_data){
.name = "ahb_clk_src",
.parent_names = mmcc_parent_names_10,
@@ -1281,6 +1282,7 @@ static struct clk_rcg2 video_core_clk_src = {
.hid_width = 5,
.parent_map = mmcc_parent_map_12,
.freq_tbl = ftbl_video_core_clk_src,
+ .flags = FORCE_ENABLE_RCGR,
.clkr.hw.init = &(struct clk_init_data){
.name = "video_core_clk_src",
.parent_names = mmcc_parent_names_12,
@@ -1323,6 +1325,7 @@ static struct clk_branch mmss_bimc_smmu_ahb_clk = {
.parent_names = (const char *[]){
"ahb_clk_src",
},
+ .flags = CLK_ENABLE_HAND_OFF,
.num_parents = 1,
.ops = &clk_branch2_ops,
},
@@ -1337,6 +1340,7 @@ static struct clk_branch mmss_bimc_smmu_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_bimc_smmu_axi_clk",
+ .flags = CLK_ENABLE_HAND_OFF,
.ops = &clk_branch2_ops,
},
},
@@ -2016,9 +2020,9 @@ static struct clk_branch mmss_camss_jpeg0_clk = {
},
};
-static DEFINE_CLK_VOTER(mmss_camss_jpeg0_vote_clk, &mmss_camss_jpeg0_clk.c, 0);
+static DEFINE_CLK_VOTER(mmss_camss_jpeg0_vote_clk, mmss_camss_jpeg0_clk, 0);
static DEFINE_CLK_VOTER(mmss_camss_jpeg0_dma_vote_clk,
- &mmss_camss_jpeg0_clk.c, 0);
+ mmss_camss_jpeg0_clk, 0);
static struct clk_branch mmss_camss_jpeg_ahb_clk = {
.halt_reg = 0x35b4,
@@ -2318,6 +2322,7 @@ static struct clk_branch mmss_mdss_ahb_clk = {
.parent_names = (const char *[]){
"ahb_clk_src",
},
+ .flags = CLK_ENABLE_HAND_OFF,
.num_parents = 1,
.ops = &clk_branch2_ops,
},
@@ -2602,7 +2607,7 @@ static struct clk_branch mmss_mdss_mdp_clk = {
"mdp_clk_src",
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_ENABLE_HAND_OFF,
.ops = &clk_branch2_ops,
},
},
diff --git a/drivers/clk/qcom/vdd-level-8996.h b/drivers/clk/qcom/vdd-level-8996.h
new file mode 100644
index 000000000000..f93dd1638b1b
--- /dev/null
+++ b/drivers/clk/qcom/vdd-level-8996.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_VDD_LEVEL_8996_H__
+#define __QCOM_VDD_LEVEL_8996_H__
+
+#include <linux/regulator/rpm-smd-regulator.h>
+#include <linux/regulator/consumer.h>
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_dig, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_dig, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+ .vdd_class = &vdd_dig, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP4(l1, f1, l2, f2, l3, f3, l4, f4) \
+ .vdd_class = &vdd_dig, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ [VDD_DIG_##l4] = (f4), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
+#define VDD_MMPLL4_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_mmpll4, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
+#define VDD_MMPLL4_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_mmpll4, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
+#define VDD_MMPLL4_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+ .vdd_class = &vdd_mmpll4, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+ VDD_DIG_NONE,
+ VDD_DIG_LOWER, /* SVS2 */
+ VDD_DIG_LOW, /* SVS */
+ VDD_DIG_NOMINAL, /* NOMINAL */
+ VDD_DIG_HIGH, /* Turbo */
+ VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* SVS2 is remapped to SVS */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_SVS */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_TURBO */
+};
+
+#endif
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 0bef7effe601..8d17ea89e266 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -2485,8 +2485,11 @@ static int _qce_sps_add_sg_data_off(struct qce_device *pce_dev,
res_within_sg = sg_dma_len(sg_src);
while (off > 0) {
- if (!sg_src)
+ if (!sg_src) {
+ pr_err("broken sg list off %d nbytes %d\n",
+ off, nbytes);
return -ENOENT;
+ }
len = sg_dma_len(sg_src);
if (off < len) {
res_within_sg = len - off;
@@ -2494,7 +2497,8 @@ static int _qce_sps_add_sg_data_off(struct qce_device *pce_dev,
}
off -= len;
sg_src = sg_next(sg_src);
- res_within_sg = sg_dma_len(sg_src);
+ if (sg_src)
+ res_within_sg = sg_dma_len(sg_src);
}
while (nbytes > 0 && sg_src) {
len = min(nbytes, res_within_sg);
@@ -2525,9 +2529,15 @@ static int _qce_sps_add_sg_data_off(struct qce_device *pce_dev,
addr += data_cnt;
len -= data_cnt;
}
- sg_src = sg_next(sg_src);
- off = 0;
- res_within_sg = sg_dma_len(sg_src);
+ if (nbytes) {
+ sg_src = sg_next(sg_src);
+ if (!sg_src) {
+ pr_err("more data bytes %d\n", nbytes);
+ return -ENOMEM;
+ }
+ res_within_sg = sg_dma_len(sg_src);
+ off = 0;
+ }
}
return 0;
}
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index faeff0b55202..a898dbcbd0ca 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -821,19 +821,16 @@ static struct qcrypto_alg *_qcrypto_aead_alg_alloc(struct crypto_priv *cp,
return q_alg;
};
-static int _qcrypto_cipher_cra_init(struct crypto_tfm *tfm)
+static int _qcrypto_cipher_ctx_init(struct qcrypto_cipher_ctx *ctx,
+ struct qcrypto_alg *q_alg)
{
- struct crypto_alg *alg = tfm->__crt_alg;
- struct qcrypto_alg *q_alg;
- struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-
-
- q_alg = container_of(alg, struct qcrypto_alg, cipher_alg);
+ if (!ctx || !q_alg) {
+ pr_err("ctx or q_alg is NULL\n");
+ return -EINVAL;
+ }
ctx->flags = 0;
-
/* update context with ptr to cp */
ctx->cp = q_alg->cp;
-
/* random first IV */
get_random_bytes(ctx->iv, QCRYPTO_MAX_IV_LENGTH);
if (_qcrypto_init_assign) {
@@ -845,6 +842,16 @@ static int _qcrypto_cipher_cra_init(struct crypto_tfm *tfm)
INIT_LIST_HEAD(&ctx->rsp_queue);
ctx->auth_alg = QCE_HASH_LAST;
return 0;
+}
+
+static int _qcrypto_cipher_cra_init(struct crypto_tfm *tfm)
+{
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct qcrypto_alg *q_alg;
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ q_alg = container_of(alg, struct qcrypto_alg, cipher_alg);
+ return _qcrypto_cipher_ctx_init(ctx, q_alg);
};
static int _qcrypto_ahash_cra_init(struct crypto_tfm *tfm)
@@ -941,13 +948,22 @@ static int _qcrypto_cra_aes_ablkcipher_init(struct crypto_tfm *tfm)
return _qcrypto_cra_ablkcipher_init(tfm);
};
+static int _qcrypto_aead_cra_init(struct crypto_aead *tfm)
+{
+ struct qcrypto_cipher_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_alg *aeadalg = crypto_aead_alg(tfm);
+ struct qcrypto_alg *q_alg = container_of(aeadalg, struct qcrypto_alg,
+ aead_alg);
+ return _qcrypto_cipher_ctx_init(ctx, q_alg);
+};
+
static int _qcrypto_cra_aead_sha1_init(struct crypto_aead *tfm)
{
int rc;
struct qcrypto_cipher_ctx *ctx = crypto_aead_ctx(tfm);
crypto_aead_set_reqsize(tfm, sizeof(struct qcrypto_cipher_req_ctx));
- rc = _qcrypto_cipher_cra_init(&tfm->base);
+ rc = _qcrypto_aead_cra_init(tfm);
ctx->auth_alg = QCE_HASH_SHA1_HMAC;
return rc;
}
@@ -958,7 +974,7 @@ static int _qcrypto_cra_aead_sha256_init(struct crypto_aead *tfm)
struct qcrypto_cipher_ctx *ctx = crypto_aead_ctx(tfm);
crypto_aead_set_reqsize(tfm, sizeof(struct qcrypto_cipher_req_ctx));
- rc = _qcrypto_cipher_cra_init(&tfm->base);
+ rc = _qcrypto_aead_cra_init(tfm);
ctx->auth_alg = QCE_HASH_SHA256_HMAC;
return rc;
}
@@ -969,7 +985,7 @@ static int _qcrypto_cra_aead_ccm_init(struct crypto_aead *tfm)
struct qcrypto_cipher_ctx *ctx = crypto_aead_ctx(tfm);
crypto_aead_set_reqsize(tfm, sizeof(struct qcrypto_cipher_req_ctx));
- rc = _qcrypto_cipher_cra_init(&tfm->base);
+ rc = _qcrypto_aead_cra_init(tfm);
ctx->auth_alg = QCE_HASH_AES_CMAC;
return rc;
}
@@ -980,7 +996,7 @@ static int _qcrypto_cra_aead_rfc4309_ccm_init(struct crypto_aead *tfm)
struct qcrypto_cipher_ctx *ctx = crypto_aead_ctx(tfm);
crypto_aead_set_reqsize(tfm, sizeof(struct qcrypto_cipher_req_ctx));
- rc = _qcrypto_cipher_cra_init(&tfm->base);
+ rc = _qcrypto_aead_cra_init(tfm);
ctx->auth_alg = QCE_HASH_AES_CMAC;
return rc;
}
@@ -992,7 +1008,7 @@ static int _qcrypto_cra_aead_aes_sha1_init(struct crypto_aead *tfm)
struct crypto_priv *cp = &qcrypto_dev;
crypto_aead_set_reqsize(tfm, sizeof(struct qcrypto_cipher_req_ctx));
- rc = _qcrypto_cipher_cra_init(&tfm->base);
+ rc = _qcrypto_aead_cra_init(tfm);
if (rc)
return rc;
ctx->cipher_aes192_fb = NULL;
@@ -1023,7 +1039,7 @@ static int _qcrypto_cra_aead_aes_sha256_init(struct crypto_aead *tfm)
struct crypto_priv *cp = &qcrypto_dev;
crypto_aead_set_reqsize(tfm, sizeof(struct qcrypto_cipher_req_ctx));
- rc = _qcrypto_cipher_cra_init(&tfm->base);
+ rc = _qcrypto_aead_cra_init(tfm);
if (rc)
return rc;
ctx->cipher_aes192_fb = NULL;
@@ -1828,7 +1844,7 @@ static void _qce_aead_complete(void *cookie, unsigned char *icv,
if (rctx->dir == QCE_ENCRYPT) {
/* copy the icv to dst */
scatterwalk_map_and_copy(icv, areq->dst,
- areq->cryptlen,
+ areq->cryptlen + areq->assoclen,
ctx->authsize, 1);
} else {
@@ -1836,8 +1852,9 @@ static void _qce_aead_complete(void *cookie, unsigned char *icv,
/* compare icv from src */
scatterwalk_map_and_copy(tmp,
- areq->src, areq->cryptlen -
- ctx->authsize, ctx->authsize, 0);
+ areq->src, areq->assoclen +
+ areq->cryptlen - ctx->authsize,
+ ctx->authsize, 0);
ret = memcmp(icv, tmp, ctx->authsize);
if (ret != 0)
ret = -EBADMSG;
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 18c05e930216..0d068e9c5805 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -604,6 +604,16 @@ static int sendcmd(struct adreno_device *adreno_dev,
if (!test_and_set_bit(ADRENO_DISPATCHER_ACTIVE,
&dispatcher->priv))
reinit_completion(&dispatcher->idle_gate);
+
+ /*
+ * We update power stats generally at the expire of
+ * cmdbatch. In cases where the cmdbatch takes a long
+ * time to finish, it will delay power stats update,
+ * in effect it will delay DCVS decision. Start a
+ * timer to update power state on expire of this timer.
+ */
+ kgsl_pwrscale_midframe_timer_restart(device);
+
} else {
kgsl_active_count_put(device);
clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 172de7406c26..cd9a82a9bf4a 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2355,6 +2355,7 @@ static int _init(struct kgsl_device *device)
case KGSL_STATE_ACTIVE:
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
del_timer_sync(&device->idle_timer);
+ kgsl_pwrscale_midframe_timer_cancel(device);
device->ftbl->stop(device);
/* fall through */
case KGSL_STATE_AWARE:
@@ -2462,6 +2463,7 @@ _aware(struct kgsl_device *device)
case KGSL_STATE_ACTIVE:
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
del_timer_sync(&device->idle_timer);
+ kgsl_pwrscale_midframe_timer_cancel(device);
break;
case KGSL_STATE_SLUMBER:
status = kgsl_pwrctrl_enable(device);
@@ -2486,6 +2488,8 @@ _nap(struct kgsl_device *device)
return -EBUSY;
}
+ kgsl_pwrscale_midframe_timer_cancel(device);
+
/*
* Read HW busy counters before going to NAP state.
* The data might be used by power scale governors
@@ -2522,6 +2526,7 @@ _slumber(struct kgsl_device *device)
/* fall through */
case KGSL_STATE_NAP:
del_timer_sync(&device->idle_timer);
+ kgsl_pwrscale_midframe_timer_cancel(device);
if (device->pwrctrl.thermal_cycle == CYCLE_ACTIVE) {
device->pwrctrl.thermal_cycle = CYCLE_ENABLE;
del_timer_sync(&device->pwrctrl.thermal_timer);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 85cd29b5364e..413a3098b0ef 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -13,6 +13,7 @@
#include <linux/export.h>
#include <linux/kernel.h>
+#include <linux/hrtimer.h>
#include "kgsl.h"
#include "kgsl_pwrscale.h"
@@ -37,6 +38,18 @@ static struct kgsl_popp popp_param[POPP_MAX] = {
{0, 0},
};
+/**
+* struct kgsl_midframe_info - midframe power stats sampling info
+* @timer - midframe sampling timer
+* @timer_check_ws - Updates powerstats on midframe expiry
+* @device - pointer to kgsl_device
+*/
+static struct kgsl_midframe_info {
+ struct hrtimer timer;
+ struct work_struct timer_check_ws;
+ struct kgsl_device *device;
+} *kgsl_midframe = NULL;
+
static void do_devfreq_suspend(struct work_struct *work);
static void do_devfreq_resume(struct work_struct *work);
static void do_devfreq_notify(struct work_struct *work);
@@ -183,9 +196,57 @@ void kgsl_pwrscale_update(struct kgsl_device *device)
if (device->state != KGSL_STATE_SLUMBER)
queue_work(device->pwrscale.devfreq_wq,
&device->pwrscale.devfreq_notify_ws);
+
+ kgsl_pwrscale_midframe_timer_restart(device);
}
EXPORT_SYMBOL(kgsl_pwrscale_update);
+void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device)
+{
+ if (kgsl_midframe) {
+ WARN_ON(!mutex_is_locked(&device->mutex));
+
+ /* If the timer is already running, stop it */
+ if (hrtimer_active(&kgsl_midframe->timer))
+ hrtimer_cancel(
+ &kgsl_midframe->timer);
+
+ hrtimer_start(&kgsl_midframe->timer,
+ ns_to_ktime(KGSL_GOVERNOR_CALL_INTERVAL
+ * NSEC_PER_USEC), HRTIMER_MODE_REL);
+ }
+}
+EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_restart);
+
+void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device)
+{
+ if (kgsl_midframe) {
+ WARN_ON(!mutex_is_locked(&device->mutex));
+ hrtimer_cancel(&kgsl_midframe->timer);
+ }
+}
+EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_cancel);
+
+static void kgsl_pwrscale_midframe_timer_check(struct work_struct *work)
+{
+ struct kgsl_device *device = kgsl_midframe->device;
+
+ mutex_lock(&device->mutex);
+ if (device->state == KGSL_STATE_ACTIVE)
+ kgsl_pwrscale_update(device);
+ mutex_unlock(&device->mutex);
+}
+
+static enum hrtimer_restart kgsl_pwrscale_midframe_timer(struct hrtimer *timer)
+{
+ struct kgsl_device *device = kgsl_midframe->device;
+
+ queue_work(device->pwrscale.devfreq_wq,
+ &kgsl_midframe->timer_check_ws);
+
+ return HRTIMER_NORESTART;
+}
+
/*
* kgsl_pwrscale_disable - temporarily disable the governor
* @device: The device
@@ -852,6 +913,17 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
data->bin.ctxt_aware_busy_penalty = 12000;
}
+ if (of_property_read_bool(device->pdev->dev.of_node,
+ "qcom,enable-midframe-timer")) {
+ kgsl_midframe = kzalloc(
+ sizeof(struct kgsl_midframe_info), GFP_KERNEL);
+ hrtimer_init(&kgsl_midframe->timer,
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ kgsl_midframe->timer.function =
+ kgsl_pwrscale_midframe_timer;
+ kgsl_midframe->device = device;
+ }
+
/*
* If there is a separate GX power rail, allow
* independent modification to its voltage through
@@ -900,6 +972,9 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend);
INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume);
INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify);
+ if (kgsl_midframe)
+ INIT_WORK(&kgsl_midframe->timer_check_ws,
+ kgsl_pwrscale_midframe_timer_check);
pwrscale->next_governor_call = ktime_add_us(ktime_get(),
KGSL_GOVERNOR_CALL_INTERVAL);
@@ -940,9 +1015,13 @@ void kgsl_pwrscale_close(struct kgsl_device *device)
pwrscale = &device->pwrscale;
if (!pwrscale->devfreqptr)
return;
+
+ kgsl_pwrscale_midframe_timer_cancel(device);
flush_workqueue(pwrscale->devfreq_wq);
destroy_workqueue(pwrscale->devfreq_wq);
devfreq_remove_device(device->pwrscale.devfreqptr);
+ kfree(kgsl_midframe);
+ kgsl_midframe = NULL;
device->pwrscale.devfreqptr = NULL;
srcu_cleanup_notifier_head(&device->pwrscale.nh);
for (i = 0; i < KGSL_PWREVENT_MAX; i++)
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index 0756a4490f22..184bfd1a2692 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -122,6 +122,9 @@ void kgsl_pwrscale_busy(struct kgsl_device *device);
void kgsl_pwrscale_sleep(struct kgsl_device *device);
void kgsl_pwrscale_wake(struct kgsl_device *device);
+void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device);
+void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device);
+
void kgsl_pwrscale_enable(struct kgsl_device *device);
void kgsl_pwrscale_disable(struct kgsl_device *device, bool turbo);
diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c
index a510490d28d6..04b1b62f85c3 100644
--- a/drivers/i2c/busses/i2c-msm-v2.c
+++ b/drivers/i2c/busses/i2c-msm-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -2236,12 +2236,12 @@ static void i2c_msm_pm_xfer_end(struct i2c_msm_ctrl *ctrl)
i2c_msm_dma_free_channels(ctrl);
i2c_msm_pm_clk_disable_unprepare(ctrl);
- if (pm_runtime_enabled(ctrl->dev)) {
- pm_runtime_mark_last_busy(ctrl->dev);
- pm_runtime_put_autosuspend(ctrl->dev);
- } else {
+
+ if (!pm_runtime_enabled(ctrl->dev))
i2c_msm_pm_suspend(ctrl->dev);
- }
+
+ pm_runtime_mark_last_busy(ctrl->dev);
+ pm_runtime_put_autosuspend(ctrl->dev);
mutex_unlock(&ctrl->xfer.mtx);
}
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index 05cd1edefb7f..1df5d8812991 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -208,9 +208,13 @@ static int hbtp_input_create_input_dev(struct hbtp_input_absinfo *absinfo)
input_mt_init_slots(input_dev, HBTP_MAX_FINGER, 0);
for (i = 0; i <= ABS_MT_LAST - ABS_MT_FIRST; i++) {
abs = absinfo + i;
- if (abs->active)
- input_set_abs_params(input_dev, abs->code,
+ if (abs->active) {
+ if (abs->code >= 0 && abs->code < ABS_CNT)
+ input_set_abs_params(input_dev, abs->code,
abs->minimum, abs->maximum, 0, 0);
+ else
+ pr_err("%s: ABS code out of bound\n", __func__);
+ }
}
if (hbtp->override_disp_coords) {
diff --git a/drivers/input/qpnp-power-on.c b/drivers/input/qpnp-power-on.c
index 760c92a47a36..967b23cae05c 100644
--- a/drivers/input/qpnp-power-on.c
+++ b/drivers/input/qpnp-power-on.c
@@ -31,6 +31,7 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/qpnp/power-on.h>
+#include <linux/power_supply.h>
#define PMIC_VER_8941 0x01
#define PMIC_VERSION_REG 0x0105
@@ -220,6 +221,11 @@ struct qpnp_pon {
bool store_hard_reset_reason;
};
+static int pon_ship_mode_en;
+module_param_named(
+ ship_mode_en, pon_ship_mode_en, int, S_IRUSR | S_IWUSR
+);
+
static struct qpnp_pon *sys_reset_dev;
static DEFINE_SPINLOCK(spon_list_slock);
static LIST_HEAD(spon_dev_list);
@@ -523,6 +529,8 @@ int qpnp_pon_system_pwr_off(enum pon_power_off_type type)
int rc = 0;
struct qpnp_pon *pon = sys_reset_dev;
struct qpnp_pon *tmp;
+ struct power_supply *batt_psy;
+ union power_supply_propval val;
unsigned long flags;
if (!pon)
@@ -557,6 +565,19 @@ int qpnp_pon_system_pwr_off(enum pon_power_off_type type)
goto out;
}
}
+ /* Set ship mode here if it has been requested */
+ if (!!pon_ship_mode_en) {
+ batt_psy = power_supply_get_by_name("battery");
+ if (batt_psy) {
+ pr_debug("Set ship mode!\n");
+ val.intval = 1;
+ rc = power_supply_set_property(batt_psy,
+ POWER_SUPPLY_PROP_SET_SHIP_MODE, &val);
+ if (rc)
+ dev_err(&pon->pdev->dev,
+ "Set ship-mode failed\n");
+ }
+ }
out:
spin_unlock_irqrestore(&spon_list_slock, flags);
return rc;
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index 77014f93927c..56750ac8e9e2 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -108,7 +108,14 @@
#define QPNP_WLED_SWITCH_FREQ_1600_KHZ 1600
#define QPNP_WLED_SWITCH_FREQ_OVERWRITE 0x80
#define QPNP_WLED_OVP_MASK GENMASK(1, 0)
-#define QPNP_WLED_TEST4_EN_VREF_UP 0x32
+#define QPNP_WLED_TEST4_EN_DEB_BYPASS_ILIM_BIT BIT(6)
+#define QPNP_WLED_TEST4_EN_SH_FOR_SS_BIT BIT(5)
+#define QPNP_WLED_TEST4_EN_CLAMP_BIT BIT(4)
+#define QPNP_WLED_TEST4_EN_SOFT_START_BIT BIT(1)
+#define QPNP_WLED_TEST4_EN_VREF_UP \
+ (QPNP_WLED_TEST4_EN_SH_FOR_SS_BIT | \
+ QPNP_WLED_TEST4_EN_CLAMP_BIT | \
+ QPNP_WLED_TEST4_EN_SOFT_START_BIT)
#define QPNP_WLED_TEST4_EN_IIND_UP 0x1
/* sink registers */
@@ -167,6 +174,7 @@
#define QPNP_WLED_SINK_TEST5_HYB 0x14
#define QPNP_WLED_SINK_TEST5_DIG 0x1E
+#define QPNP_WLED_SINK_TEST5_HVG_PULL_STR_BIT BIT(3)
#define QPNP_WLED_SWITCH_FREQ_800_KHZ_CODE 0x0B
#define QPNP_WLED_SWITCH_FREQ_1600_KHZ_CODE 0x05
@@ -1035,7 +1043,8 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
/*
* enable VREF_UP to avoid false ovp on low brightness for LCD
*/
- reg = QPNP_WLED_TEST4_EN_VREF_UP;
+ reg = QPNP_WLED_TEST4_EN_VREF_UP
+ | QPNP_WLED_TEST4_EN_DEB_BYPASS_ILIM_BIT;
rc = qpnp_wled_sec_write_reg(wled,
QPNP_WLED_TEST4_REG(base_addr), reg);
if (rc)
@@ -1550,10 +1559,13 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
return rc;
/* Configure TEST5 register */
- if (wled->dim_mode == QPNP_WLED_DIM_DIGITAL)
+ if (wled->dim_mode == QPNP_WLED_DIM_DIGITAL) {
reg = QPNP_WLED_SINK_TEST5_DIG;
- else
+ } else {
reg = QPNP_WLED_SINK_TEST5_HYB;
+ if (wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE)
+ reg |= QPNP_WLED_SINK_TEST5_HVG_PULL_STR_BIT;
+ }
rc = qpnp_wled_sec_write_reg(wled,
QPNP_WLED_SINK_TEST5_REG(wled->sink_base), reg);
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 b045d6c6e8da..54c0aa39cdd3 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
@@ -1102,11 +1102,11 @@ static int cam_smmu_map_secure_buffer_and_add_to_list(int idx,
}
if (table->sgl) {
- CDBG("DMA buf: %p, device: %p, attach: %p, table: %p\n",
+ CDBG("DMA buf: %pK, device: %pK, attach: %pK, table: %pK\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",
+ CDBG("table sgl: %pK, rc: %d, dma_address: 0x%x\n",
(void *)table->sgl, rc,
(unsigned int)table->sgl->dma_address);
} else {
@@ -1139,7 +1139,7 @@ static int cam_smmu_map_secure_buffer_and_add_to_list(int idx,
rc = -ENOSPC;
goto err_mapping_info;
}
- CDBG("dev = %p, paddr= %p, len = %u\n",
+ CDBG("dev = %pK, paddr= %pK, len = %u\n",
(void *)iommu_cb_set.cb_info[idx].dev,
(void *)*paddr_ptr, (unsigned int)*len_ptr);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index a1fb307b09c1..ab01d37790d6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -1099,7 +1099,7 @@ static int msm_vfe40_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
if (rc < 0 || !buf) {
- pr_err("%s: No fetch buffer rc= %d buf= %p\n",
+ pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
__func__, rc, buf);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index f6e0d9083b22..941119fad78e 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -1768,7 +1768,7 @@ int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
vfe_dev->buf_mgr, bufq_handle, buf_idx, &buf);
if (rc < 0 || !buf) {
- pr_err("%s: No fetch buffer rc= %d buf= %p\n",
+ pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
__func__, rc, buf);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
index 6911e8fc5f2f..ddd32fc5c339 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
@@ -91,7 +91,7 @@ static int cpp_get_clk_freq_tbl_dt(struct cpp_device *cpp_dev)
hw_info = &cpp_dev->hw_info;
if ((hw_info == NULL) || (of_node == NULL)) {
- pr_err("Invalid hw_info %p or ofnode %p\n", hw_info, of_node);
+ pr_err("Invalid hw_info %pK or ofnode %pK\n", hw_info, of_node);
rc = -EINVAL;
goto err;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index b413bf3855b8..4b6005b9af46 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -1418,6 +1418,7 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl,
case CFG_GET_ACTUATOR_INFO:
cdata->is_af_supported = 1;
cdata->cfg.cam_name = a_ctrl->cam_name;
+ rc = 0;
break;
case CFG_SET_ACTUATOR_INFO:
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index a7b3663ad7fe..6b3d84a2c145 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -4621,6 +4621,40 @@ int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
}
EXPORT_SYMBOL(qseecom_set_bandwidth);
+int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc)
+{
+ struct qseecom_registered_app_list dummy_app_entry = { {0} };
+ struct qseecom_dev_handle dummy_private_data = {0};
+ struct qseecom_command_scm_resp resp;
+ int ret = 0;
+
+ if (!desc) {
+ pr_err("desc is NULL\n");
+ return -EINVAL;
+ }
+
+ resp.result = desc->ret[0]; /*req_cmd*/
+ resp.resp_type = desc->ret[1]; /*app_id*/
+ resp.data = desc->ret[2]; /*listener_id*/
+
+ dummy_private_data.client.app_id = desc->ret[1];
+ dummy_app_entry.app_id = desc->ret[1];
+
+ mutex_lock(&app_access_lock);
+ ret = __qseecom_process_reentrancy(&resp, &dummy_app_entry,
+ &dummy_private_data);
+ mutex_unlock(&app_access_lock);
+ if (ret)
+ pr_err("Failed to req cmd %d lsnr %d on app %d, ret = %d\n",
+ (int)desc->ret[0], (int)desc->ret[2],
+ (int)desc->ret[1], ret);
+ desc->ret[0] = resp.result;
+ desc->ret[1] = resp.resp_type;
+ desc->ret[2] = resp.data;
+ return ret;
+}
+EXPORT_SYMBOL(qseecom_process_listener_from_smcinvoke);
+
static int qseecom_send_resp(void)
{
qseecom.send_resp_flag = 1;
diff --git a/drivers/misc/qseecom_kernel.h b/drivers/misc/qseecom_kernel.h
index ca0205560875..8f981903c3a1 100644
--- a/drivers/misc/qseecom_kernel.h
+++ b/drivers/misc/qseecom_kernel.h
@@ -14,6 +14,7 @@
#define __QSEECOM_KERNEL_H_
#include <linux/types.h>
+#include <soc/qcom/scm.h>
#define QSEECOM_ALIGN_SIZE 0x40
#define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1)
@@ -38,5 +39,6 @@ int qseecom_shutdown_app(struct qseecom_handle **handle);
int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len);
int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high);
+int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc);
#endif /* __QSEECOM_KERNEL_H_ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index daa7a33d12d8..f5575747d11e 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -964,6 +964,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
wil->reply_id = reply_id;
wil->reply_buf = reply;
wil->reply_size = reply_size;
+ reinit_completion(&wil->wmi_call);
spin_unlock(&wil->wmi_ev_lock);
rc = __wmi_send(wil, cmdid, buf, len);
diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c
index 5810f7bf7f2f..b7fc68a6efdd 100644
--- a/drivers/platform/msm/msm_11ad/msm_11ad.c
+++ b/drivers/platform/msm/msm_11ad/msm_11ad.c
@@ -33,7 +33,7 @@
#define WIGIG_DEVICE (0x0310)
#define SMMU_BASE 0x10000000 /* Device address range base */
-#define SMMU_SIZE 0x40000000 /* Device address range size */
+#define SMMU_SIZE ((SZ_1G * 4ULL) - SMMU_BASE)
#define WIGIG_ENABLE_DELAY 50
#define PM_OPT_SUSPEND (MSM_PCIE_CONFIG_NO_CFG_RESTORE | \
@@ -87,6 +87,8 @@ struct msm11ad_ctx {
/* SMMU */
bool use_smmu; /* have SMMU enabled? */
+ int smmu_bypass;
+ int smmu_fast_map;
struct dma_iommu_mapping *mapping;
/* bus frequency scaling */
@@ -596,11 +598,13 @@ static int msm_11ad_smmu_init(struct msm11ad_ctx *ctx)
{
int atomic_ctx = 1;
int rc;
- int bypass_enable = 1;
if (!ctx->use_smmu)
return 0;
+ dev_info(ctx->dev, "Initialize SMMU, bypass = %d, fastmap = %d\n",
+ ctx->smmu_bypass, ctx->smmu_fast_map);
+
ctx->mapping = arm_iommu_create_mapping(&platform_bus_type,
SMMU_BASE, SMMU_SIZE);
if (IS_ERR_OR_NULL(ctx->mapping)) {
@@ -608,7 +612,6 @@ static int msm_11ad_smmu_init(struct msm11ad_ctx *ctx)
dev_err(ctx->dev, "Failed to create IOMMU mapping (%d)\n", rc);
return rc;
}
- dev_info(ctx->dev, "IOMMU mapping created: %p\n", ctx->mapping);
rc = iommu_domain_set_attr(ctx->mapping->domain,
DOMAIN_ATTR_ATOMIC,
@@ -619,13 +622,24 @@ static int msm_11ad_smmu_init(struct msm11ad_ctx *ctx)
goto release_mapping;
}
- rc = iommu_domain_set_attr(ctx->mapping->domain,
- DOMAIN_ATTR_S1_BYPASS,
- &bypass_enable);
- if (rc) {
- dev_err(ctx->dev, "Set bypass attribute to SMMU failed (%d)\n",
- rc);
- goto release_mapping;
+ if (ctx->smmu_bypass) {
+ rc = iommu_domain_set_attr(ctx->mapping->domain,
+ DOMAIN_ATTR_S1_BYPASS,
+ &ctx->smmu_bypass);
+ if (rc) {
+ dev_err(ctx->dev, "Set bypass attribute to SMMU failed (%d)\n",
+ rc);
+ goto release_mapping;
+ }
+ } else if (ctx->smmu_fast_map) {
+ rc = iommu_domain_set_attr(ctx->mapping->domain,
+ DOMAIN_ATTR_FAST,
+ &ctx->smmu_fast_map);
+ if (rc) {
+ dev_err(ctx->dev, "Set fast attribute to SMMU failed (%d)\n",
+ rc);
+ goto release_mapping;
+ }
}
rc = arm_iommu_attach_device(&ctx->pcidev->dev, ctx->mapping);
@@ -870,6 +884,9 @@ static int msm_11ad_probe(struct platform_device *pdev)
ctx->use_smmu = of_property_read_bool(of_node, "qcom,smmu-support");
ctx->bus_scale = msm_bus_cl_get_pdata(pdev);
+ ctx->smmu_bypass = 1;
+ ctx->smmu_fast_map = 0;
+
/*== execute ==*/
/* turn device on */
rc = msm_11ad_init_vregs(ctx);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index a4aee80798e4..83b75fcd257e 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -278,6 +278,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(parallel_percent),
POWER_SUPPLY_ATTR(pe_start),
POWER_SUPPLY_ATTR(set_ship_mode),
+ POWER_SUPPLY_ATTR(soc_reporting_ready),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/qcom-charger/fg-core.h b/drivers/power/qcom-charger/fg-core.h
index d8b6754a465f..6f8266a3161c 100644
--- a/drivers/power/qcom-charger/fg-core.h
+++ b/drivers/power/qcom-charger/fg-core.h
@@ -335,6 +335,7 @@ struct fg_chip {
bool recharge_soc_adjusted;
bool ki_coeff_dischg_en;
bool esr_fcc_ctrl_en;
+ bool soc_reporting_ready;
struct completion soc_update;
struct completion soc_ready;
struct delayed_work profile_load_work;
diff --git a/drivers/power/qcom-charger/qpnp-fg-gen3.c b/drivers/power/qcom-charger/qpnp-fg-gen3.c
index 22025ac27ffa..7c1ece431beb 100644
--- a/drivers/power/qcom-charger/qpnp-fg-gen3.c
+++ b/drivers/power/qcom-charger/qpnp-fg-gen3.c
@@ -2050,6 +2050,7 @@ done:
fg_notify_charger(chip);
chip->profile_loaded = true;
+ chip->soc_reporting_ready = true;
fg_dbg(chip, FG_STATUS, "profile loaded successfully");
out:
vote(chip->awake_votable, PROFILE_LOAD, false, 0);
@@ -2386,6 +2387,9 @@ static int fg_psy_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
rc = fg_get_time_to_empty(chip, &pval->intval);
break;
+ case POWER_SUPPLY_PROP_SOC_REPORTING_READY:
+ pval->intval = chip->soc_reporting_ready;
+ break;
default:
pr_err("unsupported property %d\n", psp);
rc = -EINVAL;
@@ -2483,6 +2487,7 @@ static enum power_supply_property fg_psy_props[] = {
POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+ POWER_SUPPLY_PROP_SOC_REPORTING_READY,
};
static const struct power_supply_desc fg_psy_desc = {
@@ -2773,9 +2778,11 @@ static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data)
chip->profile_available = false;
chip->profile_loaded = false;
clear_cycle_counter(chip);
+ chip->soc_reporting_ready = false;
} else {
rc = fg_get_batt_profile(chip);
if (rc < 0) {
+ chip->soc_reporting_ready = true;
pr_err("Error in getting battery profile, rc:%d\n", rc);
return IRQ_HANDLED;
}
@@ -3213,9 +3220,11 @@ static int fg_parse_dt(struct fg_chip *chip)
chip->rradc_base = base;
rc = fg_get_batt_profile(chip);
- if (rc < 0)
+ if (rc < 0) {
+ chip->soc_reporting_ready = true;
pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
chip->batt_id_ohms / 1000, rc);
+ }
/* Read all the optional properties below */
rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp);
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index d32f293695bb..267df592ba8a 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -28,6 +28,7 @@
#include <asm/cacheflush.h>
#include <asm/system_misc.h>
+#include <asm/memory.h>
#include <soc/qcom/scm.h>
#include <soc/qcom/restart.h>
@@ -65,11 +66,17 @@ static struct kobject dload_kobj;
#ifdef CONFIG_QCOM_DLOAD_MODE
#define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode"
#define DL_MODE_PROP "qcom,msm-imem-download_mode"
+#ifdef CONFIG_RANDOMIZE_BASE
+#define KASLR_OFFSET_PROP "qcom,msm-imem-kaslr_offset"
+#endif
static int in_panic;
static void *dload_mode_addr;
static bool dload_mode_enabled;
static void *emergency_dload_mode_addr;
+#ifdef CONFIG_RANDOMIZE_BASE
+static void *kaslr_imem_addr;
+#endif
static bool scm_dload_supported;
static int dload_set(const char *val, struct kernel_param *kp);
@@ -510,6 +517,28 @@ static int msm_restart_probe(struct platform_device *pdev)
pr_err("unable to map imem EDLOAD mode offset\n");
}
+#ifdef CONFIG_RANDOMIZE_BASE
+#define KASLR_OFFSET_BIT_MASK 0x00000000FFFFFFFF
+ np = of_find_compatible_node(NULL, NULL, KASLR_OFFSET_PROP);
+ if (!np) {
+ pr_err("unable to find DT imem KASLR_OFFSET node\n");
+ } else {
+ kaslr_imem_addr = of_iomap(np, 0);
+ if (!kaslr_imem_addr)
+ pr_err("unable to map imem KASLR offset\n");
+ }
+
+ if (kaslr_imem_addr && scm_is_secure_device()) {
+ __raw_writel(0xdead4ead, kaslr_imem_addr);
+ __raw_writel(KASLR_OFFSET_BIT_MASK &
+ (kimage_vaddr - KIMAGE_VADDR), kaslr_imem_addr + 4);
+ __raw_writel(KASLR_OFFSET_BIT_MASK &
+ ((kimage_vaddr - KIMAGE_VADDR) >> 32),
+ kaslr_imem_addr + 8);
+ iounmap(kaslr_imem_addr);
+ }
+#endif
+
np = of_find_compatible_node(NULL, NULL,
"qcom,msm-imem-dload-type");
if (!np) {
@@ -603,4 +632,4 @@ static int __init msm_restart_init(void)
{
return platform_driver_register(&msm_restart_driver);
}
-device_initcall(msm_restart_init);
+pure_initcall(msm_restart_init);
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index ba1bf3b5f492..bd2c1a8e7540 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -925,6 +925,17 @@ config REGULATOR_CPRH_KBSS
independent voltage supplies. This driver reads both initial voltage
and CPR target quotient values out of hardware fuses.
+config REGULATOR_CPR4_MMSS_LDO
+ bool "RBCPR3 regulator for MMSS LDO"
+ depends on OF
+ select REGULATOR_CPR3
+ help
+ This driver supports Qualcomm Technologies, Inc. MMSS graphics
+ processor specific features. The MMSS CPR3 controller only uses one
+ thread to monitor the MMSS LDO voltage requirements. This driver reads
+ initial voltage values out of hardware fuses and CPR target quotient
+ values out of device tree.
+
config REGULATOR_KRYO
bool "Kryo regulator driver"
depends on OF
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 79a203418a0b..abd116d3d8af 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -114,6 +114,7 @@ obj-$(CONFIG_REGULATOR_CPR3_HMSS) += cpr3-hmss-regulator.o
obj-$(CONFIG_REGULATOR_CPR3_MMSS) += cpr3-mmss-regulator.o
obj-$(CONFIG_REGULATOR_CPR4_APSS) += cpr4-apss-regulator.o
obj-$(CONFIG_REGULATOR_CPRH_KBSS) += cprh-kbss-regulator.o
+obj-$(CONFIG_REGULATOR_CPR4_MMSS_LDO) += cpr4-mmss-ldo-regulator.o
obj-$(CONFIG_REGULATOR_QPNP_LABIBB) += qpnp-labibb-regulator.o
obj-$(CONFIG_REGULATOR_QPNP_LCDB) += qpnp-lcdb-regulator.o
obj-$(CONFIG_REGULATOR_STUB) += stub-regulator.o
diff --git a/drivers/regulator/cpr4-mmss-ldo-regulator.c b/drivers/regulator/cpr4-mmss-ldo-regulator.c
new file mode 100644
index 000000000000..9fa5c309b02a
--- /dev/null
+++ b/drivers/regulator/cpr4-mmss-ldo-regulator.c
@@ -0,0 +1,722 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/msm-ldo-regulator.h>
+
+#include "cpr3-regulator.h"
+
+#define MSMFALCON_MMSS_FUSE_CORNERS 6
+
+/**
+ * struct cpr4_msmfalcon_mmss_fuses - MMSS specific fuse data for MSMFALCON
+ * @init_voltage: Initial (i.e. open-loop) voltage fuse parameter value
+ * for each fuse corner (raw, not converted to a voltage)
+ * @offset_voltage: The closed-loop voltage margin adjustment fuse parameter
+ * value for each fuse corner (raw, not converted to a
+ * voltage)
+ * @cpr_fusing_rev: CPR fusing revision fuse parameter value
+ * @ldo_enable: The ldo enable fuse parameter for each fuse corner
+ * indicates that VDD_GFX can be configured to LDO mode in
+ * the corresponding fuse corner.
+ * @ldo_cpr_cl_enable: A fuse parameter indicates that GFX CPR can be
+ * configured to operate in closed-loop mode when VDD_GFX
+ * is configured for LDO sub-regulated mode.
+ *
+ * This struct holds the values for all of the fuses read from memory.
+ */
+struct cpr4_msmfalcon_mmss_fuses {
+ u64 init_voltage[MSMFALCON_MMSS_FUSE_CORNERS];
+ u64 offset_voltage[MSMFALCON_MMSS_FUSE_CORNERS];
+ u64 cpr_fusing_rev;
+ u64 ldo_enable[MSMFALCON_MMSS_FUSE_CORNERS];
+ u64 ldo_cpr_cl_enable;
+};
+
+/* Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 */
+#define CPR4_MSMFALCON_MMSS_FUSE_COMBO_COUNT 8
+
+/*
+ * MSMFALCON MMSS fuse parameter locations:
+ *
+ * Structs are organized with the following dimensions:
+ * Outer: 0 to 3 for fuse corners from lowest to highest corner
+ * Inner: large enough to hold the longest set of parameter segments which
+ * fully defines a fuse parameter, +1 (for NULL termination).
+ * Each segment corresponds to a contiguous group of bits from a
+ * single fuse row. These segments are concatentated together in
+ * order to form the full fuse parameter value. The segments for
+ * a given parameter may correspond to different fuse rows.
+ */
+static const struct cpr3_fuse_param
+msmfalcon_mmss_init_voltage_param[MSMFALCON_MMSS_FUSE_CORNERS][2] = {
+ {{65, 39, 43}, {} },
+ {{65, 39, 43}, {} },
+ {{65, 34, 38}, {} },
+ {{65, 34, 38}, {} },
+ {{65, 29, 33}, {} },
+ {{65, 24, 28}, {} },
+};
+
+static const struct cpr3_fuse_param msmfalcon_cpr_fusing_rev_param[] = {
+ {71, 34, 36},
+ {},
+};
+
+static const struct cpr3_fuse_param
+msmfalcon_mmss_offset_voltage_param[MSMFALCON_MMSS_FUSE_CORNERS][2] = {
+ {{} },
+ {{} },
+ {{} },
+ {{65, 52, 55}, {} },
+ {{65, 48, 51}, {} },
+ {{65, 44, 47}, {} },
+};
+
+static const struct cpr3_fuse_param
+msmfalcon_mmss_ldo_enable_param[MSMFALCON_MMSS_FUSE_CORNERS][2] = {
+ {{73, 62, 62}, {} },
+ {{73, 61, 61}, {} },
+ {{73, 60, 60}, {} },
+ {{73, 59, 59}, {} },
+ {{73, 58, 58}, {} },
+ {{73, 57, 57}, {} },
+};
+
+static const struct cpr3_fuse_param msmfalcon_ldo_cpr_cl_enable_param[] = {
+ {71, 38, 38},
+ {},
+};
+
+/* Additional MSMFALCON specific data: */
+
+/* Open loop voltage fuse reference voltages in microvolts */
+static const int msmfalcon_mmss_fuse_ref_volt[MSMFALCON_MMSS_FUSE_CORNERS] = {
+ 584000,
+ 644000,
+ 724000,
+ 788000,
+ 868000,
+ 924000,
+};
+
+#define MSMFALCON_MMSS_FUSE_STEP_VOLT 10000
+#define MSMFALCON_MMSS_OFFSET_FUSE_STEP_VOLT 10000
+#define MSMFALCON_MMSS_VOLTAGE_FUSE_SIZE 5
+
+#define MSMFALCON_MMSS_CPR_SENSOR_COUNT 11
+
+#define MSMFALCON_MMSS_CPR_CLOCK_RATE 19200000
+
+/**
+ * cpr4_msmfalcon_mmss_read_fuse_data() - load MMSS specific fuse parameter
+ * values
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * This function allocates a cpr4_msmfalcon_mmss_fuses struct, fills it with
+ * values read out of hardware fuses, and finally copies common fuse values
+ * into the regulator struct.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_msmfalcon_mmss_read_fuse_data(struct cpr3_regulator *vreg)
+{
+ void __iomem *base = vreg->thread->ctrl->fuse_base;
+ struct cpr4_msmfalcon_mmss_fuses *fuse;
+ int i, rc;
+
+ fuse = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*fuse), GFP_KERNEL);
+ if (!fuse)
+ return -ENOMEM;
+
+ rc = cpr3_read_fuse_param(base, msmfalcon_cpr_fusing_rev_param,
+ &fuse->cpr_fusing_rev);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
+ rc);
+ return rc;
+ }
+ cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
+
+ rc = cpr3_read_fuse_param(base, msmfalcon_ldo_cpr_cl_enable_param,
+ &fuse->ldo_cpr_cl_enable);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read ldo cpr closed-loop enable fuse, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ for (i = 0; i < MSMFALCON_MMSS_FUSE_CORNERS; i++) {
+ rc = cpr3_read_fuse_param(base,
+ msmfalcon_mmss_init_voltage_param[i],
+ &fuse->init_voltage[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base,
+ msmfalcon_mmss_offset_voltage_param[i],
+ &fuse->offset_voltage[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d offset voltage fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base,
+ msmfalcon_mmss_ldo_enable_param[i],
+ &fuse->ldo_enable[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d ldo enable fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+ }
+
+ vreg->fuse_combo = fuse->cpr_fusing_rev;
+ if (vreg->fuse_combo >= CPR4_MSMFALCON_MMSS_FUSE_COMBO_COUNT) {
+ cpr3_err(vreg, "invalid CPR fuse combo = %d found, not in range 0 - %d\n",
+ vreg->fuse_combo,
+ CPR4_MSMFALCON_MMSS_FUSE_COMBO_COUNT - 1);
+ return -EINVAL;
+ }
+
+ vreg->cpr_rev_fuse = fuse->cpr_fusing_rev;
+ vreg->fuse_corner_count = MSMFALCON_MMSS_FUSE_CORNERS;
+ vreg->platform_fuses = fuse;
+
+ return 0;
+}
+
+/**
+ * cpr3_msmfalcon_mmss_calculate_open_loop_voltages() - calculate the open-loop
+ * voltage for each corner of a CPR3 regulator
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_msmfalcon_mmss_calculate_open_loop_voltages(
+ struct cpr3_regulator *vreg)
+{
+ struct cpr4_msmfalcon_mmss_fuses *fuse = vreg->platform_fuses;
+ int i, rc = 0;
+ const int *ref_volt;
+ int *fuse_volt;
+
+ fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt),
+ GFP_KERNEL);
+ if (!fuse_volt)
+ return -ENOMEM;
+
+ ref_volt = msmfalcon_mmss_fuse_ref_volt;
+ for (i = 0; i < vreg->fuse_corner_count; i++) {
+ fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(ref_volt[i],
+ MSMFALCON_MMSS_FUSE_STEP_VOLT, fuse->init_voltage[i],
+ MSMFALCON_MMSS_VOLTAGE_FUSE_SIZE);
+ cpr3_info(vreg, "fuse_corner[%d] open-loop=%7d uV\n",
+ i, fuse_volt[i]);
+ }
+
+ rc = cpr3_adjust_fused_open_loop_voltages(vreg, fuse_volt);
+ if (rc) {
+ cpr3_err(vreg, "fused open-loop voltage adjustment failed, rc=%d\n",
+ rc);
+ goto done;
+ }
+
+ for (i = 1; i < vreg->fuse_corner_count; i++) {
+ if (fuse_volt[i] < fuse_volt[i - 1]) {
+ cpr3_debug(vreg, "fuse corner %d voltage=%d uV < fuse corner %d voltage=%d uV; overriding: fuse corner %d voltage=%d\n",
+ i, fuse_volt[i], i - 1, fuse_volt[i - 1],
+ i, fuse_volt[i - 1]);
+ fuse_volt[i] = fuse_volt[i - 1];
+ }
+ }
+
+ for (i = 0; i < vreg->corner_count; i++)
+ vreg->corner[i].open_loop_volt
+ = fuse_volt[vreg->corner[i].cpr_fuse_corner];
+
+ cpr3_debug(vreg, "unadjusted per-corner open-loop voltages:\n");
+ for (i = 0; i < vreg->corner_count; i++)
+ cpr3_debug(vreg, "open-loop[%2d] = %d uV\n", i,
+ vreg->corner[i].open_loop_volt);
+
+ rc = cpr3_adjust_open_loop_voltages(vreg);
+ if (rc)
+ cpr3_err(vreg, "open-loop voltage adjustment failed, rc=%d\n",
+ rc);
+
+done:
+ kfree(fuse_volt);
+ return rc;
+}
+
+/**
+ * cpr4_mmss_parse_ldo_mode_data() - Parse the LDO mode enable state for each
+ * corner of a CPR3 regulator
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * This function considers 2 sets of data: one set from device node and other
+ * set from fuses and applies set intersection to decide the final LDO mode
+ * enable state of each corner. If the device node configuration is not
+ * specified, then the function applies LDO mode disable for all corners.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_mmss_parse_ldo_mode_data(struct cpr3_regulator *vreg)
+{
+ struct cpr4_msmfalcon_mmss_fuses *fuse = vreg->platform_fuses;
+ int i, rc = 0;
+ u32 *ldo_allowed;
+ char *prop_str = "qcom,cpr-corner-allow-ldo-mode";
+
+ if (!of_find_property(vreg->of_node, prop_str, NULL)) {
+ cpr3_debug(vreg, "%s property is missing. LDO mode is disabled for all corners\n",
+ prop_str);
+ return 0;
+ }
+
+ ldo_allowed = kcalloc(vreg->corner_count, sizeof(*ldo_allowed),
+ GFP_KERNEL);
+ if (!ldo_allowed)
+ return -ENOMEM;
+
+ rc = cpr3_parse_corner_array_property(vreg, prop_str, 1, ldo_allowed);
+ if (rc) {
+ cpr3_err(vreg, "%s read failed, rc=%d\n", prop_str, rc);
+ goto done;
+ }
+
+ for (i = 0; i < vreg->corner_count; i++)
+ vreg->corner[i].ldo_mode_allowed
+ = (ldo_allowed[i] && fuse->ldo_enable[i]);
+
+done:
+ kfree(ldo_allowed);
+ return rc;
+}
+
+/**
+ * cpr4_mmss_parse_corner_operating_mode() - Parse the CPR closed-loop operation
+ * enable state for each corner of a CPR3 regulator
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * This function ensures that closed-loop operation is enabled only for LDO
+ * mode allowed corners.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_mmss_parse_corner_operating_mode(struct cpr3_regulator *vreg)
+{
+ struct cpr4_msmfalcon_mmss_fuses *fuse = vreg->platform_fuses;
+ int i, rc = 0;
+ u32 *use_closed_loop;
+ char *prop_str = "qcom,cpr-corner-allow-closed-loop";
+
+ if (!of_find_property(vreg->of_node, prop_str, NULL)) {
+ cpr3_debug(vreg, "%s property is missing. Use open-loop for all corners\n",
+ prop_str);
+ for (i = 0; i < vreg->corner_count; i++)
+ vreg->corner[i].use_open_loop = true;
+
+ return 0;
+ }
+
+ use_closed_loop = kcalloc(vreg->corner_count, sizeof(*use_closed_loop),
+ GFP_KERNEL);
+ if (!use_closed_loop)
+ return -ENOMEM;
+
+ rc = cpr3_parse_corner_array_property(vreg, prop_str, 1,
+ use_closed_loop);
+ if (rc) {
+ cpr3_err(vreg, "%s read failed, rc=%d\n", prop_str, rc);
+ goto done;
+ }
+
+ for (i = 0; i < vreg->corner_count; i++)
+ vreg->corner[i].use_open_loop
+ = !(fuse->ldo_cpr_cl_enable && use_closed_loop[i]
+ && vreg->corner[i].ldo_mode_allowed);
+
+done:
+ kfree(use_closed_loop);
+ return rc;
+}
+
+/**
+ * cpr4_mmss_parse_corner_data() - parse MMSS corner data from device tree
+ * properties of the regulator's device node
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_mmss_parse_corner_data(struct cpr3_regulator *vreg)
+{
+ int i, rc;
+ u32 *temp;
+
+ rc = cpr3_parse_common_corner_data(vreg);
+ if (rc) {
+ cpr3_err(vreg, "error reading corner data, rc=%d\n", rc);
+ return rc;
+ }
+
+ temp = kcalloc(vreg->corner_count * CPR3_RO_COUNT, sizeof(*temp),
+ GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
+
+ rc = cpr3_parse_corner_array_property(vreg, "qcom,cpr-target-quotients",
+ CPR3_RO_COUNT, temp);
+ if (rc) {
+ cpr3_err(vreg, "could not load target quotients, rc=%d\n", rc);
+ goto done;
+ }
+
+ for (i = 0; i < vreg->corner_count; i++)
+ memcpy(vreg->corner[i].target_quot, &temp[i * CPR3_RO_COUNT],
+ sizeof(*temp) * CPR3_RO_COUNT);
+
+done:
+ kfree(temp);
+ return rc;
+}
+
+/**
+ * cpr4_mmss_print_settings() - print out MMSS CPR configuration settings into
+ * the kernel log for debugging purposes
+ * @vreg: Pointer to the CPR3 regulator
+ */
+static void cpr4_mmss_print_settings(struct cpr3_regulator *vreg)
+{
+ struct cpr3_corner *corner;
+ int i;
+
+ cpr3_debug(vreg, "Corner: Frequency (Hz), Fuse Corner, Floor (uV), Open-Loop (uV), Ceiling (uV)\n");
+ for (i = 0; i < vreg->corner_count; i++) {
+ corner = &vreg->corner[i];
+ cpr3_debug(vreg, "%3d: %10u, %2d, %7d, %7d, %7d\n",
+ i, corner->proc_freq, corner->cpr_fuse_corner,
+ corner->floor_volt, corner->open_loop_volt,
+ corner->ceiling_volt);
+ }
+}
+
+/**
+ * cpr4_mmss_init_thread() - perform all steps necessary to initialize the
+ * configuration data for a CPR3 thread
+ * @thread: Pointer to the CPR3 thread
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_mmss_init_thread(struct cpr3_thread *thread)
+{
+ struct cpr3_controller *ctrl = thread->ctrl;
+ struct cpr3_regulator *vreg = &thread->vreg[0];
+ int rc;
+
+ rc = cpr3_parse_common_thread_data(thread);
+ if (rc) {
+ cpr3_err(vreg, "unable to read CPR thread data from device tree, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ if (!of_find_property(ctrl->dev->of_node, "vdd-thread0-ldo-supply",
+ NULL)) {
+ cpr3_err(vreg, "ldo supply regulator is not specified\n");
+ return -EINVAL;
+ }
+
+ vreg->ldo_regulator = devm_regulator_get(ctrl->dev, "vdd-thread0-ldo");
+ if (IS_ERR(vreg->ldo_regulator)) {
+ rc = PTR_ERR(vreg->ldo_regulator);
+ if (rc != -EPROBE_DEFER)
+ cpr3_err(vreg, "unable to request vdd-thread0-ldo regulator, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ vreg->ldo_mode_allowed = !of_property_read_bool(vreg->of_node,
+ "qcom,ldo-disable");
+ vreg->ldo_regulator_bypass = BHS_MODE;
+ vreg->ldo_type = CPR3_LDO300;
+
+ rc = cpr4_msmfalcon_mmss_read_fuse_data(vreg);
+ if (rc) {
+ cpr3_err(vreg, "unable to read CPR fuse data, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = cpr4_mmss_parse_corner_data(vreg);
+ if (rc) {
+ cpr3_err(vreg, "unable to read CPR corner data from device tree, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = cpr4_msmfalcon_mmss_calculate_open_loop_voltages(vreg);
+ if (rc) {
+ cpr3_err(vreg, "unable to calculate open-loop voltages, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = cpr3_limit_open_loop_voltages(vreg);
+ if (rc) {
+ cpr3_err(vreg, "unable to limit open-loop voltages, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ cpr3_open_loop_voltage_as_ceiling(vreg);
+
+ rc = cpr3_limit_floor_voltages(vreg);
+ if (rc) {
+ cpr3_err(vreg, "unable to limit floor voltages, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = cpr4_mmss_parse_ldo_mode_data(vreg);
+ if (rc) {
+ cpr3_err(vreg, "unable to parse ldo mode data, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = cpr4_mmss_parse_corner_operating_mode(vreg);
+ if (rc) {
+ cpr3_err(vreg, "unable to parse closed-loop operating mode data, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ cpr4_mmss_print_settings(vreg);
+
+ return 0;
+}
+
+/**
+ * cpr4_mmss_init_controller() - perform MMSS CPR4 controller specific
+ * initializations
+ * @ctrl: Pointer to the CPR3 controller
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_mmss_init_controller(struct cpr3_controller *ctrl)
+{
+ int rc;
+
+ rc = cpr3_parse_common_ctrl_data(ctrl);
+ if (rc) {
+ if (rc != -EPROBE_DEFER)
+ cpr3_err(ctrl, "unable to parse common controller data, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ ctrl->sensor_count = MSMFALCON_MMSS_CPR_SENSOR_COUNT;
+
+ /*
+ * MMSS only has one thread (0) so the zeroed array does not need
+ * further modification.
+ */
+ ctrl->sensor_owner = devm_kcalloc(ctrl->dev, ctrl->sensor_count,
+ sizeof(*ctrl->sensor_owner), GFP_KERNEL);
+ if (!ctrl->sensor_owner)
+ return -ENOMEM;
+
+ ctrl->cpr_clock_rate = MSMFALCON_MMSS_CPR_CLOCK_RATE;
+ ctrl->ctrl_type = CPR_CTRL_TYPE_CPR4;
+ ctrl->support_ldo300_vreg = true;
+
+ /*
+ * Use fixed step quotient if specified otherwise use dynamic
+ * calculated per RO step quotient
+ */
+ of_property_read_u32(ctrl->dev->of_node,
+ "qcom,cpr-step-quot-fixed",
+ &ctrl->step_quot_fixed);
+ ctrl->use_dynamic_step_quot = !ctrl->step_quot_fixed;
+
+ /* iface_clk is optional for msmfalcon */
+ ctrl->iface_clk = NULL;
+ ctrl->bus_clk = devm_clk_get(ctrl->dev, "bus_clk");
+ if (IS_ERR(ctrl->bus_clk)) {
+ rc = PTR_ERR(ctrl->bus_clk);
+ if (rc != -EPROBE_DEFER)
+ cpr3_err(ctrl, "unable request bus clock, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int cpr4_mmss_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct cpr3_controller *ctrl;
+ int rc;
+
+ if (!dev->of_node) {
+ dev_err(dev, "Device tree node is missing\n");
+ return -EINVAL;
+ }
+
+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+
+ ctrl->dev = dev;
+ /* Set to false later if anything precludes CPR operation. */
+ ctrl->cpr_allowed_hw = true;
+
+ rc = of_property_read_string(dev->of_node, "qcom,cpr-ctrl-name",
+ &ctrl->name);
+ if (rc) {
+ cpr3_err(ctrl, "unable to read qcom,cpr-ctrl-name, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = cpr3_map_fuse_base(ctrl, pdev);
+ if (rc) {
+ cpr3_err(ctrl, "could not map fuse base address\n");
+ return rc;
+ }
+
+ rc = cpr3_allocate_threads(ctrl, 0, 0);
+ if (rc) {
+ cpr3_err(ctrl, "failed to allocate CPR thread array, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ if (ctrl->thread_count != 1) {
+ cpr3_err(ctrl, "expected 1 thread but found %d\n",
+ ctrl->thread_count);
+ return -EINVAL;
+ } else if (ctrl->thread[0].vreg_count != 1) {
+ cpr3_err(ctrl, "expected 1 regulator but found %d\n",
+ ctrl->thread[0].vreg_count);
+ return -EINVAL;
+ }
+
+ rc = cpr4_mmss_init_controller(ctrl);
+ if (rc) {
+ if (rc != -EPROBE_DEFER)
+ cpr3_err(ctrl, "failed to initialize CPR controller parameters, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = cpr4_mmss_init_thread(&ctrl->thread[0]);
+ if (rc) {
+ cpr3_err(&ctrl->thread[0].vreg[0], "thread initialization failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = cpr3_mem_acc_init(&ctrl->thread[0].vreg[0]);
+ if (rc) {
+ cpr3_err(ctrl, "failed to initialize mem-acc configuration, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ platform_set_drvdata(pdev, ctrl);
+
+ return cpr3_regulator_register(pdev, ctrl);
+}
+
+static int cpr4_mmss_regulator_remove(struct platform_device *pdev)
+{
+ struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
+
+ return cpr3_regulator_unregister(ctrl);
+}
+
+static int cpr4_mmss_regulator_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
+
+ return cpr3_regulator_suspend(ctrl);
+}
+
+static int cpr4_mmss_regulator_resume(struct platform_device *pdev)
+{
+ struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
+
+ return cpr3_regulator_resume(ctrl);
+}
+
+/* Data corresponds to the SoC revision */
+static const struct of_device_id cpr4_mmss_regulator_match_table[] = {
+ {
+ .compatible = "qcom,cpr4-msmfalcon-mmss-ldo-regulator",
+ .data = (void *)NULL,
+ },
+};
+
+static struct platform_driver cpr4_mmss_regulator_driver = {
+ .driver = {
+ .name = "qcom,cpr4-mmss-ldo-regulator",
+ .of_match_table = cpr4_mmss_regulator_match_table,
+ .owner = THIS_MODULE,
+ },
+ .probe = cpr4_mmss_regulator_probe,
+ .remove = cpr4_mmss_regulator_remove,
+ .suspend = cpr4_mmss_regulator_suspend,
+ .resume = cpr4_mmss_regulator_resume,
+};
+
+static int cpr_regulator_init(void)
+{
+ return platform_driver_register(&cpr4_mmss_regulator_driver);
+}
+
+static void cpr_regulator_exit(void)
+{
+ platform_driver_unregister(&cpr4_mmss_regulator_driver);
+}
+
+MODULE_DESCRIPTION("CPR4 MMSS LDO regulator driver");
+MODULE_LICENSE("GPL v2");
+
+arch_initcall(cpr_regulator_init);
+module_exit(cpr_regulator_exit);
diff --git a/drivers/soc/qcom/avtimer.c b/drivers/soc/qcom/avtimer.c
index 2bded5e83cce..4331af8890c0 100644
--- a/drivers/soc/qcom/avtimer.c
+++ b/drivers/soc/qcom/avtimer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -331,9 +331,17 @@ static long avtimer_ioctl(struct file *file, unsigned int ioctl_num,
switch (ioctl_num) {
case IOCTL_GET_AVTIMER_TICK:
{
- uint64_t avtimer_tick;
+ uint64_t avtimer_tick = 0;
+ int rc;
+
+ rc = avcs_core_query_timer(&avtimer_tick);
+
+ if (rc) {
+ pr_err("%s: Error: Invalid AV Timer tick, rc = %d\n",
+ __func__, rc);
+ return rc;
+ }
- avcs_core_query_timer(&avtimer_tick);
pr_debug_ratelimited("%s: AV Timer tick: time %llx\n",
__func__, avtimer_tick);
if (copy_to_user((void *) ioctl_param, &avtimer_tick,
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 49510bfd6b24..c3792d5a72ac 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -781,7 +781,7 @@ static int icnss_unmap_msa_permissions(struct icnss_priv *priv, u32 index)
u32 size;
u32 dest_vmids[1] = {VMID_HLOS};
int source_vmlist[3] = {VMID_MSS_MSA, VMID_WLAN, 0};
- int dest_perms[1] = {PERM_READ|PERM_WRITE};
+ int dest_perms[1] = {PERM_READ|PERM_WRITE|PERM_EXEC};
int source_nelems = 0;
int dest_nelems = sizeof(dest_vmids)/sizeof(u32);
diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c
index d4be8c641ad8..e920dfee8530 100644
--- a/drivers/soc/qcom/smcinvoke.c
+++ b/drivers/soc/qcom/smcinvoke.c
@@ -22,6 +22,8 @@
#include <soc/qcom/scm.h>
#include <asm/cacheflush.h>
#include "smcinvoke_object.h"
+#include <soc/qcom/qseecomi.h>
+#include "../../misc/qseecom_kernel.h"
#define SMCINVOKE_TZ_PARAM_ID 0x224
#define SMCINVOKE_TZ_CMD 0x32000600
@@ -198,6 +200,12 @@ static int prepare_send_scm_msg(const uint8_t *in_buf, size_t in_buf_len,
dmac_flush_range(out_buf, out_buf + outbuf_flush_size);
ret = scm_call2(SMCINVOKE_TZ_CMD, &desc);
+
+ /* process listener request */
+ if (!ret && (desc.ret[0] == QSEOS_RESULT_INCOMPLETE ||
+ desc.ret[0] == QSEOS_RESULT_BLOCKED_ON_LISTENER))
+ ret = qseecom_process_listener_from_smcinvoke(&desc);
+
*smcinvoke_result = (int32_t)desc.ret[1];
if (ret || desc.ret[1] || desc.ret[2] || desc.ret[0]) {
pr_err("SCM call failed with ret val = %d %d %d %d\n",
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 5b3e6c36810e..e8ea99827403 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -272,6 +272,8 @@ static struct spcom_device *spcom_dev;
static int spcom_create_channel_chardev(const char *name);
static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec);
static int spcom_close(struct spcom_channel *ch);
+static void spcom_notify_rx_abort(void *handle, const void *priv,
+ const void *pkt_priv);
/**
* spcom_is_ready() - driver is initialized and ready.
@@ -467,6 +469,13 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event)
* This may happen upon remote SSR.
*/
pr_err("GLINK_REMOTE_DISCONNECTED, ch [%s].\n", ch->name);
+
+ /*
+ * Abort any blocking read() operation.
+ * The glink notification might be after REMOTE_DISCONNECT.
+ */
+ spcom_notify_rx_abort(NULL, ch, NULL);
+
/*
* after glink_close(),
* expecting notify GLINK_LOCAL_DISCONNECTED
@@ -515,7 +524,7 @@ static void spcom_notify_rx_abort(void *handle, const void *priv,
pr_debug("ch [%s] pending rx aborted.\n", ch->name);
- if (spcom_is_channel_connected(ch)) {
+ if (spcom_is_channel_connected(ch) && (!ch->rx_abort)) {
ch->rx_abort = true;
complete_all(&ch->rx_done);
}
@@ -535,9 +544,9 @@ static void spcom_notify_tx_abort(void *handle, const void *priv,
pr_debug("ch [%s] pending tx aborted.\n", ch->name);
- if (spcom_is_channel_connected(ch)) {
- complete_all(&ch->tx_done);
+ if (spcom_is_channel_connected(ch) && (!ch->tx_abort)) {
ch->tx_abort = true;
+ complete_all(&ch->tx_done);
}
}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index a5d59e7f2d90..7aa04a4fa156 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1830,15 +1830,15 @@ err_setup_exit:
static int debugfs_iomem_x32_set(void *data, u64 val)
{
- struct msm_spi_regs *debugfs_spi_regs = (struct msm_spi_regs *)data;
- struct msm_spi *dd = debugfs_spi_regs->dd;
+ struct msm_spi_debugfs_data *reg = (struct msm_spi_debugfs_data *)data;
+ struct msm_spi *dd = reg->dd;
int ret;
ret = pm_runtime_get_sync(dd->dev);
if (ret < 0)
return ret;
- writel_relaxed(val, (dd->base + debugfs_spi_regs->offset));
+ writel_relaxed(val, (dd->base + reg->offset));
/* Ensure the previous write completed. */
mb();
@@ -1849,14 +1849,14 @@ static int debugfs_iomem_x32_set(void *data, u64 val)
static int debugfs_iomem_x32_get(void *data, u64 *val)
{
- struct msm_spi_regs *debugfs_spi_regs = (struct msm_spi_regs *)data;
- struct msm_spi *dd = debugfs_spi_regs->dd;
+ struct msm_spi_debugfs_data *reg = (struct msm_spi_debugfs_data *)data;
+ struct msm_spi *dd = reg->dd;
int ret;
ret = pm_runtime_get_sync(dd->dev);
if (ret < 0)
return ret;
- *val = readl_relaxed(dd->base + debugfs_spi_regs->offset);
+ *val = readl_relaxed(dd->base + reg->offset);
/* Ensure the previous read completed. */
mb();
@@ -1870,18 +1870,21 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
static void spi_debugfs_init(struct msm_spi *dd)
{
- dd->dent_spi = debugfs_create_dir(dev_name(dd->dev), NULL);
+ char dir_name[20];
+
+ scnprintf(dir_name, sizeof(dir_name), "%s_dbg", dev_name(dd->dev));
+ dd->dent_spi = debugfs_create_dir(dir_name, NULL);
if (dd->dent_spi) {
int i;
for (i = 0; i < ARRAY_SIZE(debugfs_spi_regs); i++) {
- debugfs_spi_regs[i].dd = dd;
+ dd->reg_data[i].offset = debugfs_spi_regs[i].offset;
+ dd->reg_data[i].dd = dd;
dd->debugfs_spi_regs[i] =
debugfs_create_file(
debugfs_spi_regs[i].name,
debugfs_spi_regs[i].mode,
- dd->dent_spi,
- debugfs_spi_regs+i,
+ dd->dent_spi, &dd->reg_data[i],
&fops_iomem_x32);
}
}
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index fb906939c03a..e8e6cdce1a02 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -214,52 +214,48 @@ struct spi_cs_gpio {
};
#ifdef CONFIG_DEBUG_FS
+struct msm_spi_debugfs_data {
+ int offset;
+ struct msm_spi *dd;
+};
/* Used to create debugfs entries */
static struct msm_spi_regs{
const char *name;
mode_t mode;
int offset;
- struct msm_spi *dd;
} debugfs_spi_regs[] = {
- {"config", S_IRUGO | S_IWUSR, SPI_CONFIG, NULL},
- {"io_control", S_IRUGO | S_IWUSR, SPI_IO_CONTROL, NULL},
- {"io_modes", S_IRUGO | S_IWUSR, SPI_IO_MODES, NULL},
- {"sw_reset", S_IWUSR, SPI_SW_RESET, NULL},
- {"time_out_current", S_IRUGO, SPI_TIME_OUT_CURRENT,
- NULL},
- {"mx_output_count", S_IRUGO | S_IWUSR, SPI_MX_OUTPUT_COUNT,
- NULL},
- {"mx_output_cnt_current", S_IRUGO, SPI_MX_OUTPUT_CNT_CURRENT,
- NULL},
- {"mx_input_count", S_IRUGO | S_IWUSR, SPI_MX_INPUT_COUNT, NULL},
- {"mx_input_cnt_current", S_IRUGO, SPI_MX_INPUT_CNT_CURRENT,
- NULL},
- {"mx_read_count", S_IRUGO | S_IWUSR, SPI_MX_READ_COUNT, NULL},
- {"mx_read_cnt_current", S_IRUGO, SPI_MX_READ_CNT_CURRENT,
- NULL},
- {"operational", S_IRUGO | S_IWUSR, SPI_OPERATIONAL, NULL},
- {"error_flags", S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS, NULL},
- {"error_flags_en", S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS_EN, NULL},
- {"deassert_wait", S_IRUGO | S_IWUSR, SPI_DEASSERT_WAIT, NULL},
- {"output_debug", S_IRUGO, SPI_OUTPUT_DEBUG, NULL},
- {"input_debug", S_IRUGO, SPI_INPUT_DEBUG, NULL},
- {"test_ctrl", S_IRUGO | S_IWUSR, SPI_TEST_CTRL, NULL},
- {"output_fifo", S_IWUSR, SPI_OUTPUT_FIFO, NULL},
- {"input_fifo" , S_IRUSR, SPI_INPUT_FIFO, NULL},
- {"spi_state", S_IRUGO | S_IWUSR, SPI_STATE, NULL},
+ {"config", S_IRUGO | S_IWUSR, SPI_CONFIG },
+ {"io_control", S_IRUGO | S_IWUSR, SPI_IO_CONTROL },
+ {"io_modes", S_IRUGO | S_IWUSR, SPI_IO_MODES },
+ {"sw_reset", S_IWUSR, SPI_SW_RESET },
+ {"time_out_current", S_IRUGO, SPI_TIME_OUT_CURRENT },
+ {"mx_output_count", S_IRUGO | S_IWUSR, SPI_MX_OUTPUT_COUNT },
+ {"mx_output_cnt_current", S_IRUGO,
+ SPI_MX_OUTPUT_CNT_CURRENT },
+ {"mx_input_count", S_IRUGO | S_IWUSR, SPI_MX_INPUT_COUNT },
+ {"mx_input_cnt_current", S_IRUGO, SPI_MX_INPUT_CNT_CURRENT },
+ {"mx_read_count", S_IRUGO | S_IWUSR, SPI_MX_READ_COUNT, },
+ {"mx_read_cnt_current", S_IRUGO, SPI_MX_READ_CNT_CURRENT },
+ {"operational", S_IRUGO | S_IWUSR, SPI_OPERATIONAL },
+ {"error_flags", S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS },
+ {"error_flags_en", S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS_EN },
+ {"deassert_wait", S_IRUGO | S_IWUSR, SPI_DEASSERT_WAIT },
+ {"output_debug", S_IRUGO, SPI_OUTPUT_DEBUG },
+ {"input_debug", S_IRUGO, SPI_INPUT_DEBUG },
+ {"test_ctrl", S_IRUGO | S_IWUSR, SPI_TEST_CTRL },
+ {"output_fifo", S_IWUSR, SPI_OUTPUT_FIFO },
+ {"input_fifo", S_IRUSR, SPI_INPUT_FIFO },
+ {"spi_state", S_IRUGO | S_IWUSR, SPI_STATE },
#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
- {"fifo_word_cnt", S_IRUGO, SPI_FIFO_WORD_CNT, NULL},
+ {"fifo_word_cnt", S_IRUGO, SPI_FIFO_WORD_CNT },
#else
- {"qup_config", S_IRUGO | S_IWUSR, QUP_CONFIG, NULL},
- {"qup_error_flags", S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS, NULL},
- {"qup_error_flags_en", S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS_EN, NULL},
- {"mx_write_cnt", S_IRUGO | S_IWUSR, QUP_MX_WRITE_COUNT, NULL},
- {"mx_write_cnt_current", S_IRUGO, QUP_MX_WRITE_CNT_CURRENT,
- NULL},
- {"output_fifo_word_cnt", S_IRUGO, SPI_OUTPUT_FIFO_WORD_CNT,
- NULL},
- {"input_fifo_word_cnt", S_IRUGO, SPI_INPUT_FIFO_WORD_CNT,
- NULL},
+ {"qup_config", S_IRUGO | S_IWUSR, QUP_CONFIG },
+ {"qup_error_flags", S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS },
+ {"qup_error_flags_en", S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS_EN },
+ {"mx_write_cnt", S_IRUGO | S_IWUSR, QUP_MX_WRITE_COUNT },
+ {"mx_write_cnt_current", S_IRUGO, QUP_MX_WRITE_CNT_CURRENT },
+ {"output_fifo_word_cnt", S_IRUGO, SPI_OUTPUT_FIFO_WORD_CNT },
+ {"input_fifo_word_cnt", S_IRUGO, SPI_INPUT_FIFO_WORD_CNT },
#endif
};
#endif
@@ -349,6 +345,7 @@ struct msm_spi {
#ifdef CONFIG_DEBUG_FS
struct dentry *dent_spi;
struct dentry *debugfs_spi_regs[ARRAY_SIZE(debugfs_spi_regs)];
+ struct msm_spi_debugfs_data reg_data[ARRAY_SIZE(debugfs_spi_regs)];
#endif
struct msm_spi_platform_data *pdata; /* Platform data */
/* When set indicates multiple transfers in a single message */
@@ -515,10 +512,7 @@ static inline int msm_spi_prepare_for_write(struct msm_spi *dd)
static inline void msm_spi_start_write(struct msm_spi *dd, u32 read_count)
{
- if (read_count <= dd->input_fifo_size)
- msm_spi_write_rmn_to_fifo(dd);
- else
- msm_spi_write_word_to_fifo(dd);
+ msm_spi_write_rmn_to_fifo(dd);
}
static inline void msm_spi_set_write_count(struct msm_spi *dd, int val)
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 7158fb1239df..f685892edd39 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -2931,7 +2931,7 @@ static void __ref do_core_control(int temp)
cpu_dev = get_cpu_device(i);
trace_thermal_pre_core_offline(i);
ret = device_offline(cpu_dev);
- if (ret)
+ if (ret < 0)
pr_err("Error %d offline core %d\n",
ret, i);
trace_thermal_post_core_offline(i,
@@ -3004,7 +3004,8 @@ static int __ref update_offline_cores(int val)
cpu_dev = get_cpu_device(cpu);
trace_thermal_pre_core_offline(cpu);
ret = device_offline(cpu_dev);
- if (ret) {
+ if (ret < 0) {
+ cpus_offlined &= ~BIT(cpu);
pr_err_ratelimited(
"Unable to offline CPU%d. err:%d\n",
cpu, ret);
@@ -3074,6 +3075,14 @@ static __ref int do_hotplug(void *data)
&hotplug_notify_complete) != 0)
;
reinit_completion(&hotplug_notify_complete);
+
+ /*
+ * Suspend framework will have disabled the
+ * hotplug functionality. So wait till the suspend exits
+ * and then re-evaluate.
+ */
+ if (in_suspend)
+ continue;
mask = 0;
mutex_lock(&core_control_mutex);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 9d9eed2d5d68..b826f926b205 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -325,7 +325,7 @@ config USB_CONFIGFS_ECM_SUBSET
a simple CDC subset is used, placing fewer demands on USB.
config USB_CONFIGFS_QCRNDIS
- bool "RNDIS"
+ bool "QCRNDIS"
depends on USB_CONFIGFS
depends on RNDIS_IPA
depends on NET
diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c
index ede1c8dd51a6..5ebac7ece209 100644
--- a/drivers/usb/gadget/function/f_qc_rndis.c
+++ b/drivers/usb/gadget/function/f_qc_rndis.c
@@ -1347,19 +1347,16 @@ static struct miscdevice rndis_qc_device = {
static void qcrndis_free_inst(struct usb_function_instance *f)
{
- struct f_rndis_qc *rndis;
struct f_rndis_qc_opts *opts = container_of(f,
struct f_rndis_qc_opts, func_inst);
unsigned long flags;
- rndis = opts->rndis;
misc_deregister(&rndis_qc_device);
ipa_data_free(USB_IPA_FUNC_RNDIS);
spin_lock_irqsave(&rndis_lock, flags);
- kfree(rndis);
- _rndis_qc = NULL;
kfree(opts->rndis);
+ _rndis_qc = NULL;
kfree(opts);
spin_unlock_irqrestore(&rndis_lock, flags);
}
@@ -1441,13 +1438,6 @@ static struct usb_function_instance *qcrndis_alloc_inst(void)
return &opts->func_inst;
}
-static void rndis_qc_cleanup(void)
-{
- pr_info("rndis QC cleanup\n");
-
- misc_deregister(&rndis_qc_device);
-}
-
void *rndis_qc_get_ipa_rx_cb(void)
{
return rndis_ipa_params.ipa_rx_notify;
@@ -1485,7 +1475,6 @@ static int __init usb_qcrndis_init(void)
static void __exit usb_qcrndis_exit(void)
{
usb_function_unregister(&rndis_bamusb_func);
- rndis_qc_cleanup();
}
module_init(usb_qcrndis_init);
diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c
index 1683a9fea09a..2d0cd30c0641 100644
--- a/drivers/usb/gadget/function/u_data_ipa.c
+++ b/drivers/usb/gadget/function/u_data_ipa.c
@@ -396,7 +396,7 @@ static void ipa_data_connect_work(struct work_struct *w)
unsigned long flags;
bool is_ipa_disconnected = true;
- pr_debug("%s: Connect workqueue started", __func__);
+ pr_debug("%s: Connect workqueue started\n", __func__);
spin_lock_irqsave(&port->port_lock, flags);
@@ -446,8 +446,14 @@ static void ipa_data_connect_work(struct work_struct *w)
spin_unlock_irqrestore(&port->port_lock, flags);
usb_bam_alloc_fifos(port->usb_bam_type,
port->src_connection_idx);
-
spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb || port->rx_req == NULL) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_err("%s: port_usb is NULL, or rx_req cleaned\n",
+ __func__);
+ goto out;
+ }
+
sps_params = MSM_SPS_MODE | MSM_DISABLE_WB
| MSM_PRODUCER | port->src_pipe_idx;
port->rx_req->length = 32*1024;
@@ -459,8 +465,6 @@ static void ipa_data_connect_work(struct work_struct *w)
if (ret) {
pr_err("msm_ep_config() failed for OUT EP\n");
spin_unlock_irqrestore(&port->port_lock, flags);
- usb_bam_free_fifos(port->usb_bam_type,
- port->src_connection_idx);
goto out;
}
}
@@ -470,6 +474,12 @@ static void ipa_data_connect_work(struct work_struct *w)
usb_bam_alloc_fifos(port->usb_bam_type,
port->dst_connection_idx);
spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb || port->tx_req == NULL) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_err("%s: port_usb is NULL, or tx_req cleaned\n",
+ __func__);
+ goto unconfig_msm_ep_out;
+ }
sps_params = MSM_SPS_MODE | MSM_DISABLE_WB |
port->dst_pipe_idx;
port->tx_req->length = 32*1024;
@@ -538,6 +548,7 @@ static void ipa_data_connect_work(struct work_struct *w)
spin_unlock_irqrestore(&port->port_lock, flags);
goto disconnect_usb_bam_ipa_out;
}
+
gport->ipa_consumer_ep = port->ipa_params.ipa_cons_ep_idx;
}
@@ -572,6 +583,7 @@ static void ipa_data_connect_work(struct work_struct *w)
goto disconnect_usb_bam_ipa_out;
}
spin_lock_irqsave(&port->port_lock, flags);
+ is_ipa_disconnected = false;
/* check if USB cable is disconnected or not */
if (!port->port_usb) {
pr_debug("%s:%d: cable is disconnected.\n",
@@ -581,7 +593,6 @@ static void ipa_data_connect_work(struct work_struct *w)
}
gport->ipa_producer_ep = port->ipa_params.ipa_prod_ep_idx;
- is_ipa_disconnected = false;
}
spin_unlock_irqrestore(&port->port_lock, flags);
@@ -612,7 +623,8 @@ static void ipa_data_connect_work(struct work_struct *w)
return;
}
atomic_set(&port->pipe_connect_notified, 1);
- } else {
+ } else if (port->func_type == USB_IPA_FUNC_RMNET ||
+ port->func_type == USB_IPA_FUNC_DPL) {
/* For RmNet and DPL need to update_ipa_pipes to qti */
enum qti_port_type qti_port_type = port->func_type ==
USB_IPA_FUNC_RMNET ? QTI_PORT_RMNET : QTI_PORT_DPL;
@@ -675,13 +687,13 @@ unconfig_msm_ep_out:
port->dst_connection_idx);
spin_lock_irqsave(&port->port_lock, flags);
/* check if USB cable is disconnected or not */
- if (port->port_usb && gport->out) {
+ if (port->port_usb && gport->out)
msm_ep_unconfig(port->port_usb->out);
- usb_bam_free_fifos(port->usb_bam_type,
- port->src_connection_idx);
- }
spin_unlock_irqrestore(&port->port_lock, flags);
out:
+ if (gport->out)
+ usb_bam_free_fifos(port->usb_bam_type,
+ port->src_connection_idx);
spin_lock_irqsave(&port->port_lock, flags);
port->is_connected = false;
spin_unlock_irqrestore(&port->port_lock, flags);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 5ff3f39af38d..163de4bde2d8 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -20,7 +20,7 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
+#include <linux/gfp.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
@@ -874,6 +874,151 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
return status;
}
+static void xhci_single_step_completion(struct urb *urb)
+{
+ struct completion *done = urb->context;
+
+ complete(done);
+}
+
+/*
+ * Allocate a URB and initialize the various fields of it.
+ * This API is used by the single_step_set_feature test of
+ * EHSET where IN packet of the GetDescriptor request is
+ * sent 15secs after the SETUP packet.
+ * Return NULL if failed.
+ */
+static struct urb *xhci_request_single_step_set_feature_urb(
+ struct usb_device *udev,
+ void *dr,
+ void *buf,
+ struct completion *done)
+{
+ struct urb *urb;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct usb_host_endpoint *ep;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return NULL;
+
+ urb->pipe = usb_rcvctrlpipe(udev, 0);
+ ep = udev->ep_in[usb_pipeendpoint(urb->pipe)];
+ if (!ep) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ /*
+ * Initialize the various URB fields as these are used by the HCD
+ * driver to queue it and as well as when completion happens.
+ */
+ urb->ep = ep;
+ urb->dev = udev;
+ urb->setup_packet = dr;
+ urb->transfer_buffer = buf;
+ urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+ urb->complete = xhci_single_step_completion;
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->transfer_flags = URB_DIR_IN;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ usb_hcd_map_urb_for_dma(hcd, urb, GFP_KERNEL);
+ urb->context = done;
+ return urb;
+}
+
+/*
+ * This function implements the USB_PORT_FEAT_TEST handling of the
+ * SINGLE_STEP_SET_FEATURE test mode as defined in the Embedded
+ * High-Speed Electrical Test (EHSET) specification. This simply
+ * issues a GetDescriptor control transfer, with an inserted 15-second
+ * delay after the end of the SETUP stage and before the IN token of
+ * the DATA stage is set. The idea is that this gives the test operator
+ * enough time to configure the oscilloscope to perform a measurement
+ * of the response time between the DATA and ACK packets that follow.
+ */
+static int xhci_ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+ int retval;
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ struct usb_device *udev;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct usb_device_descriptor *buf;
+ unsigned long flags;
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ /* Obtain udev of the rhub's child port */
+ udev = usb_hub_find_child(hcd->self.root_hub, port);
+ if (!udev) {
+ xhci_err(xhci, "No device attached to the RootHub\n");
+ return -ENODEV;
+ }
+ buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!dr) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ /* Fill Setup packet for GetDescriptor */
+ dr->bRequestType = USB_DIR_IN;
+ dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+ dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+ dr->wIndex = 0;
+ dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+ urb = xhci_request_single_step_set_feature_urb(udev, dr, buf, &done);
+ if (!urb) {
+ retval = -ENOMEM;
+ goto cleanup;
+ }
+
+ /* Now complete just the SETUP stage */
+ spin_lock_irqsave(&xhci->lock, flags);
+ retval = xhci_submit_single_step_set_feature(hcd, urb, 1);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ if (retval)
+ goto out1;
+
+ if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ xhci_err(xhci, "%s SETUP stage timed out on ep0\n", __func__);
+ goto out1;
+ }
+
+ /* Sleep for 15 seconds; HC will send SOFs during this period */
+ msleep(15 * 1000);
+
+ /* Complete remaining DATA and status stages. Re-use same URB */
+ urb->status = -EINPROGRESS;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ retval = xhci_submit_single_step_set_feature(hcd, urb, 0);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ if (!retval && !wait_for_completion_timeout(&done,
+ msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ xhci_err(xhci, "%s IN stage timed out on ep0\n", __func__);
+ }
+out1:
+ usb_free_urb(urb);
+cleanup:
+ kfree(dr);
+ kfree(buf);
+ return retval;
+}
+
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
@@ -888,6 +1033,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 link_state = 0;
u16 wake_mask = 0;
u16 timeout = 0;
+ u16 test_mode = 0;
max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -961,8 +1107,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
link_state = (wIndex & 0xff00) >> 3;
if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
wake_mask = wIndex & 0xff00;
- /* The MSB of wIndex is the U1/U2 timeout */
- timeout = (wIndex & 0xff00) >> 8;
+ /* The MSB of wIndex is the U1/U2 timeout OR TEST mode*/
+ test_mode = timeout = (wIndex & 0xff00) >> 8;
wIndex &= 0xff;
if (!wIndex || wIndex > max_ports)
goto error;
@@ -1136,6 +1282,32 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp |= PORT_U2_TIMEOUT(timeout);
writel(temp, port_array[wIndex] + PORTPMSC);
break;
+ case USB_PORT_FEAT_TEST:
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+ wIndex + 1);
+ if (test_mode && test_mode <= 5) {
+ /* unlock to execute stop endpoint commands */
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_stop_device(xhci, slot_id, 1);
+ spin_lock_irqsave(&xhci->lock, flags);
+ xhci_halt(xhci);
+
+ temp = readl_relaxed(port_array[wIndex] +
+ PORTPMSC);
+ temp |= test_mode << 28;
+ writel_relaxed(temp, port_array[wIndex] +
+ PORTPMSC);
+ /* to make sure above write goes through */
+ mb();
+ } else if (test_mode == 6) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ retval = xhci_ehset_single_step_set_feature(hcd,
+ wIndex);
+ spin_lock_irqsave(&xhci->lock, flags);
+ } else {
+ goto error;
+ }
+ break;
default:
goto error;
}
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 1f37b89e7267..a5e600910057 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3545,6 +3545,156 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
return 0;
}
+/*
+ * Variant of xhci_queue_ctrl_tx() used to implement EHSET
+ * SINGLE_STEP_SET_FEATURE test mode. It differs in that the control
+ * transfer is broken up so that the SETUP stage can happen and call
+ * the URB's completion handler before the DATA/STATUS stages are
+ * executed by the xHC hardware. This assumes the control transfer is a
+ * GetDescriptor, with a DATA stage in the IN direction, and an OUT
+ * STATUS stage.
+ *
+ * This function is called twice, usually with a 15-second delay in between.
+ * - with is_setup==true, the SETUP stage for the control request
+ * (GetDescriptor) is queued in the TRB ring and sent to HW immediately
+ * - with is_setup==false, the DATA and STATUS TRBs are queued and exceuted
+ *
+ * Caller must have locked xhci->lock
+ */
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb,
+ int is_setup)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_ring *ep_ring;
+ int num_trbs;
+ int ret;
+ unsigned int slot_id, ep_index;
+ struct usb_ctrlrequest *setup;
+ struct xhci_generic_trb *start_trb;
+ int start_cycle;
+ u32 field, length_field, remainder;
+ struct urb_priv *urb_priv;
+ struct xhci_td *td;
+
+ ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+ if (!ep_ring)
+ return -EINVAL;
+
+ /* Need buffer for data stage */
+ if (urb->transfer_buffer_length <= 0)
+ return -EINVAL;
+
+ /*
+ * Need to copy setup packet into setup TRB, so we can't use the setup
+ * DMA address.
+ */
+ if (!urb->setup_packet)
+ return -EINVAL;
+ setup = (struct usb_ctrlrequest *) urb->setup_packet;
+
+ slot_id = urb->dev->slot_id;
+ ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+
+ urb_priv = kzalloc(sizeof(struct urb_priv) +
+ sizeof(struct xhci_td *), GFP_ATOMIC);
+ if (!urb_priv)
+ return -ENOMEM;
+
+ td = urb_priv->td[0] = kzalloc(sizeof(struct xhci_td), GFP_ATOMIC);
+ if (!td) {
+ kfree(urb_priv);
+ return -ENOMEM;
+ }
+
+ urb_priv->length = 1;
+ urb_priv->td_cnt = 0;
+ urb->hcpriv = urb_priv;
+
+ num_trbs = is_setup ? 1 : 2;
+
+ ret = prepare_transfer(xhci, xhci->devs[slot_id],
+ ep_index, urb->stream_id,
+ num_trbs, urb, 0, GFP_ATOMIC);
+ if (ret < 0) {
+ kfree(td);
+ kfree(urb_priv);
+ return ret;
+ }
+
+ /*
+ * Don't give the first TRB to the hardware (by toggling the cycle bit)
+ * until we've finished creating all the other TRBs. The ring's cycle
+ * state may change as we enqueue the other TRBs, so save it too.
+ */
+ start_trb = &ep_ring->enqueue->generic;
+ start_cycle = ep_ring->cycle_state;
+
+ if (is_setup) {
+ /* Queue only the setup TRB */
+ field = TRB_IDT | TRB_IOC | TRB_TYPE(TRB_SETUP);
+ if (start_cycle == 0)
+ field |= 0x1;
+
+ /* xHCI 1.0 6.4.1.2.1: Transfer Type field */
+ if (xhci->hci_version == 0x100) {
+ if (setup->bRequestType & USB_DIR_IN)
+ field |= TRB_TX_TYPE(TRB_DATA_IN);
+ else
+ field |= TRB_TX_TYPE(TRB_DATA_OUT);
+ }
+
+ /* Save the DMA address of the last TRB in the TD */
+ td->last_trb = ep_ring->enqueue;
+
+ queue_trb(xhci, ep_ring, false,
+ setup->bRequestType | setup->bRequest << 8 |
+ le16_to_cpu(setup->wValue) << 16,
+ le16_to_cpu(setup->wIndex) |
+ le16_to_cpu(setup->wLength) << 16,
+ TRB_LEN(8) | TRB_INTR_TARGET(0),
+ field);
+ } else {
+ /* Queue data TRB */
+ field = TRB_ISP | TRB_TYPE(TRB_DATA);
+ if (start_cycle == 0)
+ field |= 0x1;
+ if (setup->bRequestType & USB_DIR_IN)
+ field |= TRB_DIR_IN;
+
+ remainder = xhci_td_remainder(xhci, 0,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer_length,
+ urb, 1);
+
+ length_field = TRB_LEN(urb->transfer_buffer_length) |
+ TRB_TD_SIZE(remainder) |
+ TRB_INTR_TARGET(0);
+
+ queue_trb(xhci, ep_ring, true,
+ lower_32_bits(urb->transfer_dma),
+ upper_32_bits(urb->transfer_dma),
+ length_field,
+ field);
+
+ /* Save the DMA address of the last TRB in the TD */
+ td->last_trb = ep_ring->enqueue;
+
+ /* Queue status TRB */
+ field = TRB_IOC | TRB_TYPE(TRB_STATUS);
+ if (!(setup->bRequestType & USB_DIR_IN))
+ field |= TRB_DIR_IN;
+
+ queue_trb(xhci, ep_ring, false,
+ 0,
+ 0,
+ TRB_INTR_TARGET(0),
+ field | ep_ring->cycle_state);
+ }
+
+ giveback_first_trb(xhci, slot_id, ep_index, 0, start_cycle, start_trb);
+ return 0;
+}
+
static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
struct urb *urb, int i)
{
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index dc03aac4f88a..097cfa9e4692 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1960,4 +1960,8 @@ struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_container_
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
+/* EHSET */
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb,
+ int is_setup);
+
#endif /* __LINUX_XHCI_HCD_H */
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 8b35ac933028..6fb91134b0c5 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -601,7 +601,8 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
readl_relaxed(qphy->base +
QUSB2PHY_PLL_ANALOG_CONTROLS_TWO);
- writel_relaxed(0x1b,
+ /* use CSR & switch to SE clk */
+ writel_relaxed(0xb,
qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_TWO);
/* enable clock bypass */
diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c
index 6b455e0f1e6f..9ab88d4a7a52 100644
--- a/drivers/video/fbdev/msm/mdss_debug.c
+++ b/drivers/video/fbdev/msm/mdss_debug.c
@@ -1359,7 +1359,9 @@ static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id,
(mdata->mdp_rev ==
MDSS_MDP_HW_REV_300) ||
(mdata->mdp_rev ==
- MDSS_MDP_HW_REV_301)) {
+ MDSS_MDP_HW_REV_301) ||
+ (mdata->mdp_rev ==
+ MDSS_MDP_HW_REV_320)) {
ctrl_reg += 0x8;
value_reg += 0x8;
}
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index da3c8ca23fb6..7076b36bb6b6 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -1211,16 +1211,20 @@ static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv)
ret = mdss_dp_get_lane_mapping(dp_drv, dp_drv->orientation,
&ln_map);
- if (ret)
+ if (ret) {
+ mutex_unlock(&dp_drv->train_mutex);
goto exit;
+ }
mdss_dp_phy_share_lane_config(&dp_drv->phy_io,
dp_drv->orientation,
dp_drv->dpcd.max_lane_count);
ret = mdss_dp_enable_mainlink_clocks(dp_drv);
- if (ret)
+ if (ret) {
+ mutex_unlock(&dp_drv->train_mutex);
goto exit;
+ }
mdss_dp_mainlink_reset(&dp_drv->ctrl_io);
@@ -1238,7 +1242,6 @@ static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv)
pr_debug("end\n");
exit:
- mutex_unlock(&dp_drv->train_mutex);
return ret;
}
@@ -1351,9 +1354,16 @@ static inline bool mdss_dp_is_link_training_requested(
return (dp->test_data.test_requested == TEST_LINK_TRAINING);
}
+static inline bool mdss_dp_is_phy_test_pattern_requested(
+ struct mdss_dp_drv_pdata *dp)
+{
+ return (dp->test_data.test_requested == PHY_TEST_PATTERN);
+}
+
static inline bool mdss_dp_soft_hpd_reset(struct mdss_dp_drv_pdata *dp)
{
- return mdss_dp_is_link_training_requested(dp) &&
+ return (mdss_dp_is_link_training_requested(dp) ||
+ mdss_dp_is_phy_test_pattern_requested(dp)) &&
dp->alt_mode.dp_status.hpd_irq;
}
@@ -2501,6 +2511,57 @@ static int mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp)
}
/**
+ * mdss_dp_process_phy_test_pattern_request() - process new phy test requests
+ * @dp: Display Port Driver data
+ *
+ * This function will handle new phy test pattern requests that are initiated
+ * by the sink. The function will return 0 if a phy test pattern has been
+ * processed, otherwise it will return -EINVAL.
+ */
+static int mdss_dp_process_phy_test_pattern_request(
+ struct mdss_dp_drv_pdata *dp)
+{
+ u32 test_link_rate = 0, test_lane_count = 0;
+
+ if (!mdss_dp_is_phy_test_pattern_requested(dp))
+ return -EINVAL;
+
+ mdss_dp_send_test_response(dp);
+
+ test_link_rate = dp->test_data.test_link_rate;
+ test_lane_count = dp->test_data.test_lane_count;
+
+ pr_info("%s link rate = 0x%x, lane count = 0x%x\n",
+ mdss_dp_get_test_name(TEST_LINK_TRAINING),
+ test_link_rate, test_lane_count);
+
+ /**
+ * Retrain the mainlink if there is a change in link rate or lane
+ * count.
+ */
+ if (mdss_dp_aux_is_link_rate_valid(test_link_rate) &&
+ mdss_dp_aux_is_lane_count_valid(test_lane_count) &&
+ ((dp->dpcd.max_lane_count != test_lane_count) ||
+ (dp->link_rate != test_link_rate))) {
+
+ pr_info("updated link rate or lane count, retraining.\n");
+
+ dp->dpcd.max_lane_count = dp->test_data.test_lane_count;
+ dp->link_rate = dp->test_data.test_link_rate;
+
+ mdss_dp_link_retraining(dp);
+ }
+
+ mdss_dp_config_ctrl(dp);
+
+ mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(dp);
+
+ mdss_dp_phy_send_test_pattern(dp);
+
+ return 0;
+}
+
+/**
* mdss_dp_process_downstream_port_status_change() - process port status changes
* @dp: Display Port Driver data
*
@@ -2548,6 +2609,9 @@ static int mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp)
if (!ret)
goto exit;
+ ret = mdss_dp_process_phy_test_pattern_request(dp);
+ if (!ret)
+ goto exit;
pr_debug("done\n");
exit:
mdss_dp_reset_test_data(dp);
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h
index c4494aa9c629..399ca61e0f46 100644
--- a/drivers/video/fbdev/msm/mdss_dp.h
+++ b/drivers/video/fbdev/msm/mdss_dp.h
@@ -268,6 +268,7 @@ struct dpcd_test_request {
u32 test_requested;
u32 test_link_rate;
u32 test_lane_count;
+ u32 phy_test_pattern_sel;
u32 response;
};
@@ -509,6 +510,51 @@ enum dp_lane_count {
DP_LANE_COUNT_4 = 4,
};
+enum phy_test_pattern {
+ PHY_TEST_PATTERN_NONE,
+ PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING,
+ PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT,
+ PHY_TEST_PATTERN_PRBS7,
+ PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN,
+ PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN,
+};
+
+static inline char *mdss_dp_get_phy_test_pattern(u32 phy_test_pattern_sel)
+{
+ switch (phy_test_pattern_sel) {
+ case PHY_TEST_PATTERN_NONE:
+ return DP_ENUM_STR(PHY_TEST_PATTERN_NONE);
+ case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING:
+ return DP_ENUM_STR(PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING);
+ case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+ return DP_ENUM_STR(PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT);
+ case PHY_TEST_PATTERN_PRBS7:
+ return DP_ENUM_STR(PHY_TEST_PATTERN_PRBS7);
+ case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN:
+ return DP_ENUM_STR(PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN);
+ case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN:
+ return DP_ENUM_STR(PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN);
+ default:
+ return "unknown";
+ }
+}
+
+static inline bool mdss_dp_is_phy_test_pattern_supported(
+ u32 phy_test_pattern_sel)
+{
+ switch (phy_test_pattern_sel) {
+ case PHY_TEST_PATTERN_NONE:
+ case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING:
+ case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+ case PHY_TEST_PATTERN_PRBS7:
+ case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN:
+ case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN:
+ return true;
+ default:
+ return false;
+ }
+}
+
enum dp_aux_error {
EDP_AUX_ERR_NONE = 0,
EDP_AUX_ERR_ADDR = -1,
@@ -561,7 +607,7 @@ static inline char *mdss_dp_get_test_response(u32 test_response)
enum test_type {
UNKNOWN_TEST = 0,
TEST_LINK_TRAINING = BIT(0),
- TEST_PATTERN = BIT(1),
+ PHY_TEST_PATTERN = BIT(3),
TEST_EDID_READ = BIT(2),
};
@@ -569,7 +615,7 @@ static inline char *mdss_dp_get_test_name(u32 test_requested)
{
switch (test_requested) {
case TEST_LINK_TRAINING: return DP_ENUM_STR(TEST_LINK_TRAINING);
- case TEST_PATTERN: return DP_ENUM_STR(TEST_PATTERN);
+ case PHY_TEST_PATTERN: return DP_ENUM_STR(PHY_TEST_PATTERN);
case TEST_EDID_READ: return DP_ENUM_STR(TEST_EDID_READ);
default: return "unknown";
}
@@ -640,5 +686,10 @@ void *mdss_dp_get_hdcp_data(struct device *dev);
int mdss_dp_hdcp2p2_init(struct mdss_dp_drv_pdata *dp_drv);
bool mdss_dp_aux_clock_recovery_done(struct mdss_dp_drv_pdata *ep);
bool mdss_dp_aux_channel_eq_done(struct mdss_dp_drv_pdata *ep);
+bool mdss_dp_aux_is_link_rate_valid(u32 link_rate);
+bool mdss_dp_aux_is_lane_count_valid(u32 lane_count);
+int mdss_dp_aux_link_status_read(struct mdss_dp_drv_pdata *ep, int len);
+void mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(
+ struct mdss_dp_drv_pdata *dp);
#endif /* MDSS_DP_H */
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index b216506fe2a9..b8be110f04f0 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -537,8 +537,9 @@ char mdss_dp_gen_link_clk(struct mdss_panel_info *pinfo, char lane_cnt)
else if (min_link_rate <= DP_LINK_RATE_540)
calc_link_rate = DP_LINK_RATE_540;
else {
- pr_err("link_rate = %d is unsupported\n", min_link_rate);
- calc_link_rate = 0;
+ /* Cap the link rate to the max supported rate */
+ pr_debug("link_rate = %d is unsupported\n", min_link_rate);
+ calc_link_rate = DP_LINK_RATE_540;
}
return calc_link_rate;
@@ -960,7 +961,7 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
dp_sink_parse_sink_count(ep);
}
-static int dp_link_status_read(struct mdss_dp_drv_pdata *ep, int len)
+int mdss_dp_aux_link_status_read(struct mdss_dp_drv_pdata *ep, int len)
{
char *bp;
char data;
@@ -1031,12 +1032,12 @@ void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *dp)
}
/**
- * dp_is_link_rate_valid() - validates the link rate
+ * mdss_dp_aux_is_link_rate_valid() - validates the link rate
* @lane_rate: link rate requested by the sink
*
* Returns true if the requested link rate is supported.
*/
-static bool dp_is_link_rate_valid(u32 link_rate)
+bool mdss_dp_aux_is_link_rate_valid(u32 link_rate)
{
return (link_rate == DP_LINK_RATE_162) ||
(link_rate == DP_LINK_RATE_270) ||
@@ -1044,12 +1045,12 @@ static bool dp_is_link_rate_valid(u32 link_rate)
}
/**
- * dp_is_lane_count_valid() - validates the lane count
+ * mdss_dp_aux_is_lane_count_valid() - validates the lane count
* @lane_count: lane count requested by the sink
*
* Returns true if the requested lane count is supported.
*/
-static bool dp_is_lane_count_valid(u32 lane_count)
+bool mdss_dp_aux_is_lane_count_valid(u32 lane_count)
{
return (lane_count == DP_LANE_COUNT_1) ||
(lane_count == DP_LANE_COUNT_2) ||
@@ -1086,7 +1087,7 @@ static int dp_parse_link_training_params(struct mdss_dp_drv_pdata *ep)
bp = rp->data;
data = *bp++;
- if (!dp_is_link_rate_valid(data)) {
+ if (!mdss_dp_aux_is_link_rate_valid(data)) {
pr_err("invalid link rate = 0x%x\n", data);
ret = -EINVAL;
goto exit;
@@ -1108,7 +1109,7 @@ static int dp_parse_link_training_params(struct mdss_dp_drv_pdata *ep)
data = *bp++;
data &= 0x1F;
- if (!dp_is_lane_count_valid(data)) {
+ if (!mdss_dp_aux_is_lane_count_valid(data)) {
pr_err("invalid lane count = 0x%x\n", data);
ret = -EINVAL;
goto exit;
@@ -1157,6 +1158,53 @@ static void dp_sink_parse_sink_count(struct mdss_dp_drv_pdata *ep)
}
/**
+ * dp_parse_phy_test_params() - parses the phy test parameters
+ * @ep: Display Port Driver data
+ *
+ * Parses the DPCD (Byte 0x248) for the DP PHY test pattern that is being
+ * requested.
+ */
+static int dp_parse_phy_test_params(struct mdss_dp_drv_pdata *ep)
+{
+ char *bp;
+ char data;
+ struct edp_buf *rp;
+ int rlen;
+ int const param_len = 0x1;
+ int const phy_test_pattern_addr = 0x248;
+ int const dpcd_version_1_2 = 0x12;
+ int ret = 0;
+
+ rlen = dp_aux_read_buf(ep, phy_test_pattern_addr, param_len, 0);
+ if (rlen < param_len) {
+ pr_err("failed to read phy test pattern\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ rp = &ep->rxp;
+ bp = rp->data;
+ data = *bp++;
+
+ if (ep->dpcd.major == dpcd_version_1_2)
+ data = data & 0x7;
+ else
+ data = data & 0x3;
+
+ ep->test_data.phy_test_pattern_sel = data;
+
+ pr_debug("phy_test_pattern_sel = %s\n",
+ mdss_dp_get_phy_test_pattern(data));
+
+ if (!mdss_dp_is_phy_test_pattern_supported(data))
+ ret = -EINVAL;
+
+end:
+ return ret;
+}
+
+
+/**
* dp_is_test_supported() - checks if test requested by sink is supported
* @test_requested: test requested by the sink
*
@@ -1165,7 +1213,8 @@ static void dp_sink_parse_sink_count(struct mdss_dp_drv_pdata *ep)
static bool dp_is_test_supported(u32 test_requested)
{
return (test_requested == TEST_LINK_TRAINING) ||
- (test_requested == TEST_EDID_READ);
+ (test_requested == TEST_EDID_READ) ||
+ (test_requested == PHY_TEST_PATTERN);
}
/**
@@ -1229,8 +1278,19 @@ static void dp_sink_parse_test_request(struct mdss_dp_drv_pdata *ep)
pr_debug("%s requested\n", mdss_dp_get_test_name(data));
ep->test_data.test_requested = data;
- if (ep->test_data.test_requested == TEST_LINK_TRAINING)
+ switch (ep->test_data.test_requested) {
+ case PHY_TEST_PATTERN:
+ ret = dp_parse_phy_test_params(ep);
+ if (ret)
+ break;
+ case TEST_LINK_TRAINING:
ret = dp_parse_link_training_params(ep);
+ break;
+ default:
+ pr_debug("test 0x%x not supported\n",
+ ep->test_data.test_requested);
+ return;
+ }
/**
* Send a TEST_ACK if all test parameters are valid, otherwise send
@@ -1453,7 +1513,8 @@ char vm_voltage_swing[4][4] = {
{0x1E, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
};
-static void dp_voltage_pre_emphasise_set(struct mdss_dp_drv_pdata *dp)
+static void dp_aux_set_voltage_and_pre_emphasis_lvl(
+ struct mdss_dp_drv_pdata *dp)
{
u32 value0 = 0;
u32 value1 = 0;
@@ -1488,6 +1549,38 @@ static void dp_voltage_pre_emphasise_set(struct mdss_dp_drv_pdata *dp)
}
+/**
+ * mdss_dp_aux_update_voltage_and_pre_emphasis_lvl() - updates DP PHY settings
+ * @ep: Display Port Driver data
+ *
+ * Updates the DP PHY with the requested voltage swing and pre-emphasis
+ * levels if they are different from the current settings.
+ */
+void mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(
+ struct mdss_dp_drv_pdata *dp)
+{
+ int const num_bytes = 6;
+ struct dpcd_link_status *status = &dp->link_status;
+
+ /* Read link status for updated voltage and pre-emphasis levels. */
+ mdss_dp_aux_link_status_read(dp, num_bytes);
+
+ pr_info("Current: v_level = %d, p_level = %d\n",
+ dp->v_level, dp->p_level);
+ pr_info("Requested: v_level = %d, p_level = %d\n",
+ status->req_voltage_swing[0],
+ status->req_pre_emphasis[0]);
+
+ if ((status->req_voltage_swing[0] != dp->v_level) ||
+ (status->req_pre_emphasis[0] != dp->p_level)) {
+ dp->v_level = status->req_voltage_swing[0];
+ dp->p_level = status->req_pre_emphasis[0];
+
+ dp_aux_set_voltage_and_pre_emphasis_lvl(dp);
+ }
+
+ pr_debug("end\n");
+}
static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep)
{
int tries, old_v_level;
@@ -1500,7 +1593,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep)
dp_host_train_set(ep, 0x01); /* train_1 */
dp_cap_lane_rate_set(ep);
dp_train_pattern_set_write(ep, 0x21); /* train_1 */
- dp_voltage_pre_emphasise_set(ep);
+ dp_aux_set_voltage_and_pre_emphasis_lvl(ep);
tries = 0;
old_v_level = ep->v_level;
@@ -1508,7 +1601,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep)
usleep_time = ep->dpcd.training_read_interval;
usleep_range(usleep_time, usleep_time);
- dp_link_status_read(ep, 6);
+ mdss_dp_aux_link_status_read(ep, 6);
if (mdss_dp_aux_clock_recovery_done(ep)) {
ret = 0;
break;
@@ -1531,7 +1624,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep)
}
dp_sink_train_set_adjust(ep);
- dp_voltage_pre_emphasise_set(ep);
+ dp_aux_set_voltage_and_pre_emphasis_lvl(ep);
}
return ret;
@@ -1555,13 +1648,13 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep)
dp_train_pattern_set_write(ep, pattern | 0x20);/* train_2 */
do {
- dp_voltage_pre_emphasise_set(ep);
+ dp_aux_set_voltage_and_pre_emphasis_lvl(ep);
dp_host_train_set(ep, pattern);
usleep_time = ep->dpcd.training_read_interval;
usleep_range(usleep_time, usleep_time);
- dp_link_status_read(ep, 6);
+ mdss_dp_aux_link_status_read(ep, 6);
if (mdss_dp_aux_channel_eq_done(ep)) {
ret = 0;
@@ -1698,7 +1791,7 @@ void mdss_dp_aux_parse_sink_status_field(struct mdss_dp_drv_pdata *ep)
{
dp_sink_parse_sink_count(ep);
dp_sink_parse_test_request(ep);
- dp_link_status_read(ep, 6);
+ mdss_dp_aux_link_status_read(ep, 6);
}
int mdss_dp_dpcd_status_read(struct mdss_dp_drv_pdata *ep)
@@ -1706,7 +1799,7 @@ int mdss_dp_dpcd_status_read(struct mdss_dp_drv_pdata *ep)
struct dpcd_link_status *sp;
int ret = 0; /* not sync */
- ret = dp_link_status_read(ep, 6);
+ ret = mdss_dp_aux_link_status_read(ep, 6);
if (ret) {
sp = &ep->link_status;
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c
index b1bfe2c548ba..3b294a11f555 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.c
+++ b/drivers/video/fbdev/msm/mdss_dp_util.c
@@ -892,3 +892,87 @@ void mdss_dp_audio_enable(struct dss_io_data *ctrl_io, bool enable)
writel_relaxed(audio_ctrl, ctrl_io->base + MMSS_DP_AUDIO_CFG);
}
+
+/**
+ * mdss_dp_phy_send_test_pattern() - sends the requested PHY test pattern
+ * @ep: Display Port Driver data
+ *
+ * Updates the DP controller state and sends the requested PHY test pattern
+ * to the sink.
+ */
+void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp)
+{
+ struct dss_io_data *io = &dp->ctrl_io;
+ u32 phy_test_pattern_sel = dp->test_data.phy_test_pattern_sel;
+ u32 value = 0x0;
+
+ if (!mdss_dp_is_phy_test_pattern_supported(phy_test_pattern_sel)) {
+ pr_err("test pattern 0x%x not supported\n",
+ phy_test_pattern_sel);
+ return;
+ }
+
+ /* Disable mainlink */
+ writel_relaxed(0x0, io->base + DP_MAINLINK_CTRL);
+
+ /* Reset mainlink */
+ mdss_dp_mainlink_reset(io);
+
+ /* Enable mainlink */
+ writel_relaxed(0x0, io->base + DP_MAINLINK_CTRL);
+
+ /* Initialize DP state control */
+ mdss_dp_state_ctrl(io, 0x00);
+
+ pr_debug("phy_test_pattern_sel = %s\n",
+ mdss_dp_get_phy_test_pattern(phy_test_pattern_sel));
+
+ switch (phy_test_pattern_sel) {
+ case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING:
+ mdss_dp_state_ctrl(io, BIT(0));
+ break;
+ case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+ value = readl_relaxed(io->base +
+ DP_HBR2_COMPLIANCE_SCRAMBLER_RESET);
+ value &= ~(1 << 16);
+ writel_relaxed(value, io->base +
+ DP_HBR2_COMPLIANCE_SCRAMBLER_RESET);
+ value |= 0xFC;
+ writel_relaxed(value, io->base +
+ DP_HBR2_COMPLIANCE_SCRAMBLER_RESET);
+ writel_relaxed(0x2, io->base + DP_MAINLINK_LEVELS);
+ mdss_dp_state_ctrl(io, BIT(4));
+ break;
+ case PHY_TEST_PATTERN_PRBS7:
+ mdss_dp_state_ctrl(io, BIT(5));
+ break;
+ case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN:
+ mdss_dp_state_ctrl(io, BIT(6));
+ /* 00111110000011111000001111100000 */
+ writel_relaxed(0x3E0F83E0, io->base +
+ DP_TEST_80BIT_CUSTOM_PATTERN_REG0);
+ /* 00001111100000111110000011111000 */
+ writel_relaxed(0x0F83E0F8, io->base +
+ DP_TEST_80BIT_CUSTOM_PATTERN_REG1);
+ /* 1111100000111110 */
+ writel_relaxed(0x0000F83E, io->base +
+ DP_TEST_80BIT_CUSTOM_PATTERN_REG2);
+ break;
+ case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN:
+ value = readl_relaxed(io->base +
+ DP_HBR2_COMPLIANCE_SCRAMBLER_RESET);
+ value |= BIT(16);
+ writel_relaxed(value, io->base +
+ DP_HBR2_COMPLIANCE_SCRAMBLER_RESET);
+ value |= 0xFC;
+ writel_relaxed(value, io->base +
+ DP_HBR2_COMPLIANCE_SCRAMBLER_RESET);
+ writel_relaxed(0x2, io->base + DP_MAINLINK_LEVELS);
+ mdss_dp_state_ctrl(io, BIT(4));
+ break;
+ default:
+ pr_debug("No valid test pattern requested: 0x%x\n",
+ phy_test_pattern_sel);
+ return;
+ }
+}
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h
index 5e238d5be2b4..c046deef48a3 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.h
+++ b/drivers/video/fbdev/msm/mdss_dp_util.h
@@ -60,6 +60,11 @@
#define DP_MAINLINK_LEVELS (0x00000444)
#define DP_TU (0x0000044C)
+#define DP_HBR2_COMPLIANCE_SCRAMBLER_RESET (0x00000454)
+#define DP_TEST_80BIT_CUSTOM_PATTERN_REG0 (0x000004C0)
+#define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000004C4)
+#define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000004C8)
+
#define MMSS_DP_AUDIO_TIMING_GEN (0x00000480)
#define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000484)
#define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000488)
@@ -315,5 +320,6 @@ void mdss_dp_audio_set_sample_rate(struct dss_io_data *ctrl_io,
void mdss_dp_set_safe_to_exit_level(struct dss_io_data *ctrl_io,
uint32_t lane_cnt);
int mdss_dp_aux_read_rx_status(struct mdss_dp_drv_pdata *dp, u8 *rx_status);
+void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp);
#endif /* __DP_UTIL_H__ */
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index c63685bcf306..d9cfd2360ab3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -2105,6 +2105,48 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
set_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map);
set_bit(MDSS_CAPS_SEC_DETACH_SMMU, mdata->mdss_caps_map);
break;
+ case MDSS_MDP_HW_REV_320:
+ mdata->max_target_zorder = 7; /* excluding base layer */
+ mdata->max_cursor_size = 512;
+ mdata->per_pipe_ib_factor.numer = 8;
+ mdata->per_pipe_ib_factor.denom = 5;
+ mdata->apply_post_scale_bytes = false;
+ mdata->hflip_buffer_reused = false;
+ mdata->min_prefill_lines = 25;
+ mdata->has_ubwc = true;
+ mdata->pixel_ram_size = 50 * 1024;
+ mdata->rects_per_sspp[MDSS_MDP_PIPE_TYPE_DMA] = 2;
+
+ mem_protect_sd_ctrl_id = MEM_PROTECT_SD_CTRL_SWITCH;
+ set_bit(MDSS_QOS_PER_PIPE_IB, mdata->mdss_qos_map);
+ set_bit(MDSS_QOS_REMAPPER, mdata->mdss_qos_map);
+ set_bit(MDSS_QOS_TS_PREFILL, mdata->mdss_qos_map);
+ set_bit(MDSS_QOS_OVERHEAD_FACTOR, mdata->mdss_qos_map);
+ set_bit(MDSS_QOS_CDP, mdata->mdss_qos_map); /* cdp supported */
+ mdata->enable_cdp = false; /* disable cdp */
+ set_bit(MDSS_QOS_OTLIM, mdata->mdss_qos_map);
+ set_bit(MDSS_QOS_PER_PIPE_LUT, mdata->mdss_qos_map);
+ set_bit(MDSS_QOS_SIMPLIFIED_PREFILL, mdata->mdss_qos_map);
+ set_bit(MDSS_QOS_TS_PREFILL, mdata->mdss_qos_map);
+ set_bit(MDSS_QOS_IB_NOCR, mdata->mdss_qos_map);
+ set_bit(MDSS_QOS_WB2_WRITE_GATHER_EN, mdata->mdss_qos_map);
+ set_bit(MDSS_CAPS_YUV_CONFIG, mdata->mdss_caps_map);
+ set_bit(MDSS_CAPS_SCM_RESTORE_NOT_REQUIRED,
+ mdata->mdss_caps_map);
+ set_bit(MDSS_CAPS_3D_MUX_UNDERRUN_RECOVERY_SUPPORTED,
+ mdata->mdss_caps_map);
+ set_bit(MDSS_CAPS_QSEED3, mdata->mdss_caps_map);
+ set_bit(MDSS_CAPS_MDP_VOTE_CLK_NOT_SUPPORTED,
+ mdata->mdss_caps_map);
+ mdss_mdp_init_default_prefill_factors(mdata);
+ mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU);
+ mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT);
+ mdss_set_quirk(mdata, MDSS_QUIRK_MMSS_GDSC_COLLAPSE);
+ mdss_set_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE);
+ mdata->has_wb_ubwc = true;
+ set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map);
+ set_bit(MDSS_CAPS_SEC_DETACH_SMMU, mdata->mdss_caps_map);
+ break;
default:
mdata->max_target_zorder = 4; /* excluding base layer */
mdata->max_cursor_size = 64;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index 20aeabfdf9a4..ab2a7184aa45 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -1285,7 +1285,9 @@ static inline int mdss_mdp_panic_signal_support_mode(
IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev,
MDSS_MDP_HW_REV_116) ||
IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev,
- MDSS_MDP_HW_REV_300))
+ MDSS_MDP_HW_REV_300) ||
+ IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev,
+ MDSS_MDP_HW_REV_320))
signal_mode = MDSS_MDP_PANIC_PER_PIPE_CFG;
return signal_mode;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index c80d8f47bbb7..bb8227a74a04 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -5776,7 +5776,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
mdss_mdp_ctl_split_display_enable(split_lm_valid, ctl, sctl);
ATRACE_BEGIN("postproc_programming");
- if (ctl->mfd && ctl->mfd->dcm_state != DTM_ENTER)
+ if (ctl->is_video_mode && ctl->mfd && ctl->mfd->dcm_state != DTM_ENTER)
/* postprocessing setup, including dspp */
mdss_mdp_pp_setup_locked(ctl);
@@ -5824,6 +5824,24 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
if (ctl->ops.wait_pingpong && !mdata->serialize_wait4pp)
mdss_mdp_display_wait4pingpong(ctl, false);
+ /* Moved pp programming to post ping pong */
+ if (!ctl->is_video_mode && ctl->mfd &&
+ ctl->mfd->dcm_state != DTM_ENTER) {
+ /* postprocessing setup, including dspp */
+ mutex_lock(&ctl->flush_lock);
+ mdss_mdp_pp_setup_locked(ctl);
+ if (sctl) {
+ if (ctl->split_flush_en) {
+ ctl->flush_bits |= sctl->flush_bits;
+ sctl->flush_bits = 0;
+ sctl_flush_bits = 0;
+ } else {
+ sctl_flush_bits = sctl->flush_bits;
+ }
+ }
+ ctl_flush_bits = ctl->flush_bits;
+ mutex_unlock(&ctl->flush_lock);
+ }
/*
* if serialize_wait4pp is false then roi_bkup used in wait4pingpong
* will be of previous frame as expected.
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index 264024289691..917e6889124d 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -1123,7 +1123,8 @@ static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op)
mdss_mdp_pp_get_dcm_state(pipe, &dcm_state);
mdata = mdss_mdp_get_mdata();
- if (IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_301) ||
+ if (IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_320) ||
+ IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_301) ||
IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_300)) {
if (pipe->src_fmt->is_yuv) {
/* TODO: check csc cfg from PP block */
@@ -7664,6 +7665,7 @@ static int pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
break;
case MDSS_MDP_HW_REV_300:
case MDSS_MDP_HW_REV_301:
+ case MDSS_MDP_HW_REV_320:
/*
* Some of the REV_300 PP features are same as REV_107.
* Get the driver ops for both the versions and update the