diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2016-12-27 21:28:55 -0700 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2016-12-27 21:28:56 -0700 |
commit | aa36bb38fc87f49921c9e07fdb4a1a74482f26af (patch) | |
tree | 896eb2e151d70632bb4f04ff0a2a1f7f0dd7b694 /drivers | |
parent | 7aa1be414789d169eba3bce5345c4d009e989b6a (diff) | |
parent | 55e8426a192811d7567f19d7e781727f46b0406d (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')
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 |