diff --git a/Documentation/ABI/testing/sysfs-bus-mei b/Documentation/ABI/testing/sysfs-bus-mei index 6bd45346ac7e4d20ffb445723fe94b5e32d98b3a..3f8701e8fa241d4a2a74ea29ca1cd9772d9360c9 100644 --- a/Documentation/ABI/testing/sysfs-bus-mei +++ b/Documentation/ABI/testing/sysfs-bus-mei @@ -4,7 +4,7 @@ KernelVersion: 3.10 Contact: Samuel Ortiz linux-mei@linux.intel.com Description: Stores the same MODALIAS value emitted by uevent - Format: mei::: + Format: mei::: What: /sys/bus/mei/devices/.../name Date: May 2015 diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index ee39acacf6f8512cb81eedaf0d06685bbf004144..335595a79866c6b7ce6b8d50679098e3c23681e2 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -7,6 +7,13 @@ Description: The name of devfreq object denoted as ... is same as the name of device using devfreq. +What: /sys/class/devfreq/.../name +Date: November 2019 +Contact: Chanwoo Choi +Description: + The /sys/class/devfreq/.../name shows the name of device + of the corresponding devfreq object. + What: /sys/class/devfreq/.../governor Date: September 2011 Contact: MyungJoo Ham diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index b4795e72fe48f480e1ff93f09c008b1634aa9a9b..3b32e5fe1447e6cbc57a297dccf70c05e6e6439b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1867,6 +1867,12 @@ Built with CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y, the default is off. + kpti= [ARM64] Control page table isolation of user + and kernel address spaces. + Default: enabled on cores which need mitigation. + 0: force disabled + 1: force enabled + kvm.ignore_msrs=[KVM] Ignore guest accesses to unhandled MSRs. Default is 0 (don't ignore, but inject #GP) diff --git a/Documentation/cpu-freq/cpufreq-stats.txt b/Documentation/cpu-freq/cpufreq-stats.txt index 2bbe207354ed7c7e73ceb7f51ddb105c49827a1d..a873855c811d63f3a47cd2ec830404abb89d48c8 100644 --- a/Documentation/cpu-freq/cpufreq-stats.txt +++ b/Documentation/cpu-freq/cpufreq-stats.txt @@ -90,6 +90,9 @@ Freq_i to Freq_j. Freq_i is in descending order with increasing rows and Freq_j is in descending order with increasing columns. The output here also contains the actual freq values for each row and column for better readability. +If the transition table is bigger than PAGE_SIZE, reading this will +return an -EFBIG error. + -------------------------------------------------------------------------------- :/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table From : To diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kcov.rst index 44886c91e112d4d21a41e0c4d1a96f37a584aa68..f254173b180f804ab7921673b0046436f1d804ab 100644 --- a/Documentation/dev-tools/kcov.rst +++ b/Documentation/dev-tools/kcov.rst @@ -12,19 +12,31 @@ To achieve this goal it does not collect coverage in soft/hard interrupts and instrumentation of some inherently non-deterministic parts of kernel is disabled (e.g. scheduler, locking). -Usage ------ +kcov is also able to collect comparison operands from the instrumented code +(this feature currently requires that the kernel is compiled with clang). + +Prerequisites +------------- Configure the kernel with:: CONFIG_KCOV=y CONFIG_KCOV requires gcc built on revision 231296 or later. + +If the comparison operands need to be collected, set:: + + CONFIG_KCOV_ENABLE_COMPARISONS=y + Profiling data will only become accessible once debugfs has been mounted:: mount -t debugfs none /sys/kernel/debug -The following program demonstrates kcov usage from within a test program: +Coverage collection +------------------- + +The following program demonstrates coverage collection from within a test +program using kcov: .. code-block:: c @@ -44,6 +56,9 @@ The following program demonstrates kcov usage from within a test program: #define KCOV_DISABLE _IO('c', 101) #define COVER_SIZE (64<<10) + #define KCOV_TRACE_PC 0 + #define KCOV_TRACE_CMP 1 + int main(int argc, char **argv) { int fd; @@ -64,7 +79,7 @@ The following program demonstrates kcov usage from within a test program: if ((void*)cover == MAP_FAILED) perror("mmap"), exit(1); /* Enable coverage collection on the current thread. */ - if (ioctl(fd, KCOV_ENABLE, 0)) + if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_PC)) perror("ioctl"), exit(1); /* Reset coverage from the tail of the ioctl() call. */ __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); @@ -111,3 +126,208 @@ The interface is fine-grained to allow efficient forking of test processes. That is, a parent process opens /sys/kernel/debug/kcov, enables trace mode, mmaps coverage buffer and then forks child processes in a loop. Child processes only need to enable coverage (disable happens automatically on thread end). + +Comparison operands collection +------------------------------ + +Comparison operands collection is similar to coverage collection: + +.. code-block:: c + + /* Same includes and defines as above. */ + + /* Number of 64-bit words per record. */ + #define KCOV_WORDS_PER_CMP 4 + + /* + * The format for the types of collected comparisons. + * + * Bit 0 shows whether one of the arguments is a compile-time constant. + * Bits 1 & 2 contain log2 of the argument size, up to 8 bytes. + */ + + #define KCOV_CMP_CONST (1 << 0) + #define KCOV_CMP_SIZE(n) ((n) << 1) + #define KCOV_CMP_MASK KCOV_CMP_SIZE(3) + + int main(int argc, char **argv) + { + int fd; + uint64_t *cover, type, arg1, arg2, is_const, size; + unsigned long n, i; + + fd = open("/sys/kernel/debug/kcov", O_RDWR); + if (fd == -1) + perror("open"), exit(1); + if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) + perror("ioctl"), exit(1); + /* + * Note that the buffer pointer is of type uint64_t*, because all + * the comparison operands are promoted to uint64_t. + */ + cover = (uint64_t *)mmap(NULL, COVER_SIZE * sizeof(unsigned long), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if ((void*)cover == MAP_FAILED) + perror("mmap"), exit(1); + /* Note KCOV_TRACE_CMP instead of KCOV_TRACE_PC. */ + if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_CMP)) + perror("ioctl"), exit(1); + __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); + read(-1, NULL, 0); + /* Read number of comparisons collected. */ + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + for (i = 0; i < n; i++) { + type = cover[i * KCOV_WORDS_PER_CMP + 1]; + /* arg1 and arg2 - operands of the comparison. */ + arg1 = cover[i * KCOV_WORDS_PER_CMP + 2]; + arg2 = cover[i * KCOV_WORDS_PER_CMP + 3]; + /* ip - caller address. */ + ip = cover[i * KCOV_WORDS_PER_CMP + 4]; + /* size of the operands. */ + size = 1 << ((type & KCOV_CMP_MASK) >> 1); + /* is_const - true if either operand is a compile-time constant.*/ + is_const = type & KCOV_CMP_CONST; + printf("ip: 0x%lx type: 0x%lx, arg1: 0x%lx, arg2: 0x%lx, " + "size: %lu, %s\n", + ip, type, arg1, arg2, size, + is_const ? "const" : "non-const"); + } + if (ioctl(fd, KCOV_DISABLE, 0)) + perror("ioctl"), exit(1); + /* Free resources. */ + if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) + perror("munmap"), exit(1); + if (close(fd)) + perror("close"), exit(1); + return 0; + } + +Note that the kcov modes (coverage collection or comparison operands) are +mutually exclusive. + +Remote coverage collection +-------------------------- + +With KCOV_ENABLE coverage is collected only for syscalls that are issued +from the current process. With KCOV_REMOTE_ENABLE it's possible to collect +coverage for arbitrary parts of the kernel code, provided that those parts +are annotated with kcov_remote_start()/kcov_remote_stop(). + +This allows to collect coverage from two types of kernel background +threads: the global ones, that are spawned during kernel boot in a limited +number of instances (e.g. one USB hub_event() worker thread is spawned per +USB HCD); and the local ones, that are spawned when a user interacts with +some kernel interface (e.g. vhost workers). + +To enable collecting coverage from a global background thread, a unique +global handle must be assigned and passed to the corresponding +kcov_remote_start() call. Then a userspace process can pass a list of such +handles to the KCOV_REMOTE_ENABLE ioctl in the handles array field of the +kcov_remote_arg struct. This will attach the used kcov device to the code +sections, that are referenced by those handles. + +Since there might be many local background threads spawned from different +userspace processes, we can't use a single global handle per annotation. +Instead, the userspace process passes a non-zero handle through the +common_handle field of the kcov_remote_arg struct. This common handle gets +saved to the kcov_handle field in the current task_struct and needs to be +passed to the newly spawned threads via custom annotations. Those threads +should in turn be annotated with kcov_remote_start()/kcov_remote_stop(). + +Internally kcov stores handles as u64 integers. The top byte of a handle +is used to denote the id of a subsystem that this handle belongs to, and +the lower 4 bytes are used to denote the id of a thread instance within +that subsystem. A reserved value 0 is used as a subsystem id for common +handles as they don't belong to a particular subsystem. The bytes 4-7 are +currently reserved and must be zero. In the future the number of bytes +used for the subsystem or handle ids might be increased. + +When a particular userspace proccess collects coverage by via a common +handle, kcov will collect coverage for each code section that is annotated +to use the common handle obtained as kcov_handle from the current +task_struct. However non common handles allow to collect coverage +selectively from different subsystems. + +.. code-block:: c + + struct kcov_remote_arg { + __u32 trace_mode; + __u32 area_size; + __u32 num_handles; + __aligned_u64 common_handle; + __aligned_u64 handles[0]; + }; + + #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) + #define KCOV_DISABLE _IO('c', 101) + #define KCOV_REMOTE_ENABLE _IOW('c', 102, struct kcov_remote_arg) + + #define COVER_SIZE (64 << 10) + + #define KCOV_TRACE_PC 0 + + #define KCOV_SUBSYSTEM_COMMON (0x00ull << 56) + #define KCOV_SUBSYSTEM_USB (0x01ull << 56) + + #define KCOV_SUBSYSTEM_MASK (0xffull << 56) + #define KCOV_INSTANCE_MASK (0xffffffffull) + + static inline __u64 kcov_remote_handle(__u64 subsys, __u64 inst) + { + if (subsys & ~KCOV_SUBSYSTEM_MASK || inst & ~KCOV_INSTANCE_MASK) + return 0; + return subsys | inst; + } + + #define KCOV_COMMON_ID 0x42 + #define KCOV_USB_BUS_NUM 1 + + int main(int argc, char **argv) + { + int fd; + unsigned long *cover, n, i; + struct kcov_remote_arg *arg; + + fd = open("/sys/kernel/debug/kcov", O_RDWR); + if (fd == -1) + perror("open"), exit(1); + if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) + perror("ioctl"), exit(1); + cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if ((void*)cover == MAP_FAILED) + perror("mmap"), exit(1); + + /* Enable coverage collection via common handle and from USB bus #1. */ + arg = calloc(1, sizeof(*arg) + sizeof(uint64_t)); + if (!arg) + perror("calloc"), exit(1); + arg->trace_mode = KCOV_TRACE_PC; + arg->area_size = COVER_SIZE; + arg->num_handles = 1; + arg->common_handle = kcov_remote_handle(KCOV_SUBSYSTEM_COMMON, + KCOV_COMMON_ID); + arg->handles[0] = kcov_remote_handle(KCOV_SUBSYSTEM_USB, + KCOV_USB_BUS_NUM); + if (ioctl(fd, KCOV_REMOTE_ENABLE, arg)) + perror("ioctl"), free(arg), exit(1); + free(arg); + + /* + * Here the user needs to trigger execution of a kernel code section + * that is either annotated with the common handle, or to trigger some + * activity on USB bus #1. + */ + sleep(2); + + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + for (i = 0; i < n; i++) + printf("0x%lx\n", cover[i + 1]); + if (ioctl(fd, KCOV_DISABLE, 0)) + perror("ioctl"), exit(1); + if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) + perror("munmap"), exit(1); + if (close(fd)) + perror("close"), exit(1); + return 0; + } diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index 33f85860c924239ab46d976ad59a427735d484a0..1688ba2744b1d1107db557a35041875cecf75804 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -139,6 +139,9 @@ its hardware characteristcs. * arm,sg-enable : indicates whether scatter gather feature is enabled by default for TMC ETR configuration. + * qcom,qdss-ipa-support : indicates whether qdss to ipa bam connection + need to support. + * Required property for TPDAs: * qcom,tpda-atid: must be present. Specifies the ATID for TPDA. diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 76026a75d0cf6a58be54eb76982eddee24c619b6..5b614f215d2226fb3a6a865d2ef1f0cd648d4bc6 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -112,6 +112,12 @@ SoCs: - QCS6125 compatible = "qcom,qcs6125" +- SA2145P + compatible = "qcom,sa2145p" + +- SA2150P + compatible = "qcom,sa2150p" + Generic board variants: - CDP device: @@ -229,6 +235,7 @@ compatible = "qcom,sa6155p-adp-air" compatible = "qcom,qcs405-rumi" compatible = "qcom,qcs405-iot" compatible = "qcom,sa2150p-ccard" +compatible = "qcom,sa2145p-ccard" compatible = "qcom,qcs403-iot" compatible = "qcom,qcs401-iot" compatible = "qcom,qcs404-iot" @@ -307,3 +314,5 @@ compatible = "qcom,sdm429w-wdp" compatible = "qcom,sdm429-wdp" compatible = "qcom,qcm6125" compatible = "qcom,qcs6125" +compatible = "qcom,qcm6125-idp" +compatible = "qcom,qcs6125-idp" diff --git a/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt b/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt index e98f793b66d7cd18048e9befb2cc1e70a5dab76b..76b230ed8b41e76d4999811dd9e238f2c75e8d74 100644 --- a/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt +++ b/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt @@ -8,26 +8,27 @@ state of one subsytem to another. Modem can indicate different events Required Properties: - compatible: "qcom,sdx-ext-ipc". -Required named gpio properties: -- qcom,mdm2ap-status-gpio: gpio for modem to indicate the boot status to APQ. - -- qcom,ap2mdm-status-gpio: gpio for APQ to indicate the boot status to modem. - +Optional named gpio properties: +- qcom,status-out-gpio: gpio to indicate the boot status to remote processor. +- qcom,status-in-gpio: gpio for remote processor to indicate the boot status. -Optional named gpio properties: -- qcom,mdm2ap-status2-gpio: gpio for modem to indicate to APQ that it is in +- qcom,status-out2-gpio: gpio to indicate to remote processor that it is in E911 call or doing firmware upgrade. -- qcom,ap2mdm-status2-gpio: gpio for APQ to indicate graceful shutdown to modem. - - qcom,default-policy-nop: Set default policy from PANIC to NOP. +- qcom,wakeup-gpio-out: gpio to wakeup remote AP or modem. + +- qcom,wakeup-gpio-in: input gpio to receive wakeup signal from remote AP or + modem. + Example: sdx_ext_ipc: qcom,sdx_ext_ipc { compatible = "qcom,sdx-ext-ipc"; - qcom,ap2mdm-status-gpio = <&tlmm 64 0x00>; - qcom,ap2mdm-status2-gpio = <&tlmm 65 0x00>; - qcom,mdm2ap-status-gpio = <&tlmm 63 0x00>; - qcom,mdm2ap-status2-gpio = <&tlmm 66 0x00>; + qcom,status-in-gpio = <&tlmm 64 0x00>; + qcom,status-out-gpio = <&tlmm 63 0x00>; + qcom,status-out2-gpio = <&tlmm 66 0x00>; + qcom,wakeup-gpio-in = <&tlmm 67 0x00>; + qcom,wakeup-gpio-out = <&tlmm 68 0x00>; }; diff --git a/Documentation/devicetree/bindings/clock/qcom,sdm-cpucc.txt b/Documentation/devicetree/bindings/clock/qcom,sdm-cpucc.txt new file mode 100644 index 0000000000000000000000000000000000000000..483ca3d9e5d7a10267fa4fa3f990f7b7d5893ac3 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sdm-cpucc.txt @@ -0,0 +1,95 @@ +Qualcomm Technologies, Inc. SDM CPU clock driver +--------------------------------------------------- + +It is the clock controller driver which provides higher frequency +clocks and allows CPU frequency scaling on sdm based platforms. + +Required properties: +- compatible: Shall contain following: + "qcom,cpu-clock-sdm" +- clocks: Phandle to the clock device. +- clock-names: Names of the used clocks. Shall contain following: + "xo_ao", "gpll0_ao" +- reg: Shall contain base register offset and size. +- reg-names: Names of the bases for the above registers. Shall contain following: + "apcs-c1-rcg-base", "apcs-cci-rcg-base", "apcs_pll", "efuse" +- vdd_dig_ao-supply: The regulator(active only) powering the digital logic of APSS PLL. +- vdd_hf_pll-supply: The regulator(active only) powering the Analog logic of APSS PLL. +- cpu-vdd-supply: The regulator powering the APSS C1 RCG and APSS CCI RCG. +- qcom,speedX-bin-vY-Z: A table of CPU frequency (Hz) to regulator voltage (uV) mapping. + Format: + This represents the max frequency possible for each possible + power configuration for a CPU that's binned as speed bin X, + speed bin revision Y. Version can be between [0-3]. Z + is the mux id c1 or cci. +- #clock-cells: Shall contain 1. + +Example: + clock_cpu: qcom,clock-cpu@0b011050 { + compatible = "qcom,cpu-clock-sdm"; + clocks = <&rpmcc RPM_SMD_XO_A_CLK_SRC>, + <&gcc GPLL0_AO_OUT_MAIN>; + clock-names = "xo_ao", "gpll0_ao" ; + reg = <0xb011050 0x8>, + <0xb1d1050 0x8>, + <0xb016000 0x34>, + <0x00a412c 0x8>; + reg-names = "apcs-c1-rcg-base", + "apcs-cci-rcg-base", "apcs_pll", "efuse"; + cpu-vdd-supply = <&apc_vreg_corner>; + vdd_dig_ao-supply = <&L12A_AO; + vdd_hf_pll-supply = <&VDD_CX_LEVEL_AO>; + qcom,speed0-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1958400000 5>; + + qcom,speed0-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed1-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1804800000 5>; + + qcom,speed1-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed4-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1958400000 5>, + < 2016000000 6>; + + qcom,speed4-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed5-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>; + + qcom,speed5-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/input/qpnp-power-on.txt b/Documentation/devicetree/bindings/input/qpnp-power-on.txt index a78f088b7e0efad82738189e9c45873975864541..e13669a6acbd86a3c540f9fcd0dfecf314c59ad6 100644 --- a/Documentation/devicetree/bindings/input/qpnp-power-on.txt +++ b/Documentation/devicetree/bindings/input/qpnp-power-on.txt @@ -116,6 +116,9 @@ Optional properties: configured to support TWM modes. - qcom,pbs-client: Phandle of the PBS client node. Should be defined if 'qcom,support-twm-config' is present. +- qcom,use-legacy-hard-reset-offset Boolean property to support legacy + hard-reset offset of the PON_RB_SPARE register for + some (PON gen2) platforms. Optional Sub-nodes: - qcom,pon_1 ... qcom,pon_n: These PON child nodes correspond to features diff --git a/Documentation/devicetree/bindings/net/r8125 b/Documentation/devicetree/bindings/net/r8125 new file mode 100644 index 0000000000000000000000000000000000000000..d302869dbb4b777d972567bd6187f16f4c672e3a --- /dev/null +++ b/Documentation/devicetree/bindings/net/r8125 @@ -0,0 +1,33 @@ +Realtek r8125B Ethernet Controller + +Required properties: + +- compatible : should be "realtek,rtl-8125" + +If SMMU is present, also use: + +- qcom,smmu : if present, SMMU attach is performed +- qcom,smmu-iova-base : SMMU IOVA start address the device can access +- qcom,smmu-iova-size : SMMU IOVA size the device can access + +Optional Properties: + +- qcom,smmu-attr-fastmap : Enables SMMU fastmap +- qcom,smmu-attr-atomic : Enables DMA alloc using GFP_ATOMIC + +Example: + +&pcie_rc0 { + + r8125_x1: qcom,r8125@0 { + compatible = realtek,rtl-8125"; + + qcom,smmu; + qcom,smmu-iova-base = /bits/ 64 <0x0>; + qcom,smmu-iova-size = /bits/ 64 <0x100000000>; + + qcom,smmu-attr-atomic; + qcom,smmu-attr-fastmap; + }; +}; + diff --git a/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt b/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt index 8883f779bcd63c0e9efc109f5bb9d07da6296748..c364f472cc0b61976024d150d6a3b04c0c09a439 100644 --- a/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt @@ -48,6 +48,8 @@ Optional Properties: - qcom,phy-init: The initialization sequence to bring up the PCIe PHY. Should be specified in groups (offset, value, delay, direction). - qcom,phy-status-reg: Register offset for PHY status. + - qcom,phy-status-reg2: For sdxprairie and above use only + qcom,phy-status-reg2 as register offset for PHY status. - qcom,dbi-base-reg: Register offset for DBI base address. - qcom,slv-space-reg: Register offset for slave address space size. - qcom,pcie-vendor-id: Vendor id to be written to the Vendor ID register. diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt index 52f9e5ade3ffdc99061eee21b17f297079cdcbe6..8b29bd5c91c7e402916fa74dc09eac453be4c058 100644 --- a/Documentation/devicetree/bindings/pci/msm_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt @@ -130,6 +130,9 @@ Optional Properties: property. - clock-output-names: name of the outgoing clock signal from the PHY PLL. - qcom,keep-powerdown-phy: If present, power down phy in probe to avoid leakage. + - errata: Selects the list of erratas to configure for the + corresponding switch port. This could be a third party switch connected to + the root port. ================= Root Complex node diff --git a/Documentation/devicetree/bindings/pil/pil-blackghost.txt b/Documentation/devicetree/bindings/pil/pil-blackghost.txt new file mode 100644 index 0000000000000000000000000000000000000000..94232036acf446c5a72a7bf4141879d24b8c7222 --- /dev/null +++ b/Documentation/devicetree/bindings/pil/pil-blackghost.txt @@ -0,0 +1,33 @@ +Qualcomm Technologies Inc Blackghost(BG) PIL driver: + +Blackghost(BG) PIL driver provide interface to load and boot Blackghost(BG) +SOC. Blackghost(BG) SOC is an external SOC which communicate to MSM via +SPI. The PIL driver loads firmware into memory and invoke secure app via +qseecom to transfer and handshake the boot process. Once Blackghost(BG) SOC +is booted it raises ready interrupt which is handled by BG PIL driver, and +this event is informed to other MSM drivers, other remote subsystem via +notifier framework. The PIL driver also handles interrupt for the BG SOC +crash upon arrival of which it reset and initiates ramdump collection for BG +SOC. + +Required properties: +- compatible: Must be "qcom,pil-blackghost" +- qcom,firmware-name: Base name of the firmware image. +- qcom,bg2ap-status-gpio: GPIO used by the blackghost to indicate status to the apps. +- qcom,bg2ap-errfatal-gpio: GPIO used by the blackghost to indicate software error to the apps. +- qcom,ap2bg-status-gpio: GPIO used by the apps to indicate its status to blackghost. +- qcom,ap2bg-errfatal-gpio: GPIO used by the apps to indicate blackghost about apps reset. + +Example: + + qcom,blackghost { + compatible = "qcom,pil-blackghost"; + qcom,firmware-name = "bgelf"; + + /* GPIO inputs from blackghost */ + qcom,bg2ap-status-gpio = <&msm_gpio 97 0>; + qcom,bg2ap-errfatal-gpio = <&msm_gpio 95 0>; + /* GPIO output to blackghost */ + qcom,ap2bg-status-gpio = <&msm_gpio 17 0>; + qcom,ap2bg-errfatal-gpio = <&msm_gpio 23 0>; + }; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt index 073e2e6cb65720b88ec51a0a841a3c8e823f0791..b617dc70cc53e010bf4f643ed9c3dacd73832786 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt @@ -178,6 +178,14 @@ Charger specific properties: Definition: Boolean flag which when present enables input suspend for debug battery. +- qcom,fake-chg-status-on-debug-batt + Usage: optional + Value type: + Definition: Boolean flag which when present shows charging status as + unknown for debug battery. This needs to be specified only if + the device needs to be kept powered on always with + "svc power stayon true". + - qcom,min-freq-khz Usage: optional Value type: diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt b/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt new file mode 100644 index 0000000000000000000000000000000000000000..7da17b41529f441763cd88bcf4cc856da2944156 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt @@ -0,0 +1,20 @@ +Qualcomm Technologies Inc. bg-daemon + +BG-Daemon : When Modem goes down, to re-establish the connections, +BG-Daemon toggles the bg-reset gpio to reset BG. + +Required properties: +- compatible : should be "qcom,bg-daemon" +- qcom,bg-reset-gpio : gpio for the apps processor use to soft reset BG +- ssr-reg1-supply : Power supply needed to power up the BG device. + When BG brought up this regulator will be in normal power mode. +- ssr-reg2-supply : Power supply needed to power up the BG device. + When BG BG brought up this regulator will be in normal power mode. + +Example: + qcom,bg-daemon { + compatible = "qcom,bg-daemon"; + qcom,bg-reset-gpio = <&pm660_gpios 5 0>; + ssr-reg1-supply = <&pm660_l3>; + ssr-reg2-supply = <&pm660_l9>; + }; diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt b/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9a28a953c47d04dcc887fafe4e6857d2856aa9e --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt @@ -0,0 +1,24 @@ +Qualcomm technologies Inc bg-spi + +BG-COM SPI : bg-spi is used for the communication with Blackghost +chipset. It uses SPI protocol for communication. +BG-COM: bgcome is a thin transport layer over glink which provides +the read/write APIs to communicate with Blackghost chipset. + +Required properties: +- compatible : should be "qcom,bg-spi" +- spi-max-frequency : Maximum SPI clocking speed of device in Hz +- qcom,irq-gpio : GPIO pin +- reg : Register set + +Example: + spi@78b6000 { /* BLSP1 QUP2 */ + status = "ok"; + qcom,bg-spi { + compatible = "qcom,bg-spi"; + reg = <0>; + spi-max-frequency = <19200000>; + interrupt-parent = <&msm_gpio>; + qcom,irq-gpio = <&msm_gpio 110 1>; + }; + }; diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,glink-bgcom-xprt.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,glink-bgcom-xprt.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6e46f38e4e727ee1d64511a6895e4c9f0a000fb --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,glink-bgcom-xprt.txt @@ -0,0 +1,24 @@ +Qualcomm Technologies, Inc GLINK BGCOM transport (glink_bgcom_xprt) binding + +This binding describes the Qualcomm Technologies, Inc glink bgcom transport +driver, a bgcom-spi based communication channel for sending data between the +various subsystems in Qualcomm Technologies, Inc platforms. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,glink-bgcom-xprt" + +- label: + Usage: required + Value type: + Definition: must be "bg" + += EXAMPLE + +The following example reprsents a glink_bgcom node. + + qcom,glink-bgcom-xprt-bg { + compatible = "qcom,glink-bgcom-xprt"; + label = "bg"; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 715855b3fa5ad9a8f1476c5a9702159fcbdfa4fe..41894da6bcf87af635269bcf0318f555b78a63e2 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -349,6 +349,49 @@ Optional properties: This child device is added after lpass is up to invoke deferred probe devices. +* gpr + +Required properties: + + - compatible : "qcom,gpr" + This device is added to represent GPR module. + + - qcom,glink-channels: Indicates glink channel to be used. + - qcom,intents: Indicates the number of intents to be allocated. + - reg: This value provides the subsytem ID to be communicated with. + +* gecko-core-platform + +Required properties: + + - compatible : "qcom,gecko-core-platform" + This device is added to represent Gecko platform driver module. + +* gecko_core + +Required properties: + + - compatible : "qcom,gecko_core" + This device is added to represent Gecko core driver module. + - reg: Represents the service to be communicated with. + +* audio-pkt + +Required properties: + + - compatible : "qcom,audio-pkt" + This device is added to represent Audio packet driver module. + - qcom,audiopkt-ch-name: Glink channel name to be used. + - reg: Represents the service to be communicated with. + +* q6prm + +Required properties: + + - compatible : "qcom,q6prm" + This device is added to represent Q6 PRM driver module. + - reg: Represents the service to be communicated with. + * msm-ocmem-audio Required properties: @@ -700,6 +743,11 @@ Example: compatible = "qcom,msm-dai-q6-dev"; qcom,msm-dai-q6-dev-id = <32770>; }; + + qcom,msm-dai-q6-incall-music-dl-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32774>; + }; }; qcom,msm-pri-auxpcm { @@ -1880,6 +1928,124 @@ Example: qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; }; +* SA8155 Gecko ASoC Machine driver + +Required properties: +- compatible : "qcom,sa8155-gecko-asoc-snd-adp-star" for auto machine driver. +- qcom,model : The user-visible name of this sound card. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +Optional properties: +- qcom,mi2s-audio-intf : Property to specify if MI2S interface is used for the target +- qcom,auxpcm-audio-intf : Property to specify if AUX PCM interface is used for the target +- qcom,msm-mi2s-master : List of master/slave configuration for MI2S interfaces +- qcom,msm_audio_ssr_devs: List the snd event framework clients + +Example: + + sound-adp-star { + compatible = "qcom,sa8155-gecko-asoc-snd-adp-star"; + qcom,model = "sa8155-gecko-adp-star-snd-card"; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>, <&loopback1>, <&pcm_dtmf>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq", "msm-pcm-loopback.1", + "msm-pcm-dtmf"; + asoc-cpu = <&dai_hdmi>, <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_rx_1>, + <&dai_sec_tdm_rx_2>, <&dai_sec_tdm_rx_3>, + <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, + <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, + <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, + <&dai_tert_tdm_rx_4>, <&dai_tert_tdm_tx_0>, + <&dai_tert_tdm_tx_1>, <&dai_tert_tdm_tx_2>, + <&dai_tert_tdm_tx_3>, <&dai_quat_tdm_rx_0>, + <&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>, + <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_tx_0>, + <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>, + <&dai_quat_tdm_tx_3>, <&dai_quin_tdm_rx_0>, + <&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>, + <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_tx_0>, + <&dai_quin_tdm_tx_1>, <&dai_quin_tdm_tx_2>, + <&dai_quin_tdm_tx_3>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36882", + "msm-dai-q6-tdm.36884", "msm-dai-q6-tdm.36886", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", + "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", + "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", + "msm-dai-q6-tdm.36904", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36899", "msm-dai-q6-tdm.36901", + "msm-dai-q6-tdm.36903", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916", + "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36915", "msm-dai-q6-tdm.36917", + "msm-dai-q6-tdm.36919", "msm-dai-q6-tdm.36928", + "msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932", + "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36929", + "msm-dai-q6-tdm.36931", "msm-dai-q6-tdm.36933", + "msm-dai-q6-tdm.36935"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; + }; + * SDX ASoC Machine driver Required properties: @@ -1929,7 +2095,7 @@ Example: <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&dai_sec_auxpcm>, <&incall2_record_rx>, - <&incall_music_2_rx>; + <&incall_music_2_rx>, <&incall_music_dl_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", @@ -1939,7 +2105,7 @@ Example: "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-auxpcm.2", "msm-dai-q6-dev.32769", - "msm-dai-q6-dev.32770"; + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.32774"; }; * SDX ASoC Auto Machine driver @@ -1998,7 +2164,7 @@ Example: <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, <&dai_sec_auxpcm>, <&incall2_record_rx>, - <&incall_music_2_rx>; + <&incall_music_2_rx>, <&incall_music_dl_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", @@ -2010,7 +2176,7 @@ Example: "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", "msm-dai-q6-auxpcm.2", "msm-dai-q6-dev.32769", - "msm-dai-q6-dev.32770"; + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.32774"; asoc-codec = <&tlv320aic3x_codec>, <&stub_codec>; asoc-codec-names = "tlv320aic3x-codec", "msm-stub-codec.1"; }; diff --git a/Documentation/devicetree/bindings/sound/tfa9897.txt b/Documentation/devicetree/bindings/sound/tfa9897.txt new file mode 100644 index 0000000000000000000000000000000000000000..6e5fedbb210896fbbf59e02e2eede58102899eab --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tfa9897.txt @@ -0,0 +1,24 @@ +TFA9897 SmartpA + +Required properties: + + - compatible : "nxp,tfa98xx" + + - reg : I2C address of the device + + - dvdd-supply : Power supply for PA's dvdd + + - dvdd-voltage : Minimum and maximum voltage in uV to set for power supply + + - dvdd-current : dvdd's max current in uA + +Examples: + + i2c_smartpa@34 { + compatible = "nxp,tfa98xx"; + reg = <0x34>; + reset-gpio = <&tlmm 68 0>; + dvdd-supply = <&pm660_l9>; + dvdd-voltage = <1800000 1800000>; + dvdd-current = <15000>; + }; diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt index 1edf0820398a06adc2bc72d6f70903733a9c66e8..7c0b2a4df208c6e15e9f07c896efa226063c2519 100644 --- a/Documentation/devicetree/bindings/spi/spi_qsd.txt +++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt @@ -36,7 +36,13 @@ Optional properties: - qcom,rt-priority : whether spi message queue is set to run as a realtime task. With this spi transaction message pump with high (realtime) priority to reduce the transfer latency on the bus by minimising the delay between a transfer request - - qcom,shared : whether this qup is shared with other ee's + - qcom,shared : whether this qup is shared with other ee's and client driver is not + in control of the spi driver get_sync/put_sync_suspend. Spi driver will + take care of resources management like clock, gpios and bam for EE switching. + - qcom,shared_ee : whether this qup is used by other ee's and client driver is in + control of the spi driver get_sync/put_sync_suspend. Resources management + of clock, gpios and bam for EE switching will be taken care when client calls spi + get_sync/put_sync_suspend APIs. Optional properties which are required for support of BAM-mode: - qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index deab2aea6104d58d901119581e149d8d42e49cd7..59f9afff2e6b17340d5aecdefe073603bdf02007 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -93,6 +93,8 @@ Optional properties : capable DWC3 which does not have extcon handle. - qcom,default-mode-host: If present, start host mode on probe for an OTG capable DWC3 which does not have extcon handle. +- qcom,dual-port: If present, 2 different physical ports are supported by this + core. Please note that this flag is valid for cores supporting only host mode. Sub nodes: - Sub node for "DWC3- USB3 controller". diff --git a/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt b/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt index ebbb6d5b477075c11ceb80bbd9f6d5e440495909..f741fafcb91215f3d157a5ac5020149946ff4a06 100644 --- a/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt +++ b/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt @@ -43,6 +43,7 @@ Optional properties: - qcom,default-sink-caps: List of 32-bit values representing the nominal sink capabilities in voltage (millivolts) and current (milliamps) pairs. +- qcom,no-usb3-dp-concurrency: If present, usb3 and dp concurrency is not supported. Example: qcom,qpnp-pdphy@1700 { diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 8a0700af959672568b7713dbb6e2f8c82449e200..471a511c75088d7e5b3528f055d420a3d59e22d5 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -256,13 +256,8 @@ alternative master keys or to support rotating master keys. Instead, the master keys may be wrapped in userspace, e.g. as is done by the `fscrypt `_ tool. -Including the inode number in the IVs was considered. However, it was -rejected as it would have prevented ext4 filesystems from being -resized, and by itself still wouldn't have been sufficient to prevent -the same key from being directly reused for both XTS and CTS-CBC. - -DIRECT_KEY and per-mode keys ----------------------------- +DIRECT_KEY policies +------------------- The Adiantum encryption mode (see `Encryption modes and usage`_) is suitable for both contents and filenames encryption, and it accepts @@ -285,6 +280,21 @@ IV. Moreover: key derived using the KDF. Users may use the same master key for other v2 encryption policies. +IV_INO_LBLK_64 policies +----------------------- + +When FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 is set in the fscrypt policy, +the encryption keys are derived from the master key, encryption mode +number, and filesystem UUID. This normally results in all files +protected by the same master key sharing a single contents encryption +key and a single filenames encryption key. To still encrypt different +files' data differently, inode numbers are included in the IVs. +Consequently, shrinking the filesystem may not be allowed. + +This format is optimized for use with inline encryption hardware +compliant with the UFS or eMMC standards, which support only 64 IV +bits per I/O request and may have only a small number of keyslots. + Key identifiers --------------- @@ -308,8 +318,9 @@ If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair. AES-128-CBC was added only for low-powered embedded devices with crypto accelerators such as CAAM or CESA that do not support XTS. To -use AES-128-CBC, CONFIG_CRYPTO_SHA256 (or another SHA-256 -implementation) must be enabled so that ESSIV can be used. +use AES-128-CBC, CONFIG_CRYPTO_ESSIV and CONFIG_CRYPTO_SHA256 (or +another SHA-256 implementation) must be enabled so that ESSIV can be +used. Adiantum is a (primarily) stream cipher-based mode that is fast even on CPUs without dedicated crypto instructions. It's also a true @@ -341,10 +352,16 @@ a little endian number, except that: is encrypted with AES-256 where the AES-256 key is the SHA-256 hash of the file's data encryption key. -- In the "direct key" configuration (FSCRYPT_POLICY_FLAG_DIRECT_KEY - set in the fscrypt_policy), the file's nonce is also appended to the - IV. Currently this is only allowed with the Adiantum encryption - mode. +- With `DIRECT_KEY policies`_, the file's nonce is appended to the IV. + Currently this is only allowed with the Adiantum encryption mode. + +- With `IV_INO_LBLK_64 policies`_, the logical block number is limited + to 32 bits and is placed in bits 0-31 of the IV. The inode number + (which is also limited to 32 bits) is placed in bits 32-63. + +Note that because file logical block numbers are included in the IVs, +filesystems must enforce that blocks are never shifted around within +encrypted files, e.g. via "collapse range" or "insert range". Filenames encryption -------------------- @@ -354,10 +371,10 @@ the requirements to retain support for efficient directory lookups and filenames of up to 255 bytes, the same IV is used for every filename in a directory. -However, each encrypted directory still uses a unique key; or -alternatively (for the "direct key" configuration) has the file's -nonce included in the IVs. Thus, IV reuse is limited to within a -single directory. +However, each encrypted directory still uses a unique key, or +alternatively has the file's nonce (for `DIRECT_KEY policies`_) or +inode number (for `IV_INO_LBLK_64 policies`_) included in the IVs. +Thus, IV reuse is limited to within a single directory. With CTS-CBC, the IV reuse means that when the plaintext filenames share a common prefix at least as long as the cipher block size (16 @@ -431,12 +448,15 @@ This structure must be initialized as follows: (1) for ``contents_encryption_mode`` and FSCRYPT_MODE_AES_256_CTS (4) for ``filenames_encryption_mode``. -- ``flags`` must contain a value from ```` which - identifies the amount of NUL-padding to use when encrypting - filenames. If unsure, use FSCRYPT_POLICY_FLAGS_PAD_32 (0x3). - Additionally, if the encryption modes are both - FSCRYPT_MODE_ADIANTUM, this can contain - FSCRYPT_POLICY_FLAG_DIRECT_KEY; see `DIRECT_KEY and per-mode keys`_. +- ``flags`` contains optional flags from ````: + + - FSCRYPT_POLICY_FLAGS_PAD_*: The amount of NUL padding to use when + encrypting filenames. If unsure, use FSCRYPT_POLICY_FLAGS_PAD_32 + (0x3). + - FSCRYPT_POLICY_FLAG_DIRECT_KEY: See `DIRECT_KEY policies`_. + - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64: See `IV_INO_LBLK_64 + policies`_. This is mutually exclusive with DIRECT_KEY and is not + supported on v1 policies. - For v2 encryption policies, ``__reserved`` must be zeroed. @@ -1089,7 +1109,7 @@ policy structs (see `Setting an encryption policy`_), except that the context structs also contain a nonce. The nonce is randomly generated by the kernel and is used as KDF input or as a tweak to cause different files to be encrypted differently; see `Per-file keys`_ and -`DIRECT_KEY and per-mode keys`_. +`DIRECT_KEY policies`_. Data path changes ----------------- diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst index 42a0b6dd9e0b68539b0ec92db3a7bd455410b145..a95536b6443c8a31b3a512aafac8f965e96ac2fc 100644 --- a/Documentation/filesystems/fsverity.rst +++ b/Documentation/filesystems/fsverity.rst @@ -226,6 +226,14 @@ To do so, check for FS_VERITY_FL (0x00100000) in the returned flags. The verity flag is not settable via FS_IOC_SETFLAGS. You must use FS_IOC_ENABLE_VERITY instead, since parameters must be provided. +statx +----- + +Since Linux v5.5, the statx() system call sets STATX_ATTR_VERITY if +the file has fs-verity enabled. This can perform better than +FS_IOC_GETFLAGS and FS_IOC_MEASURE_VERITY because it doesn't require +opening the file, and opening verity files can be expensive. + Accessing verity files ====================== @@ -398,7 +406,7 @@ pages have been read into the pagecache. (See `Verifying data`_.) ext4 ---- -ext4 supports fs-verity since Linux TODO and e2fsprogs v1.45.2. +ext4 supports fs-verity since Linux v5.4 and e2fsprogs v1.45.2. To create verity files on an ext4 filesystem, the filesystem must have been formatted with ``-O verity`` or had ``tune2fs -O verity`` run on @@ -434,7 +442,7 @@ also only supports extent-based files. f2fs ---- -f2fs supports fs-verity since Linux TODO and f2fs-tools v1.11.0. +f2fs supports fs-verity since Linux v5.4 and f2fs-tools v1.11.0. To create verity files on an f2fs filesystem, the filesystem must have been formatted with ``-O verity``. diff --git a/MAINTAINERS b/MAINTAINERS index 2cb45b54ed30585aa1c3348582e18ae16ca7e65b..77c68f63e29f2696c677b51bbf8d13752983d781 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7886,6 +7886,13 @@ Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ S: Supported F: drivers/nvdimm/pmem* +LIBNVDIMM: DEVICETREE BINDINGS +M: Oliver O'Halloran +L: linux-nvdimm@lists.01.org +Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ +S: Supported +F: drivers/nvdimm/of_pmem.c + LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM M: Dan Williams L: linux-nvdimm@lists.01.org diff --git a/Makefile b/Makefile index 523a35ebafa4cee6573878fee3cfa40bab178168..dc545445d4e3534acf5a4ba5dac1388d4de23f98 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 163 +SUBLEVEL = 170 EXTRAVERSION = NAME = Petit Gorille @@ -670,8 +670,7 @@ KBUILD_AFLAGS += $(call cc-option,-fno-PIE) CFLAGS_GCOV := -fprofile-arcs -ftest-coverage \ $(call cc-option,-fno-tree-loop-im) \ $(call cc-disable-warning,maybe-uninitialized,) -CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) -export CFLAGS_GCOV CFLAGS_KCOV +export CFLAGS_GCOV # Make toolchain changes before including arch/$(SRCARCH)/Makefile to ensure # ar/cc/ld-* macros return correct values. @@ -726,6 +725,7 @@ ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLA KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO endif +include scripts/Makefile.kcov include scripts/Makefile.gcc-plugins ifdef CONFIG_READABLE_ASM @@ -1108,6 +1108,7 @@ ifdef CONFIG_STACK_VALIDATION endif endif +PHONY += prepare0 ifeq ($(KBUILD_EXTMOD),) core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ @@ -1202,8 +1203,7 @@ include/config/kernel.release: include/config/auto.conf FORCE # archprepare is used in arch Makefiles and when processed asm symlink, # version.h and scripts_basic is processed / created. -# Listed in dependency order -PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3 +PHONY += prepare archprepare prepare1 prepare2 prepare3 # prepare3 is used to check if we are building in a separate output directory, # and if so do: diff --git a/arch/arc/plat-eznps/Kconfig b/arch/arc/plat-eznps/Kconfig index 8eff057efcaebeae04b1fb801c003418090551eb..ce908e2c5282434db3643ec54674544b533877d2 100644 --- a/arch/arc/plat-eznps/Kconfig +++ b/arch/arc/plat-eznps/Kconfig @@ -7,7 +7,7 @@ menuconfig ARC_PLAT_EZNPS bool "\"EZchip\" ARC dev platform" select CPU_BIG_ENDIAN - select CLKSRC_NPS + select CLKSRC_NPS if !PHYS_ADDR_T_64BIT select EZNPS_GIC select EZCHIP_NPS_MANAGEMENT_ENET if ETHERNET help diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index b8a122e5a11b8c5c3043b6c1a040003d183398b0..d93c1347d97d51733f35a55a89dc3cbd53bb660d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1471,6 +1471,12 @@ config PAGE_OFFSET default 0xB0000000 if VMSPLIT_3G_OPT default 0xC0000000 +config COMMAND_LINE_SIZE + int "Maximum size of the command line." + default "1024" + help + This is the per architecture maximum command line size. + config NR_CPUS int "Maximum number of CPUs (2-32)" range 2 32 diff --git a/arch/arm/boot/dts/am335x-boneblack-common.dtsi b/arch/arm/boot/dts/am335x-boneblack-common.dtsi index 325daae40278a11fca64fa96d74fd64e991da546..485c27f039f59466dd1790f989b980157bfaf292 100644 --- a/arch/arm/boot/dts/am335x-boneblack-common.dtsi +++ b/arch/arm/boot/dts/am335x-boneblack-common.dtsi @@ -131,6 +131,11 @@ }; / { + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x20000000>; /* 512 MB */ + }; + clk_mcasp0_fixed: clk_mcasp0_fixed { #clock-cells = <0>; compatible = "fixed-clock"; diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index afb8eb0a0a16ee63ea1ece64e694ac847c249067..051823b7e5a1298bbe50dd36f846d7592bc941bb 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -83,7 +83,7 @@ }; lcd0: display { - compatible = "osddisplays,osd057T0559-34ts", "panel-dpi"; + compatible = "osddisplays,osd070t1718-19ts", "panel-dpi"; label = "lcd"; panel-timing { diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts index 081fa68b6f98049ad2edb1c9c6d579c0958a7a2d..c4279b0b9f12437cda06a5f3c9028be6a3caab49 100644 --- a/arch/arm/boot/dts/am43x-epos-evm.dts +++ b/arch/arm/boot/dts/am43x-epos-evm.dts @@ -45,7 +45,7 @@ }; lcd0: display { - compatible = "osddisplays,osd057T0559-34ts", "panel-dpi"; + compatible = "osddisplays,osd070t1718-19ts", "panel-dpi"; label = "lcd"; panel-timing { diff --git a/arch/arm/boot/dts/am571x-idk.dts b/arch/arm/boot/dts/am571x-idk.dts index debf9464403ef52a5c4b7e27135b1a5ed5778fd2..96a4df4109d75f6803fdf6907a1f6ec6980c5eaa 100644 --- a/arch/arm/boot/dts/am571x-idk.dts +++ b/arch/arm/boot/dts/am571x-idk.dts @@ -93,7 +93,7 @@ &pcie1_rc { status = "okay"; - gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; + gpios = <&gpio5 18 GPIO_ACTIVE_HIGH>; }; &pcie1_ep { diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi index 49aeecd312b4b10af2cb3badd68a4982fa8a921d..d578a9f7e1a0eb77bea292a997e3c5acd02303d9 100644 --- a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi +++ b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi @@ -32,6 +32,27 @@ reg = <0x0 0x80000000 0x0 0x80000000>; }; + main_12v0: fixedregulator-main_12v0 { + /* main supply */ + compatible = "regulator-fixed"; + regulator-name = "main_12v0"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + regulator-boot-on; + }; + + evm_5v0: fixedregulator-evm_5v0 { + /* Output of TPS54531D */ + compatible = "regulator-fixed"; + regulator-name = "evm_5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&main_12v0>; + regulator-always-on; + regulator-boot-on; + }; + vdd_3v3: fixedregulator-vdd_3v3 { compatible = "regulator-fixed"; regulator-name = "vdd_3v3"; diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi index 8b2c65cd61a2951dd5e170b81c2230ce449d3cf0..b822952c29f8473c1207c4733f6026df13a73092 100644 --- a/arch/arm/boot/dts/bcm-cygnus.dtsi +++ b/arch/arm/boot/dts/bcm-cygnus.dtsi @@ -165,8 +165,8 @@ mdio: mdio@18002000 { compatible = "brcm,iproc-mdio"; reg = <0x18002000 0x8>; - #size-cells = <1>; - #address-cells = <0>; + #size-cells = <0>; + #address-cells = <1>; status = "disabled"; gphy0: ethernet-phy@0 { diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi index 4745e3c7806bc199f1d2ad218a7eff7d308b0001..fdb018e1278fb51820f97510241e349591caa79e 100644 --- a/arch/arm/boot/dts/bcm283x.dtsi +++ b/arch/arm/boot/dts/bcm283x.dtsi @@ -38,7 +38,7 @@ trips { cpu-crit { - temperature = <80000>; + temperature = <90000>; hysteresis = <0>; type = "critical"; }; diff --git a/arch/arm/boot/dts/lpc3250-phy3250.dts b/arch/arm/boot/dts/lpc3250-phy3250.dts index b7bd3a110a8dd0cb9f07144af4ff46a9a51f63c8..dd0bdf765599dd6051ea2e89ce4d3b6b519f7e46 100644 --- a/arch/arm/boot/dts/lpc3250-phy3250.dts +++ b/arch/arm/boot/dts/lpc3250-phy3250.dts @@ -49,8 +49,8 @@ sd_reg: regulator@2 { compatible = "regulator-fixed"; regulator-name = "sd_reg"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; gpio = <&gpio 5 5 0>; enable-active-high; }; diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi index d077bd2b9583ea61e1ef57b08c9853c00942783a..c5b119ddb70b824a35f3fd730e14dc587a02c971 100644 --- a/arch/arm/boot/dts/lpc32xx.dtsi +++ b/arch/arm/boot/dts/lpc32xx.dtsi @@ -139,11 +139,11 @@ }; clcd: clcd@31040000 { - compatible = "arm,pl110", "arm,primecell"; + compatible = "arm,pl111", "arm,primecell"; reg = <0x31040000 0x1000>; interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clk LPC32XX_CLK_LCD>; - clock-names = "apb_pclk"; + clocks = <&clk LPC32XX_CLK_LCD>, <&clk LPC32XX_CLK_LCD>; + clock-names = "clcdclk", "apb_pclk"; status = "disabled"; }; @@ -462,7 +462,9 @@ key: key@40050000 { compatible = "nxp,lpc3220-key"; reg = <0x40050000 0x1000>; - interrupts = <54 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LPC32XX_CLK_KEY>; + interrupt-parent = <&sic1>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts index 44715c8ef756b9f44bdc7a7c69b0cdc12c26d93d..72a3fc63d0ece95bcd41ab26d85199678ea4f6e7 100644 --- a/arch/arm/boot/dts/ls1021a-twr.dts +++ b/arch/arm/boot/dts/ls1021a-twr.dts @@ -143,7 +143,7 @@ }; &enet0 { - tbi-handle = <&tbi1>; + tbi-handle = <&tbi0>; phy-handle = <&sgmii_phy2>; phy-connection-type = "sgmii"; status = "okay"; @@ -222,6 +222,13 @@ sgmii_phy2: ethernet-phy@2 { reg = <0x2>; }; + tbi0: tbi-phy@1f { + reg = <0x1f>; + device_type = "tbi-phy"; + }; +}; + +&mdio1 { tbi1: tbi-phy@1f { reg = <0x1f>; device_type = "tbi-phy"; diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 2d20f60947b951bd1181cef7326a76f82213f45c..1343c86988c54d2653bb39bc9e3ca2cf7629f69e 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -562,13 +562,22 @@ }; mdio0: mdio@2d24000 { - compatible = "gianfar"; + compatible = "fsl,etsec2-mdio"; device_type = "mdio"; #address-cells = <1>; #size-cells = <0>; reg = <0x0 0x2d24000 0x0 0x4000>; }; + mdio1: mdio@2d64000 { + compatible = "fsl,etsec2-mdio"; + device_type = "mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2d64000 0x0 0x4000>, + <0x0 0x2d50030 0x0 0x4>; + }; + ptp_clock@2d10e00 { compatible = "fsl,etsec-ptp"; reg = <0x0 0x2d10e00 0x0 0xb0>; diff --git a/arch/arm/boot/dts/stm32h743i-eval.dts b/arch/arm/boot/dts/stm32h743i-eval.dts index 6c07786e7ddb9195fc88108d5d1906deb13f6c12..0d98b2865bd7765d80369d81f589a4b48eb40ce6 100644 --- a/arch/arm/boot/dts/stm32h743i-eval.dts +++ b/arch/arm/boot/dts/stm32h743i-eval.dts @@ -71,6 +71,7 @@ }; &adc_12 { + vdda-supply = <&vdda>; vref-supply = <&vdda>; status = "okay"; adc1: adc@0 { diff --git a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts index 716a205c6dbbeca282efbe4498742634205ad8bd..1fed3231f5c18df0e73f73d47b41517121cd7e30 100644 --- a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts +++ b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts @@ -90,7 +90,7 @@ initial-mode = <1>; /* initialize in HUB mode */ disabled-ports = <1>; intn-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */ - reset-gpios = <&pio 4 16 GPIO_ACTIVE_HIGH>; /* PE16 */ + reset-gpios = <&pio 4 16 GPIO_ACTIVE_LOW>; /* PE16 */ connect-gpios = <&pio 4 17 GPIO_ACTIVE_HIGH>; /* PE17 */ refclk-frequency = <19200000>; }; diff --git a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts index 10da56e86ab800809e9f28b72bd9b94edf02a547..21b38c386f1b321ffb3b0b1a8287bcbbc78cae79 100644 --- a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts +++ b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts @@ -79,6 +79,8 @@ wifi_pwrseq: wifi_pwrseq { compatible = "mmc-pwrseq-simple"; reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */ + clocks = <&rtc 1>; + clock-names = "ext_clock"; }; sound_spdif { @@ -128,6 +130,8 @@ pinctrl-names = "default"; pinctrl-0 = <&mmc1_pins_a>; vmmc-supply = <®_vcc3v3>; + vqmmc-supply = <®_vcc3v3>; + mmc-pwrseq = <&wifi_pwrseq>; bus-width = <4>; non-removable; status = "okay"; diff --git a/arch/arm/common/mcpm_entry.c b/arch/arm/common/mcpm_entry.c index 2b913f17d50f5d91f50d3aa30e3a8a26c97847b9..c24a55b0deac75a8f68d1537fa21c01f6d0df63c 100644 --- a/arch/arm/common/mcpm_entry.c +++ b/arch/arm/common/mcpm_entry.c @@ -379,7 +379,7 @@ static int __init nocache_trampoline(unsigned long _arg) unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); phys_reset_t phys_reset; - mcpm_set_entry_vector(cpu, cluster, cpu_resume); + mcpm_set_entry_vector(cpu, cluster, cpu_resume_no_hyp); setup_mm_for_reboot(); __mcpm_cpu_going_down(cpu, cluster); diff --git a/arch/arm/configs/vendor/sa515m-perf_defconfig b/arch/arm/configs/vendor/sa515m-perf_defconfig index 5135e90bc2a3007b2fe05d992a194cdc529aeaa1..8b002ff2c1080066338b4fe914f33d7691d7233c 100644 --- a/arch/arm/configs/vendor/sa515m-perf_defconfig +++ b/arch/arm/configs/vendor/sa515m-perf_defconfig @@ -402,6 +402,7 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_DCC_V2=y CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_SECURE_BUFFER=y CONFIG_QCOM_EUD=y CONFIG_QCOM_BUS_SCALING=y diff --git a/arch/arm/configs/vendor/sa515m_defconfig b/arch/arm/configs/vendor/sa515m_defconfig index 7139ab69238e642cefe85dda571c59fba796e452..98c80cfb7720dd4d813f3a5b19315573e8a2034e 100644 --- a/arch/arm/configs/vendor/sa515m_defconfig +++ b/arch/arm/configs/vendor/sa515m_defconfig @@ -407,6 +407,7 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_DCC_V2=y CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_SECURE_BUFFER=y CONFIG_QCOM_EUD=y CONFIG_QCOM_BUS_SCALING=y diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index 9f9ae39a6056284c53adc00f35803c3fcf89087a..8a899bbc4584b56afa9dac374278efb1c0cda0af 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -59,6 +59,7 @@ CONFIG_ARCH_SDM429W=y CONFIG_PCI_MSM=y CONFIG_SMP=y CONFIG_SCHED_MC=y +CONFIG_COMMAND_LINE_SIZE=2048 CONFIG_NR_CPUS=8 CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y @@ -330,6 +331,7 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_SMD_PKT=y CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y @@ -366,6 +368,7 @@ CONFIG_QTI_ADC_TM=y CONFIG_QTI_CX_IPEAK_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_CPR=y @@ -412,17 +415,16 @@ CONFIG_MSM_FD=y CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y -CONFIG_MSM_SDE_ROTATOR=y -CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_DVB_MPQ=m CONFIG_DVB_MPQ_DEMUX=m CONFIG_DVB_MPQ_SW=y -CONFIG_DRM=y -CONFIG_DRM_MSM_REGISTER_LOGGING=y -CONFIG_DRM_SDE_EVTLOG_DEBUG=y -CONFIG_DRM_SDE_RSC=y +CONFIG_FB=y CONFIG_FB_ARMCLCD=y CONFIG_FB_VIRTUAL=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set @@ -487,6 +489,7 @@ CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y CONFIG_QCOM_GPI_DMA=y CONFIG_UIO=y CONFIG_UIO_MSM_SHAREDMEM=y @@ -494,6 +497,7 @@ CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_ION=y +CONFIG_MSM_EXT_DISPLAY=y CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y @@ -504,6 +508,7 @@ CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_SDM_GCC_429W=y CONFIG_SDM_DEBUGCC_429W=y +CONFIG_CLOCK_CPU_SDM=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y @@ -515,6 +520,7 @@ CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_BGCOM=y CONFIG_RPMSG_QCOM_SMD=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y @@ -523,6 +529,7 @@ CONFIG_QCOM_SMEM=y CONFIG_QCOM_SMD_RPM=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y +CONFIG_QCOM_SCM=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y @@ -535,6 +542,7 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 @@ -548,7 +556,9 @@ CONFIG_QCOM_EUD=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_TZ_SMMU=y CONFIG_QSEE_IPC_IRQ=y +CONFIG_QCOM_GLINK_PKT=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y CONFIG_QCOM_SMCINVOKE=y @@ -561,6 +571,9 @@ CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CX_IPEAK=y CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_BGCOM_INTERFACE=y +CONFIG_MSM_BGCOM=y +CONFIG_MSM_PIL_SSR_BG=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -596,6 +609,7 @@ CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index d8a9b3b307042faa3df7113fac28971ae974be7f..a1a1662dcb858db295698f84c157e8f079554351 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -59,6 +59,7 @@ CONFIG_ARCH_SDM429W=y # CONFIG_VDSO is not set CONFIG_SMP=y CONFIG_SCHED_MC=y +CONFIG_COMMAND_LINE_SIZE=2048 CONFIG_NR_CPUS=8 CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y @@ -341,6 +342,7 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_SMD_PKT=y CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y @@ -377,6 +379,7 @@ CONFIG_QTI_ADC_TM=y CONFIG_QTI_CX_IPEAK_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_CPR=y @@ -423,16 +426,14 @@ CONFIG_MSM_FD=y CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y -CONFIG_MSM_SDE_ROTATOR=y -CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_DVB_MPQ=m CONFIG_DVB_MPQ_DEMUX=m CONFIG_DVB_MPQ_SW=y -CONFIG_DRM=y -CONFIG_DRM_MSM_REGISTER_LOGGING=y -CONFIG_DRM_SDE_EVTLOG_DEBUG=y -CONFIG_DRM_SDE_RSC=y +CONFIG_FB=y CONFIG_FB_VIRTUAL=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_LOGO=y @@ -503,6 +504,7 @@ CONFIG_EDAC=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y CONFIG_QCOM_GPI_DMA=y CONFIG_QCOM_GPI_DMA_DEBUG=y CONFIG_DEBUG_DMA_BUF_REF=y @@ -512,13 +514,16 @@ CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_ION=y +CONFIG_MSM_EXT_DISPLAY=y CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_USB_BAM=y +CONFIG_QCOM_MDSS_PLL=y CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_SDM_GCC_429W=y CONFIG_SDM_DEBUGCC_429W=y +CONFIG_CLOCK_CPU_SDM=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y @@ -533,6 +538,7 @@ CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_BGCOM=y CONFIG_RPMSG_QCOM_SMD=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y @@ -541,6 +547,7 @@ CONFIG_QCOM_SMEM=y CONFIG_QCOM_SMD_RPM=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y +CONFIG_QCOM_SCM=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y @@ -554,6 +561,7 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 @@ -572,7 +580,9 @@ CONFIG_QCOM_EUD=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_TZ_SMMU=y CONFIG_QSEE_IPC_IRQ=y +CONFIG_QCOM_GLINK_PKT=y # CONFIG_MSM_JTAGV8 is not set CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y @@ -586,6 +596,9 @@ CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CX_IPEAK=y CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_BGCOM_INTERFACE=y +CONFIG_MSM_BGCOM=y +CONFIG_MSM_PIL_SSR_BG=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -620,6 +633,7 @@ CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig index 548d0dae04309dbc9189ecfde29b4ce1573c83ac..1a298e1b24d2cccd391d29568c5ce136ebf2eed8 100644 --- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig +++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig @@ -34,6 +34,7 @@ CONFIG_ARCH_SDXPRAIRIE=y # CONFIG_VDSO is not set CONFIG_PCI_MSM=y CONFIG_PCI_MSM_MSI=y +CONFIG_PCI_SW_QCOM_SWITCH=y CONFIG_PREEMPT=y CONFIG_HIGHMEM=y CONFIG_ARM_MODULE_PLTS=y @@ -360,6 +361,7 @@ CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y +CONFIG_QCOM_ETHERNET_UTIL=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_MSM_CLK_AOP_QMP=y CONFIG_MSM_CLK_RPMH=y diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig index 50fa20b02e8a3397c144fdffd1aa9dd72849958c..5f1f1cf780ae2275b4839097208544b5c237a493 100644 --- a/arch/arm/configs/vendor/sdxprairie_defconfig +++ b/arch/arm/configs/vendor/sdxprairie_defconfig @@ -34,6 +34,7 @@ CONFIG_ARCH_SDXPRAIRIE=y # CONFIG_VDSO is not set CONFIG_PCI_MSM=y CONFIG_PCI_MSM_MSI=y +CONFIG_PCI_SW_QCOM_SWITCH=y CONFIG_PREEMPT=y CONFIG_HIGHMEM=y CONFIG_ARM_MODULE_PLTS=y @@ -371,6 +372,7 @@ CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y +CONFIG_QCOM_ETHERNET_UTIL=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_MSM_CLK_AOP_QMP=y CONFIG_MSM_CLK_RPMH=y diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h index 452bbdcbcc835fc838b4c957f2da3e6dafd2fdc9..506314265c6f1a24e50641dbbea1d41367d322d5 100644 --- a/arch/arm/include/asm/suspend.h +++ b/arch/arm/include/asm/suspend.h @@ -10,6 +10,7 @@ struct sleep_save_sp { }; extern void cpu_resume(void); +extern void cpu_resume_no_hyp(void); extern void cpu_resume_arm(void); extern int cpu_suspend(unsigned long, int (*)(unsigned long)); diff --git a/arch/arm/include/uapi/asm/setup.h b/arch/arm/include/uapi/asm/setup.h index 6b335a9ff8c80cf5a0e62ae8652e89d956419f6e..977373fa9992982f8ae9e4574690a12e3df9622e 100644 --- a/arch/arm/include/uapi/asm/setup.h +++ b/arch/arm/include/uapi/asm/setup.h @@ -17,7 +17,9 @@ #include -#define COMMAND_LINE_SIZE 1024 +#ifdef CONFIG_COMMAND_LINE_SIZE +#define COMMAND_LINE_SIZE CONFIG_COMMAND_LINE_SIZE +#endif /* The list ends with an ATAG_NONE node. */ #define ATAG_NONE 0x00000000 diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S index 60146e32619a5912bf12b5277397f2e19213b2a8..83e463c05dcdb456e4bfb0381e2e31ac9f6be07c 100644 --- a/arch/arm/kernel/hyp-stub.S +++ b/arch/arm/kernel/hyp-stub.S @@ -159,10 +159,9 @@ ARM_BE8(orr r7, r7, #(1 << 25)) @ HSCTLR.EE #if !defined(ZIMAGE) && defined(CONFIG_ARM_ARCH_TIMER) @ make CNTP_* and CNTPCT accessible from PL1 mrc p15, 0, r7, c0, c1, 1 @ ID_PFR1 - lsr r7, #16 - and r7, #0xf - cmp r7, #1 - bne 1f + ubfx r7, r7, #16, #4 + teq r7, #0 + beq 1f mrc p15, 4, r7, c14, c1, 0 @ CNTHCTL orr r7, r7, #3 @ PL1PCEN | PL1PCTEN mcr p15, 4, r7, c14, c1, 0 @ CNTHCTL @@ -180,8 +179,8 @@ ARM_BE8(orr r7, r7, #(1 << 25)) @ HSCTLR.EE @ Check whether GICv3 system registers are available mrc p15, 0, r7, c0, c1, 1 @ ID_PFR1 ubfx r7, r7, #28, #4 - cmp r7, #1 - bne 2f + teq r7, #0 + beq 2f @ Enable system register accesses mrc p15, 4, r7, c12, c9, 5 @ ICC_HSRE diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index a8257fc9cf2a908c4dd2b5f19c819b4c7fc40588..5dc8b80bb69383643eddec5ba62164e0458b4512 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -120,6 +120,14 @@ ENDPROC(cpu_resume_after_mmu) .text .align +#ifdef CONFIG_MCPM + .arm +THUMB( .thumb ) +ENTRY(cpu_resume_no_hyp) +ARM_BE8(setend be) @ ensure we are in BE mode + b no_hyp +#endif + #ifdef CONFIG_MMU .arm ENTRY(cpu_resume_arm) @@ -135,6 +143,7 @@ ARM_BE8(setend be) @ ensure we are in BE mode bl __hyp_stub_install_secondary #endif safe_svcmode_maskall r1 +no_hyp: mov r1, #0 ALT_SMP(mrc p15, 0, r0, c0, c0, 5) ALT_UP_B(1f) @@ -163,6 +172,9 @@ ENDPROC(cpu_resume) #ifdef CONFIG_MMU ENDPROC(cpu_resume_arm) +#endif +#ifdef CONFIG_MCPM +ENDPROC(cpu_resume_no_hyp) #endif .align 2 diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 45c8f2ef4e23c3b8f61245f29c6693aef4f153d7..9274a484c6a39b245e35b6a9407604973e47e021 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2530,7 +2530,7 @@ static void _setup_iclk_autoidle(struct omap_hwmod *oh) */ static int _setup_reset(struct omap_hwmod *oh) { - int r; + int r = 0; if (oh->_state != _HWMOD_STATE_INITIALIZED) return -EINVAL; diff --git a/arch/arm/mach-qcom/board-sdm429w.c b/arch/arm/mach-qcom/board-sdm429w.c index 7fd0ea6e62f0b3adb4ca2b48e9d5f2bffc9fd514..22a5fe6e5613818a0ce1f68ab7db86d70ed2889d 100644 --- a/arch/arm/mach-qcom/board-sdm429w.c +++ b/arch/arm/mach-qcom/board-sdm429w.c @@ -29,7 +29,7 @@ static void __init sdm429w_init(void) } DT_MACHINE_START(SDM429W_DT, - "Qualcomm Technologies, Inc. QCS403 (Flattened Device Tree)") + "Qualcomm Technologies, Inc. SDM429W (Flattened Device Tree)") .init_machine = sdm429w_init, .dt_compat = sdm429w_dt_match, MACHINE_END diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c index b8a61cb112073643256dbb693a8351e07c1f4335..7f0f40178634451f007fcf570397bd329c333f5d 100644 --- a/arch/arm/mach-rpc/irq.c +++ b/arch/arm/mach-rpc/irq.c @@ -118,7 +118,7 @@ extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end; void __init rpc_init_irq(void) { - unsigned int irq, clr, set = 0; + unsigned int irq, clr, set; iomd_writeb(0, IOMD_IRQMASKA); iomd_writeb(0, IOMD_IRQMASKB); @@ -130,6 +130,7 @@ void __init rpc_init_irq(void) for (irq = 0; irq < NR_IRQS; irq++) { clr = IRQ_NOREQUEST; + set = 0; if (irq <= 6 || (irq >= 9 && irq <= 15)) clr |= IRQ_NOPROBE; diff --git a/arch/arm/mach-vexpress/spc.c b/arch/arm/mach-vexpress/spc.c index fe488523694c17618835e0224347de7a377a821b..635b0d54948741a34e8d23733fe4a343e388787e 100644 --- a/arch/arm/mach-vexpress/spc.c +++ b/arch/arm/mach-vexpress/spc.c @@ -555,8 +555,9 @@ static struct clk *ve_spc_clk_register(struct device *cpu_dev) static int __init ve_spc_clk_init(void) { - int cpu; + int cpu, cluster; struct clk *clk; + bool init_opp_table[MAX_CLUSTERS] = { false }; if (!info) return 0; /* Continue only if SPC is initialised */ @@ -582,8 +583,17 @@ static int __init ve_spc_clk_init(void) continue; } + cluster = topology_physical_package_id(cpu_dev->id); + if (init_opp_table[cluster]) + continue; + if (ve_init_opp_table(cpu_dev)) pr_warn("failed to initialise cpu%d opp table\n", cpu); + else if (dev_pm_opp_set_sharing_cpus(cpu_dev, + topology_core_cpumask(cpu_dev->id))) + pr_warn("failed to mark OPPs shared for cpu%d\n", cpu); + else + init_opp_table[cluster] = true; } platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0); diff --git a/arch/arm/plat-pxa/ssp.c b/arch/arm/plat-pxa/ssp.c index b92673efffffb630e83948604b34d3489eef2ff4..97bd43c16cd872d370229b6b4037914bb910160d 100644 --- a/arch/arm/plat-pxa/ssp.c +++ b/arch/arm/plat-pxa/ssp.c @@ -230,18 +230,12 @@ static int pxa_ssp_probe(struct platform_device *pdev) static int pxa_ssp_remove(struct platform_device *pdev) { - struct resource *res; struct ssp_device *ssp; ssp = platform_get_drvdata(pdev); if (ssp == NULL) return -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - clk_put(ssp->clk); - mutex_lock(&ssp_lock); list_del(&ssp->node); mutex_unlock(&ssp_lock); diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile index ee0625da0461c97b12cc580afc2cb551713bac09..4715d40a6d4b1e7dcd0767ecc5e9e7323090400f 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -18,7 +18,7 @@ include $(srctree)/arch/arm64/boot/dts/Makefile OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S -targets := Image Image.gz +targets := Image Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES)) ifneq ($(DTB_NAMES),) diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index 8c8db1b057dfc687aa5bcabce4732cc3653bebbd..788a6f8c5994e8faacc5001498592dc431a060fc 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -274,7 +274,8 @@ interrupts = , , ; - clocks = <&ccu 58>; + clocks = <&ccu 58>, <&osc24M>, <&rtc 0>; + clock-names = "apb", "hosc", "losc"; gpio-controller; #gpio-cells = <3>; interrupt-controller; diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi index e79f3defe00216b695791049744e0aab6e6542fc..c2ad4f97cef0f7a701fdfe49a6a9e7f00968cc2f 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi @@ -56,10 +56,10 @@ pmu { compatible = "arm,armv8-pmuv3"; - interrupts = <0 120 8>, - <0 121 8>, - <0 122 8>, - <0 123 8>; + interrupts = <0 170 4>, + <0 171 4>, + <0 172 4>, + <0 173 4>; interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts index fb5db5f33e8c34d31ed53916e2199399b5abc025..ce4a116382bfb2943d06f25347fe0d68c39a192e 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts @@ -33,11 +33,9 @@ gpio-keys-polled { compatible = "gpio-keys-polled"; - #address-cells = <1>; - #size-cells = <0>; poll-interval = <100>; - button@0 { + power-button { label = "power"; linux,code = ; gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts index e2c71753e3278b5a899b3cea45717dfb2f937e80..407d32f4fe734a93d194bea5d7db6a27cae06768 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts @@ -226,7 +226,6 @@ cap-mmc-highspeed; mmc-ddr-3_3v; max-frequency = <50000000>; - non-removable; disable-wp; mmc-pwrseq = <&emmc_pwrseq>; diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index f165f04db0c9c48152a4a920a4a7df45b59b4a0a..13ee8ffa9bbf4348efcf28ae34074eaddcec20d0 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -5,7 +5,6 @@ /* * Devices shared by all Juno boards */ - dma-ranges = <0 0 0 0 0x100 0>; memtimer: timer@2a810000 { compatible = "arm,armv7-timer-mem"; diff --git a/arch/arm64/boot/dts/arm/juno-clocks.dtsi b/arch/arm64/boot/dts/arm/juno-clocks.dtsi index e5e265dfa902500e8a139d08e57663d462a7d154..2870b5eeb198430aca0ee9301411a56e5aafaa2d 100644 --- a/arch/arm64/boot/dts/arm/juno-clocks.dtsi +++ b/arch/arm64/boot/dts/arm/juno-clocks.dtsi @@ -8,10 +8,10 @@ */ / { /* SoC fixed clocks */ - soc_uartclk: refclk7273800hz { + soc_uartclk: refclk7372800hz { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <7273800>; + clock-frequency = <7372800>; clock-output-names = "juno:uartclk"; }; diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index fdaf15bda642c15be5a4a58a863830930b9faf79..afd6433706da0a1d82840ad00b4663d79dd3e53b 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -8,7 +8,7 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sa8155p-adp-star-lpass-overlay.dtbo \ sa8155-v2-adp-air-overlay.dtbo \ sa8155p-v2-adp-air-overlay.dtbo \ - sa8155p-v2-adp-air-lpass-overlay.dts + sa8155p-v2-adp-air-lpass-overlay.dtbo sm8150-cdp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sa8155-adp-star-overlay.dtbo-base := sa8155.dtb sa8155-v2.dtb @@ -21,7 +21,7 @@ else dtb-$(CONFIG_ARCH_SM8150) += sm8150-cdp.dtb \ sa8155-adp-star.dtb \ sa8155p-adp-star.dtb \ - sa8155p-adp-star-lpass \ + sa8155p-adp-star-lpass.dtb \ sa8155-v2-adp-star.dtb \ sa8155p-v2-adp-star.dtb \ sa8155-v2-adp-air.dtb \ @@ -48,12 +48,12 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) dtbo-$(CONFIG_ARCH_SM6150) += \ sa6155-adp-star-overlay.dtbo \ sa6155p-adp-star-overlay.dtbo \ - sa6155p-adp-star-lpass-overlay.dts \ + sa6155p-adp-star-lpass-overlay.dtbo \ sa6155-adp-air-overlay.dtbo \ sa6155p-adp-air-overlay.dtbo \ sa6155p-v2-adp-star-overlay.dtbo \ sa6155p-v2-adp-air-overlay.dtbo \ - sa6155p-v2-adp-air-lpass-overlay.dts + sa6155p-v2-adp-air-lpass-overlay.dtbo sa6155-adp-star-overlay.dtbo-base := sa6155.dtb sa6155p-adp-star-overlay.dtbo-base := sa6155p.dtb @@ -102,6 +102,8 @@ dtb-$(CONFIG_ARCH_QCS405) += qcs405-iot-sku1.dtb \ qcs405-iot-sku12.dtb \ qcs407-iot-sku12.dtb \ sa2150p-ccard-emmc.dtb \ + sa2145p-ccard-nand-dc.dtb \ + sa2150p-ccard-nand-dc.dtb \ sa2150p-ccard-nand.dtb \ qcs405-iot-sku13.dtb \ qcs407-iot-sku13.dtb \ @@ -321,7 +323,15 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) trinket-usbc-idp-overlay.dtbo \ trinket-dp-idp-overlay.dtbo \ qcm6125-iot-idp-overlay.dtbo \ - qcs6125-iot-idp-overlay.dtbo + qcs6125-iot-idp-overlay.dtbo \ + qcm6125-iot-external-codec-idp-overlay.dtbo \ + qcs6125-iot-external-codec-idp-overlay.dtbo \ + qcm6125-iot-usbc-external-codec-idp-overlay.dtbo \ + qcs6125-iot-usbc-external-codec-idp-overlay.dtbo \ + qcm6125-iot-usbc-idp-overlay.dtbo \ + qcs6125-iot-usbc-idp-overlay.dtbo \ + qcm6125-iot-dp-idp-overlay.dtbo \ + qcs6125-iot-dp-idp-overlay.dtbo trinket-rumi-overlay.dtbo-base := trinket.dtb trinket-idp-overlay.dtbo-base := trinket.dtb @@ -332,6 +342,14 @@ trinket-usbc-idp-overlay.dtbo-base := trinket.dtb trinket-dp-idp-overlay.dtbo-base := trinket.dtb qcm6125-iot-idp-overlay.dtbo-base := qcm6125.dtb qcs6125-iot-idp-overlay.dtbo-base := qcs6125.dtb +qcm6125-iot-external-codec-idp-overlay.dtbo-base := qcm6125.dtb +qcs6125-iot-external-codec-idp-overlay.dtbo-base := qcs6125.dtb +qcm6125-iot-usbc-external-codec-idp-overlay.dtbo-base := qcm6125.dtb +qcs6125-iot-usbc-external-codec-idp-overlay.dtbo-base := qcs6125.dtb +qcm6125-iot-usbc-idp-overlay.dtbo-base := qcm6125.dtb +qcs6125-iot-usbc-idp-overlay.dtbo-base := qcs6125.dtb +qcm6125-iot-dp-idp-overlay.dtbo-base := qcm6125.dtb +qcs6125-iot-dp-idp-overlay.dtbo-base := qcs6125.dtb else dtb-$(CONFIG_ARCH_TRINKET) += trinket-rumi.dtb \ trinket-idp.dtb \ @@ -341,7 +359,15 @@ dtb-$(CONFIG_ARCH_TRINKET) += trinket-rumi.dtb \ trinket-usbc-idp.dtb \ trinket-dp-idp.dtb \ qcm6125-iot-idp.dtb \ - qcs6125-iot-idp.dtb + qcs6125-iot-idp.dtb \ + qcm6125-iot-external-codec-idp.dtb \ + qcs6125-iot-external-codec-idp.dtb \ + qcm6125-iot-usbc-external-codec-idp.dtb \ + qcs6125-iot-usbc-external-codec-idp.dtb \ + qcm6125-iot-usbc-idp.dtb \ + qcs6125-iot-usbc-idp.dtb \ + qcm6125-iot-dp-idp.dtb \ + qcs6125-iot-dp-idp.dtb endif ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) @@ -410,20 +436,22 @@ dtb-$(CONFIG_ARCH_SDXPRAIRIE) += sdxprairie-rumi.dtb \ sdxprairie-v2-mtp-v1.1.dtb \ sdxprairie-v2-mtp-le-cpe.dtb \ sdxprairie-v2-ttp-cpe.dtb \ - sa515m-v2-ttp.dtb \ - sa515m-v2-ttp-usb-ep.dtb \ - sa515m-v2-ttp-pcie-ep.dtb \ - sa515m-v2-ttp-flashless-usb-ep.dtb \ - sa515m-v2-ttp-flashless-pcie-ep.dtb \ - sa515m-v2-ttp-emmc.dtb \ + sa515m-v2-ttp.dtb \ + sa515m-v2-ttp-usb-ep.dtb \ + sa515m-v2-ttp-pcie-ep.dtb \ + sa515m-v2-ttp-flashless-usb-ep.dtb \ + sa515m-v2-ttp-flashless-pcie-ep.dtb \ + sa515m-v2-ttp-emmc.dtb \ sa515m-ccard.dtb \ sa515m-ccard-pcie-ep.dtb \ sa515m-ccard-usb-ep.dtb \ - sa515m-v2-ccard-flashless-pcie-ep.dtb \ - sa515m-v2-ccard-flashless-usb-ep.dtb \ + sa515m-ccard-eth-ep.dtb \ + sa515m-v2-ccard-flashless-pcie-ep.dtb \ + sa515m-v2-ccard-flashless-usb-ep.dtb \ sa515m-v2-ccard.dtb \ sa515m-v2-ccard-pcie-ep.dtb \ - sa515m-v2-ccard-usb-ep.dtb + sa515m-v2-ccard-usb-ep.dtb \ + sa515m-v2-ccard-eth-ep.dtb dtb-$(CONFIG_ARCH_MDM9607) += mdm9607-cdp.dtb \ mdm9607-mtp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi index b6b44fdf7face8b00690bede37d09d59debed242..c1028b47edde9816c071a26910c4032bd5dc1641 100644 --- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi @@ -458,6 +458,8 @@ l11 { regulator-min-microvolt = <1750000>; regulator-max-microvolt = <3337000>; + regulator-allow-set-load; + regulator-system-load = <200000>; }; l12 { diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi index 789f3e87321e2d47e51d5af9346441addd385413..7a510505e0c252778dbf787dfdbb9b9340718cbc 100644 --- a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi @@ -262,6 +262,8 @@ l21 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; + regulator-allow-set-load; + regulator-system-load = <200000>; }; l22 { regulator-min-microvolt = <3300000>; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm429.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm429.dtsi index f722c473bd27945037175ed6df120fdd284681bb..7851eb3cdfee499b399c25143b79a968d3327212 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm429.dtsi @@ -14,7 +14,7 @@ &soc { kgsl_smmu: arm,smmu-kgsl@1c40000 { - status = "disabled"; + status = "ok"; compatible = "qcom,smmu-v2"; qcom,tz-device-id = "GPU"; reg = <0x1c40000 0x10000>; @@ -26,8 +26,9 @@ ; qcom,dynamic; qcom,use-3-lvl-tables; - qcom,enable-smmu-halt; qcom,skip-init; + qcom,deferred-regulator-disable-delay = <80>; + qcom,enable-static-cb; vdd-supply = <&oxili_cx_gdsc>; qcom,regulator-names = "vdd"; clocks = <&gcc GCC_OXILI_AHB_CLK>, @@ -46,7 +47,7 @@ }; apps_iommu: qcom,iommu@1e00000 { - status = "disabled"; + status = "ok"; compatible = "qcom,qsmmu-v500"; reg = <0x1e00000 0x40000>, <0x1ee2000 0x20>; diff --git a/arch/arm64/boot/dts/qcom/pm6155.dtsi b/arch/arm64/boot/dts/qcom/pm6155.dtsi index e96b5638ff3dba52c46550d317976ec682e445c9..c5714d8a93a0837efa5c3c1138fe36778ba4b22c 100644 --- a/arch/arm64/boot/dts/qcom/pm6155.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6155.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, 2020, 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 @@ -173,3 +173,33 @@ #size-cells = <1>; }; }; + +&thermal_zones { + pm6155-1-tz { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6155_1_tz>; + wake-capable-sensor; + + trips { + pm6155_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm6155_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi index 2f7f6488d3289954a09ccdb71557a65c52b3a4b0..7ebb230eb2690efda7eb84d769299d5b4f80272a 100644 --- a/arch/arm64/boot/dts/qcom/pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/pm660.dtsi @@ -365,6 +365,7 @@ qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */ <9000 3000>; /* 9V @ 3A */ + qcom,no-usb3-dp-concurrency; }; pm660_adc_tm: vadc@3400 { diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..96696b0399be409de99c514d9391b98c8a1ac838 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp-overlay.dts @@ -0,0 +1,51 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include "qcm6125-iot-idp.dtsi" +#include "trinket-audio-overlay.dtsi" + +/ { + model = "Display Port Enable IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,msm-id = <467 0x10000>; + qcom,board-id = <34 4>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; + +&sde_dp { + status = "ok"; + qcom,dp-hpd-gpio = <&tlmm 100 0>; + qcom,dp-low-power-hw-hpd; +}; + +&mdss_dp_pll { + status = "ok"; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..2a0232f761737b484128abd200febe85fadb93a8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp.dts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcm6125.dtsi" +#include "qcm6125-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM6125 IOT Disp. Port Enable IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,board-id = <34 4>; +}; + +&sde_dp { + status = "ok"; + qcom,dp-hpd-gpio = <&tlmm 100 0>; + qcom,dp-low-power-hw-hpd; +}; + +&mdss_dp_pll { + status = "ok"; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..c8a93d2e1cc4c2c534385fb9d8bcbef257f45144 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcm6125-iot-idp.dtsi" +#include "trinket-tasha-codec-audio-overlay.dtsi" +#include "trinket-tasha-codec.dtsi" + +/ { + model = "Ext Audio Codec IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,msm-id = <467 0x10000>; + qcom,board-id = <34 1>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..586d54193c076f103a446bbc990e50f929769fdd --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcm6125.dtsi" +#include "qcm6125-iot-idp.dtsi" +#include "trinket-tasha-codec-audio-overlay.dtsi" +#include "trinket-tasha-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM6125 IOT Ext Audio Codec IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..2c9d5820eccb2efde4683ada75b47dac08e1860b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp-overlay.dts @@ -0,0 +1,29 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcm6125-iot-idp.dtsi" + +/ { + model = "USB-C Ext Audio Codec IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,msm-id = <467 0x10000>; + qcom,board-id = <34 3>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..a3c69c31f73435bdf875ea86471a79f91a8ebf7c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcm6125.dtsi" +#include "qcm6125-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies,Inc. QCM6125 IOT USBC Ext Aud Codec IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,board-id = <34 3>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..ef7a24aeb2bf265cb1c8dea13f0b549d346e57ae --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp-overlay.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcm6125-iot-idp.dtsi" +#include "qcm6125-iot-usbc-idp.dtsi" + +/ { + model = "USBC Audio IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,msm-id = <467 0x10000>; + qcom,board-id = <34 2>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..73f65a9fc2d638ec2e6fe138e5c8ab54cf3b4b45 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcm6125.dtsi" +#include "qcm6125-iot-idp.dtsi" +#include "qcm6125-iot-usbc-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM6125 IOT USBC Audio IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,board-id = <34 2>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..faafcf82f5e3ce0aac93a47d06e5c3ae907aabe9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "trinket-audio-overlay.dtsi" + +&sm6150_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs403.dtsi b/arch/arm64/boot/dts/qcom/qcs403.dtsi index 70f1c135f7db0b83162d38a4ad70d8b5f4cc5e4a..0bf174ea10ce2c400a03bab5addc2308905bae1b 100644 --- a/arch/arm64/boot/dts/qcom/qcs403.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs403.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, 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 @@ -16,7 +16,7 @@ / { model = "Qualcomm Technologies, Inc. QCS403"; qcom,msm-name = "QCS403"; - qcom,msm-id = <373 0x0>; + qcom,msm-id = <373 0x0>, <451 0x0>; cpus { /delete-node/ cpu@102; diff --git a/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi b/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi index feb80a1c13bdc797ed0b0cae4b6dcb45da39568a..4d7d6979197101ac1bc4b934b828d3ccd065b13b 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi @@ -81,6 +81,9 @@ qcom,ep92-busnum = <3>; qcom,ep92-reg = <0x64>; + qcom,clk-src-name-integ = "LPAPLL0"; + qcom,clk-src-name-fract = "LPAPLL2"; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&compr>, diff --git a/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi b/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi index f0dcd69670c90d4af81dc7a76dd47229e5b32f92..d6d5dde8eaa09210111121996cd8f58d4aaea41b 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, 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 @@ -116,8 +116,14 @@ <0>, <0>, <0>, <0>; clock-output-names = "pcie_0_pipe_clk"; - resets = <&clock_gcc GCC_PCIEPHY_0_PHY_BCR>; - reset-names = "pcie_0_phy_reset"; + + resets = <&clock_gcc GCC_PCIEPHY_0_PHY_BCR>, + <&clock_gcc GCC_PCIE_0_BCR>, + <&clock_gcc GCC_PCIE_0_PHY_BCR>; + + reset-names = "pcie_0_phy_reset", + "pcie_0_core_reset", + "pcie_phy_reset"; pcie_rc0: pcie_rc0 { #address-cells = <5>; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 67e3ed1fd95f5d96fd7dc42711e134c5673e02c0..dfbb2146b1c9b8c8aeb964adbc027ef84764919d 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -28,7 +28,7 @@ / { model = "Qualcomm Technologies, Inc. QCS405"; compatible = "qcom,qcs405"; - qcom,msm-id = <352 0x0>, <451 0x0>, <452 0x0>; + qcom,msm-id = <352 0x0>, <452 0x0>; interrupt-parent = <&wakegic>; chosen { @@ -1548,6 +1548,152 @@ < 1401600 MHZ_TO_MBPS( 710, 8) >; }; + mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <4>; + snps,rx-sched-sp; + + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + snps,route-up; + snps,priority = <0x1>; + }; + + queue1 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x1>; + snps,route-ptp; + }; + + queue2 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x2>; + snps,route-avcp; + }; + + queue3 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x3>; + snps,priority = <0xC>; + }; + }; + + mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <5>; + snps,tx-sched-sp; + queue0 { + snps,dcb-algorithm; + }; + + queue1 { + snps,dcb-algorithm; + }; + + queue2 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3E800>; + snps,low_credit = <0xFFC18000>; + }; + + queue3 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3E800>; + snps,low_credit = <0xFFC18000>; + }; + }; + + ethqos_hw: qcom,ethernet@00020000 { + compatible = "qcom,stmmac-ethqos"; + reg = <0x07A80000 0x10000>, + <0x7A96000 0x100>; + qcom,arm-smmu; + reg-names = "stmmaceth", "rgmii"; + dma-bit-mask = <32>; + emac-core-version = <0x20030000>; + interrupts-extended = <&wakegic 0 56 4>, <&wakegic 0 55 4>, + <&tlmm 61 2>, <&wakegic 0 300 4>, + <&wakegic 0 301 4>, <&wakegic 0 302 4>, + <&wakegic 0 303 4>, <&wakegic 0 304 4>, + <&wakegic 0 305 4>, <&wakegic 0 306 4>, + <&wakegic 0 307 4>, <&wakegic 0 308 4>; + interrupt-names = "macirq", "eth_lpi", + "phy-intr", "tx-ch0-intr", + "tx-ch1-intr", "tx-ch2-intr", + "tx-ch3-intr", "tx-ch4-intr", + "rx-ch0-intr", "rx-ch1-intr", + "rx-ch2-intr", "rx-ch3-intr"; + qcom,msm-bus,name = "emac"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <98 512 0 0>, <1 781 0 0>, /* No vote */ + <98 512 2500 0>, <1 781 0 40000>, /* 10Mbps vote */ + <98 512 25000 0>, <1 781 0 40000>, /* 100Mbps vote */ + <98 512 250000 0>, <1 781 0 40000>; /* 1000Mbps vote */ + qcom,bus-vector-names = "0", "10", "100", "1000"; + snps,tso; + snps,pbl = <32>; + mac-address = [00 55 7B B5 7D f7]; + clocks = <&clock_gcc GCC_ETH_AXI_CLK>, + <&clock_gcc GCC_ETH_SLAVE_AHB_CLK>, + <&clock_gcc GCC_ETH_PTP_CLK>, + <&clock_gcc GCC_ETH_RGMII_CLK>; + clock-names = "stmmaceth", "pclk", "ptp_ref", "rgmii"; + snps,ptp-ref-clk-rate = <230400000>; + snps,ptp-req-clk-rate = <57600000>; + snps,reset-gpio = <&tlmm 60 GPIO_ACTIVE_HIGH>; + qcom,phy-intr-redirect = <&tlmm 61 GPIO_ACTIVE_LOW>; + /*gdsc_emac-supply = <&emac_gdsc>;*/ + rx-fifo-depth = <16384>; + tx-fifo-depth = <20480>; + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr"; + + pinctrl-0 = <&emac_mdc>; + pinctrl-1 = <&emac_mdio>; + pinctrl-2 = <&emac_rgmii_txd0>; + pinctrl-3 = <&emac_rgmii_txd1>; + pinctrl-4 = <&emac_rgmii_txd2>; + pinctrl-5 = <&emac_rgmii_txd3>; + pinctrl-6 = <&emac_rgmii_txc>; + pinctrl-7 = <&emac_rgmii_tx_ctl>; + pinctrl-8 = <&emac_rgmii_rxd0>; + pinctrl-9 = <&emac_rgmii_rxd1>; + pinctrl-10 = <&emac_rgmii_rxd2>; + pinctrl-11 = <&emac_rgmii_rxd3>; + pinctrl-12 = <&emac_rgmii_rxc>; + pinctrl-13 = <&emac_rgmii_rx_ctl>; + pinctrl-14 = <&emac_phy_intr>; + + snps,reset-active-low; + snps,reset-delays-us = <0 10000 100000>; + phy-mode = "rgmii"; + + io-macro-info { + io-macro-bypass-mode = <0>; + io-interface = "rgmii"; + }; + + ethqos_emb_smmu: ethqos_emb_smmu { + compatible = "qcom,emac-smmu-embedded"; + iommus = <&apps_smmu 0x1400 0x0>; + qcom,iova-mapping = <0x80000000 0x40000000>; + }; + }; + emac_hw: qcom,emac@07A80000 { compatible = "qcom,emac-dwc-eqos"; reg = <0x07A80000 0x10000>, diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot-overlay.dts b/arch/arm64/boot/dts/qcom/qcs410-iot-overlay.dts index 327744a101c185e92230c29890369df6293a11ea..fc4c9f6cc43164b5077f2276368e275200b53cfe 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot-overlay.dts +++ b/arch/arm64/boot/dts/qcom/qcs410-iot-overlay.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 @@ -16,7 +16,7 @@ #include "qcs410-iot.dtsi" / { - model = "IOT"; + model = "Qualcomm Technologies, Inc. QCS410 IOT Overlay"; compatible = "qcom,qcs410-iot", "qcom,qcs410", "qcom,iot"; qcom,msm-id = <406 0x0>; qcom,board-id = <32 0>; diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot.dts b/arch/arm64/boot/dts/qcom/qcs410-iot.dts index bac1561fdc2a4aa2286055955993d38ce7b486c4..2fe709638dbc56f59428a298b97719caa314859a 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot.dts +++ b/arch/arm64/boot/dts/qcom/qcs410-iot.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 @@ -14,9 +14,14 @@ #include "qcs410.dtsi" #include "qcs410-iot.dtsi" +#include "sm6150-audio-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS410 IOT"; compatible = "qcom,qcs410-iot", "qcom,qcs410", "qcom,iot"; qcom,board-id = <32 0>; }; + +&sm6150_snd { + /delete-property/ fsa4480-i2c-handle; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi index 3144838fcefc1d26c422d61510357464ade4b620..237eaee48848d628cec0cad830826163ff2b7a8d 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 @@ -13,7 +13,15 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "qcs410.dtsi" +#include "sm6150-sde-pll.dtsi" +#include "sm6150-sde-display.dtsi" #include "qcs610-camera-sensor-idp.dtsi" / { @@ -26,6 +34,10 @@ #include "smb1390.dtsi" }; +&fsa4480 { + status = "disabled"; +}; + &pm6150l_gpios { key_vol_up { key_vol_up_default: key_vol_up_default { @@ -186,6 +198,34 @@ reg = <0 0x8fd00000 0 0x3100000>; }; +&pil_video_mem { + reg = <0 0x92e00000 0 0x500000>; +}; + +&wlan_msa_mem { + reg = <0 0x93300000 0 0x200000>; +}; + +&pil_cdsp_mem { + reg = <0 0x93500000 0 0x1e00000>; +}; + +&pil_adsp_mem { + reg = <0 0x95300000 0 0x1e00000>; +}; + +&pil_ipa_fw_mem { + reg = <0 0x97100000 0 0x10000>; +}; + +&pil_ipa_gsi_mem { + reg = <0 0x97110000 0 0x5000>; +}; + +&pil_gpu_mem { + reg = <0 0x97115000 0 0x2000>; +}; + &L16A { regulator-max-microvolt = <3304000>; }; @@ -201,3 +241,124 @@ &L5C { regulator-max-microvolt = <2912000>; }; + +&sde_dp { + status="disabled"; +}; + +&mdss_dp_pll { + status="disabled"; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dsi>; +}; + +&qupv3_se1_i2c { + status = "ok"; + lt9611: lt,lt9611@3b { + compatible = "lt,lt9611"; + reg = <0x3b>; + interrupt-parent = <&tlmm>; + interrupts = <26 0>; + interrupt-names = "lt_irq"; + lt,irq-gpio = <&tlmm 26 0x0>; + lt,reset-gpio = <&tlmm 20 0x0>; + lt,hdmi-en-gpio = <&tlmm 79 0x0>; + instance_id = <0>; + lt,non-pluggable; + lt,preferred-mode = "1920x1080"; + + pinctrl-names = "default"; + pinctrl-0 = <<9611_pins>; + + vdd-supply = <&pm6150_l13>; + vcc-supply = <&pm6150_l16>; + + lt,supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + lt,supply-entry@0 { + reg = <0>; + lt,supply-name = "vdd"; + lt,supply-min-voltage = <1800000>; + lt,supply-max-voltage = <1800000>; + lt,supply-enable-load = <200000>; + lt,supply-post-on-sleep = <50>; + }; + lt,supply-entry@1 { + reg = <1>; + lt,supply-name = "vcc"; + lt,supply-min-voltage = <3304000>; + lt,supply-max-voltage = <3304000>; + lt,supply-enable-load = <200000>; + lt,supply-post-on-sleep = <50>; + }; + + + }; + + lt,customize-modes { + lt,customize-mode-id@0 { + lt,mode-h-active = <1920>; + lt,mode-h-front-porch = <88>; + lt,mode-h-pulse-width = <44>; + lt,mode-h-back-porch = <148>; + lt,mode-h-active-high; + lt,mode-v-active = <1080>; + lt,mode-v-front-porch = <4>; + lt,mode-v-pulse-width = <5>; + lt,mode-v-back-porch = <36>; + lt,mode-v-active-high; + lt,mode-refresh-rate = <60>; + lt,mode-clock-in-khz = <148500>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lt9611_in: endpoint { + remote-endpoint = <&ext_dsi_out>; + }; + }; + }; + }; +}; + +&dsi_ext_bridge_hdmi_1080p { + qcom,mdss-dsi-ext-bridge = <0>; +}; + +&soc { + ext_dsi_bridge_display: qcom,dsi-display@50 { + label = "ext_dsi_bridge_display hdmi 1080p"; + qcom,dsi-display-active; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,dsi-panel = <&dsi_ext_bridge_hdmi_1080p>; + }; +}; + +&sde_dsi { + qcom,dsi-display-list = <&ext_dsi_bridge_display>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ext_dsi_out: endpoint { + remote-endpoint = <<9611_in>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi b/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi index 6c1d8c88de2acbb98b729e96fac9f7f479ad647a..733d9335b4fd519328e815f31a71a7bd46a57cf2 100644 --- a/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi @@ -296,6 +296,34 @@ reg = <0 0x8fd00000 0 0x3100000>; }; +&pil_video_mem { + reg = <0 0x92e00000 0 0x500000>; +}; + +&wlan_msa_mem { + reg = <0 0x93300000 0 0x200000>; +}; + +&pil_cdsp_mem { + reg = <0 0x93500000 0 0x1e00000>; +}; + +&pil_adsp_mem { + reg = <0 0x95300000 0 0x1e00000>; +}; + +&pil_ipa_fw_mem { + reg = <0 0x97100000 0 0x10000>; +}; + +&pil_ipa_gsi_mem { + reg = <0 0x97110000 0 0x5000>; +}; + +&pil_gpu_mem { + reg = <0 0x97115000 0 0x2000>; +}; + &sdhc_1 { vdd-supply = <&pm6150l_l11>; qcom,vdd-voltage-level = <2950000 2950000>; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..2830ca6cfde8d553c963704f6ebe7fa2f908ebfd --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp-overlay.dts @@ -0,0 +1,51 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include "qcs6125-iot-idp.dtsi" +#include "trinket-audio-overlay.dtsi" + +/ { + model = "Display Port Enable IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,msm-id = <468 0x10000>; + qcom,board-id = <34 4>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; + +&sde_dp { + status = "ok"; + qcom,dp-hpd-gpio = <&tlmm 100 0>; + qcom,dp-low-power-hw-hpd; +}; + +&mdss_dp_pll { + status = "ok"; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..69bf2c2be9d88d8216be395924fbc073688b8e70 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp.dts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcs6125.dtsi" +#include "qcs6125-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM6125 IOT Disp. Port Enable IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,board-id = <34 4>; +}; + +&sde_dp { + status = "ok"; + qcom,dp-hpd-gpio = <&tlmm 100 0>; + qcom,dp-low-power-hw-hpd; +}; + +&mdss_dp_pll { + status = "ok"; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..d5c75339ba9d4648ece66f54c0ba144e6c9ef388 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcs6125-iot-idp.dtsi" +#include "trinket-tasha-codec-audio-overlay.dtsi" +#include "trinket-tasha-codec.dtsi" + +/ { + model = "Ext Audio Codec IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,msm-id = <468 0x10000>; + qcom,board-id = <34 1>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..7d75678fd29a1cc0ffc1178328e47a89e25e1079 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcs6125.dtsi" +#include "qcs6125-iot-idp.dtsi" +#include "trinket-tasha-codec-audio-overlay.dtsi" +#include "trinket-tasha-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS6125 IOT Ext Audio Codec IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..8fb605f7dac8e01411abb9d24b071bd81396ab86 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp-overlay.dts @@ -0,0 +1,29 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcs6125-iot-idp.dtsi" + +/ { + model = "USB-C Ext Audio Codec IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,msm-id = <468 0x10000>; + qcom,board-id = <34 3>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..8a47d58bc4d11ecc70c619300c9f6d5a0b447f0f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcs6125.dtsi" +#include "qcs6125-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies,Inc. QCS6125IOT USBC Ext AudioCodec IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,board-id = <34 3>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..3428c7b93bc452053e34ea1bd89aeb61c41f610f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp-overlay.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcs6125-iot-idp.dtsi" +#include "qcs6125-iot-usbc-idp.dtsi" + +/ { + model = "USBC Audio IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,msm-id = <468 0x10000>; + qcom,board-id = <34 2>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..a33a34046fdcf189395b81acd843174005e829c0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcs6125.dtsi" +#include "qcs6125-iot-idp.dtsi" +#include "qcs6125-iot-usbc-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS6125 IOT USBC Audio IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,board-id = <34 2>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..faafcf82f5e3ce0aac93a47d06e5c3ae907aabe9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "trinket-audio-overlay.dtsi" + +&sm6150_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts b/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts new file mode 100644 index 0000000000000000000000000000000000000000..3ebad18c83404a486093b4d7013334397cd8747e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts @@ -0,0 +1,38 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "sa2145p-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA2145P CCARD NAND DC"; + compatible = "qcom,sa2145p-ccard", "qcom,qcs403", "qcom,sa2145p", + "qcom,ccard"; + qcom,board-id = <25 2>, <25 0x102>; +}; + +&qnand_1 { + status = "okay"; +}; + +&sdhc_1 { + status = "disabled"; +}; + +&blsp1_uart1_hs { + status = "ok"; +}; + +&blsp1_uart4_hs { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fe397be6067b313dfddac5a01cc602d293b47e4d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi @@ -0,0 +1,296 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qcs403.dtsi" + +&tlmm { + pinctrl-0 = <&status_gpio>; + pinctrl-names = "default"; + status_gpio: status_gpio { + ap2mdm_status { + pins = "gpio80"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + output-high; + }; + }; +}; + +&pcie0_perst_default { + mux { + pins = "gpio107"; + function = "gpio"; + }; + + config { + pins = "gpio107"; + drive-strength = <2>; + bias-disable; + }; +}; + +&pcie0_wake_default { + mux { + pins = "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio115"; + drive-strength = <2>; + bias-pull-down; + }; +}; + +&usb3_id_det_default { + mux { + pins = "gpio113"; + function = "gpio"; + }; + + config { + pins = "gpio113"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; +}; + +&spi_1 { + status = "disabled"; +}; + +&i2c_3 { + status = "disabled"; +}; + +&smb1351_otg_supply { + status = "disabled"; +}; + +&cnss_sdio { + status = "disabled"; +}; + +&spi_2 { + status = "okay"; + + can-controller@0 { + compatible = "qcom,nxp,mpc5746c"; + reg = <0>; + interrupt-parent = <&tlmm>; + interrupts = <34 0>; + spi-max-frequency = <5000000>; + qcom,clk-freq-mhz = <40000000>; + qcom,max-can-channels = <2>; + qcom,bits-per-word = <8>; + qcom,support-can-fd; + }; +}; + +&spi_6 { + status = "okay"; + + spidev0: spidev@0 { + compatible = "qcom,spi-msm-codec-slave"; + reg = <0>; + spi-max-frequency = <50000000>; + }; +}; + +&i2c_5 { + status = "okay"; + qcom,clk-freq-out = <100000>; +}; + +&soc { + gpio_keys { + status = "disabled"; + }; + + vreg_emac_phy: emac_phy_regulator { + compatible = "regulator-fixed"; + regulator-name = "emac_phy"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <100>; + gpio = <&tlmm 92 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vreg_rgmii_io_pads: rgmii_io_pads_regulator { + compatible = "regulator-fixed"; + regulator-name = "rgmii_io_pads"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <100>; + gpio = <&tlmm 15 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + usb2_extcon: usb2_extcon { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&tlmm 53 GPIO_ACTIVE_HIGH>; + vbus-gpio = <&tlmm 116 GPIO_ACTIVE_HIGH>; + vbus-out-gpio = <&tlmm 108 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&usb2_vbus_det_default + &usb2_id_det_default + &usb2_vbus_boost_default>; + }; + + pps { + compatible = "pps-gpio"; + gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; + + qmi-tmd-devices { + adsp { + qcom,instance-id = <0x1>; + + adsp_vdd: adsp-vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; +}; + +&thermal_zones { + aoss-lowf { + cooling-maps { + adsp_vdd_cdev { + trip = <&aoss_lowf>; + cooling-device = <&adsp_vdd 0 0>; + }; + }; + }; +}; + +&usb3 { + qcom,ignore-wakeup-src-in-hostmode; +}; + +&usb3_extcon { + id-gpio = <&tlmm 113 GPIO_ACTIVE_HIGH>; +}; + +&usb2s { + extcon = <&usb2_extcon>; +}; + +ðqos_hw { + status = "okay"; + vreg_emac_phy-supply = <&vreg_emac_phy>; + vreg_rgmii_io_pads-supply = <&vreg_rgmii_io_pads>; + rxc-skew-ps = <0>; + + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr", "dev-emac-phy_reset_state"; + pinctrl-15 = <&emac_phy_reset_state>; +}; + +&emac_hw { + status = "okay"; + vreg_emac_phy-supply = <&vreg_emac_phy>; + vreg_rgmii_io_pads-supply = <&vreg_rgmii_io_pads>; + qcom,phy-reset-delay-msecs = <10>; + rxc-skew-ps = <0>; + + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr", "dev-emac-phy_reset_state"; + pinctrl-15 = <&emac_phy_reset_state>; +}; + +&pcie0 { + pinctrl-0 = <&pcie0_perst_default + &pcie0_wake_default>; + + perst-gpio = <&tlmm 107 0>; + wake-gpio = <&tlmm 115 0>; +}; + +&sdhc_2 { + /delete-property/ qcom,nonhotplug; + /delete-property/ qcom,nonremovable; + + vdd-io-supply = <&pms405_l11>; + qcom,vdd-io-voltage-level = <2950000 2950000>; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_cd_off>; + cd-gpios = <&tlmm 21 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&gpu_bw_tbl { + status = "disabled"; +}; + +&gpubw { + status = "disabled"; +}; + +&msm_gpu { + status = "disabled"; +}; + +&kgsl_msm_iommu { + status = "disabled"; +}; + +&rpm_bus { + rpm-regulator-ldoa1 { + status = "disabled"; + pms405_l1: regulator-l1 { + status = "disabled"; + }; + }; + + rpm-regulator-ldoa2 { + status = "disabled"; + pms405_l2: regulator-l2 { + status = "disabled"; + }; + }; + + rpm-regulator-ldoa7 { + status = "disabled"; + pms405_l7: regulator-l7 { + status = "disabled"; + }; + }; + + rpm-regulator-ldoa10 { + status = "disabled"; + pms405_l10: regulator-l10 { + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts b/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts new file mode 100644 index 0000000000000000000000000000000000000000..a6183bd11c49470b26614a3681963f4d18a1f4f5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts @@ -0,0 +1,106 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "sa2150p-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA2150P CCARD NAND DC"; + compatible = "qcom,sa2150p-ccard", "qcom,qcs405", "qcom,sa2150p", + "qcom,ccard"; + qcom,board-id = <25 2>, <25 0x102>; + + cpus { + /delete-node/ cpu@102; + /delete-node/ cpu@103; + + cpu-map { + cluster0 { + /delete-node/ core2; + /delete-node/ core3; + }; + }; + }; +}; + +&soc { + cpuss_dump { + /delete-node/ qcom,l1_i_cache102; + /delete-node/ qcom,l1_i_cache103; + /delete-node/ qcom,l1_d_cache102; + /delete-node/ qcom,l1_d_cache103; + }; + + qcom,spm@b012000 { + qcom,cpu-vctl-list = <&CPU0 &CPU1>; + }; + + qcom,lpm-levels { + qcom,pm-cluster@0{ + qcom,pm-cpu { + qcom,cpu = <&CPU0 &CPU1>; + }; + }; + }; + + /delete-node/ cti@61ba000; + /delete-node/ cti@61bb000; + /delete-node/ etm@61be000; + /delete-node/ etm@61bf000; + + funnel@61a1000 { + ports { + /delete-node/ port@3; + /delete-node/ port@4; + }; + }; + + /delete-node/ qcom,cpu0-computemon; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU0 &CPU1>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 1094400 MHZ_TO_MBPS( 297, 8) >, + < 1248000 MHZ_TO_MBPS( 597, 8) >, + < 1401600 MHZ_TO_MBPS( 710, 8) >; + }; +}; + +&thermal_zones { + cpuss-max-step { + cooling-maps { + /delete-node/ cpu2_cdev; + /delete-node/ cpu3_cdev; + }; + }; + /delete-node/ cpuss-2-step; + /delete-node/ cpuss-3-step; +}; + +&qnand_1 { + status = "okay"; +}; + +&sdhc_1 { + status = "disabled"; +}; + +&blsp1_uart1_hs { + status = "ok"; +}; + +&blsp1_uart4_hs { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi index accae59b393a5e16150533e63d33abe893f21d69..8b352bad0fcdb7e5e0e7e23c8a9ee0b4af176ed4 100644 --- a/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi +++ b/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi @@ -24,6 +24,19 @@ output-high; }; }; + + wakeup_gpio_default: wakeup_gpio_default { + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + drive-strength = <2>; + bias-pull-down; + }; + }; }; &pcie0_perst_default { @@ -167,6 +180,15 @@ }; }; }; + + sdx_ext_ipc: qcom,sdx_ext_ipc { + compatible = "qcom,sdx-ext-ipc"; + qcom,wakeup-gpio-in = <&tlmm 14 0x00>; + qcom,wakeup-gpio-out = <&tlmm 79 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&wakeup_gpio_default>; + }; + }; &thermal_zones { @@ -192,6 +214,23 @@ extcon = <&usb2_extcon>; }; +ðqos_hw { + status = "okay"; + vreg_emac_phy-supply = <&vreg_emac_phy>; + vreg_rgmii_io_pads-supply = <&vreg_rgmii_io_pads>; + rxc-skew-ps = <0>; + + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr", "dev-emac-phy_reset_state"; + pinctrl-15 = <&emac_phy_reset_state>; +}; + &emac_hw { status = "okay"; vreg_emac_phy-supply = <&vreg_emac_phy>; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts new file mode 100644 index 0000000000000000000000000000000000000000..67e23a084989f13cbd5bc70ae16113e7d612053c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts @@ -0,0 +1,43 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "sdxprairie.dtsi" +#include "sa515m-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA515M CCARD ETH"; + compatible = "qcom,sa515m-ccard", + "qcom,sdxprairie", "qcom,ccard"; + qcom,board-id = <25 5>, <25 0x105>; + + /delete-node/ qcom_gadget; + qcom_gadget { + compatible = "qcom,usb-gadget"; + qcom,vid = <0x05c6>; + + composition1 { + qcom,pid = <0x9105>; + qcom,composition = "diag.diag,gsi.dpl"; + }; + }; +}; + +&ipa_hw { + qcom,ipa-config-is-auto; + qcom,use-xbl-boot; +}; + +&usb { + qcom,smmu-s1-bypass; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi index e4f9672cf79293addf249f40c85a9c0793ead8d0..69f4da650cecc6d253cefac0aa718b243e99912e 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi @@ -53,7 +53,7 @@ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, <&dai_sec_auxpcm>, <&incall2_record_rx>, - <&incall_music_2_rx>; + <&incall_music_2_rx>, <&incall_music_dl_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", @@ -65,7 +65,7 @@ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", "msm-dai-q6-auxpcm.2", "msm-dai-q6-dev.32769", - "msm-dai-q6-dev.32770"; + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.32774"; asoc-codec = <&tlv320aic3x_codec>, <&stub_codec>; asoc-codec-names = "tlv320aic3x-codec", "msm-stub-codec.1"; qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; @@ -80,6 +80,10 @@ }; }; +&mpss_adsp_mem { + reg = <0x90800000 0xf800000>; +}; + /* delete pm8150b nodes */ &thermal_zones { /delete-node/ pm8150b-wp-therm; @@ -247,6 +251,8 @@ pinctrl-1 = <&emac_pin_pps_0>; pinctrl-2 = <&emac_pin_pps_1>; qcom,phy-reset-delay-msecs = <10>; + ipa-dma-rx-desc-cnt = <512>; + ipa-dma-tx-desc-cnt = <512>; }; &vreg_rgmii_io_pads { diff --git a/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi b/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi index 13697f3235c6accb66990e1699e0ffd2ef2dd8a5..9b3b3cf860d5b8dea95b10b9ba3aec96a349564f 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 @@ -13,7 +13,7 @@ #include "sdxprairie.dtsi" &mpss_adsp_mem { - reg = <0x90800000 0xdc00000>; + reg = <0x90800000 0xf800000>; }; &pil_modem { diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts new file mode 100644 index 0000000000000000000000000000000000000000..9eeb1c42076f54e505ca4c9553fe0618c0abed5c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts @@ -0,0 +1,43 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "sdxprairie-v2.dtsi" +#include "sa515m-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA515M CCARD ETH V2"; + compatible = "qcom,sa515m-ccard", + "qcom,sdxprairie", "qcom,ccard"; + qcom,board-id = <25 5>, <25 0x105>; + + /delete-node/ qcom_gadget; + qcom_gadget { + compatible = "qcom,usb-gadget"; + qcom,vid = <0x05c6>; + + composition1 { + qcom,pid = <0x9105>; + qcom,composition = "diag.diag,gsi.dpl"; + }; + }; +}; + +&ipa_hw { + qcom,ipa-config-is-auto; + qcom,use-xbl-boot; +}; + +&usb { + qcom,smmu-s1-bypass; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts index 076abf9d0d78e1d2214a9710c0444465a6b0384c..ebeac7624478a048f820dd3e12bf1a67f92ea9b5 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts @@ -54,6 +54,7 @@ &pcie_ep { status = "ok"; + qcom,pcie-perst-enum; }; &mhi_device { @@ -74,8 +75,8 @@ &sdx_ext_ipc { compatible = "qcom,sa515m-ccard"; - qcom,ap2mdm-status-gpio = <&tlmm 76 0x00>; - qcom,mdm2ap-status-gpio = <&tlmm 33 0x00>; - qcom,mdm2ap-status2-gpio = <&tlmm 31 0x00>; + qcom,status-in-gpio = <&tlmm 76 0x00>; + qcom,status-out-gpio = <&tlmm 33 0x00>; + qcom,status-out2-gpio = <&tlmm 31 0x00>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi b/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi index 8fac0f31e969e2738a7d5446b60bc6f727366706..cd13e45e4145c6b8916eda4a4548bb64b285faef 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi @@ -13,6 +13,10 @@ #include "sdxprairie-v2.dtsi" #include "sdxprairie-mtp.dtsi" +&mpss_adsp_mem { + reg = <0x90800000 0xf800000>; +}; + /* delete pm8150b nodes */ &thermal_zones { /delete-node/ pm8150b-wp-therm; @@ -59,6 +63,11 @@ status = "disabled"; }; +ðqos_hw { + ipa-dma-rx-desc-cnt = <512>; + ipa-dma-tx-desc-cnt = <512>; +}; + &soc { bluetooth: bt_qca6390 { compatible = "qca,qca6390"; diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi index fe487e89b0fd8097085f81c46a6e86ebf893443d..4b73b902333b6a63e1baa154bdbcc235ab8eced1 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi @@ -35,7 +35,6 @@ &soc { qcom,lpass@62400000 { status = "ok"; - qcom,pil-force-shutdown; }; qcom,glink { diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi index 3d9bb16fbda5219010c4ba168fe93759faf30a57..1ecae102b065c83a33f3c589d64068bef8c098ec 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi @@ -35,7 +35,6 @@ &soc { qcom,lpass@62400000 { status = "ok"; - qcom,pil-force-shutdown; }; qcom,glink { diff --git a/arch/arm64/boot/dts/qcom/sa6155-display.dtsi b/arch/arm64/boot/dts/qcom/sa6155-display.dtsi index 4556b60ff124acae2cc9f071b2a124fb2048f939..137d946a946d935b665c5b81a85812203aee1d94 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-display.dtsi @@ -162,7 +162,7 @@ dsi_anx_7625_1: qcom,dsi-display@17 { label = "dsi_anx_7625_1"; qcom,dsi-display-active; - qcom,display-label = "primary"; + qcom,display-type = "primary"; qcom,dsi-ctrl-num = <0>; qcom,dsi-phy-num = <0>; diff --git a/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi b/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi index fb96af75665d22d27bfbdf21f4bf3230466691d5..ccef59f575bcfac5e9a3724a692bf2044fb74370 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi @@ -335,4 +335,64 @@ }; }; }; + + pm6155-1-tz { + cooling-maps { + trip1_cpu0 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass-overlay.dts b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass-overlay.dts index 01b9cf33311c6293765df6dbb6619b8c263daa62..29503f2972e53adef9c02c965c5ca6bdf2ab0df4 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass-overlay.dts @@ -19,7 +19,7 @@ #include "sa6155-adp-star.dtsi" / { - model = "LPASS Audio PLL sourced from eMAC PPO ("ADP-Star")"; + model = "LPASS Audio PLL sourced from eMAC PPO ADP-Star"; compatible = "qcom,sa6155p-adp-star", "qcom,sa6155p", "qcom,adp-star"; qcom,msm-id = <377 0x0>, <380 0>; qcom,board-id = <0x01010019 0>; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass.dts b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass.dts index c922fbc8531809c5409ca20245ec01432f78c093..184057295fa371c4a1bae208415fe2ca2660daca 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass.dts @@ -17,7 +17,7 @@ / { model = "Qualcomm Technologies, Inc. SA6155P LPASS Audio PLL sourced - from eMAC PPO ("ADP-Star")"; + from eMAC PPO ADP-Star"; compatible = "qcom,sa6155p-adp-star", "qcom,sa6155p", "qcom,adp-star"; qcom,board-id = <0x01010019 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass-overlay.dts b/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass-overlay.dts index 3a8721e8f387b58cb3953c8b76737711e4b13789..4a30f1529ac58557805da8b7b7c5be1ddfb7d5d6 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass-overlay.dts @@ -19,7 +19,7 @@ #include "sa6155-adp-air.dtsi" / { - model = "LPASS Audio PLL sourced from eMAC PPO ("ADP-Air")"; + model = "LPASS Audio PLL sourced from eMAC PPO ADP-Air"; compatible = "qcom,sa6155p-adp-air", "qcom,sa6155p", "qcom,adp-air"; com,board-id = <0x04010019 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass.dts b/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass.dts index 54b4bf4ab6a72dede9a3129a60eff9b15e12288a..965969a8354fbf9546f0b2bc352605d765d6fe97 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass.dts @@ -17,7 +17,7 @@ / { model = "Qualcomm Technologies, Inc. SA6155P v2 LPASS Audio PLL sourced - from eMAC PPO ("ADP-Air")"; + from eMAC PPO ADP-Air"; compatible = "qcom,sa6155p-adp-air", "qcom,sa6155p", "qcom,adp-air"; qcom,board-id = <0x04010019 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-vm-la.dts b/arch/arm64/boot/dts/qcom/sa6155p-vm-la.dts index 8a2835a735dc12135e43831cd477d4d76a0c4b8b..ba1dc8d7dc83643ad85ff175de0d26f0c237cced 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-vm-la.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-vm-la.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA6155P Virtual Machine"; compatible = "qcom,sa6155p"; qcom,pmic-name = "PM6150"; - qcom,board-id = <0 0>; + qcom,board-id = <0x1000001 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi b/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi index 176c0e0f9d54ea414c2decf3ee2fe468d2d8c066..dba72305096dfb90ea36ac6198958982247c3cd4 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi @@ -23,6 +23,106 @@ qcom,msm-name = "SA6155P"; qcom,msm-id = <377 0x0>; + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + capacity-dmips-mhz = <1024>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + capacity-dmips-mhz = <1024>; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + capacity-dmips-mhz = <347>; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + capacity-dmips-mhz = <347>; + }; + + CPU4: cpu@4 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x4>; + capacity-dmips-mhz = <347>; + }; + + CPU5: cpu@5 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x5>; + capacity-dmips-mhz = <347>; + }; + + CPU6: cpu@6 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x6>; + capacity-dmips-mhz = <347>; + }; + + CPU7: cpu@7 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x7>; + capacity-dmips-mhz = <347>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU2>; + }; + + core1 { + cpu = <&CPU3>; + }; + + core2 { + cpu = <&CPU4>; + }; + + core3 { + cpu = <&CPU5>; + }; + + core4 { + cpu = <&CPU6>; + }; + + core5 { + cpu = <&CPU7>; + }; + }; + }; + }; + + aliases { pci-domain0 = &pcie0; /* PCIe0 domain */ }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi index 133e874c038b51a10068e02a6db34d6e39793656..9f47fd1779eea86ebe59f1c937266d695c0245a4 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi @@ -80,7 +80,6 @@ &soc { qcom,lpass@17300000 { status = "ok"; - qcom,pil-force-shutdown; }; qcom,ssc@5c00000 { diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi index 9d3d1093e9645c4705496fbd0f17205d8d940e25..925a9c239c57ad87f33a2bd8454fd156f5e8cd6f 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi @@ -201,7 +201,7 @@ dsi_anx_7625_1: qcom,dsi-display@17 { label = "dsi_anx_7625_1"; qcom,dsi-display-active; - qcom,display-label = "primary"; + qcom,display-type = "primary"; qcom,dsi-ctrl-num = <0>; qcom,dsi-phy-num = <0>; diff --git a/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi b/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi index 0d69f1da72580776d02c2c9dc2832821631d38c6..c369f3e1a1bd9b6ada2ac7ad5afc044305efda7b 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi @@ -18,6 +18,10 @@ }; &soc { + gecko_core_platform: gecko_core_platform { + compatible = "qcom,gecko-core-platform"; + }; + tdm_pri_rx: qcom,msm-dai-tdm-pri-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37120>; @@ -596,6 +600,118 @@ qcom,msm-dai-q6 { }; }; +&gecko_core_platform { + msm_gecko_ion: qcom,msm-audio-ion { + compatible = "qcom,msm-audio-ion"; + qcom,smmu-version = <2>; + qcom,smmu-enabled; + iommus = <&apps_smmu 0x1b21 0x0>; + }; + + sound-adp-star { + compatible = "qcom,sa8155-gecko-asoc-snd-adp-star"; + qcom,model = "sa8155-adp-star-gecko-snd-card"; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + + qcom,sec-tdm-gpios = <&tdm_sec_rx>; + qcom,tert-tdm-gpios = <&tdm_tert_rx>; + qcom,quat-tdm-gpios = <&tdm_quat_rx>; + qcom,quin-tdm-gpios = <&tdm_quin_rx>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>, <&loopback1>, <&pcm_dtmf>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq", "msm-pcm-loopback.1", + "msm-pcm-dtmf"; + asoc-cpu = <&dai_hdmi>, <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_rx_1>, + <&dai_sec_tdm_rx_2>, <&dai_sec_tdm_rx_3>, + <&dai_sec_tdm_rx_7>, <&dai_sec_tdm_tx_0>, + <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, + <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, + <&dai_tert_tdm_rx_1>, <&dai_tert_tdm_rx_2>, + <&dai_tert_tdm_rx_3>, <&dai_tert_tdm_rx_4>, + <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>, + <&dai_tert_tdm_tx_2>, <&dai_tert_tdm_tx_3>, + <&dai_tert_tdm_tx_7>, <&dai_quat_tdm_rx_0>, + <&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>, + <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_rx_7>, + <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>, + <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>, + <&dai_quat_tdm_tx_7>, <&dai_quin_tdm_rx_0>, + <&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>, + <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_rx_7>, + <&dai_quin_tdm_tx_0>, <&dai_quin_tdm_tx_1>, + <&dai_quin_tdm_tx_2>, <&dai_quin_tdm_tx_3>, + <&dai_quin_tdm_tx_7>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36882", + "msm-dai-q6-tdm.36884", "msm-dai-q6-tdm.36886", + "msm-dai-q6-tdm.36894", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", + "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", + "msm-dai-q6-tdm.36898", "msm-dai-q6-tdm.36900", + "msm-dai-q6-tdm.36902", "msm-dai-q6-tdm.36904", + "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899", + "msm-dai-q6-tdm.36901", "msm-dai-q6-tdm.36903", + "msm-dai-q6-tdm.36911", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916", + "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36926", + "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36915", + "msm-dai-q6-tdm.36917", "msm-dai-q6-tdm.36919", + "msm-dai-q6-tdm.36927", "msm-dai-q6-tdm.36928", + "msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932", + "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36942", + "msm-dai-q6-tdm.36929", "msm-dai-q6-tdm.36931", + "msm-dai-q6-tdm.36933", "msm-dai-q6-tdm.36935", + "msm-dai-q6-tdm.36943"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + }; +}; + +&msm_gecko_ion { + iommus = <&apps_smmu 0x1b21 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + &qupv3_se4_i2c { status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi index fd0725339f2034851ebcb739a673a9744f2cec60..41df55dbe659ed4057ce63a5cef7fafa39e47733 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi @@ -164,6 +164,8 @@ pm8150_1_gpios: &pm8150_gpios { }; }; +#include + &thermal_zones { pm8150_2_temp_alarm: pm8150_2_tz { polling-delay-passive = <100>; @@ -189,5 +191,123 @@ pm8150_1_gpios: &pm8150_gpios { type = "passive"; }; }; + + cooling-maps { + trip1_cpu0 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm8150_tz { + cooling-maps { + trip1_cpu0 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi b/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi index 33e45516d62d735313817680cee60cf2f1575d62..994c4bf4eb71ad92628f0a5877a86a19731771f4 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, 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 @@ -459,13 +459,6 @@ = ; qcom,min-dropout-voltage-level = <(-1)>; }; - - cx_cdev: regulator-cdev { - compatible = "qcom,rpmh-reg-cdev"; - mboxes = <&qmp_aop 0>; - qcom,reg-resource-name = "cx"; - #cooling-cells = <2>; - }; }; /* PM8150_2 S10 = VDD_MX supply */ @@ -497,14 +490,6 @@ qcom,init-voltage-level = ; }; - - mx_cdev: mx-cdev-lvl { - compatible = "qcom,regulator-cooling-device"; - regulator-cdev-supply = <&VDD_MX_LEVEL>; - regulator-levels = ; - #cooling-cells = <2>; - }; }; rpmh-regulator-ldoc1 { @@ -617,13 +602,6 @@ qcom,init-voltage-level = ; }; - - ebi_cdev: regulator-cdev { - compatible = "qcom,rpmh-reg-cdev"; - mboxes = <&qmp_aop 0>; - qcom,reg-resource-name = "ebi"; - #cooling-cells = <2>; - }; }; rpmh-regulator-ldoc12 { diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi index ed42cb2d5ee620d7e6ceb1f32e886b4495362be8..3713d9262e234a8bf75243cf0a224550bd5453ae 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi @@ -440,6 +440,20 @@ }; }; + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + + afe_pcm_rx_1: qcom,msm-dai-q6-be-afe-pcm-rx-1 { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <226>; + }; + + afe_proxy_tx_1: qcom,msm-dai-q6-afe-proxy-tx-1 { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <242>; + }; + }; + qcom,avtimer@170f7000 { compatible = "qcom,avtimer"; reg = <0x170f700c 0x4>, @@ -482,10 +496,11 @@ <&dai_mi2s4>, <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, - <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, - <&afe_proxy_tx>, <&incall_record_rx>, - <&incall_record_tx>, <&incall_music_rx>, - <&incall_music_2_rx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, + <&afe_proxy_rx>, <&afe_proxy_tx>, + <&afe_pcm_rx_1>, <&afe_proxy_tx_1>, + <&incall_record_rx>, <&incall_record_tx>, + <&incall_music_rx>, <&incall_music_2_rx>, <&usb_audio_rx>, <&usb_audio_tx>, <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, @@ -519,6 +534,7 @@ "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.226", "msm-dai-q6-dev.242", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts index d544cb066f2fdcd579aca0e802dd89214665e8f7..0e2e5d138d32a8b18af7ae084774a842d10cbd4b 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8155 Multi LA Virtual Machine"; compatible = "qcom,sa8155"; qcom,pmic-name = "PM8150"; - qcom,board-id = <0 0>; + qcom,board-id = <0x2000001 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dtsi index 81db0640bdec8053d8550d3b38abeecad3483cbc..d52ebe8531166654906ccebd18daa3ba5cb374cb 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dtsi @@ -19,6 +19,8 @@ label = "pmem_shared_mem"; }; }; + + /delete-node/ cpus; }; &slpi_tlmm { diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-la.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-la.dts index ae614ef9b5f7ed0081131b787f0cf259c8212207..30cffa4f8ea3dc2587b6b146aac5cae40e418864 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-la.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-la.dts @@ -20,5 +20,5 @@ model = "Qualcomm Technologies, Inc. SA8155 Single LA Virtual Machine"; compatible = "qcom,sa8155"; qcom,pmic-name = "PM8150"; - qcom,board-id = <0 0>; + qcom,board-id = <0x1000001 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-la.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-la.dtsi index 8a4394d75675c3a25780c6489e1c8e1418657dbe..9c965a0fe57bb987d5496e92b6a4b68ba835a48f 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-la.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-la.dtsi @@ -30,7 +30,7 @@ pil_ipa_fw_mem: pil_ipa_fw_region { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x99700000 0x0 0x10000>; + reg = <0x0 0x98700000 0x0 0x10000>; }; pil_ipa_gsi_mem: pil_ipa_gsi_region { diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts index aefc080f6b717cfdbd81b3eb101939e78b51da56..7c5562bf00f40b207d0654879f5b1867a5c7c6de 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8155 Multi LV Virtual Machine"; compatible = "qcom,sa8155"; qcom,pmic-name = "PM8150"; - qcom,board-id = <0 0>; + qcom,board-id = <0x2000002 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi index 6b13c11640df43f2fcac226d3a70d65fe6d423be..c2ef8679006ab4351ef6e80a5b60585eaa76bd81 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi @@ -19,6 +19,8 @@ label = "pmem_shared_mem"; }; }; + + /delete-node/ cpus; }; &hab { diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts index 7eec6fa776fd6ea0a908d543231d17b8085553dd..46b3281f8716d2de5d5a9ddbd3c37f8d2e2269dc 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts @@ -19,6 +19,6 @@ model = "Qualcomm Technologies, Inc. SA8155 Single LV Virtual Machine"; compatible = "qcom,sa8155"; qcom,pmic-name = "PM8150"; - qcom,board-id = <0 0>; + qcom,board-id = <0x1000002 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi index 80e6b7f1f3e92ba8e8078c7a9cdc8b70905c0a53..ae9b504816090cee833f806476fd164453255b3e 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi @@ -21,6 +21,10 @@ }; }; +&hab { + vmid = <3>; +}; + &slpi_tlmm { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-pcie.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-pcie.dtsi index 25a6729be2862be121c2cab1371038dd464e2679..aaa7cdd99828ea371eb5cc7e3bf4180f93f0f834 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-pcie.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, 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 @@ -283,4 +283,320 @@ status = "disabled"; }; + + pcie1: qcom,pcie@1c08000 { + compatible = "qcom,pci-msm"; + cell-index = <1>; + + reg = <0x1c08000 0x4000>, + <0x1c0e000 0x2000>, + <0x40000000 0xf1d>, + <0x40000f20 0xa8>, + <0x40001000 0x1000>, + <0x40100000 0x100000>, + <0x40200000 0x100000>, + <0x40300000 0x1fd00000>; + + reg-names = "parf", "phy", "dm_core", "elbi", + "iatu", "conf", "io", "bars"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x40200000 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x40300000 0x0 0x1fd00000>; + interrupt-parent = <&pcie1>; + interrupts = <0 1 2 3 4>; + interrupt-names = "int_global_int", "int_a", "int_b", "int_c", + "int_d"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc 0 306 0 + 0 0 0 1 &intc 0 434 0 + 0 0 0 2 &intc 0 435 0 + 0 0 0 3 &intc 0 438 0 + 0 0 0 4 &intc 0 439 0>; + + qcom,phy-sequence = <0x0a40 0x03 0x0 + 0x0010 0x00 0x0 + 0x001c 0x31 0x0 + 0x0020 0x01 0x0 + 0x0024 0xde 0x0 + 0x0028 0x07 0x0 + 0x0030 0x4c 0x0 + 0x0034 0x06 0x0 + 0x0048 0x90 0x0 + 0x0058 0x0f 0x0 + 0x0074 0x06 0x0 + 0x0078 0x06 0x0 + 0x007c 0x16 0x0 + 0x0080 0x16 0x0 + 0x0084 0x36 0x0 + 0x0088 0x36 0x0 + 0x0094 0x08 0x0 + 0x00a4 0x42 0x0 + 0x00ac 0x0a 0x0 + 0x00b0 0x1a 0x0 + 0x00b4 0x14 0x0 + 0x00b8 0x34 0x0 + 0x00bc 0x82 0x0 + 0x00c4 0x68 0x0 + 0x00cc 0x55 0x0 + 0x00d0 0x55 0x0 + 0x00d4 0x03 0x0 + 0x00d8 0xab 0x0 + 0x00dc 0xaa 0x0 + 0x00e0 0x02 0x0 + 0x010c 0x02 0x0 + 0x0110 0x24 0x0 + 0x0118 0xb4 0x0 + 0x011c 0x03 0x0 + 0x0154 0x34 0x0 + 0x0158 0x01 0x0 + 0x016c 0x08 0x0 + 0x01ac 0xb9 0x0 + 0x01b0 0x1e 0x0 + 0x01b4 0x94 0x0 + 0x01b8 0x18 0x0 + 0x01bc 0x11 0x0 + 0x023c 0x11 0x0 + 0x0284 0x35 0x0 + 0x0288 0x82 0x0 + 0x029c 0x12 0x0 + 0x0304 0x02 0x0 + 0x0408 0x0c 0x0 + 0x0414 0x03 0x0 + 0x0434 0x7f 0x0 + 0x0444 0x70 0x0 + 0x0460 0x30 0x0 + 0x0464 0x00 0x0 + 0x04d4 0x04 0x0 + 0x04d8 0x07 0x0 + 0x04dc 0x0d 0x0 + 0x04e8 0x00 0x0 + 0x04ec 0x0e 0x0 + 0x04f0 0x4a 0x0 + 0x04f4 0x0f 0x0 + 0x04f8 0xc0 0x0 + 0x04fc 0x00 0x0 + 0x0510 0x17 0x0 + 0x0518 0x1c 0x0 + 0x051c 0x03 0x0 + 0x0524 0x1e 0x0 + 0x0570 0xff 0x0 + 0x0574 0xff 0x0 + 0x0578 0xff 0x0 + 0x057c 0x7f 0x0 + 0x0580 0x66 0x0 + 0x0584 0x24 0x0 + 0x0588 0xe4 0x0 + 0x058c 0xec 0x0 + 0x0590 0x3b 0x0 + 0x0594 0x36 0x0 + 0x0598 0xd4 0x0 + 0x059c 0x54 0x0 + 0x05a0 0xdb 0x0 + 0x05a4 0x3b 0x0 + 0x05a8 0x31 0x0 + 0x05bc 0x0c 0x0 + 0x063c 0x11 0x0 + 0x0684 0x35 0x0 + 0x0688 0x82 0x0 + 0x069c 0x12 0x0 + 0x0704 0x20 0x0 + 0x0808 0x0c 0x0 + 0x0814 0x03 0x0 + 0x0834 0x7f 0x0 + 0x0844 0x70 0x0 + 0x0860 0x30 0x0 + 0x0864 0x00 0x0 + 0x08d4 0x04 0x0 + 0x08d8 0x07 0x0 + 0x08dc 0x0d 0x0 + 0x08e8 0x00 0x0 + 0x08ec 0x0e 0x0 + 0x08f0 0x4a 0x0 + 0x08f4 0x0f 0x0 + 0x08f8 0xc0 0x0 + 0x08fc 0x00 0x0 + 0x0910 0x17 0x0 + 0x0918 0x1c 0x0 + 0x091c 0x03 0x0 + 0x0924 0x1e 0x0 + 0x0970 0xff 0x0 + 0x0974 0xff 0x0 + 0x0978 0xff 0x0 + 0x097c 0x7f 0x0 + 0x0980 0x66 0x0 + 0x0984 0x24 0x0 + 0x0988 0xe4 0x0 + 0x098c 0xec 0x0 + 0x0990 0x3b 0x0 + 0x0994 0x36 0x0 + 0x0998 0xd4 0x0 + 0x099c 0x54 0x0 + 0x09a0 0xdb 0x0 + 0x09a4 0x3b 0x0 + 0x09a8 0x31 0x0 + 0x09bc 0x0c 0x0 + 0x0adc 0x05 0x0 + 0x0b88 0x88 0x0 + 0x0b98 0x0b 0x0 + 0x0ba4 0x01 0x0 + 0x0bec 0x12 0x0 + 0x0e0c 0x0d 0x0 + 0x0e14 0x07 0x0 + 0x0e1c 0xc1 0x0 + 0x0e40 0x01 0x0 + 0x0e48 0x01 0x0 + 0x0e90 0x00 0x0 + 0x0eb4 0x33 0x0 + 0x0ebc 0x00 0x0 + 0x0ee0 0x58 0x0 + 0x0ea4 0x0f 0x0 + 0x0a00 0x00 0x0 + 0x0a44 0x03 0x0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_clkreq_default + &pcie1_perst_default + &pcie1_wake_default>; + + perst-gpio = <&tlmm 102 0>; + wake-gpio = <&tlmm 104 0>; + + gdsc-vdd-supply = <&pcie_1_gdsc>; + vreg-1.8-supply = <&pm8150_2_l8>; + vreg-0.9-supply = <&pm8150_2_l18>; + vreg-cx-supply = <&VDD_CX_LEVEL>; + + qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>; + qcom,vreg-0.9-voltage-level = <880000 880000 24000>; + qcom,vreg-cx-voltage-level = ; + qcom,bw-scale = ; + + msi-parent = <&pcie1_msi>; + + qcom,no-l0s-supported; + + qcom,ep-latency = <10>; + + qcom,slv-addr-space-size = <0x20000000>; + + qcom,phy-status-offset = <0xa14>; + qcom,phy-status-bit = <6>; + qcom,phy-power-down-offset = <0xa40>; + qcom,core-preset = <0x77777777>; + + qcom,boot-option = <0x1>; + + linux,pci-domain = <1>; + + qcom,pcie-phy-ver = <2111>; + qcom,use-19p2mhz-aux-clk; + + qcom,smmu-sid-base = <0x1e00>; + + iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, + <0x100 &apps_smmu 0x1e01 0x1>, + <0x200 &apps_smmu 0x1e02 0x1>, + <0x300 &apps_smmu 0x1e03 0x1>, + <0x400 &apps_smmu 0x1e04 0x1>, + <0x500 &apps_smmu 0x1e05 0x1>, + <0x600 &apps_smmu 0x1e06 0x1>, + <0x700 &apps_smmu 0x1e07 0x1>, + <0x800 &apps_smmu 0x1e08 0x1>, + <0x900 &apps_smmu 0x1e09 0x1>, + <0xa00 &apps_smmu 0x1e0a 0x1>, + <0xb00 &apps_smmu 0x1e0b 0x1>, + <0xc00 &apps_smmu 0x1e0c 0x1>, + <0xd00 &apps_smmu 0x1e0d 0x1>, + <0xe00 &apps_smmu 0x1e0e 0x1>, + <0xf00 &apps_smmu 0x1e0f 0x1>; + + qcom,msm-bus,name = "pcie1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 500 800>; + + clocks = <&clock_virt GCC_PCIE_1_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_virt GCC_PCIE_1_AUX_CLK>, + <&clock_virt GCC_PCIE_1_CFG_AHB_CLK>, + <&clock_virt GCC_PCIE_1_MSTR_AXI_CLK>, + <&clock_virt GCC_PCIE_1_SLV_AXI_CLK>, + <&clock_virt GCC_PCIE_1_CLKREF_CLK>, + <&clock_virt GCC_PCIE_1_SLV_Q2A_AXI_CLK>, + <&clock_virt GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&clock_virt GCC_PCIE1_PHY_REFGEN_CLK>, + <&clock_virt GCC_PCIE_PHY_AUX_CLK>; + + clock-names = "pcie_1_pipe_clk", "pcie_1_ref_clk_src", + "pcie_1_aux_clk", "pcie_1_cfg_ahb_clk", + "pcie_1_mstr_axi_clk", "pcie_1_slv_axi_clk", + "pcie_1_ldo", "pcie_1_slv_q2a_axi_clk", + "pcie_tbu_clk", "pcie_phy_refgen_clk", + "pcie_phy_aux_clk"; + + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_virt GCC_PCIE_1_BCR>, + <&clock_virt GCC_PCIE_1_PHY_BCR>; + + reset-names = "pcie_1_core_reset", + "pcie_1_phy_reset"; + + status = "disabled"; + + pcie_rc1: pcie_rc1 { + #address-cells = <5>; + #size-cells = <0>; + reg = <0 0 0 0 0>; + pci-ids = "17cb:0108"; + }; + }; + + pcie1_msi: qcom,pcie1_msi@17a00040 { + compatible = "qcom,pci-msi"; + msi-controller; + reg = <0x17a00040 0x0>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + status = "disabled"; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi index 5689a863ec988be1a35c1e2157c66873d102fc23..540e18690a992414ac800f8479a9be5e796f0448 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi @@ -16,10 +16,119 @@ qcom,msm-name = "SA8155 V2"; qcom,msm-id = <362 0x20000>; + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + capacity-dmips-mhz = <1024>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + capacity-dmips-mhz = <902>; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + capacity-dmips-mhz = <902>; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + capacity-dmips-mhz = <902>; + }; + + CPU4: cpu@4 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x4>; + capacity-dmips-mhz = <320>; + }; + + CPU5: cpu@5 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x5>; + capacity-dmips-mhz = <320>; + }; + + CPU6: cpu@6 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x6>; + capacity-dmips-mhz = <320>; + }; + + CPU7: cpu@7 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x7>; + capacity-dmips-mhz = <320>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU1>; + }; + + core1 { + cpu = <&CPU2>; + }; + + core2 { + cpu = <&CPU3>; + }; + }; + + cluster2 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + + core3 { + cpu = <&CPU7>; + }; + }; + }; + }; + aliases { pci-domain0 = &pcie0; /* PCIe0 domain */ sdhc2 = &sdhc_2; /* SDC2 SD card slot */ }; + + reserved_memory: reserved-memory { + + smem_region: smem { + no-map; + reg = <0x0 0x86000000 0x0 0x200000>; + }; + }; }; @@ -871,6 +980,57 @@ qcom,glb-db-receivers = <&hgsl_tcsr_receiver0 &hgsl_tcsr_receiver1>; }; + + tcsr_mutex_block: syscon@1f40000 { + compatible = "syscon"; + reg = <0x1f40000 0x20000>; + }; + + tcsr_mutex: hwlock@1f40000 { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + mutex-id = <11>; + }; + + smem: qcom,smem@8600000 { + compatible = "qcom,smem"; + memory-region = <&smem_region>; + hwlocks = <&tcsr_mutex 3>; + smem-host-id = <10>; + }; + + gvm_intr: mailbox@17c00000 { + compatible = "qcom,sm8150-apcs-hmss-global"; + reg = <0x1c900000 0x100>; + #mbox-cells = <1>; + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_cdsp: cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&gvm_intr 4>; + mbox-names = "cdsp_smem"; + interrupts = <0 51 0>; + vm-support; + + label = "cdsp"; + qcom,glink-label = "cdsp"; + + qcom,cdsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + }; + }; }; #include "sm8150-pinctrl.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sa8155.dtsi b/arch/arm64/boot/dts/qcom/sa8155.dtsi index c41c5e788f1a1c419601c1b96fc42f9a49ca087d..18f6d27a9d83810a14f52524aee0f0c05eb30708 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155.dtsi @@ -221,26 +221,10 @@ }; &thermal_zones { - cpu-1-7-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - gpuss-0-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - camera-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - mdm-scl-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; + /delete-node/ cpu-1-7-lowf; + /delete-node/ gpuss-0-lowf; + /delete-node/ camera-lowf; + /delete-node/ mdm-scl-lowf; lmh-dcvs-01 { trips { @@ -263,7 +247,7 @@ gpuss-max-step { trips { gpu-trip0 { - temperature = <100000>; + temperature = <105000>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi b/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi index 5236ff4aa0861e742ed0a91c0a872248832afe39..ebeac6853f38c17db528028fc1ef5f4a65b8d25c 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi @@ -120,6 +120,64 @@ type = "passive"; }; }; + + cooling-maps { + trip1_cpu0 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; }; pm8195_2_temp_alarm: pm8195_2_tz { @@ -146,6 +204,64 @@ type = "passive"; }; }; + + cooling-maps { + trip1_cpu0 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; }; pm8195_3_temp_alarm: pm8195_3_tz { @@ -172,5 +288,63 @@ type = "passive"; }; }; + + cooling-maps { + trip1_cpu0 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dts b/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dts index 69fc9ed11e9b6188432d1fac68753f5155a1a7e7..c59921d1b4c5478a6fb3aaff3b6cf9d46256a439 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dts +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8195 Multi LA Virtual Machine"; compatible = "qcom,sa8195p"; qcom,pmic-name = "PM8195"; - qcom,board-id = <0 0>; + qcom,board-id = <0x2000001 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dtsi index 2ffc10c40925c3f014e2acf4df3179ae97048df4..49aa13c1e6c981a12ec1386572c548f41b8af49f 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dtsi @@ -19,6 +19,7 @@ }; }; + /delete-node/ cpus; }; &slpi_tlmm { diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-la.dts b/arch/arm64/boot/dts/qcom/sa8195-vm-la.dts index 1d54538f77f93ae2b2e16d2d29f4e58d1bc08992..bb721e12b6480e4168ae230fac15fae0901ebfc8 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-la.dts +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-la.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8195 Single LA Virtual Machine"; compatible = "qcom,sa8195p"; qcom,pmic-name = "PM8195"; - qcom,board-id = <0 0>; + qcom,board-id = <0x1000001 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dts b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dts index 4a570f9897d93593e47922596c40dcdccc08a096..76a24b42f78efbec76719889fe16aea85bc4640e 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dts +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8195 Multi LV Virtual Machine"; compatible = "qcom,sa8195p"; qcom,pmic-name = "PM8195"; - qcom,board-id = <0 0>; + qcom,board-id = <0x2000002 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi index f55efa749ab192f196e316d6912ead671e553b46..074d40913c28044b55c92bd0fe9bb672144e7912 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi @@ -19,6 +19,7 @@ }; }; + /delete-node/ cpus; }; &hab { diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dts b/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dts index 10b40d2c3e506bfb18ca0ed39ee46d85c1517aa7..107d2016c9c9b6ec6e143c7a87001abd6914b697 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dts +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8195 Single LV Virtual Machine"; compatible = "qcom,sa8195p"; qcom,pmic-name = "PM8195"; - qcom,board-id = <0 0>; + qcom,board-id = <0x1000002 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi index d79b893c40deee7319141a72b2ae7c2a4900a3bd..32e1be94cae597cdbc338c1e6196f7cdf66a4f32 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi @@ -24,6 +24,105 @@ qcom,msm-name = "SA8195P"; qcom,msm-id = <405 0x20000>; + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + capacity-dmips-mhz = <1024>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + capacity-dmips-mhz = <1024>; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + capacity-dmips-mhz = <1024>; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + capacity-dmips-mhz = <1024>; + }; + + CPU4: cpu@4 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x4>; + capacity-dmips-mhz = <306>; + }; + + CPU5: cpu@5 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x5>; + capacity-dmips-mhz = <306>; + }; + + CPU6: cpu@6 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x6>; + capacity-dmips-mhz = <306>; + }; + + CPU7: cpu@7 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x7>; + capacity-dmips-mhz = <306>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + + cluster2 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + + core3 { + cpu = <&CPU7>; + }; + }; + }; + }; + aliases { sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ }; diff --git a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi index aa218ee813f09c0833f990c3aefc94523d6cdc66..36ffa616fecdb7ad814f04ba82bd7783f2bd4ad1 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi @@ -243,7 +243,7 @@ dsi_anx_7625_1: qcom,dsi-display@17 { label = "dsi_anx_7625_1"; qcom,dsi-display-active; - qcom,display-label = "primary"; + qcom,display-type = "primary"; qcom,dsi-ctrl-num = <0>; qcom,dsi-phy-num = <0>; diff --git a/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi index 1ca9f004c58c430c987690a383a5a0737eb3ecb7..9d3ff0740904d86c107295b31fb77218e79b6b87 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi @@ -41,13 +41,6 @@ qcom,init-voltage-level = ; }; - - ebi_cdev: regulator-cdev { - compatible = "qcom,rpmh-reg-cdev"; - mboxes = <&qmp_aop 0>; - qcom,reg-resource-name = "ebi"; - #cooling-cells = <2>; - }; }; /* PM8195_1 S2 = VDDCX_MM supply */ @@ -79,14 +72,6 @@ qcom,init-voltage-level = ; }; - - mm_cx_cdev: mm-cx-cdev-lvl { - compatible = "qcom,regulator-cooling-device"; - regulator-cdev-supply = <&VDD_MMCX_LEVEL_AO>; - regulator-levels = ; - #cooling-cells = <2>; - }; }; rpmh-regulator-smpa3 { @@ -188,14 +173,6 @@ qcom,init-voltage-level = ; }; - - mx_cdev: mx-cdev-lvl { - compatible = "qcom,regulator-cooling-device"; - regulator-cdev-supply = <&VDD_MX_LEVEL>; - regulator-levels = ; - #cooling-cells = <2>; - }; }; rpmh-regulator-ldoa2 { @@ -647,12 +624,6 @@ = ; qcom,min-dropout-voltage-level = <(-1)>; }; - cx_cdev: regulator-cdev { - compatible = "qcom,rpmh-reg-cdev"; - mboxes = <&qmp_aop 0>; - qcom,reg-resource-name = "cx"; - #cooling-cells = <2>; - }; }; rpmh-regulator-smpe4 { diff --git a/arch/arm64/boot/dts/qcom/sa8195p.dtsi b/arch/arm64/boot/dts/qcom/sa8195p.dtsi index 7b728de681fed3708e6e668f286358387667663c..3e31e5d48b2ac383febd5eac85b7b4ec31c3897e 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p.dtsi @@ -294,6 +294,11 @@ status = "ok"; }; +&usb2 { + qcom,ignore-wakeup-src-in-hostmode; + status = "ok"; +}; + &slpi_tlmm { status = "ok"; }; @@ -379,6 +384,32 @@ status = "ok"; }; +&usb2_phy2 { + vdd-supply = <&pm8195_3_l5>; + vdda18-supply = <&pm8195_1_l12>; + vdda33-supply = <&pm8195_3_l16>; + status = "ok"; +}; + +&usb_qmp_phy0 { + vdd-supply = <&pm8195_3_l9>; + core-supply = <&pm8195_1_l9>; + status = "ok"; +}; + +&usb2_phy3 { + vdd-supply = <&pm8195_3_l5>; + vdda18-supply = <&pm8195_1_l12>; + vdda33-supply = <&pm8195_3_l16>; + status = "ok"; +}; + +&usb_qmp_phy1 { + vdd-supply = <&pm8195_3_l9>; + core-supply = <&pm8195_1_l9>; + status = "ok"; +}; + &mdss_dsi_phy0 { vdda-0p9-supply = <&pm8195_3_l5>; }; @@ -425,26 +456,11 @@ }; &thermal_zones { - cpu-1-7-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - gpuss-0-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - camera-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - mdm-scl-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; + /delete-node/ cpu-1-7-lowf; + /delete-node/ gpuss-0-lowf; + /delete-node/ camera-lowf; + /delete-node/ mdm-scl-lowf; + /delete-node/ pcie-lowf; lmh-dcvs-01 { trips { @@ -467,7 +483,7 @@ quad-gpuss-max-step { trips { gpu-trip0 { - temperature = <100000>; + temperature = <105000>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts index 898355091fdb139ba2197bdf1faf58ee749da19b..03c3a00fa5ade81682ef7232aba6f201c5f02a80 100644 --- a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts @@ -14,6 +14,7 @@ /dts-v1/; /plugin/; +#include #include "sda429-bg-dvt2-wtp.dtsi" / { @@ -24,3 +25,30 @@ qcom,pmic-id = <0x0002001b 0x0 0x0 0x0>; }; +&i2c_4 { + status = "ok"; + + raydium_ts@39 { + compatible = "raydium,raydium-ts"; + reg = <0x39>; + interrupt-parent = <&tlmm>; + interrupts = <13 0x2008>; + vdd_ana-supply = <&pm660_l11>; + vcc_i2c-supply = <&pm660_l13>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + raydium,reset-gpio = <&tlmm 64 0x00>; + raydium,irq-gpio = <&tlmm 65 0x00>; + raydium,num-max-touches = <2>; + raydium,soft-reset-delay-ms = <50>; + raydium,hard-reset-delay-ms = <100>; + raydium,x_max = <416>; + raydium,y_max = <416>; + raydium,display-coords= <0 0 416 416>; + raydium,fw_id = <0x2202>; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi index a1160641d216e2c630d2e22359e2a5dc29c38912..3c32d1d0eaeecd8fc4b0db9468357ff553e3cb2e 100644 --- a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; @@ -52,3 +52,40 @@ status = "disabled"; }; +&pm660_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 93 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>; + clock-names = "ref_clk"; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sda429-wdp.dtsi b/arch/arm64/boot/dts/qcom/sda429-wdp.dtsi index a1160641d216e2c630d2e22359e2a5dc29c38912..30c022abd36f6f2449e7f12807948eb984ba351b 100644 --- a/arch/arm64/boot/dts/qcom/sda429-wdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sda429-wdp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; diff --git a/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts index 138cb9e932923c43181f37b5c4b1293e44d819d5..7bbdfa9ae059821dde85da69022fce35fef8413c 100644 --- a/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts @@ -14,6 +14,7 @@ /dts-v1/; /plugin/; +#include #include "sda429-wtp.dtsi" / { @@ -26,9 +27,6 @@ &i2c_4 { status = "ok"; - tsc@24 { - status = "disabled"; - }; raydium_ts@39 { compatible = "raydium,raydium-ts"; diff --git a/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi b/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi index a1160641d216e2c630d2e22359e2a5dc29c38912..3c32d1d0eaeecd8fc4b0db9468357ff553e3cb2e 100644 --- a/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; @@ -52,3 +52,40 @@ status = "disabled"; }; +&pm660_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 93 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>; + clock-names = "ref_clk"; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts index 6f5cd9c5b07d1f284dff6e48650591948c5e5824..5f21ceecaaa231fd6f537f6ab152a697c9464791 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts @@ -14,7 +14,9 @@ /dts-v1/; /plugin/; +#include #include "sdm429-bg-dvt2-wtp.dtsi" +#include "sdm429-mdss-panels.dtsi" / { model = "Qualcomm Technologies, Inc. SDM429 QRD BG WTP Overlay"; @@ -25,3 +27,81 @@ }; +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + /delete-property/ vdda-supply; + /delete-property/ vddio-supply; + vdda-supply = <&L6A>; /* 0.8v */ + vddio-supply = <&L13A>; /* 1.8v */ + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda"; + qcom,supply-min-voltage = <800000>; + qcom,supply-max-voltage = <800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_auo_416p_amoled_cmd>; + /delete-property/ vdd-supply; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_te_active>; + pinctrl-1 = <&mdss_te_suspend>; + vddio-supply = <&L11A>; + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 60 0>; + qcom,platform-enable-gpio = <&pm660_gpios 12 0>; + +}; + +&mdss_dsi0_pll { + /delete-property/ vddio-supply; + vddio-supply = <&L13A>; +}; + +&mdss_dsi1 { + status = "disabled"; +}; + +&mdss_dsi1_pll { + status = "disabled"; +}; + +&i2c_4 { + status = "ok"; + + raydium_ts@39 { + compatible = "raydium,raydium-ts"; + reg = <0x39>; + interrupt-parent = <&tlmm>; + interrupts = <13 0x2008>; + vdd_ana-supply = <&pm660_l11>; + vcc_i2c-supply = <&pm660_l13>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + raydium,reset-gpio = <&tlmm 64 0x00>; + raydium,irq-gpio = <&tlmm 65 0x00>; + raydium,num-max-touches = <2>; + raydium,soft-reset-delay-ms = <50>; + raydium,hard-reset-delay-ms = <100>; + raydium,x_max = <416>; + raydium,y_max = <416>; + raydium,display-coords= <0 0 416 416>; + raydium,fw_id = <0x2202>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi index a1160641d216e2c630d2e22359e2a5dc29c38912..3c32d1d0eaeecd8fc4b0db9468357ff553e3cb2e 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; @@ -52,3 +52,40 @@ status = "disabled"; }; +&pm660_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 93 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>; + clock-names = "ref_clk"; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi b/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6ac3d71f82f59a9ac6881f4cdec310b2eb6b6b9a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi @@ -0,0 +1,100 @@ +/* Copyright (c) 2020, 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. + */ + +&soc { + + qcom,blackghost { + compatible = "qcom,pil-blackghost"; + qcom,pil-force-shutdown; + qcom,firmware-name = "bg-wear"; + /* GPIO inputs from blackghost */ + qcom,bg2ap-status-gpio = <&tlmm 44 0>; + qcom,bg2ap-errfatal-gpio = <&tlmm 72 0>; + /* GPIO output to blackghost */ + qcom,ap2bg-status-gpio = <&tlmm 61 0>; + qcom,ap2bg-errfatal-gpio = <&tlmm 62 0>; + }; + + spi_3: spi@78b7000 { /* BLSP1 QUP3*/ + status = "ok"; + qcom,bg-spi { + compatible = "qcom,bg-spi"; + reg = <0>; + spi-max-frequency = <16000000>; + interrupt-parent = <&tlmm>; + qcom,irq-gpio = <&tlmm 43 1>; + }; + }; + + i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */ + status = "disabled"; + }; + + qcom,bg-daemon { + compatible = "qcom,bg-daemon"; + qcom,bg-reset-gpio = <&pm660_gpios 5 0>; + ssr-reg1-supply = <&pm660_l3>; + ssr-reg2-supply = <&pm660_l9>; + }; + + qcom,glink-bgcom-xprt-bg { + compatible = "qcom,glink-bgcom-xprt"; + label = "bg"; + }; + + qcom,glink_pkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-bg-daemon { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "bg-daemon"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_daemon"; + }; + + qcom,glinkpkt-bg-daemon-ctrl { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "bg-daemon-ctl"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_daemon_ctrl"; + }; + + qcom,glinkpkt-bg-display-ctrl { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "display-ctrl"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_display_ctrl"; + }; + + qcom,glinkpkt-bg-display-data { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "display-data"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_display_data"; + }; + + qcom,glinkpkt-bg-rsb-ctrl { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "RSB_CTRL"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_rsb_ctrl"; + }; + + qcom,glinkpkt-bg-sso-ctrl { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "sso-ctrl"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_sso_ctrl"; + }; + + qcom,glinkpkt-bg-buzzer-ctrl { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "buzzer-ctrl"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_buzzer_ctrl"; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi index 06f9e76d7983bf96096cac74a1c4d867e591d9bc..e661a4f1db0bc6355fa9b25d952e77369955c02b 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi @@ -198,7 +198,6 @@ interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>, <0 238 IRQ_TYPE_LEVEL_HIGH>; spi-max-frequency = <50000000>; - qcom,use-bam; qcom,ver-reg-exists; qcom,bam-consumer-pipe-index = <8>; qcom,bam-producer-pipe-index = <9>; diff --git a/arch/arm64/boot/dts/qcom/sdm429-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm429-ion.dtsi index 9456915bb884e9c3dbd6c38366223131a4e9d4c3..7d41a0a14982068dcb0b033f568bf67ab21c3ac6 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-ion.dtsi @@ -23,6 +23,7 @@ }; qcom,ion-heap@8 { /* CP_MM HEAP */ + status = "disabled"; reg = <8>; memory-region = <&secure_mem>; qcom,ion-heap-type = "SECURE_DMA"; diff --git a/arch/arm64/boot/dts/qcom/sdm429-mdss.dtsi b/arch/arm64/boot/dts/qcom/sdm429-mdss.dtsi index a6e35db6f54caf37a66fb0606dacbac2d6cc04a5..c6452438728a891bebeab706e0337dbf53b540a9 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-mdss.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-mdss.dtsi @@ -185,12 +185,11 @@ <22 512 0 1000>; }; - /*TODO*/ smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb { compatible = "qcom,smmu_mdp_unsec"; iommus = <&apps_iommu 0x2800 0>; /* For NS ctx bank */ }; - /*TODO*/ + smmu_mdp_sec: qcom,smmu_mdp_sec_cb { compatible = "qcom,smmu_mdp_sec"; iommus = <&apps_iommu 0x2801 0>; /* For SEC Ctx Bank */ @@ -243,10 +242,10 @@ clocks = <&gcc_mdss MDSS_MDP_VOTE_CLK>, <&gcc GCC_MDSS_AHB_CLK>, <&gcc GCC_MDSS_AXI_CLK>, - <&gcc_mdss BYTE0_CLK_SRC>, /*TODO*/ - <&gcc_mdss BYTE1_CLK_SRC>, /*TODO*/ - <&gcc_mdss PCLK0_CLK_SRC>, /*TODO*/ - <&gcc_mdss PCLK1_CLK_SRC>; /*TODO*/ + <&mdss_dsi0_pll BYTE_CLK_SRC_0_CLK>, + <&mdss_dsi1_pll BYTE_CLK_SRC_1_CLK>, + <&mdss_dsi0_pll PCLK_SRC_MUX_0_CLK>, + <&mdss_dsi1_pll PCLK_SRC_MUX_1_CLK>; clock-names = "mdp_core_clk", "iface_clk", "bus_clk", "ext_byte0_clk", "ext_byte1_clk", "ext_pixel0_clk", "ext_pixel1_clk"; diff --git a/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi index 78e6b2cf2c3b57cd7d76aca1d0d46ebb5932e478..5ede5718b03811df8c62f0560501b7e08699ca37 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi @@ -352,6 +352,71 @@ }; }; + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 17 NFC Read Interrupt */ + pins = "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 17 NFC Read Interrupt */ + pins = "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_disable_active: nfc_disable_active { + /* active state */ + mux { + /* 16: NFC ENABLE 130: FW DNLD */ + /* 93: ESE Enable */ + pins = "gpio16", "gpio130", "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio16", "gpio130", "gpio93"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_disable_suspend: nfc_disable_suspend { + /* sleep state */ + mux { + /* 16: NFC ENABLE 130: FW DNLD */ + /* 93: ESE Enable */ + pins = "gpio16", "gpio130", "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio16", "gpio130", "gpio93"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + + i2c_6{ i2c_6_active: i2c_6_active { mux { @@ -825,5 +890,159 @@ }; }; }; + + wcnss_pmux_5wire { + /* Active configuration of bus pins */ + wcnss_default: wcnss_default { + wcss_wlan2 { + pins = "gpio76"; + function = "wcss_wlan2"; + }; + wcss_wlan1 { + pins = "gpio77"; + function = "wcss_wlan1"; + }; + wcss_wlan0 { + pins = "gpio78"; + function = "wcss_wlan0"; + }; + wcss_wlan { + pins = "gpio79", "gpio80"; + function = "wcss_wlan"; + }; + + config { + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + drive-strength = <6>; /* 6 MA */ + bias-pull-up; /* PULL UP */ + }; + }; + + wcnss_sleep: wcnss_sleep { + wcss_wlan2 { + pins = "gpio76"; + function = "wcss_wlan2"; + }; + wcss_wlan1 { + pins = "gpio77"; + function = "wcss_wlan1"; + }; + wcss_wlan0 { + pins = "gpio78"; + function = "wcss_wlan0"; + }; + wcss_wlan { + pins = "gpio79", "gpio80"; + function = "wcss_wlan"; + }; + + config { + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL Down */ + }; + }; + }; + + wcnss_pmux_gpio: wcnss_pmux_gpio { + wcnss_gpio_default: wcnss_gpio_default { + /* Active configuration of bus pins */ + mux { + /* Uses general purpose pins */ + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + function = "gpio"; + + }; + + config { + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + drive-strength = <6>; /* 6 MA */ + bias-pull-up; /* PULL UP */ + }; + }; + }; + + pmx_ts_int_active { + ts_int_active: ts_int_active { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_active { + ts_reset_active: ts_reset_active { + mux { + pins = "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio64"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio64"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + ts_release: ts_release { + mux { + pins = "gpio65", "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio65", "gpio64"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm429-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm429-vidc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0fceee84ac5daf1c13ff51b7b54cc33468a22378 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm429-vidc.dtsi @@ -0,0 +1,168 @@ +/* Copyright (c) 2015-2020, 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. + */ + +&soc { + qcom,vidc@1d00000 { + compatible = "qcom,msm-vidc"; + reg = <0x01d00000 0xff000>; + interrupts = <0 44 0>; + qcom,hfi-version = "3xx"; + venus-supply = <&venus_gdsc>; + venus-core0-supply = <&venus_core0_gdsc>; + clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>, + <&gcc GCC_VENUS0_CORE0_VCODEC0_CLK>, + <&gcc GCC_VENUS0_AHB_CLK>, + <&gcc GCC_VENUS0_AXI_CLK>; + clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x0>; + qcom,sw-power-collapse; + qcom,slave-side-cp; + qcom,dcvs-tbl = + <108000 108000 244800 0x00000004>, /* Encoder */ + <108000 108000 244800 0x0f00000c>; /* Decoder */ + qcom,dcvs-limit = + <8160 30>, /* Encoder */ + <8160 30>; /* Decoder */ + qcom,hfi = "venus"; + qcom,reg-presets = <0xe0020 0x05555556>, + <0xe0024 0x05555556>, + <0x80124 0x00000003>; + qcom,qdss-presets = <0x826000 0x1000>, + <0x827000 0x1000>, + <0x822000 0x1000>, + <0x803000 0x1000>, + <0x9180000 0x1000>, + <0x9181000 0x1000>; + qcom,max-hw-load = <352800>; /* 1080p@30 + 720p@30 */ + qcom,firmware-name = "venus"; + qcom,allowed-clock-rates = <360000000 320000000 + 308570000 240000000 166150000>; + qcom,clock-freq-tbl { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,cycles-per-mb = <2316>; + qcom,low-power-mode-factor = <32768>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xf3ffffff>; + qcom,cycles-per-mb = <788>; + }; + qcom,profile-hevcdec { + qcom,codec-mask = <0x0c000000>; + qcom,cycles-per-mb = <1015>; + }; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_iommu 0x800 0x00>, + <&apps_iommu 0x807 0x00>, + <&apps_iommu 0x808 0x27>, + <&apps_iommu 0x811 0x20>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x5dc00000 0x7f000000 + 0xdcc00000 0x1000000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_iommu 0x900 0x00>, + <&apps_iommu 0x90a 0x04>, + <&apps_iommu 0x909 0x22>; + buffer-types = <0x241>; + virtual-addr-pool = <0x4b000000 0x12c00000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_iommu 0x90c 0x20>; + buffer-types = <0x106>; + virtual-addr-pool = <0x25800000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_iommu 0x940 0x00>, + <&apps_iommu 0x907 0x08>, + <&apps_iommu 0x908 0x20>, + <&apps_iommu 0x90d 0x20>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + + /* Buses */ + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "venus-ddr-gov"; + qcom,bus-range-kbps = <1000 917000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1 1>; + }; + }; + + venus-ddr-gov { + compatible = "qcom,msm-vidc,governor,table"; + name = "venus-ddr-gov"; + status = "ok"; + qcom,bus-freq-table { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,load-busfreq-tbl = + <244800 841000>, /* 1080p30E */ + <216000 740000>, /* 720p60E */ + <194400 680000>, /* FWVGA120E */ + <144000 496000>, /* VGA120E */ + <108000 370000>, /* 720p30E */ + <97200 340000>, /* FWVGA60E */ + <48600 170000>, /* FWVGA30E */ + <72000 248000>, /* VGA60E */ + <36000 124000>, /* VGA30E */ + <18000 70000>, /* QVGA60E */ + <9000 35000>, /* QVGA30E */ + <0 0>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xffffffff>; + qcom,load-busfreq-tbl = + <244800 605000>, /* 1080p30D */ + <216000 540000>, /* 720p60D */ + <194400 484000>, /* FWVGA120D */ + <144000 360000>, /* VGA120D */ + <108000 270000>, /* 720p30D */ + <97200 242000>, /* FWVGA60D */ + <48600 121000>, /* FWVGA30D */ + <72000 180000>, /* VGA60D */ + <36000 90000>, /* VGA30D */ + <18000 45000>, /* HVGA30D */ + <0 0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm429-wdp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-wdp.dtsi index a1160641d216e2c630d2e22359e2a5dc29c38912..30c022abd36f6f2449e7f12807948eb984ba351b 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-wdp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; diff --git a/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts index 403d0b7911af317ece14967fd3b30277f097e14e..1a802084a9e3c2b156efb2d0cfe270549c3dc7ee 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts @@ -14,6 +14,7 @@ /dts-v1/; /plugin/; +#include #include "sdm429-wtp.dtsi" #include "sdm429-mdss-panels.dtsi" @@ -29,6 +30,28 @@ qcom,mdss-pref-prim-intf = "dsi"; }; +&mdss_dsi { + /delete-property/ vdda-supply; + /delete-property/ vddio-supply; + vdda-supply = <&L6A>; /* 0.8v */ + vddio-supply = <&L13A>; /* 1.8v */ + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda"; + qcom,supply-min-voltage = <800000>; + qcom,supply-max-voltage = <800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; +}; + &mdss_dsi0 { qcom,dsi-pref-prim-pan = <&dsi_auo_416p_amoled_cmd>; /delete-property/ vdd-supply; @@ -36,18 +59,27 @@ pinctrl-0 = <&mdss_te_active>; pinctrl-1 = <&mdss_te_suspend>; vddio-supply = <&L11A>; + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 60 0>; qcom,platform-enable-gpio = <&pm660_gpios 12 0>; + +}; + +&mdss_dsi0_pll { + /delete-property/ vddio-supply; + vddio-supply = <&L13A>; }; &mdss_dsi1 { status = "disabled"; }; +&mdss_dsi1_pll { + status = "disabled"; +}; + &i2c_4 { status = "ok"; - tsc@24 { - status = "disabled"; - }; raydium_ts@39 { compatible = "raydium,raydium-ts"; diff --git a/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi index a1160641d216e2c630d2e22359e2a5dc29c38912..3c32d1d0eaeecd8fc4b0db9468357ff553e3cb2e 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; @@ -52,3 +52,40 @@ status = "disabled"; }; +&pm660_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 93 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>; + clock-names = "ref_clk"; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 9e709b8e2c27b757e6c2f6819082890ad4c4915f..899b9f6e41cf50e57ad1fa8bec7289f3ba9be47b 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -16,6 +16,8 @@ #include #include #include +#include +#include / { model = "Qualcomm Technologies, Inc. SDM429"; @@ -122,11 +124,11 @@ }; gpu_mem: gpu_region@0 { - compatible = "shared-dma-pool"; - reusable; - alloc-ranges = <0x0 0x80000000 0x0 0x10000000>; - alignment = <0 0x400000>; - size = <0 0x800000>; + compatible = "shared-dma-pool"; + reusable; + alloc-ranges = <0x0 0x80000000 0x0 0x10000000>; + alignment = <0 0x400000>; + size = <0 0x800000>; }; linux,cma { @@ -140,6 +142,34 @@ }; + qcom_seecom: qseecom@85b00000 { + compatible = "qcom,qseecom"; + reg = <0x85b00000 0x800000>; + reg-names = "secapp-region"; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,commonlib64-loaded-by-uefi; + qcom,support-bus-scaling; + qcom,msm-bus,name = "qseecom-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 0 0>, + <55 512 120000 1200000>, + <55 512 393600 3936000>; + clocks = <&gcc CRYPTO_CLK_SRC>, + <&gcc GCC_CRYPTO_CLK>, + <&gcc GCC_CRYPTO_AHB_CLK>, + <&gcc GCC_CRYPTO_AXI_CLK>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + qcom,ce-opp-freq = <100000000>; + }; + aliases { sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ sdhc2 = &sdhc_2; /* SDC2 for SD card */ @@ -156,6 +186,8 @@ #include "sdm429-cpu.dtsi" #include "sdm429-ion.dtsi" #include "msm-arm-smmu-sdm429.dtsi" +#include "sdm429w-gpu.dtsi" +#include "sdm429-vidc.dtsi" &soc { #address-cells = <1>; #size-cells = <1>; @@ -312,6 +344,77 @@ #clock-cells = <1>; }; + cpu: qcom,clock-cpu@b011050 { + compatible = "qcom,cpu-clock-sdm"; + reg = <0xb011050 0x8>, + <0xb1d1050 0x8>, + <0xB016000 0x34>, + <0x00a412c 0x8>, + <0x0b011200 0x100>; + reg-names = "apcs-c1-rcg-base", + "apcs-cci-rcg-base", "apcs_pll", "efuse", + "spm_c1_base"; + clocks = <&rpmcc RPM_SMD_XO_A_CLK_SRC>, + <&gcc GPLL0_AO_OUT_MAIN>; + clock-names = "xo_ao", "gpll0_ao" ; + cpu-vdd-supply = <&apc_vreg_corner>; + vdd_hf_pll-supply = <&L12A_AO>; + vdd_dig_ao-supply = <&VDD_CX_LEVEL_AO>; + qcom,speed0-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1958400000 5>; + + qcom,speed0-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed1-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1804800000 5>; + + qcom,speed1-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed4-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1958400000 5>, + < 2016000000 6>; + + qcom,speed4-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed5-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>; + + qcom,speed5-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + #clock-cells = <1>; + }; + cpu-pmu { compatible = "arm,armv8-pmuv3"; interrupts = <1 7 0xff00>; @@ -366,6 +469,13 @@ status = "disabled"; }; + qcom,rmtfs_sharedmem@00000000 { + compatible = "qcom,sharedmem-uio"; + reg = <0x00000000 0x00180000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + }; + sdhc_1: sdhci@7824900 { compatible = "qcom,sdhci-msm"; reg = <0x7824900 0x500>, <0x7824000 0x800>, <0x7824e00 0x200>; @@ -498,6 +608,162 @@ }; }; + qcom,lpass@c000000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xc000000 0x00100>; + + vdd_cx-supply = <&pm660_s2_level>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&rpmcc CXO_SMD_PIL_LPASS_CLK>, + <&gcc GCC_CRYPTO_CLK>, + <&gcc GCC_CRYPTO_AHB_CLK>, + <&gcc GCC_CRYPTO_AXI_CLK>, + <&gcc CRYPTO_CLK_SRC>; + + qcom,scm_core_clk_src-freq = <80000000>; + clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + + qcom,pas-id = <1>; + qcom,mas-crypto = <&mas_crypto>; + qcom,complete-ramdump; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + + /* GPIO inputs from lpass */ + interrupts-extended = <&intc 0 293 1>, + <&adsp_smp2p_in 0 0>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + /* GPIO output to lpass */ + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + memory-region = <&adsp_fw_mem>; + }; + + qcom,pronto@a21b000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x0a21b000 0x3000>; + + vdd_pronto_pll-supply = <&pm660_l12>; + qcom,proxy-reg-names = "vdd_pronto_pll"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&rpmcc CXO_SMD_PIL_PRONTO_CLK>, + <&gcc GCC_CRYPTO_CLK>, + <&gcc GCC_CRYPTO_AHB_CLK>, + <&gcc GCC_CRYPTO_AXI_CLK>, + <&gcc CRYPTO_CLK_SRC>; + clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,pas-id = <6>; + qcom,mas-crypto = <&mas_crypto>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <422>; + qcom,sysmon-id = <6>; + qcom,ssctl-instance-id = <0x13>; + qcom,firmware-name = "wcnss"; + + /* GPIO inputs from wcnss */ + interrupts-extended = <&intc 0 149 1>, + <&wcnss_smp2p_in 0 0>, + <&wcnss_smp2p_in 2 0>, + <&wcnss_smp2p_in 1 0>, + <&wcnss_smp2p_in 3 0>, + <&wcnss_smp2p_in 7 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack", + "qcom,shutdown-ack"; + + /* GPIO output to wcnss */ + qcom,smem-states = <&wcnss_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + memory-region = <&wcnss_fw_mem>; + }; + + pil_modem: qcom,mss@4080000 { + compatible = "qcom,pil-q6v55-mss"; + reg = <0x4080000 0x100>, + <0x0194f000 0x010>, + <0x01950000 0x008>, + <0x01951000 0x008>, + <0x04020000 0x040>, + <0x01871000 0x004>; + reg-names = "qdsp6_base", "halt_q6", "halt_modem", + "halt_nc", "rmb_base", "restart_reg", + "cxip_lm_vote_clear"; + + clocks = <&rpmcc CXO_SMD_PIL_MSS_CLK>, + <&gcc GCC_MSS_CFG_AHB_CLK>, + <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>, + <&gcc GCC_BOOT_ROM_AHB_CLK>; + clock-names = "xo", "iface_clk", "bus_clk", "mem_clk"; + qcom,proxy-clock-names = "xo"; + qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk"; + + vdd_mss-supply = <&S6A>; + vdd_cx-supply = <&pm660_s1_level_ao>; + vdd_cx-voltage = ; + vdd_mx-supply = <&pm660_s2_level_ao>; + vdd_mx-uV = ; + vdd_pll-supply = <&L12A>; + qcom,vdd_pll = <1800000>; + vdd_mss-uV = ; + + qcom,pas-id = <5>; + qcom,pil-mss-memsetup; + qcom,firmware-name = "modem"; + qcom,pil-self-auth; + qcom,sequential-fw-load; + qcom,override-acc-1 = <0x80800000>; + qcom,sysmon-id = <0>; + qcom,ssctl-instance-id = <0x12>; + memory-region = <&modem_mem>; + qcom,qdsp6v56-1-8-inrush-current; + qcom,reset-clk; + + /* Inputs from mss */ + interrupts-extended = <&intc 0 24 1>, + <&modem_smp2p_in 0 0>, + <&modem_smp2p_in 2 0>, + <&modem_smp2p_in 1 0>, + <&modem_smp2p_in 3 0>, + <&modem_smp2p_in 7 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack", + "qcom,shutdown-ack"; + + /* Outputs to mss */ + qcom,smem-states = <&modem_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + status = "ok"; + }; + rpm_bus: qcom,rpm-smd { }; usb_otg: usb@78db000 { @@ -719,7 +985,7 @@ adsp_smsm: adsp@2 { reg = <2>; - interrupts = <0 289 IRQ_TYPE_EDGE_RISING>; + interrupts = <0 290 IRQ_TYPE_EDGE_RISING>; interrupt-controller; #interrupt-cells = <2>; }; @@ -776,6 +1042,22 @@ }; }; + qcom,adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + restrict-access; + }; + + qcom,msm_fastrpc { + compatible ="qcom,msm-fastrpc-legacy-compute"; + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-legacy-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_iommu 0x2008 0x7>; + sids = <0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf>; + }; + }; + wcnss-smp2p { compatible = "qcom,smp2p"; qcom,smem = <451>, <431>; @@ -892,6 +1174,94 @@ }; }; + qcom_tzlog: tz-log@08600720 { + compatible = "qcom,tz-log"; + reg = <0x08600720 0x2000>; + }; + + qcom,wcnss-wlan@0a000000 { + compatible = "qcom,wcnss_wlan"; + reg = <0x0a000000 0x280000>, + <0xb011008 0x04>, + <0x0a21b000 0x3000>, + <0x03204000 0x00000100>, + <0x03200800 0x00000200>, + <0x0a100400 0x00000200>, + <0x0a205050 0x00000200>, + <0x0a219000 0x00000020>, + <0x0a080488 0x00000008>, + <0x0a080fb0 0x00000008>, + <0x0a08040c 0x00000008>, + <0x0a0120a8 0x00000008>, + <0x0a012448 0x00000008>, + <0x0a080c00 0x00000001>; + + reg-names = "wcnss_mmio", "wcnss_fiq", + "pronto_phy_base", "riva_phy_base", + "riva_ccu_base", "pronto_a2xb_base", + "pronto_ccpu_base", "pronto_saw2_base", + "wlan_tx_phy_aborts","wlan_brdg_err_source", + "wlan_tx_status", "alarms_txctl", + "alarms_tactl", "pronto_mcu_base"; + + interrupts = <0 145 0 0 146 0>; + interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq"; + + qcom,pronto-vddmx-supply = <&pm660_s2_level_ao>; + qcom,pronto-vddcx-supply = <&pm660_s1_level>; + qcom,pronto-vddpx-supply = <&pm660_l13>; + qcom,iris-vddxo-supply = <&pm660_l12>; + qcom,iris-vddrfa-supply = <&pm660_l5>; + qcom,iris-vdddig-supply = <&pm660_l13>; + + qcom,iris-vddxo-voltage-level = <1800000 0 1800000>; + qcom,iris-vddrfa-voltage-level = <1300000 0 1300000>; + qcom,iris-vddpa-voltage-level = <3300000 0 3300000>; + qcom,iris-vdddig-voltage-level = <1800000 0 1800000>; + + qcom,vddmx-voltage-level = ; + qcom,vddcx-voltage-level = ; + qcom,vddpx-voltage-level = <1800000 0 1800000>; + + qcom,iris-vddxo-current = <10000>; + qcom,iris-vddrfa-current = <100000>; + qcom,iris-vddpa-current = <515000>; + qcom,iris-vdddig-current = <10000>; + + qcom,pronto-vddmx-current = <0>; + qcom,pronto-vddcx-current = <0>; + qcom,pronto-vddpx-current = <0>; + + pinctrl-names = "wcnss_default", "wcnss_sleep", + "wcnss_gpio_default"; + pinctrl-0 = <&wcnss_default>; + pinctrl-1 = <&wcnss_sleep>; + pinctrl-2 = <&wcnss_gpio_default>; + + gpios = <&tlmm 76 0>, <&tlmm 77 0>, <&tlmm 78 0>, + <&tlmm 79 0>, <&tlmm 80 0>; + + clocks = <&rpmcc CXO_SMD_WLAN_CLK>, + <&rpmcc RPM_SMD_RF_CLK2>, + <&rpmcc SNOC_WCNSS_A_CLK>; + + clock-names = "xo", "rf_clk", "snoc_wcnss"; + + qcom,smem-states = <&apps_smsm 10>, <&apps_smsm 9>; + qcom,smem-state-names = "tx-enable", "tx-rings-empty"; + + qcom,snoc-wcnss-clock-freq = <200000000>; + + qcom,has-autodetect-xo; + qcom,is-pronto-v3; + qcom,has-pronto-hw; + qcom,has-vsys-adc-channel; + }; + qcom,bam_dmux@4044000 { compatible = "qcom,bam_dmux"; reg = <0x4044000 0x19000>; @@ -923,6 +1293,11 @@ qcom,ea-pc = <0x230>; status = "disabled"; }; + qcom,msm-adsp-loader { + status = "ok"; + compatible = "qcom,adsp-loader"; + qcom,adsp-state = <0>; + }; }; #include "sdm429-gdsc.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm429w-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm429w-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7322180d8e3e5178bf7f0125481a4930e846e106 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm429w-gpu.dtsi @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2020, 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. + */ + +&soc { + msm_bus: qcom,kgsl-busmon { + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + /* + * active-only flag is used while registering the bus + * governor.It helps release the bus vote when the CPU + * subsystem is inactive + */ + qcom,active-only; + qcom,bw-tbl = + < 0 >, /* off */ + < 769 >, /* 1. DDR:100.80 MHz BIMC: 50.40 MHz */ + < 1611 >, /* 2. DDR:211.20 MHz BIMC: 105.60 MHz */ + < 2273 >, /* 3. DDR:297.60 MHz BIMC: 148.80 MHz */ + < 2929 >, /* 4. DDR:384.00 MHz BIMC: 192.00 MHz */ + < 4248 >, /* 5. DDR:556.80 MHz BIMC: 278.40 MHz */ + < 5346 >, /* 6. DDR:662.40 MHz BIMC: 331.20 MHz */ + < 5712 >, /* 7. DDR:748.80 MHz BIMC: 374.40 MHz */ + < 6150 >, /* 8. DDR:796.80 MHz BIMC: 398.40 MHz */ + < 7105 >; /* 9. DDR:931.20 MHz BIMC: 465.60 MHz */ + }; + + msm_gpu: qcom,kgsl-3d0@1c00000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + reg = <0x1c00000 0x40000 + 0xa0000 0x6fff>; + reg-names = "kgsl_3d0_reg_memory", "qfprom_memory"; + interrupts = <0 33 0>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + qcom,chipid = <0x05000400>; + + qcom,initial-pwrlevel = <0>; + qcom,idle-timeout = <80>; //msecs + qcom,strtstp-sleepwake; + + qcom,highest-bank-bit = <14>; + qcom,snapshot-size = <1048576>; //bytes + + clocks = <&gcc GCC_OXILI_GFX3D_CLK>, + <&gcc GCC_OXILI_AHB_CLK>, + <&gcc GCC_BIMC_GFX_CLK>, + <&gcc GCC_BIMC_GPU_CLK>, + <&gcc GCC_OXILI_TIMER_CLK>, + <&gcc GCC_OXILI_AON_CLK>; + + clock-names = "core_clk", "iface_clk", + "mem_iface_clk", "alt_mem_iface_clk", + "rbbmtimer_clk", "alwayson_clk"; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + qcom,bus-width = <16>; + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <10>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, /* off */ + <26 512 0 806400>, /* 1. 100.80 MHz */ + <26 512 0 1689600>, /* 2. 211.20 MHz */ + <26 512 0 2380800>, /* 3. 297.60 MHz */ + <26 512 0 3072000>, /* 4. 384.00 MHz */ + <26 512 0 4454400>, /* 5. 556.80 MHz */ + <26 512 0 5299200>, /* 6. 662.40 MHz */ + <26 512 0 5990400>, /* 7. 748.80 MHz */ + <26 512 0 6374400>, /* 8. 796.80 MHz */ + <26 512 0 7449600>; /* 9. 931.20 MHz */ + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&oxili_cx_gdsc>; + vdd-supply = <&oxili_gx_gdsc>; + + /* CPU latency parameter */ + qcom,pm-qos-active-latency = <360>; + qcom,pm-qos-wakeup-latency = <360>; + + /* Quirks */ + qcom,gpu-quirk-two-pass-use-wfi; + qcom,gpu-quirk-dp2clockgating-disable; + qcom,gpu-quirk-lmloadkill-disable; + + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + + /* Context aware jump target power level */ + qcom,ca-target-pwrlevel = <1>; + + /* Enable gpu cooling device */ + #cooling-cells = <2>; + + /* Power levels */ + qcom,gpu-pwrlevels { + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <2>; + qcom,bus-min = <2>; + qcom,bus-max = <2>; + }; + qcom,gpu-pwrlevel@1{ + reg = <1>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; + + kgsl_msm_iommu: qcom,kgsl-iommu@1c40000 { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x1c40000 0x10000>; + qcom,protect = <0x40000 0x10000>; + qcom,micro-mmu-control = <0x6000>; + + clocks = <&gcc GCC_OXILI_AHB_CLK>, + <&gcc GCC_BIMC_GFX_CLK>; + + clock-names = "gpu_ahb_clk", "gcc_bimc_gfx_clk"; + + qcom,secure_align_mask = <0xfff>; + qcom,retention; + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0>; + qcom,gpu-offset = <0x48000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi index d70a7943140acc3f80a235c30cced925f122225b..1cf4c8ad62a05c0aa3fce78bca48ec1f839e46ee 100644 --- a/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi @@ -250,4 +250,5 @@ &usb_otg { extcon = <&pm660_charger>; vbus_otg-supply = <&smb2_vbus>; + qcom,vdd-voltage-level = <0 800000 800000>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm660-mdss-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm660-mdss-pll.dtsi index 82194721a419036de3047e086d4893ee8ea7076f..959971594e896c53ecf5ff24697908da7c2cb335 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-mdss-pll.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm660-mdss-pll.dtsi @@ -84,7 +84,7 @@ }; mdss_dp_pll: qcom,mdss_dp_pll@c011000 { - compatible = "qcom,mdss_dp_pll_14nm"; + compatible = "qcom,mdss_dp_pll_sdm660"; status = "ok"; label = "MDSS DP PLL"; cell-index = <0>; diff --git a/arch/arm64/boot/dts/qcom/sdm660-usbc-audio-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm660-usbc-audio-mtp-overlay.dts index 72dc5c277fd72189869ee21bf082e770ae0e9479..661437a49e92370e2def3fb9761fa62b1574136f 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-usbc-audio-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm660-usbc-audio-mtp-overlay.dts @@ -26,4 +26,6 @@ &tavil_snd { qcom,msm-mbhc-usbc-audio-supported = <1>; qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm660.dtsi b/arch/arm64/boot/dts/qcom/sdm660.dtsi index 25e48f860f970c396bdd5e171ceb2cf0d7936361..22175bcdfa2f56d591f2b0aefc8865ad71523c15 100644 --- a/arch/arm64/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm660.dtsi @@ -1016,6 +1016,20 @@ reg = <0xc8c0900 0x4>; }; + clock_debug: qcom,cc-debug@62000 { + compatible = "qcom,gcc-debug-sdm660"; + reg = <0x62000 0x4>; + reg-names = "dbg_offset"; + clocks = <&clock_rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "xo_clk_src"; + qcom,cc-count = <8>; + qcom,gcc = <&clock_gcc>; + qcom,cpu = <&cpu_debug>; + qcom,mmss = <&mmss_debug>; + qcom,gpu = <&gpu_debug>; + #clock-cells = <1>; + }; + generic_bw_opp_table: generic-bw-opp-table { compatible = "operating-points-v2"; BW_OPP_ENTRY( 100, 4); /* 381 MB/s */ diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index e5d0292f551832fda14d148b5667df2494ef5091..86098aa8ccbabffb1a4a2b09c67a2ddfd28c550e 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -1470,6 +1470,7 @@ "tsens_tm_physical"; interrupts = <0 506 0>, <0 508 0>; interrupt-names = "tsens-upper-lower", "tsens-critical"; + tsens-reinit-wa; #thermal-sensor-cells = <1>; }; @@ -1481,6 +1482,7 @@ "tsens_tm_physical"; interrupts = <0 507 0>, <0 509 0>; interrupt-names = "tsens-upper-lower", "tsens-critical"; + tsens-reinit-wa; #thermal-sensor-cells = <1>; }; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8a3da7c6b69d0557bd1c0736b17613b9c0f36143 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi @@ -0,0 +1,2636 @@ +/* Copyright (c) 2020, 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. + */ + +&soc { + csr: csr@0x6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + + qcom,blk-size = <1>; + }; + + swao_csr: csr@6b0e000 { + compatible = "qcom,coresight-csr"; + reg = <0x6b0e000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-swao-csr"; + qcom,timestamp-support; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,blk-size = <1>; + }; + + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator0_out_tmc_etr: endpoint { + remote-endpoint= + <&tmc_etr_in_replicator0>; + }; + }; + + port@1 { + reg = <1>; + replicator0_out_replicator1_in: endpoint { + remote-endpoint= + <&replicator1_in_replicator0_out>; + }; + }; + + port@2 { + reg = <0>; + replicator0_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint= + <&tmc_etf_out_replicator0>; + }; + }; + }; + }; + + replicator_qdss1: replicator@604a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x604a000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <1>; + replicator1_out_funnel_swao: endpoint { + remote-endpoint= + <&funnel_swao_in_replicator1_out>; + }; + }; + + port@1 { + reg = <1>; + replicator1_in_replicator0_out: endpoint { + slave-mode; + remote-endpoint= + <&replicator0_out_replicator1_in>; + }; + }; + }; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x05e0 0>, + <&apps_smmu 0x04a0 0>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + arm,buffer-size = <0x400000>; + + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0>; + coresight-csr = <&csr>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + port { + tmc_etr_in_replicator0: endpoint { + slave-mode; + remote-endpoint = <&replicator0_out_tmc_etr>; + }; + }; + }; + + tmc_etf: tmc@6047000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6047000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-ctis = <&cti0>; + coresight-csr = <&csr>; + arm,default-sink; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_out_replicator0: endpoint { + remote-endpoint = + <&replicator0_in_tmc_etf>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + }; + + }; + + funnel_merg: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_merg_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + }; + }; + + funnel_in0: funnel@6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + + port@1 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@2 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + }; + }; + + funnel_in1: funnel@0x6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + + port@1 { + reg = <0>; + funnel_in1_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in1>; + }; + }; + + port@2 { + reg = <1>; + funnel_in1_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_funnel_in1>; + }; + }; + + port@3 { + reg = <4>; + funnel_in1_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in1>; + }; + }; + + port@4 { + reg = <6>; + funnel_in1_in_tpda_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpda_modem_in_tpdm_modem>; + }; + }; + }; + }; + + replicator_swao: replicator@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6b0a000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* Always have EUD before funnel leading to ETR. If both + * sink are active we need to give preference to EUD + * over ETR + */ + port@0 { + reg = <1>; + replicator_swao_out_eud: endpoint { + remote-endpoint = + <&dummy_eud_in_replicator_swao>; + }; + }; + + port@1 { + reg = <0>; + replicator_swao_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_replicator_swao>; + }; + }; + + port@2 { + reg = <0>; + replicator_swao_in_tmc_etf_swao: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_swao_out_replicator_swao>; + }; + }; + }; + }; + + dummy_eud: dummy_sink { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-eud"; + + qcom,dummy-sink; + port { + dummy_eud_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_eud>; + }; + }; + }; + + tmc_etf_swao: tmc@6b09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6b09000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf-swao"; + coresight-csr = <&csr>; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_swao_out_replicator_swao: endpoint { + remote-endpoint= + <&replicator_swao_in_tmc_etf_swao>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_swao_in_funnel_swao: endpoint { + slave-mode; + remote-endpoint= + <&funnel_swao_out_tmc_etf_swao>; + }; + }; + }; + }; + + funnel_swao:funnel@6b08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6b08000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_swao_out_tmc_etf_swao: endpoint { + remote-endpoint = + <&tmc_etf_swao_in_funnel_swao>; + }; + }; + + port@1 { + reg = <5>; + funnel_swao_in_ssc_etm0: endpoint { + slave-mode; + remote-endpoint= + <&ssc_etm0_out_funnel_swao>; + }; + }; + + port@2 { + reg = <6>; + funnel_swao_in_replicator1_out: endpoint { + slave-mode; + remote-endpoint= + <&replicator1_out_funnel_swao>; + }; + }; + + port@3 { + reg = <7>; + funnel_swao_in_tpda_swao: endpoint { + slave-mode; + remote-endpoint= + <&tpda_swao_out_funnel_swao>; + }; + }; + }; + }; + + tpda_swao: tpda@6b01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6b01000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-swao"; + + qcom,tpda-atid = <71>; + qcom,dsb-elem-size = <1 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_swao_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_tpda_swao>; + }; + + }; + + port@1 { + reg = <0>; + tpda_swao_in_tpdm_swao0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao0_out_tpda_swao>; + }; + }; + + port@2 { + reg = <1>; + tpda_swao_in_tpdm_swao1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao1_out_tpda_swao>; + }; + }; + }; + }; + + tpdm_swao0: tpdm@6b02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + + reg = <0x6b02000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_swao0_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao0>; + }; + }; + }; + + tpdm_swao1: tpdm@6b03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b03000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name="coresight-tpdm-swao-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_swao1_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao1>; + }; + }; + }; + + ssc_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-ssc-etm0"; + qcom,inst-id = <8>; + + port { + ssc_etm0_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_ssc_etm0>; + }; + }; + }; + + tpda_modem: tpda@6832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-modem"; + + qcom,tpda-atid = <67>; + qcom,dsb-elem-size = <0 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_modem_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_tpda_modem>; + }; + }; + + port@1 { + reg = <0>; + tpda_modem_in_tpdm_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem_out_tpda_modem>; + }; + }; + }; + }; + + tpdm_modem: tpdm@6830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-modem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_modem_out_tpda_modem: endpoint { + remote-endpoint = <&tpda_modem_in_tpdm_modem>; + }; + }; + }; + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_modem_etm0>; + }; + }; + }; + + funnel_dl_mm: funnel@6c0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6c0b000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_mm_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_mm>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_mm_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_funnel_dl_mm>; + }; + }; + }; + }; + + tpdm_qm: tpdm@69d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_qm_out_funnel_dl_mm: endpoint { + remote-endpoint = <&funnel_dl_mm_in_tpdm_qm>; + }; + }; + }; + + funnel_dl_mm1: funnel_1@6c0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867000 0x10>, + <0x6c0b000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-dl-mm1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_mm1_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_mm1>; + }; + }; + + port@1 { + reg = <1>; + funnel_dl_mm1_in_tpdm_mm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mm_out_funnel_dl_mm1>; + }; + }; + }; + }; + + tpdm_mm: tpdm@6c08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c08000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_mm_out_funnel_dl_mm1: endpoint { + remote-endpoint = <&funnel_dl_mm1_in_tpdm_mm>; + }; + }; + }; + + funnel_turing: funnel@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6861000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_turing>; + }; + }; + + port@1 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + }; + }; + + tpdm_turing: tpdm@6860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + + funnel_turing_1: funnel_1@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867010 0x10>, + <0x6861000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-turing-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_turing_1>; + }; + }; + + port@1 { + reg = <1>; + funnel_turing_1_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing_1>; + }; + }; + }; + }; + + turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port{ + turing_etm0_out_funnel_turing_1: endpoint { + remote-endpoint = + <&funnel_turing_1_in_turing_etm0>; + }; + }; + }; + + funnel_apss_merg: funnel@7810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7810000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_merg_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merg>; + }; + }; + + port@2 { + reg = <2>; + funnel_apss_merg_in_tpda_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpda_olc_out_funnel_apss_merg>; + }; + }; + + port@3 { + reg = <3>; + funnel_apss_merg_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_silver_out_funnel_apss_merg>; + }; + }; + + port@4 { + reg = <4>; + funnel_apss_merg_in_tpda_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_gold_out_funnel_apss_merg>; + }; + }; + + port@5 { + reg = <5>; + funnel_apss_merg_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merg>; + }; + }; + }; + }; + + tpda_olc: tpda@7832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-olc"; + + qcom,tpda-atid = <69>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_olc_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_olc>; + }; + }; + + port@1 { + reg = <0>; + tpda_olc_in_tpdm_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_olc_out_tpda_olc>; + }; + }; + }; + }; + + tpdm_olc: tpdm@7830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-olc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_olc_out_tpda_olc: endpoint { + remote-endpoint = <&tpda_olc_in_tpdm_olc>; + }; + }; + }; + + tpda_apss: tpda@7862000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7862000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + tpdm_apss: tpdm@7860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_apss_out_tpda_apss: endpoint { + remote-endpoint = <&tpda_apss_in_tpdm_apss>; + }; + }; + }; + + tpda_llm_silver: tpda@78c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78c0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-silver"; + + qcom,tpda-atid = <72>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_llm_silver_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver>; + }; + }; + }; + }; + + tpdm_llm_silver: tpdm@78a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78a0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-silver"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_silver_out_tpda_llm_silver: endpoint { + remote-endpoint = + <&tpda_llm_silver_in_tpdm_llm_silver>; + }; + }; + }; + + tpda_llm_gold: tpda@78d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78d0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-gold"; + + qcom,tpda-atid = <73>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_llm_gold_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_gold>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_gold_in_tpdm_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_gold_out_tpda_llm_gold>; + }; + }; + }; + }; + + tpdm_llm_gold: tpdm@78b0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78b0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-gold"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_gold_out_tpda_llm_gold: endpoint { + remote-endpoint = + <&tpda_llm_gold_in_tpdm_llm_gold>; + }; + }; + }; + + funnel_apss: funnel@7800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7800000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss>; + }; + }; + + port@8 { + reg = <7>; + funnel_apss_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss>; + }; + }; + }; + }; + + etm0: etm@7040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7040000 0x1000>; + cpu = <&CPU0>; + + coresight-name = "coresight-etm0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + + port { + etm0_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@7140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7140000 0x1000>; + cpu = <&CPU1>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm1_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@7240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7240000 0x1000>; + cpu = <&CPU2>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm2_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@7340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7340000 0x1000>; + cpu = <&CPU3>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm3_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm3>; + }; + }; + }; + + etm4: etm@7440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7440000 0x1000>; + cpu = <&CPU4>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm4_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: etm@7540000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7540000 0x1000>; + cpu = <&CPU5>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm5_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: etm@7640000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7640000 0x1000>; + cpu = <&CPU6>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm6_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: etm@7740000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7740000 0x1000>; + cpu = <&CPU7>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm7_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm7>; + }; + }; + }; + + cti0_apss: cti@78e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78e0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_apss: cti@78f0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78f0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_apss: cti@7900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7900000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu0: cti@7020000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7020000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu1: cti@7120000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7120000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu2: cti@7220000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7220000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu3: cti@7320000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7320000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu4: cti@7420000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7420000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu4"; + cpu = <&CPU4>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu5: cti@7520000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7520000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu5"; + cpu = <&CPU5>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu6: cti@7620000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7620000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu6"; + cpu = <&CPU6>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu7: cti@7720000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7720000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu7"; + cpu = <&CPU7>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlct: cti@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c29000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mss_q6: cti@683b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x683b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mss-q6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing: cti@6867000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6867000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_aop_m3: cti@6b21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b21000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-aop-m3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_titan: cti@6c13000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c13000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-titan"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_venus_arm9: cti@6c20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-venus-arm9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlmm: cti@6c09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c09000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlmm: cti@6c0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c0a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlct: cti@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c29000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_swao:cti@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b04000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_swao: cti@6b05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b05000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_swao: cti@6b06000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b06000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3_swao: cti@6b07000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b07000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr0: cti@6a02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr0: cti@6a03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@6a10000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a10000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@6a11000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a11000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + hwevent: hwevent@91866f0 { + compatible = "qcom,coresight-hwevent"; + reg = <0x091866f0 0x4>, + <0x91966f0 0x4>, + <0x9186038 0x4>, + <0x9196038 0x4>, + <0x17e00034 0x4>, + <0x18200050 0x80>, + <0x02c8d050 0x80>, + <0x0af20050 0x80>; + reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl", + "ddr-ch23-ctrl", "apss-testbus-mux-cfg", + "apss-rsc-hwevent-mux0-select", + "gpu-rsc-hwevent-mux0-select", + "sde-rsc-hwevent-mux0-select"; + + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + + port@2 { + reg = <5>; + funnel_qatb_in_funnel_turing_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_1_out_funnel_qatb>; + }; + }; + + port@3 { + reg = <6>; + funnel_qatb_in_funnel_lpass_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_lpass_1_out_funnel_qatb>; + }; + }; + }; + }; + + tpda: tpda@6004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <10 32>, + <13 32>; + qcom,tc-elem-size = <13 32>; + qcom,dsb-elem-size = <0 32>, + <2 32>, + <3 32>, + <5 32>, + <6 32>, + <10 32>, + <11 32>, + <13 32>; + qcom,cmb-elem-size = <3 64>, + <7 64>, + <10 64>, + <13 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + }; + + port@1 { + reg = <0>; + tpda_in_funnel_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_mm_out_tpda>; + }; + }; + + port@2 { + reg = <1>; + tpda_in_funnel_dl_mm1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_mm1_out_tpda>; + }; + }; + + port@3 { + reg = <2>; + tpda_in_tpdm_center: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_center_out_tpda>; + }; + }; + + port@4 { + reg = <3>; + tpda_in_tpdm_npu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_out_tpda>; + }; + }; + + port@5 { + reg = <5>; + tpda_in_funnel_ddr_0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr_0_out_tpda>; + }; + }; + + port@6 { + reg = <8>; + tpda_in_funnel_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_south_out_tpda>; + }; + }; + + port@7 { + reg = <9>; + tpda_in_funnel_lpass: endpoint { + slave-mode; + remote-endpoint = + <&funnel_lpass_out_tpda>; + }; + }; + + port@8 { + reg = <10>; + tpda_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda>; + }; + }; + + + port@9 { + reg = <11>; + tpda_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda>; + }; + }; + + port@10 { + reg = <13>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + + port@11 { + reg = <16>; + tpda_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda>; + }; + }; + }; + }; + + funnel_lpass: funnel@6846000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6846000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-lpass"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_lpass_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_lpass>; + }; + }; + + port@1 { + reg = <0>; + funnel_lpass_in_tpdm_lpass: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpass_out_funnel_lpass>; + }; + }; + }; + }; + + tpdm_lpass: tpdm@6844000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6844000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-lpass"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_lpass_out_funnel_lpass: endpoint { + remote-endpoint = <&funnel_lpass_in_tpdm_lpass>; + }; + }; + }; + + funnel_lpass_1: funnel_1@6846000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867020 0x10>, + <0x6846000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-lpass-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_lpass_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_lpass_1>; + }; + }; + + port@1 { + reg = <2>; + funnel_lpass_1_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_lpass_1>; + }; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_lpass_1: endpoint { + remote-endpoint = + <&funnel_lpass_1_in_audio_etm0>; + }; + }; + }; + + funnel_dl_south: funnel@69c2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x69c2000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dl_south_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_south>; + }; + }; + + port@1 { + reg = <1>; + funnel_dl_south_in_tpdm_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_south_out_funnel_dl_south>; + }; + }; + + port@2 { + reg = <3>; + funnel_dl_south_in_funnel_wcss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_wcss_out_funnel_dl_south>; + }; + }; + }; + }; + + tpdm_dl_south: tpdm@69c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69c0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dl_south_out_funnel_dl_south: endpoint { + remote-endpoint = + <&funnel_dl_south_in_tpdm_dl_south>; + }; + }; + }; + + funnel_wcss: funnel@6ac2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6ac2000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-wcss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_wcss_out_funnel_dl_south: endpoint { + remote-endpoint = + <&funnel_dl_south_in_funnel_wcss>; + }; + }; + + port@2 { + reg = <1>; + funnel_wcss_in_tpdm_wcss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_out_funnel_wcss>; + }; + }; + }; + }; + + tpdm_wcss: tpdm@699c000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-wcss"; + qcom,dummy-source; + + port { + tpdm_wcss_out_funnel_wcss: endpoint { + remote-endpoint = <&funnel_wcss_in_tpdm_wcss>; + }; + }; + }; + + funnel_ddr_0: funnel@6a05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6a05000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_ddr_0_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_ddr_0>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr_0_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_funnel_ddr_0>; + }; + }; + }; + }; + + tpdm_ddr: tpdm@6a00000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6a00000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_ddr_out_funnel_ddr_0: endpoint { + remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>; + }; + }; + }; + + tpdm_center: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-center"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_center_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_center>; + }; + }; + }; + + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x684c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; + }; + + tpdm_vsense: tpdm@6840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6840000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_vsense_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_vsense>; + }; + }; + }; + + tpdm_npu: tpdm@6980000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6980000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu"; + + clocks = <&clock_aop QDSS_CLK>, + <&clock_gcc GCC_NPU_TRIG_CLK>, + <&clock_gcc GCC_NPU_AT_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_APB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_ATB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK_SRC>, + <&clock_npucc NPU_CC_NPU_CORE_CTI_CLK>; + + clock-names = "apb_pclk", + "gcc_npu_trig_clk", + "gcc_npu_at_clk", + "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_core_cti_clk"; + + qcom,tpdm-clks = "gcc_npu_trig_clk", + "gcc_npu_at_clk", + "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_core_cti_clk"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,tpdm-regs = "vdd", "vdd_cx"; + + port{ + tpdm_npu_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_npu>; + }; + }; + }; + + tpdm_pimem: tpdm@6850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6850000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_pimem_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_pimem>; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + + reg = <0x6002000 0x1000>, + <0x16280000 0x180000>, + <0x7820f0 0x4>; + reg-names = "stm-base", "stm-stimulus-base", "stm-debug-status"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + }; + + ipcb_tgu: tgu@6b0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x06B0C000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi index 9bf56e7ddaba4a74bf3c5350cfc586255bd89bdc..65b478bb9716d11fbea3829e62b5743c611a253a 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi @@ -70,15 +70,6 @@ opp-microvolt = ; }; - opp-256000000 { - opp-hz = /bits/ 64 <256000000>; - opp-microvolt = ; - }; - - opp-177000000 { - opp-hz = /bits/ 64 <177000000>; - opp-microvolt = ; - }; }; msm_gpu: qcom,kgsl-3d0@2c00000 { @@ -247,22 +238,6 @@ qcom,gpu-pwrlevel@5 { reg = <5>; - qcom,gpu-freq = <256000000>; - qcom,bus-freq = <5>; - qcom,bus-min = <5>; - qcom,bus-max = <7>; - }; - - qcom,gpu-pwrlevel@6 { - reg = <6>; - qcom,gpu-freq = <177000000>; - qcom,bus-freq = <4>; - qcom,bus-min = <3>; - qcom,bus-max = <5>; - }; - - qcom,gpu-pwrlevel@7 { - reg = <7>; qcom,gpu-freq = <0>; qcom,bus-freq = <0>; qcom,bus-min = <0>; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi index c45e50bdc39f0d66f5b78ceaa91bd2bc107d9c74..8017279a097d874350a81370a9eda592124fba8f 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi @@ -5001,7 +5001,7 @@ config { pins = "gpio85", "gpio86"; drive-strength = <2>; - bias-disable; + bias-pull-down; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi index 9362ddd57f99fae0d387debc6a99f78db25629f7..9807f0bb4c927e6c38432ad9f8f2267b5ed55819 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, 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 @@ -46,26 +46,25 @@ qcom,core-clk-rate = <200000000>; qcom,core-clk-rate-hs = <66666667>; - qcom,num-gsi-evt-buffs = <0x3>; - qcom,gsi-reg-offset = - <0x0fc /* GSI_GENERAL_CFG */ - 0x110 /* GSI_DBL_ADDR_L */ - 0x120 /* GSI_DBL_ADDR_H */ - 0x130 /* GSI_RING_BASE_ADDR_L */ - 0x144 /* GSI_RING_BASE_ADDR_H */ - 0x1a4>; /* GSI_IF_STS */ qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + qcom,charging-disabled; qcom,msm-bus,name = "usb0"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = + /* suspend vote */ , - , , + + /* nominal vote */ , - , + , + + /* svs vote */ + , ; dwc3@a600000 { @@ -149,7 +148,7 @@ #size-cells = <1>; ranges; - interrupts = <0 491 0>, <0 135 0>, <0 487 0>, <0 490 0>; + interrupts = <0 491 0>, <0 135 0>, <0 520 0>, <0 490 0>; interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", "ss_phy_irq", "dm_hs_phy_irq"; qcom,use-pdc-interrupts; @@ -169,36 +168,25 @@ qcom,core-clk-rate = <200000000>; qcom,core-clk-rate-hs = <66666667>; - qcom,num-gsi-evt-buffs = <0x3>; - qcom,gsi-reg-offset = - <0x0fc /* GSI_GENERAL_CFG */ - 0x110 /* GSI_DBL_ADDR_L */ - 0x120 /* GSI_DBL_ADDR_H */ - 0x130 /* GSI_RING_BASE_ADDR_L */ - 0x144 /* GSI_RING_BASE_ADDR_H */ - 0x1a4>; /* GSI_IF_STS */ qcom,dwc-usb3-msm-tx-fifo-size = <27696>; qcom,charging-disabled; qcom,msm-bus,name = "usb1"; qcom,msm-bus,num-cases = <3>; - qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = /* suspend vote */ , - , , /* nominal vote */ , - , , /* svs vote */ , - , ; status = "disabled"; @@ -236,6 +224,395 @@ resets = <&clock_gcc GCC_QUSB2PHY_SEC_BCR>; reset-names = "phy_reset"; + qcom,param-override-seq = <0x43 0x70>; + + status = "disabled"; + }; + + /* Tertiary USB port related controller */ + usb2: ssusb@a400000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a400000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x60 0x0>; + qcom,smmu-s1-bypass; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 539 0>, <0 487 0>, <0 526 0>, + <0 551 0>, <0 510 0>, <0 548 0>; + interrupt-names = "dp_hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq1", + "ss_phy_irq1", "dm_hs_phy_irq1"; + qcom,use-pdc-interrupts; + + USB3_GDSC-supply = <&usb30_mp_gdsc>; + clocks = <&clock_gcc GCC_USB30_MP_MASTER_CLK>, + <&clock_gcc GCC_CFG_NOC_USB3_MP_AXI_CLK>, + <&clock_gcc GCC_AGGRE_USB3_MP_AXI_CLK>, + <&clock_gcc GCC_USB30_MP_MOCK_UTMI_CLK>, + <&clock_gcc GCC_USB30_MP_SLEEP_CLK>, + <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "xo"; + + resets = <&clock_gcc GCC_USB30_MP_BCR>; + reset-names = "core_reset"; + + qcom,core-clk-rate = <200000000>; + qcom,charging-disabled; + qcom,dual-port; + + qcom,msm-bus,name = "usb2"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + /* suspend vote */ + , + + /* nominal vote */ + , + + /* svs vote */ + ; + + status = "disabled"; + + dwc3@a400000 { + compatible = "snps,dwc3"; + reg = <0x0a400000 0xcd00>; + interrupts = <0 654 0>; + usb-phy = <&usb2_phy2>, <&usb_qmp_phy0>, + <&usb2_phy3>, <&usb_qmp_phy1>; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,ssp-u3-u0-quirk; + snps,usb3-u1u2-disable; + snps,dis_u3_susphy_quirk; + usb-core-id = <2>; + maximum-speed = "super-speed-plus"; + dr_mode = "host"; + }; + }; + + /* Tertiary USB port 0 related High Speed PHY */ + usb2_phy2: hsphy@88e4000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0x88e4000 0x110>; + reg-names = "hsusb_phy_base"; + + vdd-supply = <&pm8150_2_l5>; + vdda18-supply = <&pm8150_1_l12>; + vdda33-supply = <&pm8150_2_l16>; + qcom,vdd-voltage-level = <0 880000 880000>; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&clock_gcc GCC_QUSB2PHY_MP0_BCR>; + reset-names = "phy_reset"; + qcom,param-override-seq = <0x43 0x70>; + + status = "disabled"; + }; + + /* Tertiary USB port 0 related QMP PHY */ + usb_qmp_phy0: ssphy@88eb000 { + compatible = "qcom,usb-ssphy-qmp-v2"; + reg = <0x88eb000 0x1000>, + <0x088eb88c 0x4>; + reg-names = "qmp_phy_base", + "pcs_clamp_enable_reg"; + + vdd-supply = <&pm8150_1_l9>; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,vdd-max-load-uA = <47000>; + core-supply = <&pm8150_2_l16>; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + ; + + clocks = <&clock_gcc GCC_USB3_MP_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_MP_PHY_PIPE_0_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_SEC_CLKREF_CLK>, + <&clock_gcc GCC_USB3_MP_PHY_COM_AUX_CLK>; + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk", "com_aux_clk"; + + resets = <&clock_gcc GCC_USB3_UNIPHY_MP0_BCR>, + <&clock_gcc GCC_USB3UNIPHY_PHY_MP0_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; + + status = "disabled"; + }; + + /* Tertiary USB port 1 related High Speed PHY */ + usb2_phy3: hsphy@88e5000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0x88e5000 0x110>; + reg-names = "hsusb_phy_base"; + + vdd-supply = <&pm8150_2_l5>; + vdda18-supply = <&pm8150_1_l12>; + vdda33-supply = <&pm8150_2_l16>; + qcom,vdd-voltage-level = <0 880000 880000>; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&clock_gcc GCC_QUSB2PHY_MP1_BCR>; + reset-names = "phy_reset"; + qcom,param-override-seq = <0x43 0x70>; + + status = "disabled"; + }; + + /* Tertiary USB port 1 related QMP PHY */ + usb_qmp_phy1: ssphy@88ec000 { + compatible = "qcom,usb-ssphy-qmp-v2"; + reg = <0x88ec000 0x1000>, + <0x088ec88c 0x4>; + reg-names = "qmp_phy_base", + "pcs_clamp_enable_reg"; + + vdd-supply = <&pm8150_1_l9>; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,vdd-max-load-uA = <47000>; + core-supply = <&pm8150_2_l16>; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + ; + + clocks = <&clock_gcc GCC_USB3_MP_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_MP_PHY_PIPE_1_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_1_CLKREF_CLK>, + <&clock_gcc GCC_USB3_MP_PHY_COM_AUX_CLK>; + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk", "com_aux_clk"; + + resets = <&clock_gcc GCC_USB3_UNIPHY_MP1_BCR>, + <&clock_gcc GCC_USB3UNIPHY_PHY_MP1_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi index 4140806336ae557af302117147fa3e717cfb1186..22b5b9dc3c3158c31972096df576f827e1008918 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi @@ -45,20 +45,6 @@ opp-microvolt = ; }; - opp-315000000 { - opp-hz = /bits/ 64 <315000000>; - opp-microvolt = ; - }; - - opp-235000000 { - opp-hz = /bits/ 64 <235000000>; - opp-microvolt = ; - }; - - opp-156000000 { - opp-hz = /bits/ 64 <156000000>; - opp-microvolt = ; - }; }; }; /* GPU overrides */ @@ -144,30 +130,6 @@ qcom,gpu-pwrlevel@5 { reg = <5>; - qcom,gpu-freq = <315000000>; - qcom,bus-freq = <3>; - qcom,bus-min = <3>; - qcom,bus-max = <8>; - }; - - qcom,gpu-pwrlevel@6 { - reg = <6>; - qcom,gpu-freq = <235000000>; - qcom,bus-freq = <2>; - qcom,bus-min = <1>; - qcom,bus-max = <8>; - }; - - qcom,gpu-pwrlevel@7 { - reg = <7>; - qcom,gpu-freq = <156000000>; - qcom,bus-freq = <2>; - qcom,bus-min = <1>; - qcom,bus-max = <8>; - }; - - qcom,gpu-pwrlevel@8 { - reg = <8>; qcom,gpu-freq = <0>; qcom,bus-freq = <0>; qcom,bus-min = <0>; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index d967177aec66eabbd778d4ea29e31e0c59c48716..d417ff891224e8e8fe06ec759c221e1da26da266 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -2841,6 +2841,7 @@ #include "sdmshrike-regulators.dtsi" #include "sdmshrike-ion.dtsi" #include "sdmshrike-bus.dtsi" +#include "sdmshrike-coresight.dtsi" #include "msm-arm-smmu-sdmshrike.dtsi" #include "sdmshrike-usb.dtsi" #include "sdmshrike-qupv3.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi index 9d46f6101156fd609fb0802ca9506670c5b04fb8..dd63984d819f03546ce8eef96255055d644c6437 100644 --- a/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi @@ -169,6 +169,10 @@ qcom,msm-dai-q6-dev-id = <32770>; }; + incall_music_dl_rx: qcom,msm-dai-q6-incall-music-dl-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32774>; + }; }; pcm_dtmf: qcom,msm-pcm-dtmf { diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi index 1501f2ee2226e361af4341ac393bfacefdc4ae42..26204b4f6814ef485f04c9a11353f2863d411e00 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi @@ -40,7 +40,7 @@ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, <&dai_sec_auxpcm>, <&incall2_record_rx>, - <&incall_music_2_rx>; + <&incall_music_2_rx>, <&incall_music_dl_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", @@ -52,6 +52,6 @@ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", "msm-dai-q6-auxpcm.2", "msm-dai-q6-dev.32769", - "msm-dai-q6-dev.32770"; + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.32774"; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi index f48d52a7c9e50ac895e49c7353e0d07798ccbd14..e7c6121925bdc526056fde8cc9638d89fe86e9f9 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi @@ -165,6 +165,13 @@ arm,buffer-size = <0x400000>; + qcom,qdss-ipa-support; + ipa-conn-data-base-pa = <0x1468B000>; + ipa-conn-data-size = <0x3000>; + ipa-conn-desc-base-pa = <0x1468E000>; + ipa-conn-desc-size = <0x1000>; + ipa-peer-evt-reg-pa = <0x6077818>; + coresight-name = "coresight-tmc-etr"; coresight-ctis = <&cti0 &cti0>; coresight-csr = <&csr>; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi index 8c020724a1d454d27aef4df2c2266a84ccb8b8c2..75e75921902a1af8af85674ecfd50545181890b2 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi @@ -209,7 +209,9 @@ <0x100 &apps_smmu 0x0201 0x1>, <0x200 &apps_smmu 0x0202 0x1>, <0x300 &apps_smmu 0x0203 0x1>, - <0x400 &apps_smmu 0x0204 0x1>; + <0x400 &apps_smmu 0x0204 0x1>, + <0x208 &apps_smmu 0x0205 0x1>, + <0x210 &apps_smmu 0x0206 0x1>; qcom,msm-bus,name = "pcie0"; qcom,msm-bus,num-cases = <2>; @@ -252,17 +254,20 @@ pcie0_bus1_dev0_fn0: pcie0_bus1_dev0_fn0 { reg = <0 0 0 0 0>; pci-ids = "12d8:b304"; + errata = <0>; /* BDF 2.1.0 */ pcie0_bus2_dev1_fn0: pcie0_bus2_dev1_fn0 { reg = <0x800 0 0 0 0>; pci-ids = "12d8:b304"; + errata = <1>; }; /* BDF 2.2.0 */ pcie0_bus2_dev2_fn0: pcie0_bus2_dev2_fn0 { reg = <0x1000 0 0 0 0>; pci-ids = "12d8:b304"; + errata = <2>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi index edba1fd6cdbb397160ef58b33abcec738df82986..aaf72774fa188354b99778c8c424eb87abde17d7 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi @@ -1685,5 +1685,18 @@ bias-pull-down; }; }; + + wakeup_gpio_default: wakeup_gpio_default { + mux { + pins = "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio22"; + drive-strength = <2>; + bias-pull-down; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..931dc712da9050d82d9f689b6aedec0d8170dacb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi @@ -0,0 +1,38 @@ +/* Copyright (c) 2020, 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. + */ + + +&pcie0_rp { + realtek,rtl8125@pcie0_rp { + reg = <0 0 0 0 0>; + + compatible = "realtek,rtl-8125"; + + pci-ids = + "10ec:8125", + "10ec:3000"; + + qcom,smmu; + + /* IOVA range is restricted to avoid conflicts with PCI BAR + * space, Q6 SMEM and IOVA spaces used by peripherals that are + * currently attached to IPA. + */ + qcom,smmu-iova-base = /bits/ 64 <0x80000000>; + qcom,smmu-iova-size = /bits/ 64 <0x0FE40000>; + + qcom,smmu-attr-atomic; + qcom,smmu-attr-fastmap; + + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts b/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts index af338a7787c5a376e81bb81a23cde4664b09af1b..165a3275f2afaf9fc6e0af46e86ebd856bbf9fdb 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts +++ b/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts @@ -16,9 +16,66 @@ #include "sdxprairie-cdp.dtsi" / { - model = "Qualcomm Technologies, Inc. SDXPRAIRIE v2 CDP - TELEMATICS AU DSDA"; + model = "Qualcomm Technologies, Inc. SDXPRAIRIE v2 CDP TEL AU DSDA"; compatible = "qcom,sdxprairie-cdp", "qcom,sdxprairie", "qcom,cdp"; qcom,board-id = <0x6010001 0x0>; }; + +/* delete pm8150b nodes */ +&thermal_zones { + /delete-node/ pm8150b-wp-therm; + /delete-node/ pm8150b_tz; + /delete-node/ pm8150b-ibat-lvl0; + /delete-node/ pm8150b-ibat-lvl1; + /delete-node/ pm8150b-vbat-lvl0; + /delete-node/ pm8150b-vbat-lvl1; + /delete-node/ pm8150b-vbat-lvl2; + /delete-node/ pm8150b-bcl-lvl0; + /delete-node/ pm8150b-bcl-lvl1; + /delete-node/ pm8150b-bcl-lvl2; + /delete-node/ soc; +}; + +&usb { + extcon = <&vbus_detect>; +}; + +&spmi_bus { + /delete-node/ qpnp,fg; + /delete-node/ bcl@1d00; + /delete-node/ qcom,usb-pdphy@1700; + /delete-node/ qcom,qpnp-smb5; + /delete-node/ adc_tm@3500; + /delete-node/ vadc@3100; + /delete-node/ qcom,pm8150b@2; + /delete-node/ qcom,pm8150b@3; +}; + +&qnand_1 { + status = "ok"; +}; + +&blsp1_uart2b_hs { + status = "okay"; +}; + +&vbus_detect { + status = "okay"; +}; + +ðqos_hw { + /delete-property/ vreg_rgmii-supply; + pinctrl-names = "default", + "dev-emac_pin_pps_0", + "dev-emac_pin_pps_1"; + pinctrl-0 = <&vreg_rgmii_off_default>; + pinctrl-1 = <&emac_pin_pps_0>; + pinctrl-2 = <&emac_pin_pps_1>; + qcom,phy-reset-delay-msecs = <10>; +}; + +&vreg_rgmii_io_pads { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index 4282950bec5e65894313d10f458a39f9c591d031..0edcac4c5c0cbde0041c24292b7b754a6adf289d 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -547,7 +547,6 @@ qcom,use-ipa-pm; qcom,use-xbl-boot; qcom,arm-smmu; - qcom,smmu-fast-map; qcom,wlan-ce-db-over-pcie; qcom,bandwidth-vote-for-ipa; qcom,msm-bus,name = "ipa"; @@ -608,6 +607,8 @@ /* modem tables in IMEM */ <0x14688000 0x14688000 0x3000>; qcom,ipa-q6-smem-size = <26624>; + qcom,smmu-fast-map; + qcom,geometry-mapping = <0x0 0xF0000000>; }; ipa_smmu_wlan: ipa_smmu_wlan { @@ -844,7 +845,6 @@ <125 512 0 0>, <125 512 393600 393600>; qcom,no-clock-support; - qcom,smmu-s1-enable; iommus = <&apps_smmu 0x0066 0x0011>, <&apps_smmu 0x0076 0x0011>; }; @@ -873,7 +873,6 @@ qcom,use-sw-ahash-algo; qcom,use-sw-hmac-algo; qcom,no-clock-support; - qcom,smmu-s1-enable; iommus = <&apps_smmu 0x0064 0x0011>, <&apps_smmu 0x0074 0x0011>; }; @@ -1236,7 +1235,7 @@ qcom,pcie-active-config; qcom,pcie-aggregated-irq; qcom,pcie-mhi-a7-irq; - qcom,phy-status-reg = <0x814>; + qcom,phy-status-reg2 = <0x1214>; qcom,mhi-soc-reset-offset = <0xb01b8>; qcom,phy-init = <0x1240 0x001 0x0 0x1 @@ -1527,6 +1526,7 @@ compatible = "qcom,emac-smmu-embedded"; iommus = <&apps_smmu 0x1c0 0xf>; qcom,iova-mapping = <0x80000000 0x40000000>; + qcom,smmu-geometry; }; }; @@ -1588,14 +1588,19 @@ compatible = "qcom,emac-smmu-embedded"; iommus = <&apps_smmu 0x1c0 0xf>; qcom,iova-mapping = <0x80000000 0x40000000>; + qcom,smmu-geometry; }; }; sdx_ext_ipc: qcom,sdx_ext_ipc { compatible = "qcom,sdx-ext-ipc"; - qcom,ap2mdm-status-gpio = <&tlmm 64 0x00>; - qcom,mdm2ap-status-gpio = <&tlmm 63 0x00>; - qcom,mdm2ap-status2-gpio = <&tlmm 66 0x00>; + qcom,status-in-gpio = <&tlmm 64 0x00>; + qcom,status-out-gpio = <&tlmm 63 0x00>; + qcom,status-out2-gpio = <&tlmm 66 0x00>; + qcom,wakeup-gpio-in = <&tlmm 87 0x00>; + qcom,wakeup-gpio-out = <&tlmm 22 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&wakeup_gpio_default>; status = "disabled"; }; }; @@ -1613,6 +1618,7 @@ #include "sdxprairie-coresight.dtsi" #include "sdxprairie-aqc.dtsi" #include "sdxprairie-thermal.dtsi" +#include "sdxprairie-qcom-smmu.dtsi" &gdsc_usb30 { status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 4eed5815d029d51ceb527224aef696565d641609..fae82d8413309f85275d4f3e6d5beb5f217f0e40 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -634,7 +634,7 @@ }; disp_rdump_memory: disp_rdump_region@9c000000 { - reg = <0x0 0x9c000000 0x0 0x01000000>; + reg = <0x0 0x9c000000 0x0 0x0f00000>; label = "disp_rdump_region"; }; @@ -2387,13 +2387,15 @@ <&adsp_smp2p_in 0 0>, <&adsp_smp2p_in 2 0>, <&adsp_smp2p_in 1 0>, - <&adsp_smp2p_in 3 0>; + <&adsp_smp2p_in 3 0>, + <&adsp_smp2p_in 7 0>; interrupt-names = "qcom,wdog", "qcom,err-fatal", "qcom,proxy-unvote", "qcom,err-ready", - "qcom,stop-ack"; + "qcom,stop-ack", + "qcom,shutdown-ack"; /* Outputs to lpass */ qcom,smem-states = <&adsp_smp2p_out 0>; @@ -2478,13 +2480,15 @@ <&cdsp_smp2p_in 0 0>, <&cdsp_smp2p_in 2 0>, <&cdsp_smp2p_in 1 0>, - <&cdsp_smp2p_in 3 0>; + <&cdsp_smp2p_in 3 0>, + <&cdsp_smp2p_in 7 0>; interrupt-names = "qcom,wdog", "qcom,err-fatal", "qcom,proxy-unvote", "qcom,err-ready", - "qcom,stop-ack"; + "qcom,stop-ack", + "qcom,shutdown-ack"; /* Outputs to turing */ qcom,smem-states = <&cdsp_smp2p_out 0>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index fd3cd5e26b428591ab8c8c5d27b5fcea619d42f2..172fc111907f04daa07d7ab802e6a01db952e229 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, 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 @@ -622,13 +622,16 @@ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK_SRC>, <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, - <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>; + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&clock_rpmh RPMH_CXO_CLK>; clock-names = "core_aux_clk", "core_usb_ref_clk_src", "core_usb_ref_clk", "core_usb_pipe_clk", "link_clk", "link_iface_clk", "crypto_clk", "pixel_clk_rcg", "pixel_parent", "pixel1_clk_rcg", "pixel1_parent", - "strm0_pixel_clk", "strm1_pixel_clk"; + "strm0_pixel_clk", "strm1_pixel_clk", + "link_clk_rcg", "xo_clk"; qcom,phy-version = <0x420>; qcom,aux-cfg0-settings = [20 00]; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index f4db2d9f7441245b8b25a1d3837973982aba0ed9..bcc15b5f454eab49bcb1f25ec797f73205d24941 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1736,13 +1737,15 @@ <&adsp_smp2p_in 0 0>, <&adsp_smp2p_in 2 0>, <&adsp_smp2p_in 1 0>, - <&adsp_smp2p_in 3 0>; + <&adsp_smp2p_in 3 0>, + <&adsp_smp2p_in 7 0>; interrupt-names = "qcom,wdog", "qcom,err-fatal", "qcom,proxy-unvote", "qcom,err-ready", - "qcom,stop-ack"; + "qcom,stop-ack", + "qcom,shutdown-ack"; /* Outputs to lpass */ qcom,smem-states = <&adsp_smp2p_out 0>; @@ -1893,13 +1896,15 @@ <&cdsp_smp2p_in 0 0>, <&cdsp_smp2p_in 2 0>, <&cdsp_smp2p_in 1 0>, - <&cdsp_smp2p_in 3 0>; + <&cdsp_smp2p_in 3 0>, + <&cdsp_smp2p_in 7 0>; interrupt-names = "qcom,wdog", "qcom,err-fatal", "qcom,proxy-unvote", "qcom,err-ready", - "qcom,stop-ack"; + "qcom,stop-ack", + "qcom,shutdown-ack"; /* Outputs to turing */ qcom,smem-states = <&cdsp_smp2p_out 0>; @@ -2733,6 +2738,26 @@ qcom,intents = <0x200 20>; }; + qcom,gpr { + compatible = "qcom,gpr"; + qcom,glink-channels = "to_apps"; + qcom,intents = <0x200 20>; + reg = ; + gecko_core { + compatible = "qcom,gecko_core"; + reg = ; + }; + audio-pkt { + compatible = "qcom,audio-pkt"; + qcom,audiopkt-ch-name = "apr_audio_svc"; + reg = ; + }; + q6prm { + compatible = "qcom,q6prm"; + reg = ; + }; + }; + qcom,msm_fastrpc_rpmsg { compatible = "qcom,msm-fastrpc-rpmsg"; qcom,glink-channels = "fastrpcglink-apps-dsp"; diff --git a/arch/arm64/boot/dts/qcom/trinket-sde.dtsi b/arch/arm64/boot/dts/qcom/trinket-sde.dtsi index 880b7857510c57f108d95ba4e09cfa6ff6aedf49..1d06c5eb9ec727b7aded95d9a3574f823b6cd6c5 100644 --- a/arch/arm64/boot/dts/qcom/trinket-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-sde.dtsi @@ -99,9 +99,6 @@ qcom,sde-cdm-off = <0x7a200>; qcom,sde-cdm-size = <0x224>; - - qcom,sde-qdss-off = <0x81a00>; - qcom,sde-dither-off = <0x30e0 0x30e0>; qcom,sde-dither-version = <0x00010000>; qcom,sde-dither-size = <0x20>; diff --git a/arch/arm64/boot/dts/qcom/trinket.dtsi b/arch/arm64/boot/dts/qcom/trinket.dtsi index 2bb87b62d3e8351a6834767400be56c1374961bf..7169990ed365991852b925bd0627adbcecddc1f2 100644 --- a/arch/arm64/boot/dts/qcom/trinket.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket.dtsi @@ -448,12 +448,6 @@ reg = <0 0x46200000 0 0x2d00000>; }; - pil_camera_mem: camera_region@4ab00000 { - compatible = "removed-dma-pool"; - no-map; - reg = <0 0x4ab00000 0 0x500000>; - }; - pil_modem_mem: modem_region@4b000000 { compatible = "removed-dma-pool"; no-map; diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index 71fc12c519731f8f73ace331ad6f4846594752ba..885cd4ea3d3b57f1e5fb059945dabc6732943e61 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -9,6 +9,7 @@ CONFIG_TASK_IO_ACCOUNTING=y CONFIG_PSI=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_RT_GROUP_SCHED=y @@ -150,6 +151,7 @@ CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -194,10 +196,6 @@ CONFIG_NET_CLS_ACT=y CONFIG_VSOCKETS=y CONFIG_VIRTIO_VSOCKETS=y CONFIG_BPF_JIT=y -CONFIG_CAN=y -# CONFIG_CAN_BCM is not set -# CONFIG_CAN_GW is not set -CONFIG_CAN_VCAN=y CONFIG_CFG80211=y # CONFIG_CFG80211_DEFAULT_PS is not set CONFIG_MAC80211=y @@ -218,7 +216,6 @@ CONFIG_UID_SYS_STATS=y CONFIG_SCSI=y # CONFIG_SCSI_PROC_FS is not set CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_VIRTIO=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -229,6 +226,7 @@ CONFIG_DM_VERITY_FEC=y CONFIG_DM_VERITY_AVB=y CONFIG_DM_BOW=y CONFIG_NETDEVICES=y +CONFIG_DUMMY=y CONFIG_NETCONSOLE=y CONFIG_NETCONSOLE_DYNAMIC=y CONFIG_TUN=y @@ -299,7 +297,6 @@ CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_DEV_BUS=y -CONFIG_VIRTIO_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_VIRTIO=y # CONFIG_HW_RANDOM_CAVIUM is not set @@ -368,6 +365,7 @@ CONFIG_HID_SAITEK=y CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SPEEDLINK=y +CONFIG_HID_STEAM=y CONFIG_HID_SUNPLUS=y CONFIG_HID_GREENASIA=y CONFIG_GREENASIA_FF=y @@ -400,7 +398,7 @@ CONFIG_RTC_DRV_PL030=y CONFIG_RTC_DRV_PL031=y CONFIG_VIRTIO_PCI=y # CONFIG_VIRTIO_PCI_LEGACY is not set -CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_PMEM=y CONFIG_VIRTIO_INPUT=y CONFIG_VIRTIO_MMIO=y CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y @@ -415,6 +413,8 @@ CONFIG_MAILBOX=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_LIBNVDIMM=y +# CONFIG_ND_BLK is not set CONFIG_ARM_SCPI_PROTOCOL=y # CONFIG_ARM_SCPI_POWER_DOMAIN is not set CONFIG_EXT4_FS=y @@ -430,6 +430,7 @@ CONFIG_QUOTA=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y diff --git a/arch/arm64/configs/vendor/atoll-perf_defconfig b/arch/arm64/configs/vendor/atoll-perf_defconfig index 2e005fecf38ef0ddbd848e63d026911c153a8194..79f67c9a835014bd06b92d628ec70f587e950f4b 100644 --- a/arch/arm64/configs/vendor/atoll-perf_defconfig +++ b/arch/arm64/configs/vendor/atoll-perf_defconfig @@ -90,6 +90,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y diff --git a/arch/arm64/configs/vendor/atoll_defconfig b/arch/arm64/configs/vendor/atoll_defconfig index 868e40ce5ec036366755b640ea32e2cd2f8fa215..b3b4b1bb63ddbf352318f51d6864dec42b5f5933 100644 --- a/arch/arm64/configs/vendor/atoll_defconfig +++ b/arch/arm64/configs/vendor/atoll_defconfig @@ -96,6 +96,7 @@ CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y diff --git a/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig b/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig index 9b8c8fa371d92e6d125a6e8e62245d3b8a0edc09..eae30c1b4fb02d0536b7f3ce01792cffac453a86 100644 --- a/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig +++ b/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig @@ -435,13 +435,16 @@ CONFIG_IPA_UT=y CONFIG_QCOM_CLK_VIRT=y CONFIG_VIRTIO_CLK=y CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y +CONFIG_QCOM_GVM_IPC=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_VIRTIO=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_QMI_HELPERS=y @@ -455,6 +458,7 @@ CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_GLINK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_MSM_HAB=y CONFIG_QCOM_HGSL_TCSR_SIGNAL=y diff --git a/arch/arm64/configs/vendor/qti-quin-gvm_defconfig b/arch/arm64/configs/vendor/qti-quin-gvm_defconfig index b2efa820a67fa280c1ff9136428f557763c3ea91..1559e097deeb37f8e388461c7702738c1da3b17d 100644 --- a/arch/arm64/configs/vendor/qti-quin-gvm_defconfig +++ b/arch/arm64/configs/vendor/qti-quin-gvm_defconfig @@ -446,13 +446,16 @@ CONFIG_IPA_UT=y CONFIG_QCOM_CLK_VIRT=y CONFIG_VIRTIO_CLK=y CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y +CONFIG_QCOM_GVM_IPC=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_VIRTIO=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_QMI_HELPERS=y @@ -466,6 +469,7 @@ CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_GLINK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_MSM_HAB=y CONFIG_QCOM_HGSL_TCSR_SIGNAL=y diff --git a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig index 71b80351e0773c143259967f661b506497e5f40b..8949cf9519a04b6bf250a465c6720977b04442a7 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig @@ -204,17 +204,6 @@ CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_CAN=y CONFIG_QTI_CAN=y -CONFIG_BT=y -# CONFIG_BT_BREDR is not set -# CONFIG_BT_LE is not set -# CONFIG_BT_DEBUGFS is not set -CONFIG_MSM_BT_POWER=y -CONFIG_CFG80211=y -CONFIG_CFG80211_INTERNAL_REGDB=y -CONFIG_MAC80211=m -CONFIG_MAC80211_RC_MINSTREL_VHT=y -CONFIG_MAC80211_DEBUGFS=y -CONFIG_RFKILL=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_MTD=y @@ -288,6 +277,7 @@ CONFIG_I2C_MSM_V2=y CONFIG_SPI=y CONFIG_SPI_QUP=y CONFIG_SPMI=y +CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y CONFIG_PTP_1588_CLOCK=y @@ -415,6 +405,8 @@ CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_DCC_V2=y +CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y @@ -435,6 +427,7 @@ CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y CONFIG_PWM=y CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y @@ -492,6 +485,7 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_HARDENED_USERCOPY_PAGESPAN=y CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_CMAC=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/vendor/sa2150p-nand_defconfig b/arch/arm64/configs/vendor/sa2150p-nand_defconfig index 0993256a8b2f12f9e0756ea62680926c3d6a09c0..1f8ddc2423f679c30aa8846486f7564be8f6863c 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand_defconfig @@ -210,17 +210,6 @@ CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_CAN=y CONFIG_QTI_CAN=y -CONFIG_BT=y -# CONFIG_BT_BREDR is not set -# CONFIG_BT_LE is not set -# CONFIG_BT_DEBUGFS is not set -CONFIG_MSM_BT_POWER=y -CONFIG_CFG80211=y -CONFIG_CFG80211_INTERNAL_REGDB=y -CONFIG_MAC80211=m -CONFIG_MAC80211_RC_MINSTREL_VHT=y -CONFIG_MAC80211_DEBUGFS=y -CONFIG_RFKILL=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_MTD=y @@ -298,6 +287,7 @@ CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y CONFIG_PTP_1588_CLOCK=y @@ -433,6 +423,8 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y +CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y @@ -452,6 +444,7 @@ CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y CONFIG_PWM=y CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y @@ -542,6 +535,7 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_HARDENED_USERCOPY_PAGESPAN=y CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_CMAC=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/vendor/sa2150p-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-perf_defconfig index 1effd0037e87bff3e7ad7caba4b7e0091bdbb426..8999e9e723b141f13754508eca92f54872de1d49 100644 --- a/arch/arm64/configs/vendor/sa2150p-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-perf_defconfig @@ -249,6 +249,9 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_STMMAC_ETH=y +# CONFIG_DWMAC_GENERIC is not set +# CONFIG_DWMAC_IPQ806X is not set CONFIG_AT803X_PHY=y CONFIG_MICREL_PHY=y CONFIG_PPP=y @@ -290,7 +293,6 @@ CONFIG_SPI_QUP=y CONFIG_SPMI=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y -CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_QCS405=y CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y @@ -415,6 +417,8 @@ CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_DCC_V2=y +CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y diff --git a/arch/arm64/configs/vendor/sa2150p_defconfig b/arch/arm64/configs/vendor/sa2150p_defconfig index 74fdcd58b8167886cffe7e3060bf427b9349d21e..dc423314434cb9ccfc1cec2777f267fc1c5b00a1 100644 --- a/arch/arm64/configs/vendor/sa2150p_defconfig +++ b/arch/arm64/configs/vendor/sa2150p_defconfig @@ -255,6 +255,9 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_STMMAC_ETH=y +# CONFIG_DWMAC_GENERIC is not set +# CONFIG_DWMAC_IPQ806X is not set CONFIG_AT803X_PHY=y CONFIG_MICREL_PHY=y CONFIG_PPP=y @@ -300,7 +303,6 @@ CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y -CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_QCS405=y CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y @@ -433,6 +435,8 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y +CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index ace282a41b0be84a18dfb45b3a4d1ee8b3b4c762..b8c0a33903e4df6095f7f2ad553a1d8020ae2929 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -76,7 +76,6 @@ CONFIG_SETEND_EMULATION=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_KRYO_PMU_WORKAROUND=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y @@ -86,6 +85,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index d796e2fe093ec39d2cd1c1e6b57b4271fd28dbf8..4c1c7996e8b004b3ae49718956372c17593f0ed1 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -81,7 +81,6 @@ CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_KRYO_PMU_WORKAROUND=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y @@ -92,6 +91,7 @@ CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y diff --git a/arch/arm64/configs/vendor/trinket-perf_defconfig b/arch/arm64/configs/vendor/trinket-perf_defconfig index 4ec93eb1019aac2f96c54eacf881070ff5f47946..8b34e9fd3e20433dfc92f16419395e7196253254 100644 --- a/arch/arm64/configs/vendor/trinket-perf_defconfig +++ b/arch/arm64/configs/vendor/trinket-perf_defconfig @@ -89,6 +89,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y @@ -283,6 +284,7 @@ CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y CONFIG_DM_DEFAULT_KEY=y +CONFIG_DM_SNAPSHOT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y diff --git a/arch/arm64/configs/vendor/trinket_defconfig b/arch/arm64/configs/vendor/trinket_defconfig index 54a087e1c4bb0e8ea5e79ac126736ff5042c56dd..714b5cfa7d80e1a8609a10b28b706729a7d893ab 100644 --- a/arch/arm64/configs/vendor/trinket_defconfig +++ b/arch/arm64/configs/vendor/trinket_defconfig @@ -96,6 +96,7 @@ CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y @@ -294,6 +295,7 @@ CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y CONFIG_DM_DEFAULT_KEY=y +CONFIG_DM_SNAPSHOT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index e42c1f0ae6cf7febfccba956ec0eed8ab47f4717..47ba6a57dc457ec536d3e8a5ca4db13f3098852f 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -296,6 +296,11 @@ static inline bool __kvm_cpu_uses_extended_idmap(void) return __cpu_uses_extended_idmap(); } +/* + * Can't use pgd_populate here, because the extended idmap adds an extra level + * above CONFIG_PGTABLE_LEVELS (which is 2 or 3 if we're using the extended + * idmap), and pgd_populate is only available if CONFIG_PGTABLE_LEVELS = 4. + */ static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd, pgd_t *hyp_pgd, pgd_t *merged_hyp_pgd, diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index b670fe3a8b30d0439255c9c807bc8994933a7f67..3cfc64d1060cd1e0d0294a3ad2211761bc064234 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -805,13 +805,6 @@ static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int _ MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK)); } -#ifdef CONFIG_ARM64_VHE -static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused) -{ - return is_kernel_in_hyp_mode(); -} -#endif - static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry, int __unused) { @@ -849,6 +842,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), MIDR_ALL_VERSIONS(MIDR_CORTEX_A72), MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), + { /* sentinel */ } }; char const *str = "kpti command line option"; bool meltdown_safe; @@ -1019,6 +1013,11 @@ static bool has_hw_dbm(const struct arm64_cpu_capabilities *cap, #endif #ifdef CONFIG_ARM64_VHE +static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused) +{ + return is_kernel_in_hyp_mode(); +} + static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused) { /* @@ -1378,9 +1377,9 @@ static void __update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, static void update_cpu_capabilities(u16 scope_mask) { - __update_cpu_capabilities(arm64_features, scope_mask, "detected:"); __update_cpu_capabilities(arm64_errata, scope_mask, "enabling workaround for"); + __update_cpu_capabilities(arm64_features, scope_mask, "detected:"); } static int __enable_cpu_capability(void *arg) @@ -1435,8 +1434,8 @@ __enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps, static void __init enable_cpu_capabilities(u16 scope_mask) { - __enable_cpu_capabilities(arm64_features, scope_mask); __enable_cpu_capabilities(arm64_errata, scope_mask); + __enable_cpu_capabilities(arm64_features, scope_mask); } /* diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index 2757519e53efbc1a5ae6e586db63544b37d18179..95b5f7679e397459bd8ab4ac7e516011c30ad214 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -256,8 +256,7 @@ static int create_safe_exec_page(void *src_start, size_t length, } pte = pte_offset_kernel(pmd, dst_addr); - set_pte(pte, __pte(virt_to_phys((void *)dst) | - pgprot_val(PAGE_KERNEL_EXEC))); + set_pte(pte, pfn_pte(virt_to_pfn(dst), PAGE_KERNEL_EXEC)); /* * Load our new page tables. A strict BBM approach requires that we diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 818ee98e2bf223384bc8ac311a578a423100528e..7060791a7c0d7f93f025d533585bb02cada9fab4 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -652,8 +652,8 @@ static void __init map_kernel(pgd_t *pgd) * entry instead. */ BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); - set_pud(pud_set_fixmap_offset(pgd, FIXADDR_START), - __pud(__pa_symbol(bm_pmd) | PUD_TYPE_TABLE)); + pud_populate(&init_mm, pud_set_fixmap_offset(pgd, FIXADDR_START), + lm_alias(bm_pmd)); pud_clear_fixmap(); } else { BUG(); @@ -1166,7 +1166,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) break; } - set_pmd(pmd, __pmd(__pa(p) | PROT_SECT_NORMAL)); + pmd_set_huge(pmd, __pa(p), __pgprot(PROT_SECT_NORMAL)); } else vmemmap_verify((pte_t *)pmd, node, addr, next); } while (addr = next, addr != end); @@ -1372,35 +1372,35 @@ int __init arch_ioremap_pmd_supported(void) return !IS_ENABLED(CONFIG_ARM64_PTDUMP_DEBUGFS); } -int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot) +int pud_set_huge(pud_t *pudp, phys_addr_t phys, pgprot_t prot) { pgprot_t sect_prot = __pgprot(PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))); pud_t new_pud = pfn_pud(__phys_to_pfn(phys), sect_prot); /* Only allow permission changes for now */ - if (!pgattr_change_is_safe(READ_ONCE(pud_val(*pud)), + if (!pgattr_change_is_safe(READ_ONCE(pud_val(*pudp)), pud_val(new_pud))) return 0; BUG_ON(phys & ~PUD_MASK); - set_pud(pud, new_pud); + set_pud(pudp, new_pud); return 1; } -int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot) +int pmd_set_huge(pmd_t *pmdp, phys_addr_t phys, pgprot_t prot) { pgprot_t sect_prot = __pgprot(PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))); pmd_t new_pmd = pfn_pmd(__phys_to_pfn(phys), sect_prot); /* Only allow permission changes for now */ - if (!pgattr_change_is_safe(READ_ONCE(pmd_val(*pmd)), + if (!pgattr_change_is_safe(READ_ONCE(pmd_val(*pmdp)), pmd_val(new_pmd))) return 0; BUG_ON(phys & ~PMD_MASK); - set_pmd(pmd, new_pmd); + set_pmd(pmdp, new_pmd); return 1; } diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index fb3dfb2a667ee11626cf9c999e5b303fcc9b9c83..d4e283b4f335e28ad924b723791df6066a7c465a 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h @@ -105,7 +105,7 @@ static inline void atomic_##op(int i, atomic_t *v) \ "1: %0 = memw_locked(%1);\n" \ " %0 = "#op "(%0,%2);\n" \ " memw_locked(%1,P3)=%0;\n" \ - " if !P3 jump 1b;\n" \ + " if (!P3) jump 1b;\n" \ : "=&r" (output) \ : "r" (&v->counter), "r" (i) \ : "memory", "p3" \ @@ -121,7 +121,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ "1: %0 = memw_locked(%1);\n" \ " %0 = "#op "(%0,%2);\n" \ " memw_locked(%1,P3)=%0;\n" \ - " if !P3 jump 1b;\n" \ + " if (!P3) jump 1b;\n" \ : "=&r" (output) \ : "r" (&v->counter), "r" (i) \ : "memory", "p3" \ @@ -138,7 +138,7 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ "1: %0 = memw_locked(%2);\n" \ " %1 = "#op "(%0,%3);\n" \ " memw_locked(%2,P3)=%1;\n" \ - " if !P3 jump 1b;\n" \ + " if (!P3) jump 1b;\n" \ : "=&r" (output), "=&r" (val) \ : "r" (&v->counter), "r" (i) \ : "memory", "p3" \ @@ -187,7 +187,7 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) " }" " memw_locked(%2, p3) = %1;" " {" - " if !p3 jump 1b;" + " if (!p3) jump 1b;" " }" "2:" : "=&r" (__oldval), "=&r" (tmp) diff --git a/arch/hexagon/include/asm/bitops.h b/arch/hexagon/include/asm/bitops.h index 2691a1857d203db2522ae178fe744225c71d2da9..634306cda00675b0b172e87ad6162f6bf23df722 100644 --- a/arch/hexagon/include/asm/bitops.h +++ b/arch/hexagon/include/asm/bitops.h @@ -52,7 +52,7 @@ static inline int test_and_clear_bit(int nr, volatile void *addr) "1: R12 = memw_locked(R10);\n" " { P0 = tstbit(R12,R11); R12 = clrbit(R12,R11); }\n" " memw_locked(R10,P1) = R12;\n" - " {if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n" + " {if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n" : "=&r" (oldval) : "r" (addr), "r" (nr) : "r10", "r11", "r12", "p0", "p1", "memory" @@ -76,7 +76,7 @@ static inline int test_and_set_bit(int nr, volatile void *addr) "1: R12 = memw_locked(R10);\n" " { P0 = tstbit(R12,R11); R12 = setbit(R12,R11); }\n" " memw_locked(R10,P1) = R12;\n" - " {if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n" + " {if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n" : "=&r" (oldval) : "r" (addr), "r" (nr) : "r10", "r11", "r12", "p0", "p1", "memory" @@ -102,7 +102,7 @@ static inline int test_and_change_bit(int nr, volatile void *addr) "1: R12 = memw_locked(R10);\n" " { P0 = tstbit(R12,R11); R12 = togglebit(R12,R11); }\n" " memw_locked(R10,P1) = R12;\n" - " {if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n" + " {if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n" : "=&r" (oldval) : "r" (addr), "r" (nr) : "r10", "r11", "r12", "p0", "p1", "memory" @@ -237,7 +237,7 @@ static inline int ffs(int x) int r; asm("{ P0 = cmp.eq(%1,#0); %0 = ct0(%1);}\n" - "{ if P0 %0 = #0; if !P0 %0 = add(%0,#1);}\n" + "{ if (P0) %0 = #0; if (!P0) %0 = add(%0,#1);}\n" : "=&r" (r) : "r" (x) : "p0"); diff --git a/arch/hexagon/include/asm/cmpxchg.h b/arch/hexagon/include/asm/cmpxchg.h index a6e34e2acbbaf6cc07f377db35faa7c744ba23e3..db258424059f4f5ab5257d928bd39e4071fe4a03 100644 --- a/arch/hexagon/include/asm/cmpxchg.h +++ b/arch/hexagon/include/asm/cmpxchg.h @@ -44,7 +44,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, __asm__ __volatile__ ( "1: %0 = memw_locked(%1);\n" /* load into retval */ " memw_locked(%1,P0) = %2;\n" /* store into memory */ - " if !P0 jump 1b;\n" + " if (!P0) jump 1b;\n" : "=&r" (retval) : "r" (ptr), "r" (x) : "memory", "p0" diff --git a/arch/hexagon/include/asm/futex.h b/arch/hexagon/include/asm/futex.h index c889f5993ecd35f1646e06fa1fab846860655ac6..e8e5e47afb377ad697d9b9de2ec0a9bd203c8df6 100644 --- a/arch/hexagon/include/asm/futex.h +++ b/arch/hexagon/include/asm/futex.h @@ -16,7 +16,7 @@ /* For example: %1 = %4 */ \ insn \ "2: memw_locked(%3,p2) = %1;\n" \ - " if !p2 jump 1b;\n" \ + " if (!p2) jump 1b;\n" \ " %1 = #0;\n" \ "3:\n" \ ".section .fixup,\"ax\"\n" \ @@ -84,10 +84,10 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, "1: %1 = memw_locked(%3)\n" " {\n" " p2 = cmp.eq(%1,%4)\n" - " if !p2.new jump:NT 3f\n" + " if (!p2.new) jump:NT 3f\n" " }\n" "2: memw_locked(%3,p2) = %5\n" - " if !p2 jump 1b\n" + " if (!p2) jump 1b\n" "3:\n" ".section .fixup,\"ax\"\n" "4: %0 = #%6\n" diff --git a/arch/hexagon/include/asm/spinlock.h b/arch/hexagon/include/asm/spinlock.h index 53a8d588588787cba2b22202c2ee675fba83e6df..007056263b8eb88fe2591f37efb5b9496113d084 100644 --- a/arch/hexagon/include/asm/spinlock.h +++ b/arch/hexagon/include/asm/spinlock.h @@ -44,9 +44,9 @@ static inline void arch_read_lock(arch_rwlock_t *lock) __asm__ __volatile__( "1: R6 = memw_locked(%0);\n" " { P3 = cmp.ge(R6,#0); R6 = add(R6,#1);}\n" - " { if !P3 jump 1b; }\n" + " { if (!P3) jump 1b; }\n" " memw_locked(%0,P3) = R6;\n" - " { if !P3 jump 1b; }\n" + " { if (!P3) jump 1b; }\n" : : "r" (&lock->lock) : "memory", "r6", "p3" @@ -60,7 +60,7 @@ static inline void arch_read_unlock(arch_rwlock_t *lock) "1: R6 = memw_locked(%0);\n" " R6 = add(R6,#-1);\n" " memw_locked(%0,P3) = R6\n" - " if !P3 jump 1b;\n" + " if (!P3) jump 1b;\n" : : "r" (&lock->lock) : "memory", "r6", "p3" @@ -75,7 +75,7 @@ static inline int arch_read_trylock(arch_rwlock_t *lock) __asm__ __volatile__( " R6 = memw_locked(%1);\n" " { %0 = #0; P3 = cmp.ge(R6,#0); R6 = add(R6,#1);}\n" - " { if !P3 jump 1f; }\n" + " { if (!P3) jump 1f; }\n" " memw_locked(%1,P3) = R6;\n" " { %0 = P3 }\n" "1:\n" @@ -102,9 +102,9 @@ static inline void arch_write_lock(arch_rwlock_t *lock) __asm__ __volatile__( "1: R6 = memw_locked(%0)\n" " { P3 = cmp.eq(R6,#0); R6 = #-1;}\n" - " { if !P3 jump 1b; }\n" + " { if (!P3) jump 1b; }\n" " memw_locked(%0,P3) = R6;\n" - " { if !P3 jump 1b; }\n" + " { if (!P3) jump 1b; }\n" : : "r" (&lock->lock) : "memory", "r6", "p3" @@ -118,7 +118,7 @@ static inline int arch_write_trylock(arch_rwlock_t *lock) __asm__ __volatile__( " R6 = memw_locked(%1)\n" " { %0 = #0; P3 = cmp.eq(R6,#0); R6 = #-1;}\n" - " { if !P3 jump 1f; }\n" + " { if (!P3) jump 1f; }\n" " memw_locked(%1,P3) = R6;\n" " %0 = P3;\n" "1:\n" @@ -141,9 +141,9 @@ static inline void arch_spin_lock(arch_spinlock_t *lock) __asm__ __volatile__( "1: R6 = memw_locked(%0);\n" " P3 = cmp.eq(R6,#0);\n" - " { if !P3 jump 1b; R6 = #1; }\n" + " { if (!P3) jump 1b; R6 = #1; }\n" " memw_locked(%0,P3) = R6;\n" - " { if !P3 jump 1b; }\n" + " { if (!P3) jump 1b; }\n" : : "r" (&lock->lock) : "memory", "r6", "p3" @@ -163,7 +163,7 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock) __asm__ __volatile__( " R6 = memw_locked(%1);\n" " P3 = cmp.eq(R6,#0);\n" - " { if !P3 jump 1f; R6 = #1; %0 = #0; }\n" + " { if (!P3) jump 1f; R6 = #1; %0 = #0; }\n" " memw_locked(%1,P3) = R6;\n" " %0 = P3;\n" "1:\n" diff --git a/arch/hexagon/kernel/stacktrace.c b/arch/hexagon/kernel/stacktrace.c index 41866a06adf7f394c784e2d6703b6aa1665f4ab8..ec4ef682923d970e499b1cd1317f4dc112c69fa3 100644 --- a/arch/hexagon/kernel/stacktrace.c +++ b/arch/hexagon/kernel/stacktrace.c @@ -24,8 +24,6 @@ #include #include -register unsigned long current_frame_pointer asm("r30"); - struct stackframe { unsigned long fp; unsigned long rets; @@ -43,7 +41,7 @@ void save_stack_trace(struct stack_trace *trace) low = (unsigned long)task_stack_page(current); high = low + THREAD_SIZE; - fp = current_frame_pointer; + fp = (unsigned long)__builtin_frame_address(0); while (fp >= low && fp <= (high - sizeof(*frame))) { frame = (struct stackframe *)fp; diff --git a/arch/hexagon/kernel/vm_entry.S b/arch/hexagon/kernel/vm_entry.S index 67c6ccc14770320c21f334b16c13e1c480a99cd7..9f4a73ff720300dd3641e65df84ecb9d501a16fe 100644 --- a/arch/hexagon/kernel/vm_entry.S +++ b/arch/hexagon/kernel/vm_entry.S @@ -382,7 +382,7 @@ ret_from_fork: R26.L = #LO(do_work_pending); R0 = #VM_INT_DISABLE; } - if P0 jump check_work_pending + if (P0) jump check_work_pending { R0 = R25; callr R24 diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c index 2081b8cd5591c6d77385de8594e737c9d421f7be..b9aee983e6f4cda91fcc709abb85471d2f5f4b63 100644 --- a/arch/m68k/amiga/cia.c +++ b/arch/m68k/amiga/cia.c @@ -88,10 +88,19 @@ static irqreturn_t cia_handler(int irq, void *dev_id) struct ciabase *base = dev_id; int mach_irq; unsigned char ints; + unsigned long flags; + /* Interrupts get disabled while the timer irq flag is cleared and + * the timer interrupt serviced. + */ mach_irq = base->cia_irq; + local_irq_save(flags); ints = cia_set_irq(base, CIA_ICR_ALL); amiga_custom.intreq = base->int_mask; + if (ints & 1) + generic_handle_irq(mach_irq); + local_irq_restore(flags); + mach_irq++, ints >>= 1; for (; ints; mach_irq++, ints >>= 1) { if (ints & 1) generic_handle_irq(mach_irq); diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index 3d2b63bedf0589c67cdf0471007157bb913f18ac..56f02ea2c248d844e43fb88a4e3742315d741400 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -142,7 +142,7 @@ struct mfptimerbase { .name = "MFP Timer D" }; -static irqreturn_t mfptimer_handler(int irq, void *dev_id) +static irqreturn_t mfp_timer_d_handler(int irq, void *dev_id) { struct mfptimerbase *base = dev_id; int mach_irq; @@ -344,7 +344,7 @@ void __init atari_init_IRQ(void) st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6; /* request timer D dispatch handler */ - if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED, + if (request_irq(IRQ_MFP_TIMD, mfp_timer_d_handler, IRQF_SHARED, stmfp_base.name, &stmfp_base)) pr_err("Couldn't register %s interrupt\n", stmfp_base.name); diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c index c549b48174ec8342620816d846ea7d492f36d0b1..972181c1fe4b77c64e4bfe0ae5e0bea2737bc846 100644 --- a/arch/m68k/atari/time.c +++ b/arch/m68k/atari/time.c @@ -24,6 +24,18 @@ DEFINE_SPINLOCK(rtc_lock); EXPORT_SYMBOL_GPL(rtc_lock); +static irqreturn_t mfp_timer_c_handler(int irq, void *dev_id) +{ + irq_handler_t timer_routine = dev_id; + unsigned long flags; + + local_irq_save(flags); + timer_routine(0, NULL); + local_irq_restore(flags); + + return IRQ_HANDLED; +} + void __init atari_sched_init(irq_handler_t timer_routine) { @@ -32,7 +44,8 @@ atari_sched_init(irq_handler_t timer_routine) /* start timer C, div = 1:100 */ st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60; /* install interrupt service routine for MFP Timer C */ - if (request_irq(IRQ_MFP_TIMC, timer_routine, 0, "timer", timer_routine)) + if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, 0, "timer", + timer_routine)) pr_err("Couldn't register timer interrupt\n"); } diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c index 2cfff47650407479cae907205df89ea039934a37..0e602c32b246f9de280390295090ae030b9125c9 100644 --- a/arch/m68k/bvme6000/config.c +++ b/arch/m68k/bvme6000/config.c @@ -45,11 +45,6 @@ extern int bvme6000_set_clock_mmss (unsigned long); extern void bvme6000_reset (void); void bvme6000_set_vectors (void); -/* Save tick handler routine pointer, will point to xtime_update() in - * kernel/timer/timekeeping.c, called via bvme6000_process_int() */ - -static irq_handler_t tick_handler; - int __init bvme6000_parse_bootinfo(const struct bi_record *bi) { @@ -159,12 +154,18 @@ irqreturn_t bvme6000_abort_int (int irq, void *dev_id) static irqreturn_t bvme6000_timer_int (int irq, void *dev_id) { + irq_handler_t timer_routine = dev_id; + unsigned long flags; volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE; - unsigned char msr = rtc->msr & 0xc0; + unsigned char msr; + local_irq_save(flags); + msr = rtc->msr & 0xc0; rtc->msr = msr | 0x20; /* Ack the interrupt */ + timer_routine(0, NULL); + local_irq_restore(flags); - return tick_handler(irq, dev_id); + return IRQ_HANDLED; } /* @@ -183,9 +184,8 @@ void bvme6000_sched_init (irq_handler_t timer_routine) rtc->msr = 0; /* Ensure timer registers accessible */ - tick_handler = timer_routine; - if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0, - "timer", bvme6000_timer_int)) + if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0, "timer", + timer_routine)) panic ("Couldn't register timer int"); rtc->t1cr_omr = 0x04; /* Mode 2, ext clk */ diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c index 289d928a46cbe1c2cbcce1f5e94dc9fbd43db331..d30b03ea93a27e39c1ea0637b2aec5198d28841a 100644 --- a/arch/m68k/hp300/time.c +++ b/arch/m68k/hp300/time.c @@ -38,13 +38,19 @@ static irqreturn_t hp300_tick(int irq, void *dev_id) { + irq_handler_t timer_routine = dev_id; + unsigned long flags; unsigned long tmp; - irq_handler_t vector = dev_id; + + local_irq_save(flags); in_8(CLOCKBASE + CLKSR); asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE)); + timer_routine(0, NULL); + local_irq_restore(flags); + /* Turn off the network and SCSI leds */ blinken_leds(0, 0xe0); - return vector(irq, NULL); + return IRQ_HANDLED; } u32 hp300_gettimeoffset(void) diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index 9f59a662ace57dbc4b2dbfb7c0bb006216ec7e0f..863806e6775a8ce6a62a55106d84a681bce49f80 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -54,16 +54,6 @@ static __u8 rbv_clear; static int gIER,gIFR,gBufA,gBufB; -/* - * Timer defs. - */ - -#define TICK_SIZE 10000 -#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */ -#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) -#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) - - /* * On Macs with a genuine VIA chip there is no way to mask an individual slot * interrupt. This limitation also seems to apply to VIA clone logic cores in @@ -278,22 +268,6 @@ void __init via_init(void) } } -/* - * Start the 100 Hz clock - */ - -void __init via_init_clock(irq_handler_t func) -{ - via1[vACR] |= 0x40; - via1[vT1LL] = MAC_CLOCK_LOW; - via1[vT1LH] = MAC_CLOCK_HIGH; - via1[vT1CL] = MAC_CLOCK_LOW; - via1[vT1CH] = MAC_CLOCK_HIGH; - - if (request_irq(IRQ_MAC_TIMER_1, func, 0, "timer", func)) - pr_err("Couldn't register %s interrupt\n", "timer"); -} - /* * Debugging dump, used in various places to see what's going on. */ @@ -321,29 +295,6 @@ void via_debug_dump(void) } } -/* - * This is always executed with interrupts disabled. - * - * TBI: get time offset between scheduling timer ticks - */ - -u32 mac_gettimeoffset(void) -{ - unsigned long ticks, offset = 0; - - /* read VIA1 timer 2 current value */ - ticks = via1[vT1CL] | (via1[vT1CH] << 8); - /* The probability of underflow is less than 2% */ - if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50) - /* Check for pending timer interrupt in VIA1 IFR */ - if (via1[vIFR] & 0x40) offset = TICK_SIZE; - - ticks = MAC_CLOCK_TICK - ticks; - ticks = ticks * 10000L / MAC_CLOCK_TICK; - - return (ticks + offset) * 1000; -} - /* * Flush the L2 cache on Macs that have it by flipping * the system into 24-bit mode for an instant. @@ -447,6 +398,8 @@ void via_nubus_irq_shutdown(int irq) * via6522.c :-), disable/pending masks added. */ +#define VIA_TIMER_1_INT BIT(6) + void via1_irq(struct irq_desc *desc) { int irq_num; @@ -456,6 +409,21 @@ void via1_irq(struct irq_desc *desc) if (!events) return; + irq_num = IRQ_MAC_TIMER_1; + irq_bit = VIA_TIMER_1_INT; + if (events & irq_bit) { + unsigned long flags; + + local_irq_save(flags); + via1[vIFR] = irq_bit; + generic_handle_irq(irq_num); + local_irq_restore(flags); + + events &= ~irq_bit; + if (!events) + return; + } + irq_num = VIA1_SOURCE_BASE; irq_bit = 1; do { @@ -612,3 +580,56 @@ int via2_scsi_drq_pending(void) return via2[gIFR] & (1 << IRQ_IDX(IRQ_MAC_SCSIDRQ)); } EXPORT_SYMBOL(via2_scsi_drq_pending); + +/* timer and clock source */ + +#define VIA_CLOCK_FREQ 783360 /* VIA "phase 2" clock in Hz */ +#define VIA_TIMER_INTERVAL (1000000 / HZ) /* microseconds per jiffy */ +#define VIA_TIMER_CYCLES (VIA_CLOCK_FREQ / HZ) /* clock cycles per jiffy */ + +#define VIA_TC (VIA_TIMER_CYCLES - 2) /* including 0 and -1 */ +#define VIA_TC_LOW (VIA_TC & 0xFF) +#define VIA_TC_HIGH (VIA_TC >> 8) + +void __init via_init_clock(irq_handler_t timer_routine) +{ + if (request_irq(IRQ_MAC_TIMER_1, timer_routine, 0, "timer", NULL)) { + pr_err("Couldn't register %s interrupt\n", "timer"); + return; + } + + via1[vT1LL] = VIA_TC_LOW; + via1[vT1LH] = VIA_TC_HIGH; + via1[vT1CL] = VIA_TC_LOW; + via1[vT1CH] = VIA_TC_HIGH; + via1[vACR] |= 0x40; +} + +u32 mac_gettimeoffset(void) +{ + unsigned long flags; + u8 count_high; + u16 count, offset = 0; + + /* + * Timer counter wrap-around is detected with the timer interrupt flag + * but reading the counter low byte (vT1CL) would reset the flag. + * Also, accessing both counter registers is essentially a data race. + * These problems are avoided by ignoring the low byte. Clock accuracy + * is 256 times worse (error can reach 0.327 ms) but CPU overhead is + * reduced by avoiding slow VIA register accesses. + */ + + local_irq_save(flags); + count_high = via1[vT1CH]; + if (count_high == 0xFF) + count_high = 0; + if (count_high > 0 && (via1[vIFR] & VIA_TIMER_1_INT)) + offset = VIA_TIMER_CYCLES; + local_irq_restore(flags); + + count = count_high << 8; + count = VIA_TIMER_CYCLES - count + offset; + + return ((count * VIA_TIMER_INTERVAL) / VIA_TIMER_CYCLES) * 1000; +} diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index 8778612d1f312d5c2c7e588a8b8828adce68eca6..78ae803c833e1f32c45fdb8d7958e6116eddb0d2 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -46,11 +46,6 @@ extern void mvme147_reset (void); static int bcd2int (unsigned char b); -/* Save tick handler routine pointer, will point to xtime_update() in - * kernel/time/timekeeping.c, called via mvme147_process_int() */ - -irq_handler_t tick_handler; - int __init mvme147_parse_bootinfo(const struct bi_record *bi) { @@ -106,16 +101,23 @@ void __init config_mvme147(void) static irqreturn_t mvme147_timer_int (int irq, void *dev_id) { + irq_handler_t timer_routine = dev_id; + unsigned long flags; + + local_irq_save(flags); m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR; m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1; - return tick_handler(irq, dev_id); + timer_routine(0, NULL); + local_irq_restore(flags); + + return IRQ_HANDLED; } void mvme147_sched_init (irq_handler_t timer_routine) { - tick_handler = timer_routine; - if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1", NULL)) + if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1", + timer_routine)) pr_err("Couldn't register timer interrupt\n"); /* Init the clock with a value */ diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c index 6fa06d4d16bf08d41a56c705dd5699485b0e3516..3116dd576bb3c8b1a8afd59596e4a2f79e35214e 100644 --- a/arch/m68k/mvme16x/config.c +++ b/arch/m68k/mvme16x/config.c @@ -51,11 +51,6 @@ extern void mvme16x_reset (void); int bcd2int (unsigned char b); -/* Save tick handler routine pointer, will point to xtime_update() in - * kernel/time/timekeeping.c, called via mvme16x_process_int() */ - -static irq_handler_t tick_handler; - unsigned short mvme16x_config; EXPORT_SYMBOL(mvme16x_config); @@ -354,8 +349,15 @@ static irqreturn_t mvme16x_abort_int (int irq, void *dev_id) static irqreturn_t mvme16x_timer_int (int irq, void *dev_id) { - *(volatile unsigned char *)0xfff4201b |= 8; - return tick_handler(irq, dev_id); + irq_handler_t timer_routine = dev_id; + unsigned long flags; + + local_irq_save(flags); + *(volatile unsigned char *)0xfff4201b |= 8; + timer_routine(0, NULL); + local_irq_restore(flags); + + return IRQ_HANDLED; } void mvme16x_sched_init (irq_handler_t timer_routine) @@ -363,14 +365,13 @@ void mvme16x_sched_init (irq_handler_t timer_routine) uint16_t brdno = be16_to_cpu(mvme_bdid.brdno); int irq; - tick_handler = timer_routine; /* Using PCCchip2 or MC2 chip tick timer 1 */ *(volatile unsigned long *)0xfff42008 = 0; *(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */ *(volatile unsigned char *)0xfff42017 |= 3; *(volatile unsigned char *)0xfff4201b = 0x16; - if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0, - "timer", mvme16x_timer_int)) + if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0, "timer", + timer_routine)) panic ("Couldn't register timer int"); if (brdno == 0x0162 || brdno == 0x172) diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c index 3e7603202977e715a6afc07e4ca0f3d713e0c3ed..1c696906c159f5acb5d39f773324d93bfa5508b5 100644 --- a/arch/m68k/q40/q40ints.c +++ b/arch/m68k/q40/q40ints.c @@ -127,10 +127,10 @@ void q40_mksound(unsigned int hz, unsigned int ticks) sound_ticks = ticks << 1; } -static irq_handler_t q40_timer_routine; - -static irqreturn_t q40_timer_int (int irq, void * dev) +static irqreturn_t q40_timer_int(int irq, void *dev_id) { + irq_handler_t timer_routine = dev_id; + ql_ticks = ql_ticks ? 0 : 1; if (sound_ticks) { unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL; @@ -139,8 +139,13 @@ static irqreturn_t q40_timer_int (int irq, void * dev) *DAC_RIGHT=sval; } - if (!ql_ticks) - q40_timer_routine(irq, dev); + if (!ql_ticks) { + unsigned long flags; + + local_irq_save(flags); + timer_routine(0, NULL); + local_irq_restore(flags); + } return IRQ_HANDLED; } @@ -148,11 +153,9 @@ void q40_sched_init (irq_handler_t timer_routine) { int timer_irq; - q40_timer_routine = timer_routine; timer_irq = Q40_IRQ_FRAME; - if (request_irq(timer_irq, q40_timer_int, 0, - "timer", q40_timer_int)) + if (request_irq(timer_irq, q40_timer_int, 0, "timer", timer_routine)) panic("Couldn't register timer int"); master_outb(-1, FRAME_CLEAR_REG); diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c index 6bbca30c91884850e45cc07db24b4b17a00b06e5..a5824abb4a39c2f75a42d3ae8a8a93ee038da465 100644 --- a/arch/m68k/sun3/sun3ints.c +++ b/arch/m68k/sun3/sun3ints.c @@ -61,8 +61,10 @@ static irqreturn_t sun3_int7(int irq, void *dev_id) static irqreturn_t sun3_int5(int irq, void *dev_id) { + unsigned long flags; unsigned int cnt; + local_irq_save(flags); #ifdef CONFIG_SUN3 intersil_clear(); #endif @@ -76,6 +78,7 @@ static irqreturn_t sun3_int5(int irq, void *dev_id) cnt = kstat_irqs_cpu(irq, 0); if (!(cnt % 20)) sun3_leds(led_pattern[cnt % 160 / 20]); + local_irq_restore(flags); return IRQ_HANDLED; } diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c index 7a2c53d9f779aff6beb908eedab1a28130ad992d..48b43903253e42f565a6ac917de80137da1548ed 100644 --- a/arch/m68k/sun3x/time.c +++ b/arch/m68k/sun3x/time.c @@ -78,15 +78,19 @@ u32 sun3x_gettimeoffset(void) } #if 0 -static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sun3x_timer_tick(int irq, void *dev_id) { - void (*vector)(int, void *, struct pt_regs *) = dev_id; + irq_handler_t timer_routine = dev_id; + unsigned long flags; - /* Clear the pending interrupt - pulse the enable line low */ - disable_irq(5); - enable_irq(5); + local_irq_save(flags); + /* Clear the pending interrupt - pulse the enable line low */ + disable_irq(5); + enable_irq(5); + timer_routine(0, NULL); + local_irq_restore(flags); - vector(irq, NULL, regs); + return IRQ_HANDLED; } #endif diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile index c69f297fc1df3d29d3ddd9c1147f58a7cbb59847..d89651e538f64042857c63692b7ffc2b3ae35271 100644 --- a/arch/mips/bcm63xx/Makefile +++ b/arch/mips/bcm63xx/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += clk.o cpu.o cs.o gpio.o irq.o nvram.o prom.o reset.o \ - setup.o timer.o dev-dsp.o dev-enet.o dev-flash.o \ - dev-pcmcia.o dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o \ - dev-wdt.o dev-usb-usbd.o + setup.o timer.o dev-enet.o dev-flash.o dev-pcmcia.o \ + dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o dev-wdt.o \ + dev-usb-usbd.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-y += boards/ diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index b2097c0d2ed78b554ab321c6620767d3ccd29f71..36ec3dc2c999a94c9771408f3efc5e3c72972f22 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -289,14 +288,6 @@ static struct board_info __initdata board_96348gw_10 = { .has_pccard = 1, .has_ehci0 = 1, - .has_dsp = 1, - .dsp = { - .gpio_rst = 6, - .gpio_int = 34, - .cs = 2, - .ext_irq = 2, - }, - .leds = { { .name = "adsl-fail", @@ -401,14 +392,6 @@ static struct board_info __initdata board_96348gw = { .has_ohci0 = 1, - .has_dsp = 1, - .dsp = { - .gpio_rst = 6, - .gpio_int = 34, - .ext_irq = 2, - .cs = 2, - }, - .leds = { { .name = "adsl-fail", @@ -898,9 +881,6 @@ int __init board_register_devices(void) if (board.has_usbd) bcm63xx_usbd_register(&board.usbd); - if (board.has_dsp) - bcm63xx_dsp_register(&board.dsp); - /* Generate MAC address for WLAN and register our SPROM, * do this after registering enet devices */ diff --git a/arch/mips/bcm63xx/dev-dsp.c b/arch/mips/bcm63xx/dev-dsp.c deleted file mode 100644 index 5bb5b154c9bd3cb4aec195f3c1e991b6011d8e96..0000000000000000000000000000000000000000 --- a/arch/mips/bcm63xx/dev-dsp.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Broadcom BCM63xx VoIP DSP registration - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2009 Florian Fainelli - */ - -#include -#include -#include - -#include -#include -#include -#include - -static struct resource voip_dsp_resources[] = { - { - .start = -1, /* filled at runtime */ - .end = -1, /* filled at runtime */ - .flags = IORESOURCE_MEM, - }, - { - .start = -1, /* filled at runtime */ - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device bcm63xx_voip_dsp_device = { - .name = "bcm63xx-voip-dsp", - .id = -1, - .num_resources = ARRAY_SIZE(voip_dsp_resources), - .resource = voip_dsp_resources, -}; - -int __init bcm63xx_dsp_register(const struct bcm63xx_dsp_platform_data *pd) -{ - struct bcm63xx_dsp_platform_data *dpd; - u32 val; - - /* Get the memory window */ - val = bcm_mpi_readl(MPI_CSBASE_REG(pd->cs - 1)); - val &= MPI_CSBASE_BASE_MASK; - voip_dsp_resources[0].start = val; - voip_dsp_resources[0].end = val + 0xFFFFFFF; - voip_dsp_resources[1].start = pd->ext_irq; - - /* copy given platform data */ - dpd = bcm63xx_voip_dsp_device.dev.platform_data; - memcpy(dpd, pd, sizeof (*pd)); - - return platform_device_register(&bcm63xx_voip_dsp_device); -} diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index 331b9e0a8072edaabbf1a7ad660df7a9920b3383..baa34e4deb78014394aa7edab2952ccc00e7d428 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -29,6 +29,9 @@ KBUILD_AFLAGS := $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \ -DKERNEL_ENTRY=$(VMLINUX_ENTRY_ADDRESS) +# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. +KCOV_INSTRUMENT := n + # decompressor objects (linked with vmlinuz) vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 57b34257be2bf03826bbf332b4461e834e1f791d..98eb15b0524c45789354458e815fe522d0037172 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -60,21 +60,11 @@ * instruction, so the lower 16 bits must be zero. Should be true on * on any sane architecture; generic code does not use this assumption. */ -extern const unsigned long mips_io_port_base; +extern unsigned long mips_io_port_base; -/* - * Gcc will generate code to load the value of mips_io_port_base after each - * function call which may be fairly wasteful in some cases. So we don't - * play quite by the book. We tell gcc mips_io_port_base is a long variable - * which solves the code generation issue. Now we need to violate the - * aliasing rules a little to make initialization possible and finally we - * will need the barrier() to fight side effects of the aliasing chat. - * This trickery will eventually collapse under gcc's optimizer. Oh well. - */ static inline void set_io_port_base(unsigned long base) { - * (unsigned long *) &mips_io_port_base = base; - barrier(); + mips_io_port_base = base; } /* diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_dsp.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_dsp.h deleted file mode 100644 index 4e4970787371a6f4d035d78d040f196d25c0d486..0000000000000000000000000000000000000000 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_dsp.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __BCM63XX_DSP_H -#define __BCM63XX_DSP_H - -struct bcm63xx_dsp_platform_data { - unsigned gpio_rst; - unsigned gpio_int; - unsigned cs; - unsigned ext_irq; -}; - -int __init bcm63xx_dsp_register(const struct bcm63xx_dsp_platform_data *pd); - -#endif /* __BCM63XX_DSP_H */ diff --git a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h index 5e5b1bc4a32478534f106256309124fc3126c2ee..830f53f28e3f786bc8d2f132e64e330243fbad23 100644 --- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h +++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h @@ -7,7 +7,6 @@ #include #include #include -#include /* * flash mapping @@ -31,7 +30,6 @@ struct board_info { unsigned int has_ohci0:1; unsigned int has_ehci0:1; unsigned int has_usbd:1; - unsigned int has_dsp:1; unsigned int has_uart0:1; unsigned int has_uart1:1; @@ -43,9 +41,6 @@ struct board_info { /* USB config */ struct bcm63xx_usbd_platform_data usbd; - /* DSP config */ - struct bcm63xx_dsp_platform_data dsp; - /* GPIO LEDs */ struct gpio_led leds[5]; diff --git a/arch/mips/kernel/cacheinfo.c b/arch/mips/kernel/cacheinfo.c index 428ef218920398c6162b82e5688ab61dfe311580..3ea95568ece4950908cdd79308d0035568ade367 100644 --- a/arch/mips/kernel/cacheinfo.c +++ b/arch/mips/kernel/cacheinfo.c @@ -61,6 +61,25 @@ static int __init_cache_level(unsigned int cpu) return 0; } +static void fill_cpumask_siblings(int cpu, cpumask_t *cpu_map) +{ + int cpu1; + + for_each_possible_cpu(cpu1) + if (cpus_are_siblings(cpu, cpu1)) + cpumask_set_cpu(cpu1, cpu_map); +} + +static void fill_cpumask_cluster(int cpu, cpumask_t *cpu_map) +{ + int cpu1; + int cluster = cpu_cluster(&cpu_data[cpu]); + + for_each_possible_cpu(cpu1) + if (cpu_cluster(&cpu_data[cpu1]) == cluster) + cpumask_set_cpu(cpu1, cpu_map); +} + static int __populate_cache_leaves(unsigned int cpu) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -68,14 +87,20 @@ static int __populate_cache_leaves(unsigned int cpu) struct cacheinfo *this_leaf = this_cpu_ci->info_list; if (c->icache.waysize) { + /* L1 caches are per core */ + fill_cpumask_siblings(cpu, &this_leaf->shared_cpu_map); populate_cache(dcache, this_leaf, 1, CACHE_TYPE_DATA); + fill_cpumask_siblings(cpu, &this_leaf->shared_cpu_map); populate_cache(icache, this_leaf, 1, CACHE_TYPE_INST); } else { populate_cache(dcache, this_leaf, 1, CACHE_TYPE_UNIFIED); } - if (c->scache.waysize) + if (c->scache.waysize) { + /* L2 cache is per cluster */ + fill_cpumask_cluster(cpu, &this_leaf->shared_cpu_map); populate_cache(scache, this_leaf, 2, CACHE_TYPE_UNIFIED); + } if (c->tcache.waysize) populate_cache(tcache, this_leaf, 3, CACHE_TYPE_UNIFIED); diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 795caa763da32451b4398382928ff063a6158824..05ed4ed411c733ad27310a0a2acb4da1df080f2d 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -75,7 +75,7 @@ static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; * mips_io_port_base is the begin of the address space to which x86 style * I/O ports are mapped. */ -const unsigned long mips_io_port_base = -1; +unsigned long mips_io_port_base = -1; EXPORT_SYMBOL(mips_io_port_base); static struct resource code_resource = { .name = "Kernel code", }; diff --git a/arch/mips/net/ebpf_jit.c b/arch/mips/net/ebpf_jit.c index 42faa95ce66425b55b5632fb9e4fc5ff4c3221ac..57a7a9d68475a3502b37206f27ed8714e076f791 100644 --- a/arch/mips/net/ebpf_jit.c +++ b/arch/mips/net/ebpf_jit.c @@ -612,6 +612,7 @@ static void emit_const_to_reg(struct jit_ctx *ctx, int dst, u64 value) static int emit_bpf_tail_call(struct jit_ctx *ctx, int this_idx) { int off, b_off; + int tcc_reg; ctx->flags |= EBPF_SEEN_TC; /* @@ -624,14 +625,14 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int this_idx) b_off = b_imm(this_idx + 1, ctx); emit_instr(ctx, bne, MIPS_R_AT, MIPS_R_ZERO, b_off); /* - * if (--TCC < 0) + * if (TCC-- < 0) * goto out; */ /* Delay slot */ - emit_instr(ctx, daddiu, MIPS_R_T5, - (ctx->flags & EBPF_TCC_IN_V1) ? MIPS_R_V1 : MIPS_R_S4, -1); + tcc_reg = (ctx->flags & EBPF_TCC_IN_V1) ? MIPS_R_V1 : MIPS_R_S4; + emit_instr(ctx, daddiu, MIPS_R_T5, tcc_reg, -1); b_off = b_imm(this_idx + 1, ctx); - emit_instr(ctx, bltz, MIPS_R_T5, b_off); + emit_instr(ctx, bltz, tcc_reg, b_off); /* * prog = array->ptrs[index]; * if (prog == NULL) diff --git a/arch/nios2/kernel/nios2_ksyms.c b/arch/nios2/kernel/nios2_ksyms.c index bf2f55d10a4d84f6896a70da6993731368708c6b..4e704046a150c164379d42cada3d09d6f6910107 100644 --- a/arch/nios2/kernel/nios2_ksyms.c +++ b/arch/nios2/kernel/nios2_ksyms.c @@ -9,12 +9,20 @@ #include #include +#include +#include + /* string functions */ EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memmove); +/* memory management */ + +EXPORT_SYMBOL(empty_zero_page); +EXPORT_SYMBOL(flush_icache_range); + /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that @@ -31,3 +39,7 @@ DECLARE_EXPORT(__udivsi3); DECLARE_EXPORT(__umoddi3); DECLARE_EXPORT(__umodsi3); DECLARE_EXPORT(__muldi3); +DECLARE_EXPORT(__ucmpdi2); +DECLARE_EXPORT(__lshrdi3); +DECLARE_EXPORT(__ashldi3); +DECLARE_EXPORT(__ashrdi3); diff --git a/arch/parisc/include/asm/cmpxchg.h b/arch/parisc/include/asm/cmpxchg.h index f627c37dad9c92a7beeb277ead459726afcf5dad..ab5c215cf46c3d81a5ef840fe46ffe740174c7ec 100644 --- a/arch/parisc/include/asm/cmpxchg.h +++ b/arch/parisc/include/asm/cmpxchg.h @@ -44,8 +44,14 @@ __xchg(unsigned long x, __volatile__ void *ptr, int size) ** if (((unsigned long)p & 0xf) == 0) ** return __ldcw(p); */ -#define xchg(ptr, x) \ - ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) +#define xchg(ptr, x) \ +({ \ + __typeof__(*(ptr)) __ret; \ + __typeof__(*(ptr)) _x_ = (x); \ + __ret = (__typeof__(*(ptr))) \ + __xchg((unsigned long)_x_, (ptr), sizeof(*(ptr))); \ + __ret; \ +}) /* bug catcher for when unsupported size is used - won't link */ extern void __cmpxchg_called_with_bad_pointer(void); diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 0f04c878113ef297ca1d38aef3062996b2848f19..9c78ef29825723bcd6ceb5f0c7c7ff7221dde366 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -385,7 +385,9 @@ vdso_install: ifeq ($(CONFIG_PPC64),y) $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@ endif +ifdef CONFIG_VDSO32 $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso32 $@ +endif archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi index e1a961f05dcd5b04b640827810cd198ff6fcb753..baa0c503e741b87f89609ca66c907fd5b36ecea7 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi @@ -63,6 +63,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe1000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy0: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi index c288f3c6c6378dc5fd3c20cf1605ecd031013c89..93095600e8086f617b515047a4c70275d1cf88f8 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi @@ -60,6 +60,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xf1000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy6: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi index 94f3e71750124b5c8a58861909d5d017b05262ca..ff4bd38f064599947096249e51149f8a0e43383f 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi @@ -63,6 +63,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe3000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy1: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi index 94a76982d214b7b963d4b66a9f5161793a2b8b55..1fa38ed6f59e269c70a6de0e8ca41d40024bcb62 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi @@ -60,6 +60,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xf3000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy7: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi index b5ff5f71c6b8b01874dd1b436e416409c2ac0759..a8cc9780c0c4225ac48c3fba7ca096089bf1c2f3 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe1000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy0: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi index ee44182c634853566c9740b04631c3564e8bd020..8b8bd70c93823df4ca8fc71574f6e9417c7bf1cb 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe3000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy1: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi index f05f0d775039b53aab57cdcd28fa8ac3ebde3490..619c880b54d8d39202cb58579974992ef2bf919f 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe5000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy2: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi index a9114ec510759e74036766b1ec1dbcaf42bcfa07..d7ebb73a400d06978aaedadd2efd62770159393c 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe7000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy3: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi index 44dd00ac7367fd6a100131eec3b7388741062383..b151d696a0699b24e90a5c290dba6cc41e6acccf 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe9000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy4: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi index 5b1b84b58602fa46e06cebb7be6b390d59372434..adc0ae0013a3ce89f8d1e26bd14a6f6f15af4526 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xeb000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy5: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi index 0e1daaef9e74b8fe2b6f51369a11c66b238e7dfd..435047e0e250e2e95d73d0e3de6b605060beb378 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi @@ -60,6 +60,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xf1000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy14: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi index 68c5ef779266a8692e712a0ddcfa51db0822d945..c098657cca0a7b8330590ef69b129af4b06b8e4d 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi @@ -60,6 +60,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xf3000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy15: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi index 605363cc1117fbf38b334e68a9b21815325cfe74..9d06824815f342ca7b1d30c5e94159da76e936e9 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe1000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy8: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi index 1955dfa136348f12ea29e0c4fdd3abb7438784fe..70e947730c4ba72b715763fb1fe2ddf6c6ef0fec 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe3000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy9: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi index 2c1476454ee01bb81069c325ed7c02c20f70963d..ad96e6529595960f14be688feee58d3e3a6b84e9 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe5000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy10: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi index b8b541ff5fb034e597c427431e15b4e01ed0de26..034bc4b71f7a506a064b37c320beea2bedd0f390 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe7000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy11: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi index 4b2cfddd1b1553bbb34d53a236cd399fb96441b1..93ca23d82b39ba9cfdf0558afe1da18d0518550d 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe9000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy12: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi index 0a52ddf7cc171e6b830bc2707bc0be9d8ac26ee0..23b3117a2fd2a3871627bc34a68e14d0159e52ca 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xeb000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy13: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/include/asm/archrandom.h b/arch/powerpc/include/asm/archrandom.h index 9c63b596e6ce549885dd9bc9b3c4982ccef50f21..a09595f00cabeed16bc0f57ebe13cd798170f434 100644 --- a/arch/powerpc/include/asm/archrandom.h +++ b/arch/powerpc/include/asm/archrandom.h @@ -28,7 +28,7 @@ static inline int arch_get_random_seed_int(unsigned int *v) unsigned long val; int rc; - rc = arch_get_random_long(&val); + rc = arch_get_random_seed_long(&val); if (rc) *v = val; diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c index a8f20e5928e132588a4387b6260ef1884a7a920e..9edb454301336efb69fa8289fc7d2e49242dc0fb 100644 --- a/arch/powerpc/kernel/cacheinfo.c +++ b/arch/powerpc/kernel/cacheinfo.c @@ -865,4 +865,25 @@ void cacheinfo_cpu_offline(unsigned int cpu_id) if (cache) cache_cpu_clear(cache, cpu_id); } + +void cacheinfo_teardown(void) +{ + unsigned int cpu; + + lockdep_assert_cpus_held(); + + for_each_online_cpu(cpu) + cacheinfo_cpu_offline(cpu); +} + +void cacheinfo_rebuild(void) +{ + unsigned int cpu; + + lockdep_assert_cpus_held(); + + for_each_online_cpu(cpu) + cacheinfo_cpu_online(cpu); +} + #endif /* (CONFIG_PPC_PSERIES && CONFIG_SUSPEND) || CONFIG_HOTPLUG_CPU */ diff --git a/arch/powerpc/kernel/cacheinfo.h b/arch/powerpc/kernel/cacheinfo.h index 955f5e999f1b81e8faad5a653f2777b0f65912c3..52bd3fc6642da11329abb3ec465f6709b897a651 100644 --- a/arch/powerpc/kernel/cacheinfo.h +++ b/arch/powerpc/kernel/cacheinfo.h @@ -6,4 +6,8 @@ extern void cacheinfo_cpu_online(unsigned int cpu_id); extern void cacheinfo_cpu_offline(unsigned int cpu_id); +/* Allow migration/suspend to tear down and rebuild the hierarchy. */ +extern void cacheinfo_teardown(void); +extern void cacheinfo_rebuild(void); + #endif /* _PPC_CACHEINFO_H */ diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c index 2357df60de95291f285c3f3a3894915d3c7934fa..7ed2b1b6643cc9da9c826e473a19e1527f29244f 100644 --- a/arch/powerpc/kernel/dt_cpu_ftrs.c +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c @@ -705,8 +705,10 @@ static bool __init cpufeatures_process_feature(struct dt_cpu_feature *f) m = &dt_cpu_feature_match_table[i]; if (!strcmp(f->name, m->name)) { known = true; - if (m->enable(f)) + if (m->enable(f)) { + cur_cpu_spec->cpu_features |= m->cpu_ftr_bit_mask; break; + } pr_info("not enabling: %s (disabled or unsupported by kernel)\n", f->name); @@ -714,17 +716,12 @@ static bool __init cpufeatures_process_feature(struct dt_cpu_feature *f) } } - if (!known && enable_unknown) { - if (!feat_try_enable_unknown(f)) { - pr_info("not enabling: %s (unknown and unsupported by kernel)\n", - f->name); - return false; - } + if (!known && (!enable_unknown || !feat_try_enable_unknown(f))) { + pr_info("not enabling: %s (unknown and unsupported by kernel)\n", + f->name); + return false; } - if (m->cpu_ftr_bit_mask) - cur_cpu_spec->cpu_features |= m->cpu_ftr_bit_mask; - if (known) pr_debug("enabling: %s\n", f->name); else diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 5e44462960213bba8b3955caeb222da7d33b0238..ef6a58838e7ce5777e106f84df2a4f787b1473fe 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -134,7 +134,6 @@ extern void kvm_spapr_tce_release_iommu_group(struct kvm *kvm, continue; kref_put(&stit->kref, kvm_spapr_tce_liobn_put); - return; } } } diff --git a/arch/powerpc/mm/dump_hashpagetable.c b/arch/powerpc/mm/dump_hashpagetable.c index 5c4c93dcff190bf5a4babd9f8a8197aadd27347d..f666d74f05f517059d768cb362e9a95192362169 100644 --- a/arch/powerpc/mm/dump_hashpagetable.c +++ b/arch/powerpc/mm/dump_hashpagetable.c @@ -343,7 +343,7 @@ static unsigned long hpte_find(struct pg_state *st, unsigned long ea, int psize) /* Look in secondary table */ if (slot == -1) - slot = base_hpte_find(ea, psize, true, &v, &r); + slot = base_hpte_find(ea, psize, false, &v, &r); /* No entry found */ if (slot == -1) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 30bf13b72e5e5740560fc562aaeee951040e0a92..3c5abfbbe60efb1ca74cd6ab91449b52875c1c27 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -353,6 +353,14 @@ void __init mem_init(void) BUILD_BUG_ON(MMU_PAGE_COUNT > 16); #ifdef CONFIG_SWIOTLB + /* + * Some platforms (e.g. 85xx) limit DMA-able memory way below + * 4G. We force memblock to bottom-up mode to ensure that the + * memory allocated in swiotlb_init() is DMA-able. + * As it's the last memblock allocation, no need to reset it + * back to to-down. + */ + memblock_set_bottom_up(true); swiotlb_init(0); #endif diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 3188040022c4f7cc942aab9b6590b4727f85b5bc..1c37f08bcddd51f4e33612bd50badb24cfb98b06 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -95,7 +95,7 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs) { return 0; } -static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { } +static inline void perf_get_data_addr(struct perf_event *event, struct pt_regs *regs, u64 *addrp) { } static inline u32 perf_get_misc_flags(struct pt_regs *regs) { return 0; @@ -126,7 +126,7 @@ static unsigned long ebb_switch_in(bool ebb, struct cpu_hw_events *cpuhw) static inline void power_pmu_bhrb_enable(struct perf_event *event) {} static inline void power_pmu_bhrb_disable(struct perf_event *event) {} static void power_pmu_sched_task(struct perf_event_context *ctx, bool sched_in) {} -static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {} +static inline void power_pmu_bhrb_read(struct perf_event *event, struct cpu_hw_events *cpuhw) {} static void pmao_restore_workaround(bool ebb) { } static bool use_ic(u64 event) { @@ -174,7 +174,7 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs) * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC, the * [POWER7P_]MMCRA_SDAR_VALID bit in MMCRA, or the SDAR_VALID bit in SIER. */ -static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) +static inline void perf_get_data_addr(struct perf_event *event, struct pt_regs *regs, u64 *addrp) { unsigned long mmcra = regs->dsisr; bool sdar_valid; @@ -435,7 +435,7 @@ static __u64 power_pmu_bhrb_to(u64 addr) } /* Processing BHRB entries */ -static void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) +static void power_pmu_bhrb_read(struct perf_event *event, struct cpu_hw_events *cpuhw) { u64 val; u64 addr; @@ -463,8 +463,7 @@ static void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) * exporting it to userspace (avoid exposure of regions * where we could have speculative execution) */ - if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN) && - is_kernel_addr(addr)) + if (is_kernel_addr(addr) && perf_allow_kernel(&event->attr) != 0) continue; /* Branches are read most recent first (ie. mfbhrb 0 is @@ -2077,12 +2076,12 @@ static void record_and_restart(struct perf_event *event, unsigned long val, if (event->attr.sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR)) - perf_get_data_addr(regs, &data.addr); + perf_get_data_addr(event, regs, &data.addr); if (event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK) { struct cpu_hw_events *cpuhw; cpuhw = this_cpu_ptr(&cpu_hw_events); - power_pmu_bhrb_read(cpuhw); + power_pmu_bhrb_read(event, cpuhw); data.br_stack = &cpuhw->bhrb_stack; } diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index e2d031a3ec1577f4b28e13733f112af52e09a9cc..961c131a5b7e8cf0c5a234898dd9df7a6528916a 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -1118,6 +1118,23 @@ void __init pnv_pci_init(void) if (!firmware_has_feature(FW_FEATURE_OPAL)) return; +#ifdef CONFIG_PCIEPORTBUS + /* + * On PowerNV PCIe devices are (currently) managed in cooperation + * with firmware. This isn't *strictly* required, but there's enough + * assumptions baked into both firmware and the platform code that + * it's unwise to allow the portbus services to be used. + * + * We need to fix this eventually, but for now set this flag to disable + * the portbus driver. The AER service isn't required since that AER + * events are handled via EEH. The pciehp hotplug driver can't work + * without kernel changes (and portbus binding breaks pnv_php). The + * other services also require some thinking about how we're going + * to integrate them. + */ + pcie_ports_disabled = true; +#endif + /* Look for IODA IO-Hubs. */ for_each_compatible_node(np, NULL, "ibm,ioda-hub") { pnv_pci_init_ioda_hub(np); diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index 9739a055e5f7b61d4886dd4a7be617784fa1bf43..2d3668acb6ef54e52ca21a31aff1367a6cc25c76 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -23,6 +23,7 @@ #include #include #include "pseries.h" +#include "../../kernel/cacheinfo.h" static struct kobject *mobility_kobj; @@ -359,11 +360,20 @@ void post_mobility_fixup(void) */ cpus_read_lock(); + /* + * It's common for the destination firmware to replace cache + * nodes. Release all of the cacheinfo hierarchy's references + * before updating the device tree. + */ + cacheinfo_teardown(); + rc = pseries_devicetree_update(MIGRATION_SCOPE); if (rc) printk(KERN_ERR "Post-mobility device tree update " "failed: %d\n", rc); + cacheinfo_rebuild(); + cpus_read_unlock(); /* Possibly switch to a new RFI flush type */ diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 6293a8768a9123038eeced9e8dc2c4874feed275..bec0952c55958622ca804cd178651a4cf6dbc974 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -189,7 +189,7 @@ config HAVE_MMIOTRACE_SUPPORT config X86_DECODER_SELFTEST bool "x86 instruction decoder selftest" - depends on DEBUG_KERNEL && KPROBES + depends on DEBUG_KERNEL && INSTRUCTION_DECODER depends on !COMPILE_TEST ---help--- Perform x86 instruction decoder selftests at build time. diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 4b3d92a37c801ac00a2ba4cafd08c279bca40897..39fdede523f216042af652ce8098078b2706cec2 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -227,6 +227,11 @@ ENTRY(efi32_stub_entry) leal efi32_config(%ebp), %eax movl %eax, efi_config(%ebp) + /* Disable paging */ + movl %cr0, %eax + btrl $X86_CR0_PG_BIT, %eax + movl %eax, %cr0 + jmp startup_32 ENDPROC(efi32_stub_entry) #endif diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index a21970185ddf26903b07f8f855d08388eb4ad6c5..015003dc8b2168b1efb5e4d0673a5c4781e113a9 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -12,6 +12,7 @@ CONFIG_TASK_IO_ACCOUNTING=y CONFIG_PSI=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y CONFIG_CGROUPS=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y @@ -159,6 +160,7 @@ CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -205,10 +207,6 @@ CONFIG_NET_CLS_ACT=y CONFIG_VSOCKETS=y CONFIG_VIRTIO_VSOCKETS=y CONFIG_BPF_JIT=y -CONFIG_CAN=y -# CONFIG_CAN_BCM is not set -# CONFIG_CAN_GW is not set -CONFIG_CAN_VCAN=y CONFIG_CFG80211=y CONFIG_MAC80211=y CONFIG_RFKILL=y @@ -232,7 +230,6 @@ CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_SPI_ATTRS=y -CONFIG_SCSI_VIRTIO=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -245,6 +242,7 @@ CONFIG_DM_VERITY_FEC=y CONFIG_DM_ANDROID_VERITY=y CONFIG_DM_BOW=y CONFIG_NETDEVICES=y +CONFIG_DUMMY=y CONFIG_NETCONSOLE=y CONFIG_NETCONSOLE_DYNAMIC=y CONFIG_TUN=y @@ -281,7 +279,6 @@ CONFIG_USB_USBNET=y # CONFIG_WLAN_VENDOR_TI is not set # CONFIG_WLAN_VENDOR_ZYDAS is not set # CONFIG_WLAN_VENDOR_QUANTENNA is not set -CONFIG_MAC80211_HWSIM=y CONFIG_VIRT_WIFI=y CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_EVDEV=y @@ -314,7 +311,6 @@ CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_DEV_BUS=y -CONFIG_VIRTIO_CONSOLE=y CONFIG_HW_RANDOM=y # CONFIG_HW_RANDOM_INTEL is not set # CONFIG_HW_RANDOM_AMD is not set @@ -390,6 +386,7 @@ CONFIG_HID_SAITEK=y CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SPEEDLINK=y +CONFIG_HID_STEAM=y CONFIG_HID_SUNPLUS=y CONFIG_HID_GREENASIA=y CONFIG_GREENASIA_FF=y @@ -417,7 +414,7 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_TEST=y CONFIG_SW_SYNC=y CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_PMEM=y CONFIG_VIRTIO_INPUT=y CONFIG_VIRTIO_MMIO=y CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y @@ -430,6 +427,8 @@ CONFIG_ION_SYSTEM_HEAP=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_LIBNVDIMM=y +# CONFIG_ND_BLK is not set # CONFIG_FIRMWARE_MEMMAP is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y @@ -447,6 +446,7 @@ CONFIG_QFMT_V2=y CONFIG_AUTOFS4_FS=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 6ed99de2ddf5994e45388e276eab33eb050e1189..c1f7b3cb84a9bace4767bc227a253953c96a8cb2 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -375,7 +375,7 @@ int x86_add_exclusive(unsigned int what) * LBR and BTS are still mutually exclusive. */ if (x86_pmu.lbr_pt_coexist && what == x86_lbr_exclusive_pt) - return 0; + goto out; if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) { mutex_lock(&pmc_reserve_mutex); @@ -387,6 +387,7 @@ int x86_add_exclusive(unsigned int what) mutex_unlock(&pmc_reserve_mutex); } +out: atomic_inc(&active_events); return 0; @@ -397,11 +398,15 @@ int x86_add_exclusive(unsigned int what) void x86_del_exclusive(unsigned int what) { + atomic_dec(&active_events); + + /* + * See the comment in x86_add_exclusive(). + */ if (x86_pmu.lbr_pt_coexist && what == x86_lbr_exclusive_pt) return; atomic_dec(&x86_pmu.lbr_exclusive[what]); - atomic_dec(&active_events); } int x86_setup_perfctr(struct perf_event *event) diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c index 510f9461407e79109ba41d58d8b2567e1f4b14a0..5a1cd9c3addf795522ce50a15b0204388b518f93 100644 --- a/arch/x86/events/intel/bts.c +++ b/arch/x86/events/intel/bts.c @@ -563,9 +563,11 @@ static int bts_event_init(struct perf_event *event) * Note that the default paranoia setting permits unprivileged * users to profile the kernel. */ - if (event->attr.exclude_kernel && perf_paranoid_kernel() && - !capable(CAP_SYS_ADMIN)) - return -EACCES; + if (event->attr.exclude_kernel) { + ret = perf_allow_kernel(&event->attr); + if (ret) + return ret; + } if (x86_add_exclusive(x86_lbr_exclusive_bts)) return -EBUSY; diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 4a60ed8c44133567e16e2f939418ff7d2f3f21fc..0307e34d2272fb41f74627aa2eaa5c13e72d1318 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3087,8 +3087,9 @@ static int intel_pmu_hw_config(struct perf_event *event) if (x86_pmu.version < 3) return -EINVAL; - if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + ret = perf_allow_cpu(&event->attr); + if (ret) + return ret; event->hw.config |= ARCH_PERFMON_EVENTSEL_ANY; diff --git a/arch/x86/events/intel/p4.c b/arch/x86/events/intel/p4.c index d32c0eed38ca92665d378fa2d0792eed12aad818..4f9ac72968db3f333e6f62001812c5aa831d96d7 100644 --- a/arch/x86/events/intel/p4.c +++ b/arch/x86/events/intel/p4.c @@ -776,8 +776,9 @@ static int p4_validate_raw_event(struct perf_event *event) * the user needs special permissions to be able to use it */ if (p4_ht_active() && p4_event_bind_map[v].shared) { - if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + v = perf_allow_cpu(&event->attr); + if (v) + return v; } /* ESCR EventMask bits may be invalid */ diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c index 665d0f6cd62f76af9ec04b0196ee9c69568c7f0d..3f731d7f04bf65f2726bd7b0349a12c3b995d88c 100644 --- a/arch/x86/kernel/cpu/intel_rdt.c +++ b/arch/x86/kernel/cpu/intel_rdt.c @@ -526,7 +526,7 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r) if (static_branch_unlikely(&rdt_mon_enable_key)) rmdir_mondata_subdir_allrdtgrp(r, d->id); list_del(&d->list); - if (is_mbm_enabled()) + if (r->mon_capable && is_mbm_enabled()) cancel_delayed_work(&d->mbm_over); if (is_llc_occupancy_enabled() && has_busy_rmid(r, d)) { /* diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c index 2dae1b3c42fccee965ce244582f2fcc0e99aab6a..0ec30b2384c052c8299d3d72acf395618f2706f8 100644 --- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c @@ -1107,7 +1107,7 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type, if (rdt_mon_capable) { ret = mongroup_create_dir(rdtgroup_default.kn, - NULL, "mon_groups", + &rdtgroup_default, "mon_groups", &kn_mongrp); if (ret) { dentry = ERR_PTR(ret); @@ -1260,7 +1260,11 @@ static void free_all_child_rdtgrp(struct rdtgroup *rdtgrp) list_for_each_entry_safe(sentry, stmp, head, mon.crdtgrp_list) { free_rmid(sentry->mon.rmid); list_del(&sentry->mon.crdtgrp_list); - kfree(sentry); + + if (atomic_read(&sentry->waitcount) != 0) + sentry->flags = RDT_DELETED; + else + kfree(sentry); } } @@ -1294,7 +1298,11 @@ static void rmdir_all_sub(void) kernfs_remove(rdtgrp->kn); list_del(&rdtgrp->rdtgroup_list); - kfree(rdtgrp); + + if (atomic_read(&rdtgrp->waitcount) != 0) + rdtgrp->flags = RDT_DELETED; + else + kfree(rdtgrp); } /* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */ update_closid_rmid(cpu_online_mask, &rdtgroup_default); @@ -1491,7 +1499,7 @@ static int mkdir_mondata_all(struct kernfs_node *parent_kn, /* * Create the mon_data directory first. */ - ret = mongroup_create_dir(parent_kn, NULL, "mon_data", &kn); + ret = mongroup_create_dir(parent_kn, prgrp, "mon_data", &kn); if (ret) return ret; @@ -1525,7 +1533,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, uint files = 0; int ret; - prdtgrp = rdtgroup_kn_lock_live(prgrp_kn); + prdtgrp = rdtgroup_kn_lock_live(parent_kn); if (!prdtgrp) { ret = -ENODEV; goto out_unlock; @@ -1581,7 +1589,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, kernfs_activate(kn); /* - * The caller unlocks the prgrp_kn upon success. + * The caller unlocks the parent_kn upon success. */ return 0; @@ -1592,7 +1600,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, out_free_rgrp: kfree(rdtgrp); out_unlock: - rdtgroup_kn_unlock(prgrp_kn); + rdtgroup_kn_unlock(parent_kn); return ret; } @@ -1630,7 +1638,7 @@ static int rdtgroup_mkdir_mon(struct kernfs_node *parent_kn, */ list_add_tail(&rdtgrp->mon.crdtgrp_list, &prgrp->mon.crdtgrp_list); - rdtgroup_kn_unlock(prgrp_kn); + rdtgroup_kn_unlock(parent_kn); return ret; } @@ -1667,7 +1675,7 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn, * Create an empty mon_groups directory to hold the subset * of tasks and cpus to monitor. */ - ret = mongroup_create_dir(kn, NULL, "mon_groups", NULL); + ret = mongroup_create_dir(kn, rdtgrp, "mon_groups", NULL); if (ret) goto out_id_free; } @@ -1680,7 +1688,7 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn, out_common_fail: mkdir_rdt_prepare_clean(rdtgrp); out_unlock: - rdtgroup_kn_unlock(prgrp_kn); + rdtgroup_kn_unlock(parent_kn); return ret; } @@ -1792,11 +1800,6 @@ static int rdtgroup_rmdir_ctrl(struct kernfs_node *kn, struct rdtgroup *rdtgrp, closid_free(rdtgrp->closid); free_rmid(rdtgrp->mon.rmid); - /* - * Free all the child monitor group rmids. - */ - free_all_child_rdtgrp(rdtgrp); - list_del(&rdtgrp->rdtgroup_list); /* @@ -1806,6 +1809,11 @@ static int rdtgroup_rmdir_ctrl(struct kernfs_node *kn, struct rdtgroup *rdtgrp, kernfs_get(kn); kernfs_remove(rdtgrp->kn); + /* + * Free all the child monitor group rmids. + */ + free_all_child_rdtgrp(rdtgrp); + return 0; } diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 8e36f249646e25d20bc2bcc04b7a0ccc292e498c..904e18bb38c52d50b9e3913a417984652614b325 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -438,7 +438,7 @@ static void kgdb_disable_hw_debug(struct pt_regs *regs) */ void kgdb_roundup_cpus(unsigned long flags) { - apic->send_IPI_allbutself(APIC_DM_NMI); + apic->send_IPI_allbutself(NMI_VECTOR); } #endif diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 5400a24e1a8c04d515f7e9fde2d399adf1802a8c..c5d7b4ae17cab7c5ec6bb578a0b7ccc13ab82a36 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -651,9 +651,6 @@ void native_flush_tlb_others(const struct cpumask *cpumask, * that UV should be updated so that smp_call_function_many(), * etc, are optimal on UV. */ - unsigned int cpu; - - cpu = smp_processor_id(); cpumask = uv_flush_tlb_others(cpumask, info); if (cpumask) smp_call_function_many(cpumask, flush_tlb_func_remote, diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 5b513ccffde404adbd1ea2929226669f2a282825..cadd7fd290fa8a3bc12151994ae51148864bf040 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -257,10 +257,6 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size) return; } - /* No need to reserve regions that will never be freed. */ - if (md.attribute & EFI_MEMORY_RUNTIME) - return; - size += addr % EFI_PAGE_SIZE; size = round_up(size, EFI_PAGE_SIZE); addr = round_down(addr, EFI_PAGE_SIZE); @@ -290,6 +286,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size) early_memunmap(new, new_size); efi_memmap_install(new_phys, num_entries); + e820__range_update(addr, size, E820_TYPE_RAM, E820_TYPE_RESERVED); + e820__update_table(e820_table); } /* diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 93863c6173e66030909dfba5a958639b16b58e86..959bee9fa9118e37edbfce3a8b3811056de26a74 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -4541,20 +4541,28 @@ static void bfq_prepare_request(struct request *rq, struct bio *bio) spin_unlock_irq(&bfqd->lock); } -static void bfq_idle_slice_timer_body(struct bfq_queue *bfqq) +static void +bfq_idle_slice_timer_body(struct bfq_data *bfqd, struct bfq_queue *bfqq) { - struct bfq_data *bfqd = bfqq->bfqd; enum bfqq_expiration reason; unsigned long flags; spin_lock_irqsave(&bfqd->lock, flags); - bfq_clear_bfqq_wait_request(bfqq); + /* + * Considering that bfqq may be in race, we should firstly check + * whether bfqq is in service before doing something on it. If + * the bfqq in race is not in service, it has already been expired + * through __bfq_bfqq_expire func and its wait_request flags has + * been cleared in __bfq_bfqd_reset_in_service func. + */ if (bfqq != bfqd->in_service_queue) { spin_unlock_irqrestore(&bfqd->lock, flags); return; } + bfq_clear_bfqq_wait_request(bfqq); + if (bfq_bfqq_budget_timeout(bfqq)) /* * Also here the queue can be safely expired @@ -4599,7 +4607,7 @@ static enum hrtimer_restart bfq_idle_slice_timer(struct hrtimer *timer) * early. */ if (bfqq) - bfq_idle_slice_timer_body(bfqq); + bfq_idle_slice_timer_body(bfqd, bfqq); return HRTIMER_NORESTART; } diff --git a/block/blk-map.c b/block/blk-map.c index e31be14da8ea1a7e55277665943a8ae29b417716..f72a3af689b6e79db93972546f0419af0f551bd5 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -152,7 +152,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, return 0; unmap_rq: - __blk_rq_unmap_user(bio); + blk_rq_unmap_user(bio); fail: rq->bio = NULL; return ret; diff --git a/block/blk-merge.c b/block/blk-merge.c index 2c55ed82901d916e57d377fd85764f45b2ffaafc..82dc0c1df283646a8a4e949267938677672aac24 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -309,13 +309,7 @@ void blk_recalc_rq_segments(struct request *rq) void blk_recount_segments(struct request_queue *q, struct bio *bio) { - unsigned short seg_cnt; - - /* estimate segment number by bi_vcnt for non-cloned bio */ - if (bio_flagged(bio, BIO_CLONED)) - seg_cnt = bio_segments(bio); - else - seg_cnt = bio->bi_vcnt; + unsigned short seg_cnt = bio_segments(bio); if (test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags) && (seg_cnt < queue_max_segments(q))) diff --git a/block/blk-settings.c b/block/blk-settings.c index 474b0b95fcd16e0069639bfc264637a601703a99..6c2faaa38cc1e47f41cb81f2e223df82f6db4c4b 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -379,7 +379,7 @@ EXPORT_SYMBOL(blk_queue_max_segment_size); * storage device can address. The default of 512 covers most * hardware. **/ -void blk_queue_logical_block_size(struct request_queue *q, unsigned short size) +void blk_queue_logical_block_size(struct request_queue *q, unsigned int size) { q->limits.logical_block_size = size; diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 422bba808f7374aca4db1c68a6fa867ba43eae01..0679c35adf556f8b7e605d7c73d0a31a55a4acb4 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -139,11 +139,13 @@ void af_alg_release_parent(struct sock *sk) sk = ask->parent; ask = alg_sk(sk); - lock_sock(sk); + local_bh_disable(); + bh_lock_sock(sk); ask->nokey_refcnt -= nokey; if (!last) last = !--ask->refcnt; - release_sock(sk); + bh_unlock_sock(sk); + local_bh_enable(); if (last) sock_put(sk); diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index f8ec3d4ba4a80f8eefed739d9e8a852865a7ac02..1348541da463a0cfe57a20e2fa9ddef432194d96 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -394,7 +394,7 @@ static int pcrypt_sysfs_add(struct padata_instance *pinst, const char *name) int ret; pinst->kobj.kset = pcrypt_kset; - ret = kobject_add(&pinst->kobj, NULL, name); + ret = kobject_add(&pinst->kobj, NULL, "%s", name); if (!ret) kobject_uevent(&pinst->kobj, KOBJ_ADD); @@ -505,11 +505,12 @@ static int __init pcrypt_init(void) static void __exit pcrypt_exit(void) { + crypto_unregister_template(&pcrypt_tmpl); + pcrypt_fini_padata(&pencrypt); pcrypt_fini_padata(&pdecrypt); kset_unregister(pcrypt_kset); - crypto_unregister_template(&pcrypt_tmpl); } module_init(pcrypt_init); diff --git a/crypto/tgr192.c b/crypto/tgr192.c index 321bc6ff2a9d1ff714b3f27e49b68f0d48ce17e0..904c8444aa0a210c6a14757b96bf0b8db48fcebf 100644 --- a/crypto/tgr192.c +++ b/crypto/tgr192.c @@ -25,8 +25,9 @@ #include #include #include -#include #include +#include +#include #define TGR192_DIGEST_SIZE 24 #define TGR160_DIGEST_SIZE 20 @@ -468,10 +469,9 @@ static void tgr192_transform(struct tgr192_ctx *tctx, const u8 * data) u64 a, b, c, aa, bb, cc; u64 x[8]; int i; - const __le64 *ptr = (const __le64 *)data; for (i = 0; i < 8; i++) - x[i] = le64_to_cpu(ptr[i]); + x[i] = get_unaligned_le64(data + i * sizeof(__le64)); /* save */ a = aa = tctx->a; diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 05fb821c255872bbf7949392e7a255273e546ee4..7e91575496b6703939270362b57311a50370e399 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1980,7 +1980,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw, offset = to_interleave_offset(offset, mmio); writeq(cmd, mmio->addr.base + offset); - nvdimm_flush(nfit_blk->nd_region); + nvdimm_flush(nfit_blk->nd_region, NULL); if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH) readq(mmio->addr.base + offset); @@ -2029,7 +2029,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, } if (rw) - nvdimm_flush(nfit_blk->nd_region); + nvdimm_flush(nfit_blk->nd_region, NULL); rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0; return rc; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index cda9a0b5bdaaa2c9783f460c8c8a1594e55cb1ae..7473ff46de66c00eba6cfdb744c175012cbddac8 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -191,7 +191,6 @@ struct ata_port_operations ahci_pmp_retry_srst_ops = { EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops); static bool ahci_em_messages __read_mostly = true; -EXPORT_SYMBOL_GPL(ahci_em_messages); module_param(ahci_em_messages, bool, 0444); /* add other LED protocol types when they become supported */ MODULE_PARM_DESC(ahci_em_messages, diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index ce47eb17901d02a7af0ccce0efa24c95218f510c..a106d15f6def0b907a4b217f6b289f044793db7a 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -372,7 +372,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, here = (eni_vcc->descr+skip) & (eni_vcc->words-1); dma[j++] = (here << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT) | MID_DT_JK; - j++; + dma[j++] = 0; } here = (eni_vcc->descr+size+skip) & (eni_vcc->words-1); if (!eff) size += skip; @@ -445,7 +445,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, if (size != eff) { dma[j++] = (here << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT) | MID_DT_JK; - j++; + dma[j++] = 0; } if (!j || j > 2*RX_DMA_BUF) { printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n"); diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 6b6368a565261b5037d5d5f83899a9d664671222..0e449ee11ac7f7fe71bd75bc6b5e6e80b5609299 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -927,6 +927,7 @@ static int fs_open(struct atm_vcc *atm_vcc) } if (!to) { printk ("No more free channels for FS50..\n"); + kfree(vcc); return -EBUSY; } vcc->channo = dev->channo; @@ -937,6 +938,7 @@ static int fs_open(struct atm_vcc *atm_vcc) if (((DO_DIRECTION(rxtp) && dev->atm_vccs[vcc->channo])) || ( DO_DIRECTION(txtp) && test_bit (vcc->channo, dev->tx_inuse))) { printk ("Channel is in use for FS155.\n"); + kfree(vcc); return -EBUSY; } } @@ -950,6 +952,7 @@ static int fs_open(struct atm_vcc *atm_vcc) tc, sizeof (struct fs_transmit_config)); if (!tc) { fs_dprintk (FS_DEBUG_OPEN, "fs: can't alloc transmit_config.\n"); + kfree(vcc); return -ENOMEM; } diff --git a/drivers/base/core.c b/drivers/base/core.c index 3f81c64037885643c93cc00ae6de353d5ef54934..8d6659a7248816cf15a8d9bae264e250e4163b20 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -180,11 +180,20 @@ struct device_link *device_link_add(struct device *consumer, struct device *supplier, u32 flags) { struct device_link *link; + bool rpm_put_supplier = false; if (!consumer || !supplier || ((flags & DL_FLAG_STATELESS) && (flags & DL_FLAG_AUTOREMOVE))) return NULL; + if (flags & DL_FLAG_PM_RUNTIME && flags & DL_FLAG_RPM_ACTIVE) { + if (pm_runtime_get_sync(supplier) < 0) { + pm_runtime_put_noidle(supplier); + return NULL; + } + rpm_put_supplier = true; + } + device_links_write_lock(); device_pm_lock(); @@ -209,13 +218,8 @@ struct device_link *device_link_add(struct device *consumer, if (flags & DL_FLAG_PM_RUNTIME) { if (flags & DL_FLAG_RPM_ACTIVE) { - if (pm_runtime_get_sync(supplier) < 0) { - pm_runtime_put_noidle(supplier); - kfree(link); - link = NULL; - goto out; - } link->rpm_active = true; + rpm_put_supplier = false; } pm_runtime_new_link(consumer); /* @@ -286,6 +290,10 @@ struct device_link *device_link_add(struct device *consumer, out: device_pm_unlock(); device_links_write_unlock(); + + if (rpm_put_supplier) + pm_runtime_put(supplier); + return link; } EXPORT_SYMBOL_GPL(device_link_add); diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 08541979c86deb360f8dea54ee318aece997c205..3ccbf5e0eefc2b42afb85d6823b4277d137b2e29 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -957,7 +957,7 @@ EXPORT_SYMBOL_GPL(pm_system_wakeup); void pm_system_cancel_wakeup(void) { - atomic_dec(&pm_abort_suspend); + atomic_dec_if_positive(&pm_abort_suspend); } void pm_wakeup_clear(bool reset) diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index f499a469e66d08d7dfcb50e123c82fc920f32ea9..12b2cc9a3fbe8a1050133582e7f553b599fbcbbf 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -78,7 +78,7 @@ static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u16 device, u8 address) v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD); } - v = BCMA_CORE_PCI_MDIODATA_START; + v |= BCMA_CORE_PCI_MDIODATA_START; v |= BCMA_CORE_PCI_MDIODATA_READ; v |= BCMA_CORE_PCI_MDIODATA_TA; @@ -121,7 +121,7 @@ static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u16 device, v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD); } - v = BCMA_CORE_PCI_MDIODATA_START; + v |= BCMA_CORE_PCI_MDIODATA_START; v |= BCMA_CORE_PCI_MDIODATA_WRITE; v |= BCMA_CORE_PCI_MDIODATA_TA; v |= data; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 7ea13b5497fdcae5f34d6fa9346874c950c90a27..b998e3abca7abc107185adde145e20e65d1c72e5 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -334,6 +334,8 @@ static int drbd_thread_setup(void *arg) thi->name[0], resource->name); + allow_kernel_signal(DRBD_SIGKILL); + allow_kernel_signal(SIGXCPU); restart: retval = thi->function(thi); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 32ac5f551e55f22cdc4c14b7321007cfd939156b..e6887714fe0a8501235168cd22c5adcbf29635af 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1115,8 +1115,8 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity, if (!VDEV_IS_EXTENDED(info->vdevice)) { err = xen_translate_vdev(info->vdevice, &minor, &offset); if (err) - return err; - nr_parts = PARTS_PER_DISK; + return err; + nr_parts = PARTS_PER_DISK; } else { minor = BLKIF_MINOR_EXT(info->vdevice); nr_parts = PARTS_PER_EXT_DISK; diff --git a/drivers/bus/mhi/controllers/mhi_qcom.c b/drivers/bus/mhi/controllers/mhi_qcom.c index 81a7ee7964879d9a28e1bc7ddea0190bc5f7e4b8..26811368e6c3387f492db4f12d6b29b5d731fcd7 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_qcom.c @@ -33,13 +33,16 @@ struct firmware_info { }; static const struct firmware_info firmware_table[] = { - {.dev_id = 0x308, .fw_image = "sdx65m/sbl1.mbn"}, - {.dev_id = 0x307, .fw_image = "sdx60m/sbl1.mbn"}, - {.dev_id = 0x306, .fw_image = "sdx55m/sbl1.mbn"}, + {.dev_id = 0x308, .fw_image = "sdx65m/sbl1.mbn", + .edl_image = "sdx65m/edl.mbn"}, + {.dev_id = 0x307, .fw_image = "sdx60m/sbl1.mbn", + .edl_image = "sdx60m/edl.mbn"}, + {.dev_id = 0x306, .fw_image = "sdx55m/sbl1.mbn", + .edl_image = "sdx55m/edl.mbn"}, {.dev_id = 0x305, .fw_image = "sdx50m/sbl1.mbn"}, {.dev_id = 0x304, .fw_image = "sbl.mbn", .edl_image = "edl.mbn"}, /* default, set to debug.mbn */ - {.fw_image = "debug.mbn"}, + {.fw_image = "debug.mbn", .edl_image = "debug.mbn"}, }; static int debug_mode; diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index 1d3261855a8157e31ca8cd5ac150c40b563483c9..3efe2ef28298fd194d4731d25f3765a468e6f4a8 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -752,6 +752,8 @@ struct mhi_bus { /* default MHI timeout */ #define MHI_TIMEOUT_MS (1000) +#define MHI_FORCE_WAKE_DELAY_US (100) + extern struct mhi_bus mhi_bus; struct mhi_controller *find_mhi_controller_by_name(const char *name); diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 1ae24eba776993bc109c37319ee7bace01469b84..550d0effa98d49ee83a5046d7825000a16a8b187 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -404,35 +404,42 @@ void mhi_pm_m1_transition(struct mhi_controller *mhi_cntrl) enum MHI_PM_STATE state; write_lock_irq(&mhi_cntrl->pm_lock); + /* Just check if we are racing with device_wake assertion */ + if (atomic_read(&mhi_cntrl->dev_wake)) + MHI_VERB("M2 transition request post dev_wake:%d\n", + atomic_read(&mhi_cntrl->dev_wake)); + /* if it fails, means we transition to M3 */ state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_M2); - if (state == MHI_PM_M2) { - MHI_VERB("Entered M2 State\n"); - mhi_set_mhi_state(mhi_cntrl, MHI_STATE_M2); - mhi_cntrl->dev_state = MHI_STATE_M2; - mhi_cntrl->M2++; - - write_unlock_irq(&mhi_cntrl->pm_lock); - wake_up_all(&mhi_cntrl->state_event); - - /* transfer pending, exit M2 immediately */ - if (unlikely(atomic_read(&mhi_cntrl->pending_pkts) || - atomic_read(&mhi_cntrl->dev_wake))) { - MHI_VERB( - "Exiting M2 Immediately, pending_pkts:%d dev_wake:%d\n", - atomic_read(&mhi_cntrl->pending_pkts), - atomic_read(&mhi_cntrl->dev_wake)); - read_lock_bh(&mhi_cntrl->pm_lock); - mhi_cntrl->wake_get(mhi_cntrl, true); - mhi_cntrl->wake_put(mhi_cntrl, true); - read_unlock_bh(&mhi_cntrl->pm_lock); - } else { - mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, - MHI_CB_IDLE); - } - } else { + if (state != MHI_PM_M2) { + /* Nothing to be done, handle M3 transition later */ write_unlock_irq(&mhi_cntrl->pm_lock); + return; } + + MHI_VERB("Entered M2 State\n"); + mhi_set_mhi_state(mhi_cntrl, MHI_STATE_M2); + mhi_cntrl->dev_state = MHI_STATE_M2; + mhi_cntrl->M2++; + + write_unlock_irq(&mhi_cntrl->pm_lock); + wake_up_all(&mhi_cntrl->state_event); + + /* transfer pending, exit M2 immediately */ + if (unlikely(atomic_read(&mhi_cntrl->pending_pkts) || + atomic_read(&mhi_cntrl->dev_wake))) { + MHI_VERB( + "Exiting M2 Immediately, pending_pkts:%d dev_wake:%d\n", + atomic_read(&mhi_cntrl->pending_pkts), + atomic_read(&mhi_cntrl->dev_wake)); + read_lock_bh(&mhi_cntrl->pm_lock); + mhi_cntrl->wake_get(mhi_cntrl, true); + mhi_cntrl->wake_put(mhi_cntrl, true); + read_unlock_bh(&mhi_cntrl->pm_lock); + return; + } + + mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, MHI_CB_IDLE); } int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl) @@ -1580,6 +1587,57 @@ int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote) } EXPORT_SYMBOL(mhi_device_get_sync); +int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev, int timeout_us) +{ + struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; + + read_lock_bh(&mhi_cntrl->pm_lock); + if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { + read_unlock_bh(&mhi_cntrl->pm_lock); + return -EIO; + } + + mhi_cntrl->wake_get(mhi_cntrl, true); + read_unlock_bh(&mhi_cntrl->pm_lock); + + atomic_inc(&mhi_dev->dev_vote); + pm_wakeup_hard_event(&mhi_cntrl->mhi_dev->dev); + mhi_cntrl->runtime_get(mhi_cntrl, mhi_cntrl->priv_data); + + /* Return if client doesn't want us to wait */ + if (!timeout_us) { + if (mhi_cntrl->pm_state != MHI_PM_M0) + MHI_ERR("Return without waiting for M0\n"); + + mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); + return 0; + } + + while (mhi_cntrl->pm_state != MHI_PM_M0 && + !MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) && + timeout_us > 0) { + udelay(MHI_FORCE_WAKE_DELAY_US); + timeout_us -= MHI_FORCE_WAKE_DELAY_US; + } + + if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) || timeout_us <= 0) { + MHI_ERR("Did not enter M0 state, cur_state:%s pm_state:%s\n", + TO_MHI_STATE_STR(mhi_cntrl->dev_state), + to_mhi_pm_state_str(mhi_cntrl->pm_state)); + read_lock_bh(&mhi_cntrl->pm_lock); + mhi_cntrl->wake_put(mhi_cntrl, false); + read_unlock_bh(&mhi_cntrl->pm_lock); + atomic_dec(&mhi_dev->dev_vote); + mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); + return -ETIMEDOUT; + } + + mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); + + return 0; +} +EXPORT_SYMBOL(mhi_device_get_sync_atomic); + void mhi_device_put(struct mhi_device *mhi_dev, int vote) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index e92667284635a3adc4b7c203dd3ceb0e65234523..b92228b9851d68c3d75cf5a8525d86a928978c65 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -609,7 +609,7 @@ config MSM_FASTCVPD config MSM_ADSPRPC tristate "QTI ADSP RPC driver" - depends on QCOM_GLINK + depends on QCOM_GLINK || RPMSG_QCOM_SMD help Provides a communication mechanism that allows for clients to make remote method invocations across processor boundary to diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index c3823ec9bf853e9d16aa258508f7ed6ada5984e3..8ed94351e897238c09a4da1a056d6fcc29a66829 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -4002,6 +4002,92 @@ static int fastrpc_cb_probe(struct device *dev) return err; } + +static int fastrpc_cb_legacy_probe(struct device *dev) +{ + struct fastrpc_channel_ctx *chan; + struct fastrpc_session_ctx *first_sess = NULL, *sess = NULL; + const char *name; + unsigned int *sids = NULL, sids_size = 0; + int err = 0, ret = 0, i; + + unsigned int start = 0x80000000; + + VERIFY(err, NULL != (name = of_get_property(dev->of_node, + "label", NULL))); + if (err) + goto bail; + + for (i = 0; i < NUM_CHANNELS; i++) { + if (!gcinfo[i].name) + continue; + if (!strcmp(name, gcinfo[i].name)) + break; + } + VERIFY(err, i < NUM_CHANNELS); + if (err) + goto bail; + + chan = &gcinfo[i]; + VERIFY(err, chan->sesscount < NUM_SESSIONS); + if (err) + goto bail; + + first_sess = &chan->session[chan->sesscount]; + + VERIFY(err, NULL != of_get_property(dev->of_node, + "sids", &sids_size)); + if (err) + goto bail; + + VERIFY(err, NULL != (sids = kzalloc(sids_size, GFP_KERNEL))); + if (err) + goto bail; + ret = of_property_read_u32_array(dev->of_node, "sids", sids, + sids_size/sizeof(unsigned int)); + if (ret) + goto bail; + + VERIFY(err, !IS_ERR_OR_NULL(first_sess->smmu.mapping = + arm_iommu_create_mapping(&platform_bus_type, + start, 0x78000000))); + if (err) + goto bail; + + VERIFY(err, !arm_iommu_attach_device(dev, first_sess->smmu.mapping)); + if (err) { + pr_err("adsprpc: %s: attaching iommu device failed for %s with err %d", + __func__, dev_name(dev), err); + goto bail; + } + + + for (i = 0; i < sids_size/sizeof(unsigned int); i++) { + VERIFY(err, chan->sesscount < NUM_SESSIONS); + if (err) + goto bail; + sess = &chan->session[chan->sesscount]; + sess->smmu.cb = sids[i]; + sess->smmu.dev = dev; + sess->smmu.dev_name = dev_name(dev); + sess->smmu.mapping = first_sess->smmu.mapping; + sess->smmu.enabled = 1; + sess->used = 0; + sess->smmu.coherent = false; + sess->smmu.secure = false; + chan->sesscount++; + if (!sess->smmu.dev->dma_parms) + sess->smmu.dev->dma_parms = devm_kzalloc(sess->smmu.dev, + sizeof(*sess->smmu.dev->dma_parms), GFP_KERNEL); + dma_set_max_seg_size(sess->smmu.dev, DMA_BIT_MASK(32)); + dma_set_seg_boundary(sess->smmu.dev, + (unsigned long)DMA_BIT_MASK(64)); + } +bail: + kfree(sids); + return err; +} + static void init_secure_vmid_list(struct device *dev, char *prop_name, struct secure_vm *destvm) { @@ -4097,6 +4183,10 @@ static int fastrpc_probe(struct platform_device *pdev) "qcom,msm-fastrpc-compute-cb")) return fastrpc_cb_probe(dev); + if (of_device_is_compatible(dev->of_node, + "qcom,msm-fastrpc-legacy-compute-cb")) + return fastrpc_cb_legacy_probe(dev); + if (of_device_is_compatible(dev->of_node, "qcom,msm-adsprpc-mem-region")) { me->dev = dev; @@ -4291,7 +4381,7 @@ static struct platform_driver fastrpc_driver = { static const struct rpmsg_device_id fastrpc_rpmsg_match[] = { { FASTRPC_GLINK_GUID }, - { }, + { FASTRPC_SMD_GUID }, }; static const struct of_device_id fastrpc_rpmsg_of_match[] = { diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 8629e3e288864d1029308cfa47c6d0409256ec36..9b953e6b7b5c1b9e0558dd1bc8cb83f8931ba9b6 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -4290,7 +4290,7 @@ static void diag_debug_init(void) * to be logged to IPC */ diag_debug_mask = DIAG_DEBUG_PERIPHERALS | DIAG_DEBUG_DCI | - DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE; + DIAG_DEBUG_MHI | DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE; } #else static void diag_debug_init(void) diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c index 754a53a4e22932678fa5753c975a2f0ca17b9f35..f8f4425df428be2eafe63b3e9f95d9280afa64da 100644 --- a/drivers/char/diag/diagfwd_bridge.c +++ b/drivers/char/diag/diagfwd_bridge.c @@ -87,7 +87,7 @@ static int diagfwd_bridge_mux_write_done(unsigned char *buf, int len, return -EINVAL; ch = &bridge_info[buf_ctx]; if (ch->dev_ops && ch->dev_ops->fwd_complete) { - DIAG_LOG(DIAG_DEBUG_MHI, + DIAG_LOG(DIAG_DEBUG_BRIDGE, "Write done completion received for buf %pK len:%d\n", buf, len); ch->dev_ops->fwd_complete(ch->ctxt, buf, len, 0); diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index 404f265beb2a85253e91af7b9ed7c4c527afcdb9..a5c3832f46f3af21879bea13810c5f2919932207 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, 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 @@ -149,9 +149,12 @@ static void mhi_buf_tbl_remove(struct diag_mhi_info *mhi_info, int type, list_del(&item->link); if (type == TYPE_MHI_READ_CH) { DIAG_LOG(DIAG_DEBUG_MHI, - "Callback received on buffer:%pK from mhi\n", buf); + "Freeing read channel buffer: %pK\n", buf); diagmem_free(driver, item->buf, mhi_info->mempool); } + DIAG_LOG(DIAG_DEBUG_MHI, + "Removing %s channel item entry from table: %pK\n", + mhi_info->name, buf); kfree(item); found = 1; } @@ -189,7 +192,7 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) &mhi_info->read_done_list, link) { if (tp->buf == buf) { DIAG_LOG(DIAG_DEBUG_MHI, - "buffer:%pK removed from table for ch:%s\n", + "Read buffer:%pK removed from table for ch:%s\n", buf, mhi_info->name); list_del(&tp->link); kfree(tp); @@ -211,6 +214,9 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) item = list_entry(start, struct diag_mhi_buf_tbl_t, link); list_del(&item->link); + DIAG_LOG(DIAG_DEBUG_MHI, + "Write buffer %pK removed from table for ch: %s\n", + buf, mhi_info->name); diag_remote_dev_write_done(mhi_info->dev_id, item->buf, item->len, mhi_info->id); kfree(item); @@ -237,6 +243,9 @@ static int __mhi_close(struct diag_mhi_info *mhi_info, int close_flag) if (close_flag == CLOSE_CHANNELS) { mutex_lock(&mhi_info->ch_mutex); + DIAG_LOG(DIAG_DEBUG_MHI, + "diag: %s mhi channel closed, calling mhi unprepare\n", + mhi_info->name); mhi_unprepare_from_transfer(mhi_info->mhi_dev); mutex_unlock(&mhi_info->ch_mutex); } @@ -252,8 +261,11 @@ static int mhi_close(int id) return -EINVAL; } - if (!diag_mhi[id].enabled) + if (!diag_mhi[id].enabled) { + pr_err("diag: %s: mhi channel with index: %d is not enabled\n", + __func__, id); return -ENODEV; + } /* * This function is called whenever the channel needs to be closed * explicitly by Diag. Close both the read and write channels (denoted @@ -286,9 +298,16 @@ static int __mhi_open(struct diag_mhi_info *mhi_info, int open_flag) return -ENODEV; if (open_flag == OPEN_CHANNELS) { if ((atomic_read(&(mhi_info->read_ch.opened))) && - (atomic_read(&(mhi_info->write_ch.opened)))) + (atomic_read(&(mhi_info->write_ch.opened)))) { + DIAG_LOG(DIAG_DEBUG_MHI, + "Read and write channel already open: %s\n", + mhi_info->name); return 0; + } mutex_lock(&mhi_info->ch_mutex); + DIAG_LOG(DIAG_DEBUG_MHI, + "Prepare mhi for transfer on port: %s\n", + mhi_info->name); err = mhi_prepare_for_transfer(mhi_info->mhi_dev); mutex_unlock(&mhi_info->ch_mutex); if (err) { @@ -298,9 +317,9 @@ static int __mhi_open(struct diag_mhi_info *mhi_info, int open_flag) } atomic_set(&mhi_info->read_ch.opened, 1); atomic_set(&mhi_info->write_ch.opened, 1); - DIAG_LOG(DIAG_DEBUG_BRIDGE, - "opened mhi read/write channel, port: %d\n", - mhi_info->id); + DIAG_LOG(DIAG_DEBUG_MHI, + "opened mhi read/write channel, port: %s\n", + mhi_info->name); } else if (open_flag == CHANNELS_OPENED) { if (!atomic_read(&(mhi_info->read_ch.opened)) || !atomic_read(&(mhi_info->write_ch.opened))) { @@ -387,7 +406,7 @@ static void mhi_read_done_work_fn(struct work_struct *work) spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags); if (!buf) break; - DIAG_LOG(DIAG_DEBUG_BRIDGE, + DIAG_LOG(DIAG_DEBUG_MHI, "read from mhi port %d buf %pK len:%d\n", mhi_info->id, buf, len); /* @@ -453,7 +472,7 @@ static void mhi_read_work_fn(struct work_struct *work) goto fail; } - DIAG_LOG(DIAG_DEBUG_BRIDGE, + DIAG_LOG(DIAG_DEBUG_MHI, "queueing a read buf %pK, ch: %s\n", buf, mhi_info->name); @@ -525,6 +544,8 @@ static int mhi_write(int id, unsigned char *buf, int len, int ctxt) spin_unlock_irqrestore(&ch->lock, flags); goto fail; } + DIAG_LOG(DIAG_DEBUG_MHI, "diag: queueing a write buf %pK, ch: %s\n", + buf, diag_mhi[id].name); err = mhi_queue_transfer(diag_mhi[id].mhi_dev, DMA_TO_DEVICE, buf, len, mhi_flags); @@ -602,7 +623,7 @@ static void diag_mhi_read_cb(struct mhi_device *mhi_dev, spin_lock_irqsave(&mhi_info->read_ch.lock, flags); tp = kmalloc(sizeof(*tp), GFP_ATOMIC); if (!tp) { - DIAG_LOG(DIAG_DEBUG_BRIDGE, + DIAG_LOG(DIAG_DEBUG_MHI, "no mem for list\n"); spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags); return; @@ -611,7 +632,7 @@ static void diag_mhi_read_cb(struct mhi_device *mhi_dev, &mhi_info->read_ch.buf_tbl, link) { if (item->buf == buf) { DIAG_LOG(DIAG_DEBUG_MHI, - "Callback received on buffer:%pK from mhi\n", + "Read callback received on buffer:%pK from mhi\n", buf); tp->buf = buf; tp->len = result->bytes_xferd; @@ -651,6 +672,9 @@ static void diag_mhi_write_cb(struct mhi_device *mhi_dev, __func__); return; } + DIAG_LOG(DIAG_DEBUG_MHI, + "Write callback received on buffer:%pK from mhi\n", + buf); mhi_buf_tbl_remove(mhi_info, TYPE_MHI_WRITE_CH, buf, result->bytes_xferd); diag_remote_dev_write_done(mhi_info->dev_id, buf, @@ -670,6 +694,11 @@ static void diag_mhi_remove(struct mhi_device *mhi_dev) return; if (!mhi_info->enabled) return; + + DIAG_LOG(DIAG_DEBUG_MHI, + "Remove called on mhi channel: %s\n", + mhi_info->name); + __mhi_close(mhi_info, CHANNELS_CLOSED); spin_lock_irqsave(&mhi_info->lock, flags); mhi_info->enabled = 0; @@ -684,11 +713,11 @@ static int diag_mhi_probe(struct mhi_device *mhi_dev, unsigned long flags; struct diag_mhi_info *mhi_info = &diag_mhi[index]; - DIAG_LOG(DIAG_DEBUG_BRIDGE, + DIAG_LOG(DIAG_DEBUG_MHI, "received probe for %d\n", index); diag_mhi[index].mhi_dev = mhi_dev; - DIAG_LOG(DIAG_DEBUG_BRIDGE, + DIAG_LOG(DIAG_DEBUG_MHI, "diag: mhi device is ready to open\n"); spin_lock_irqsave(&mhi_info->lock, flags); mhi_info->enabled = 1; @@ -758,7 +787,7 @@ int diag_mhi_init(void) i, err); goto fail; } - DIAG_LOG(DIAG_DEBUG_BRIDGE, "mhi port %d is initailzed\n", i); + DIAG_LOG(DIAG_DEBUG_MHI, "mhi port %d is initailzed\n", i); } return 0; diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 67549ce88cc94251ad43e40074c7156f2736ea79..774748497acedf2da7d3d195b57d29fe485cf94f 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -18,10 +18,11 @@ #include #include #include +#include struct ttyprintk_port { struct tty_port port; - struct mutex port_write_mutex; + spinlock_t spinlock; }; static struct ttyprintk_port tpk_port; @@ -100,11 +101,12 @@ static int tpk_open(struct tty_struct *tty, struct file *filp) static void tpk_close(struct tty_struct *tty, struct file *filp) { struct ttyprintk_port *tpkp = tty->driver_data; + unsigned long flags; - mutex_lock(&tpkp->port_write_mutex); + spin_lock_irqsave(&tpkp->spinlock, flags); /* flush tpk_printk buffer */ tpk_printk(NULL, 0); - mutex_unlock(&tpkp->port_write_mutex); + spin_unlock_irqrestore(&tpkp->spinlock, flags); tty_port_close(&tpkp->port, tty, filp); } @@ -116,13 +118,14 @@ static int tpk_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct ttyprintk_port *tpkp = tty->driver_data; + unsigned long flags; int ret; /* exclusive use of tpk_printk within this tty */ - mutex_lock(&tpkp->port_write_mutex); + spin_lock_irqsave(&tpkp->spinlock, flags); ret = tpk_printk(buf, count); - mutex_unlock(&tpkp->port_write_mutex); + spin_unlock_irqrestore(&tpkp->spinlock, flags); return ret; } @@ -172,7 +175,7 @@ static int __init ttyprintk_init(void) { int ret = -ENOMEM; - mutex_init(&tpk_port.port_write_mutex); + spin_lock_init(&tpk_port.spinlock); ttyprintk_driver = tty_alloc_driver(1, TTY_DRIVER_RESET_TERMIOS | diff --git a/drivers/char/virtio_fastrpc.c b/drivers/char/virtio_fastrpc.c index 7a6de1fc4592013caa8750f2a2e81fff526a0701..845acd8c1d6cfb3f3a83058194bb510ab3135ee1 100644 --- a/drivers/char/virtio_fastrpc.c +++ b/drivers/char/virtio_fastrpc.c @@ -61,7 +61,6 @@ #define DEBUGFS_SIZE 3072 #define PID_SIZE 10 #define UL_SIZE 25 -#define FASTRPC_STATIC_HANDLE_KERNEL 1 #define VIRTIO_FASTRPC_CMD_OPEN 1 #define VIRTIO_FASTRPC_CMD_CLOSE 2 @@ -98,6 +97,33 @@ memmove((dst), (src), (size));\ } while (0) +#define PERF_KEYS \ + "count:flush:map:copy:rpmsg:getargs:putargs:invalidate:invoke:tid:ptr" +#define FASTRPC_STATIC_HANDLE_KERNEL 1 +#define FASTRPC_STATIC_HANDLE_LISTENER 3 +#define FASTRPC_STATIC_HANDLE_MAX 20 + +#define PERF_END (void)0 + +#define PERF(enb, cnt, ff) \ + {\ + struct timespec startT = {0};\ + int64_t *counter = cnt;\ + if (enb && counter) {\ + getnstimeofday(&startT);\ + } \ + ff ;\ + if (enb && counter) {\ + *counter += getnstimediff(&startT);\ + } \ + } + +#define GET_COUNTER(perf_ptr, offset) \ + (perf_ptr != NULL ?\ + (((offset >= 0) && (offset < PERF_KEY_MAX)) ?\ + (int64_t *)(perf_ptr + offset)\ + : (int64_t *)NULL) : (int64_t *)NULL) + struct virt_msg_hdr { u32 pid; /* GVM pid */ u32 tid; /* GVM tid */ @@ -181,9 +207,37 @@ struct fastrpc_apps { struct virt_fastrpc_msg *msgtable[FASTRPC_MSG_MAX]; }; +enum fastrpc_perfkeys { + PERF_COUNT = 0, + PERF_FLUSH = 1, + PERF_MAP = 2, + PERF_COPY = 3, + PERF_LINK = 4, + PERF_GETARGS = 5, + PERF_PUTARGS = 6, + PERF_INVARGS = 7, + PERF_INVOKE = 8, + PERF_KEY_MAX = 9, +}; + +struct fastrpc_perf { + int64_t count; + int64_t flush; + int64_t map; + int64_t copy; + int64_t link; + int64_t getargs; + int64_t putargs; + int64_t invargs; + int64_t invoke; + int64_t tid; + struct hlist_node hn; +}; + struct fastrpc_file { spinlock_t hlock; struct hlist_head maps; + struct hlist_head perf; struct hlist_head remote_bufs; uint32_t mode; uint32_t profile; @@ -195,6 +249,7 @@ struct fastrpc_file { int dsp_proc_init; struct fastrpc_apps *apps; struct dentry *debugfs_file; + struct mutex perf_mutex; struct mutex map_mutex; /* Identifies the device (MINOR_NUM_DEV / MINOR_NUM_SECURE_DEV) */ int dev_minor; @@ -242,6 +297,45 @@ static inline int64_t getnstimediff(struct timespec *start) return ns; } +static inline int64_t *getperfcounter(struct fastrpc_file *fl, int key) +{ + int err = 0; + int64_t *val = NULL; + struct fastrpc_perf *perf = NULL, *fperf = NULL; + struct hlist_node *n = NULL; + + VERIFY(err, !IS_ERR_OR_NULL(fl)); + if (err) + goto bail; + + mutex_lock(&fl->perf_mutex); + hlist_for_each_entry_safe(perf, n, &fl->perf, hn) { + if (perf->tid == current->pid) { + fperf = perf; + break; + } + } + + if (IS_ERR_OR_NULL(fperf)) { + fperf = kzalloc(sizeof(*fperf), GFP_KERNEL); + + VERIFY(err, !IS_ERR_OR_NULL(fperf)); + if (err) { + mutex_unlock(&fl->perf_mutex); + kfree(fperf); + goto bail; + } + + fperf->tid = current->pid; + hlist_add_head(&fperf->hn, &fl->perf); + } + + val = ((int64_t *)fperf) + key; + mutex_unlock(&fl->perf_mutex); +bail: + return val; +} + static void *get_a_tx_buf(void) { struct fastrpc_apps *me = &gfa; @@ -486,6 +580,11 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, struct fastrpc_mmap **maps; size_t copylen = 0, size = 0; char *payload; + struct timespec invoket = {0}; + int64_t *perf_counter = getperfcounter(fl, PERF_COUNT); + + if (fl->profile) + getnstimeofday(&invoket); bufs = REMOTE_SCALARS_LENGTH(invoke->sc); size = bufs * sizeof(*lpra) + bufs * sizeof(*fds) @@ -508,6 +607,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, fds = NULL; } + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_MAP), /* calculate len required for copying */ for (i = 0; i < inbufs + outbufs; i++) { size_t len = lpra[i].buf.len; @@ -530,6 +630,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, if (i < inbufs) outbufs_offset += len; } + PERF_END); size = bufs * sizeof(*rpra) + copylen + sizeof(*vmsg); msg = virt_alloc_msg(size); if (!msg) @@ -551,6 +652,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, rpra = (struct virt_fastrpc_buf *)vmsg->pra; payload = (char *)&rpra[bufs]; + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_COPY), for (i = 0; i < inbufs + outbufs; i++) { size_t len = lpra[i].buf.len; struct sg_table *table; @@ -582,7 +684,16 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, payload += len; } } + PERF_END); + if (fl->profile) { + int64_t *count = GET_COUNTER(perf_counter, PERF_GETARGS); + + if (count) + *count += getnstimediff(&invoket); + } + + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_LINK), sg_init_one(sg, vmsg, size); mutex_lock(&me->lock); @@ -594,6 +705,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, virtqueue_kick(me->svq); mutex_unlock(&me->lock); + PERF_END); wait_for_completion(&msg->work); @@ -605,6 +717,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, rpra = (struct virt_fastrpc_buf *)rsp->pra; payload = (char *)&rpra[bufs] + outbufs_offset; + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_PUTARGS), for (i = inbufs; i < inbufs + outbufs; i++) { if (!maps[i]) { K_COPY_TO_USER(err, kernel, lpra[i].buf.pv, @@ -619,6 +732,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, } payload += rpra[i].len; } + PERF_END); bail: if (rsp) { sg_init_one(sg, rsp, me->buf_size); @@ -651,8 +765,11 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, int domain = fl->domain; int handles, err = 0; struct timespec invoket = {0}; + int64_t *perf_counter = getperfcounter(fl, PERF_COUNT); + + if (fl->profile) + getnstimeofday(&invoket); - getnstimeofday(&invoket); if (!kernel) { VERIFY(err, invoke->handle != FASTRPC_STATIC_HANDLE_KERNEL); if (err) { @@ -679,6 +796,20 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, } err = virt_fastrpc_invoke(fl, kernel, inv); + if (fl->profile) { + if (invoke->handle != FASTRPC_STATIC_HANDLE_LISTENER) { + int64_t *count = GET_COUNTER(perf_counter, PERF_INVOKE); + + if (count) + *count += getnstimediff(&invoket); + } + if (invoke->handle > FASTRPC_STATIC_HANDLE_MAX) { + int64_t *count = GET_COUNTER(perf_counter, PERF_COUNT); + + if (count) + *count = *count + 1; + } + } bail: return err; } @@ -703,6 +834,8 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, if (fl) { len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "\n%s %d\n", " CHANNEL =", fl->domain); + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %9s %d\n", "profile", ":", fl->profile); } if (len > DEBUGFS_SIZE) @@ -931,6 +1064,7 @@ static int fastrpc_open(struct inode *inode, struct file *filp) spin_lock_init(&fl->hlock); INIT_HLIST_HEAD(&fl->maps); + INIT_HLIST_HEAD(&fl->perf); INIT_HLIST_HEAD(&fl->remote_bufs); fl->tgid = current->tgid; fl->apps = me; @@ -943,12 +1077,14 @@ static int fastrpc_open(struct inode *inode, struct file *filp) fl->dsp_proc_init = 0; filp->private_data = fl; mutex_init(&fl->map_mutex); + mutex_init(&fl->perf_mutex); return 0; } static int fastrpc_file_free(struct fastrpc_file *fl) { struct fastrpc_mmap *map = NULL, *lmap = NULL; + struct fastrpc_perf *perf = NULL, *fperf = NULL; if (!fl) return 0; @@ -975,6 +1111,21 @@ static int fastrpc_file_free(struct fastrpc_file *fl) } while (lmap); mutex_unlock(&fl->map_mutex); + mutex_lock(&fl->perf_mutex); + do { + struct hlist_node *pn = NULL; + + fperf = NULL; + hlist_for_each_entry_safe(perf, pn, &fl->perf, hn) { + hlist_del_init(&perf->hn); + fperf = perf; + break; + } + kfree(fperf); + } while (fperf); + mutex_unlock(&fl->perf_mutex); + mutex_destroy(&fl->perf_mutex); + fastrpc_remote_buf_list_free(fl); mutex_destroy(&fl->map_mutex); kfree(fl); @@ -1736,8 +1887,7 @@ static long fastrpc_ioctl(struct file *file, unsigned int ioctl_num, fl->mode = (uint32_t)ioctl_param; break; case FASTRPC_MODE_PROFILE: - err = -ENOTTY; - dev_err(me->dev, "profile mode is not supported\n"); + fl->profile = (uint32_t)ioctl_param; break; case FASTRPC_MODE_SESSION: err = -ENOTTY; @@ -1749,8 +1899,43 @@ static long fastrpc_ioctl(struct file *file, unsigned int ioctl_num, } break; case FASTRPC_IOCTL_GETPERF: - err = -ENOTTY; - dev_err(me->dev, "get perf is not supported\n"); + K_COPY_FROM_USER(err, 0, &p.perf, + param, sizeof(p.perf)); + if (err) + goto bail; + p.perf.numkeys = sizeof(struct fastrpc_perf)/sizeof(int64_t); + if (p.perf.keys) { + char *keys = PERF_KEYS; + + K_COPY_TO_USER(err, 0, (void *)p.perf.keys, + keys, strlen(keys)+1); + if (err) + goto bail; + } + if (p.perf.data) { + struct fastrpc_perf *perf = NULL, *fperf = NULL; + struct hlist_node *n = NULL; + + mutex_lock(&fl->perf_mutex); + hlist_for_each_entry_safe(perf, n, &fl->perf, hn) { + if (perf->tid == current->pid) { + fperf = perf; + break; + } + } + + mutex_unlock(&fl->perf_mutex); + + if (fperf) { + K_COPY_TO_USER(err, 0, + (void *)p.perf.data, fperf, + sizeof(*fperf) - + sizeof(struct hlist_node)); + } + } + K_COPY_TO_USER(err, 0, param, &p.perf, sizeof(p.perf)); + if (err) + goto bail; break; case FASTRPC_IOCTL_CONTROL: K_COPY_FROM_USER(err, 0, &p.cp, param, diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c index 727ed8e1bb726fd424f97427507abe6f46fe84a9..8e4581004695c44f11ea66250773c60720f4bbb8 100644 --- a/drivers/clk/clk-highbank.c +++ b/drivers/clk/clk-highbank.c @@ -293,6 +293,7 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk /* Map system registers */ srnp = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); hb_clk->reg = of_iomap(srnp, 0); + of_node_put(srnp); BUG_ON(!hb_clk->reg); hb_clk->reg += reg; diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 1a292519d84f258336d06b5bbac9e27b2013678a..999a90a1660926594c14126e4fd38d72301ff51d 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -1382,6 +1382,7 @@ static void __init clockgen_init(struct device_node *np) pr_err("%s: Couldn't map %pOF regs\n", __func__, guts); } + of_node_put(guts); } } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f5a48671389b301ceeb717b24c50f71e948fbe1f..5d5e1be282dbac0c1842d93c1dce42360da0f6c4 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3684,11 +3684,17 @@ static int __clk_core_init(struct clk_core *core) if (core->flags & CLK_IS_CRITICAL) { unsigned long flags; - clk_core_prepare(core); + ret = clk_core_prepare(core); + if (ret) + goto out; flags = clk_enable_lock(); - clk_core_enable(core); + ret = clk_core_enable(core); clk_enable_unlock(flags); + if (ret) { + clk_core_unprepare(core); + goto out; + } } /* @@ -4109,6 +4115,7 @@ static int clk_add_and_print_opp(struct clk_hw *hw, unsigned long rate, int uv, int n) { struct clk_core *core = hw->core; + unsigned long rrate; int j, ret = 0; for (j = 0; j < count; j++) { @@ -4119,8 +4126,11 @@ static int clk_add_and_print_opp(struct clk_hw *hw, return ret; } - if (n == 0 || n == core->num_rate_max - 1 || - rate == clk_hw_round_rate(hw, INT_MAX)) + clk_prepare_lock(); + rrate = clk_hw_round_rate(hw, INT_MAX); + clk_prepare_unlock(); + + if (n == 0 || n == core->num_rate_max - 1 || rate == rrate) pr_info("%s: set OPP pair(%lu Hz: %u uV) on %s\n", core->name, rate, uv, dev_name(device_list[j])); @@ -4175,7 +4185,9 @@ static void clk_populate_clock_opp_table(struct device_node *np, } for (n = 0; ; n++) { + clk_prepare_lock(); rrate = clk_hw_round_rate(hw, rate + 1); + clk_prepare_unlock(); if (!rrate) { pr_err("clk_round_rate failed for %s\n", core->name); diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index 8eb93eb2f857398f68e470d8d13e9937eecaedb5..e0547654cb7bdbf0fcdbbc83967ceb9c686a2b99 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -431,6 +431,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); anatop_base = base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); /* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */ if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) { diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index e6d389e333d7d15bdb30cde8d2db45abc1706f3b..baa07553a0ddc40a7bca57a46f55afa8ac82eafb 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -164,6 +164,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop"); base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 0ac9b30c8b90618c8dfe81be4fc69f52b3931c56..9f5e5b9d4a25a48f133a98b35e91019371ee8f20 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -416,6 +416,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop"); base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); clks[IMX7D_PLL_ARM_MAIN_SRC] = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel)); clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel)); diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 6dae54325a91ddb32bb733b9d7d5cf48d0ecc023..a334667c450a1edf446e301e6be13b375a64053d 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -203,6 +203,7 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop"); anatop_base = of_iomap(np, 0); BUG_ON(!anatop_base); + of_node_put(np); np = ccm_node; ccm_base = of_iomap(np, 0); diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index d083b860f08333ad1caf8082664efdeaf1e0099d..10689d8cd3867024b6e83ec4fd37fcd694090cb7 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -134,7 +134,7 @@ static DEFINE_SPINLOCK(ssp3_lock); static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"}; static DEFINE_SPINLOCK(timer_lock); -static const char *timer_parent_names[] = {"clk32", "vctcxo_2", "vctcxo_4", "vctcxo"}; +static const char *timer_parent_names[] = {"clk32", "vctcxo_4", "vctcxo_2", "vctcxo"}; static DEFINE_SPINLOCK(reset_lock); diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c index 2c7c1085f88300ca84ac529831876af25376a047..8fdfa97900cd86e15863beb62be4a288cad9549f 100644 --- a/drivers/clk/mvebu/armada-370.c +++ b/drivers/clk/mvebu/armada-370.c @@ -177,8 +177,10 @@ static void __init a370_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &a370_coreclks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, a370_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init); diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c index 0ec44ae9a2a2676ea383925d3841cffa0dd93a67..df529982adc972868e90b7cb4f39392244f4397d 100644 --- a/drivers/clk/mvebu/armada-xp.c +++ b/drivers/clk/mvebu/armada-xp.c @@ -228,7 +228,9 @@ static void __init axp_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &axp_coreclks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, axp_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init); diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c index 59fad9546c847946d71bd8348dcff615f936e0e4..5f258c9bb68bfc72a830d8ac56e428e75ccc19e0 100644 --- a/drivers/clk/mvebu/dove.c +++ b/drivers/clk/mvebu/dove.c @@ -190,10 +190,14 @@ static void __init dove_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &dove_coreclks); - if (ddnp) + if (ddnp) { dove_divider_clk_init(ddnp); + of_node_put(ddnp); + } - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, dove_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init); diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index a2a8d614039da91a1b3f99272aa98e5952b79037..890ebf623261b78d237881eb39a51c51e9074a73 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c @@ -333,6 +333,8 @@ static void __init kirkwood_clk_init(struct device_node *np) if (cgnp) { mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc); + + of_node_put(cgnp); } } CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", diff --git a/drivers/clk/mvebu/mv98dx3236.c b/drivers/clk/mvebu/mv98dx3236.c index 6e203af73cac1dff2fd409c7700a02376186085a..c8a0d03d2cd60c78d416cd57e2a0be3de5999f54 100644 --- a/drivers/clk/mvebu/mv98dx3236.c +++ b/drivers/clk/mvebu/mv98dx3236.c @@ -174,7 +174,9 @@ static void __init mv98dx3236_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &mv98dx3236_core_clocks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", mv98dx3236_clk_init); diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index ecae059fdff6af1e61d6f129782e60aac2599ab4..7b0db60cda9f74ec8712ca606dbe112fa9c3db7b 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -688,3 +688,11 @@ config SDM_DEBUGCC_429W Support for the debug clock controller on Qualcomm Technologies, Inc SDM429W devices. Say Y if you want to support the clock measurement functionality. + +config CLOCK_CPU_SDM + bool "CPU SDM Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the cpu clock controller on SDM based devices(e.g. SDM429). + Say Y if you want to support CPU clock scaling using + CPUfreq drivers for dynamic power management. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 4c1779de5a597d2a6c27d94c4f7a3212a2e05f0f..8fe6d4e11a5acf40292039ed8a60db38d556bff8 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_CLOCK_CPU_OSM) += clk-cpu-osm.o obj-$(CONFIG_CLOCK_CPU_OSM_660) += clk-cpu-osm-660.o obj-$(CONFIG_CLOCK_CPU_QCS405) += clk-cpu-qcs405.o +obj-$(CONFIG_CLOCK_CPU_SDM) += clk-cpu-sdm.o obj-$(CONFIG_CLOCK_CPU_SDXPRAIRIE) += clk-cpu-sdxprairie.o obj-$(CONFIG_DEBUGCC_SDXPRAIRIE) += debugcc-sdxprairie.o obj-$(CONFIG_GCC_SDXPRAIRIE) += gcc-sdxprairie.o diff --git a/drivers/clk/qcom/clk-cpu-sdm.c b/drivers/clk/qcom/clk-cpu-sdm.c new file mode 100644 index 0000000000000000000000000000000000000000..d3d47609e8dbcee2d347fbfebe1c97af43374d1f --- /dev/null +++ b/drivers/clk/qcom/clk-cpu-sdm.c @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk-pll.h" +#include "clk-debug.h" +#include "clk-rcg.h" +#include "clk-regmap-mux-div.h" +#include "common.h" +#include "vdd-level-cpu.h" + +#define to_clk_regmap_mux_div(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_regmap_mux_div, clkr) + +static DEFINE_VDD_REGULATORS(vdd_hf_pll, VDD_HF_PLL_NUM, 2, vdd_hf_levels); +static DEFINE_VDD_REGS_INIT(vdd_cpu_c1, 1); +static DEFINE_VDD_REGS_INIT(vdd_cpu_cci, 1); + +enum apcs_mux_clk_parent { + P_BI_TCXO_AO, + P_GPLL0_AO_OUT_MAIN, + P_APCS_CPU_PLL, +}; + +struct pll_spm_ctrl { + u32 offset; + u32 force_event_offset; + u32 event_bit; + void __iomem *spm_base; +}; + +static struct pll_spm_ctrl apcs_pll_spm = { + .offset = 0x50, + .force_event_offset = 0x4, + .event_bit = 0x4, +}; + +static const struct parent_map apcs_mux_clk_parent_map0[] = { + { P_BI_TCXO_AO, 0 }, + { P_GPLL0_AO_OUT_MAIN, 4 }, + { P_APCS_CPU_PLL, 5 }, +}; + +static const char *const apcs_mux_clk_parent_name0[] = { + "bi_tcxo_ao", + "gpll0_ao_out_main", + "apcs_cpu_pll", +}; + +static const struct parent_map apcs_mux_clk_parent_map1[] = { + { P_BI_TCXO_AO, 0 }, + { P_GPLL0_AO_OUT_MAIN, 4 }, +}; + +static const char *const apcs_mux_clk_parent_name1[] = { + "bi_tcxo_ao", + "gpll0_ao_out_main", +}; + +static int cpucc_clk_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long prate, u8 index) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + + return __mux_div_set_src_div(cpuclk, cpuclk->parent_map[index].cfg, + cpuclk->div); +} + +static int cpucc_clk_set_parent(struct clk_hw *hw, u8 index) +{ + return 0; +} + +static int cpucc_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + + return __mux_div_set_src_div(cpuclk, cpuclk->src, cpuclk->div); +} + +static int cpucc_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_hw *xo, *apcs_gpll0_hw, *apcs_cpu_pll_hw; + struct clk_rate_request parent_req = { }; + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + unsigned long apcs_gpll0_rate, apcs_gpll0_rrate, rate = req->rate; + unsigned long mask = BIT(cpuclk->hid_width) - 1; + u32 div = 1; + int ret; + + xo = clk_hw_get_parent_by_index(hw, P_BI_TCXO_AO); + if (rate == clk_hw_get_rate(xo)) { + req->best_parent_hw = xo; + req->best_parent_rate = rate; + cpuclk->div = div; + cpuclk->src = cpuclk->parent_map[P_BI_TCXO_AO].cfg; + return 0; + } + + apcs_gpll0_hw = clk_hw_get_parent_by_index(hw, P_GPLL0_AO_OUT_MAIN); + apcs_cpu_pll_hw = clk_hw_get_parent_by_index(hw, P_APCS_CPU_PLL); + + apcs_gpll0_rate = clk_hw_get_rate(apcs_gpll0_hw); + apcs_gpll0_rrate = DIV_ROUND_UP(apcs_gpll0_rate, 1000000) * 1000000; + + if (rate <= apcs_gpll0_rrate) { + req->best_parent_hw = apcs_gpll0_hw; + req->best_parent_rate = apcs_gpll0_rrate; + div = DIV_ROUND_CLOSEST(2 * apcs_gpll0_rrate, rate) - 1; + div = min_t(unsigned long, div, mask); + req->rate = clk_rcg2_calc_rate(req->best_parent_rate, 0, + 0, 0, div); + cpuclk->src = cpuclk->parent_map[P_GPLL0_AO_OUT_MAIN].cfg; + } else { + parent_req.rate = rate; + parent_req.best_parent_hw = apcs_cpu_pll_hw; + + req->best_parent_hw = apcs_cpu_pll_hw; + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); + if (ret) + return ret; + + req->best_parent_rate = parent_req.rate; + cpuclk->src = cpuclk->parent_map[P_APCS_CPU_PLL].cfg; + } + + cpuclk->div = div; + + return 0; +} + +static void cpucc_clk_list_registers(struct seq_file *f, struct clk_hw *hw) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + int i = 0, size = 0, val; + + static struct clk_register_data data[] = { + {"CMD_RCGR", 0x0}, + {"CFG_RCGR", 0x4}, + }; + + size = ARRAY_SIZE(data); + for (i = 0; i < size; i++) { + regmap_read(cpuclk->clkr.regmap, + cpuclk->reg_offset + data[i].offset, &val); + clock_debug_output(f, false, + "%20s: 0x%.8x\n", data[i].name, val); + } +} + +static unsigned long cpucc_clk_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + struct clk_hw *parent; + const char *name = clk_hw_get_name(hw); + unsigned long parent_rate; + u32 i, div, src = 0; + u32 num_parents = clk_hw_get_num_parents(hw); + int ret; + + ret = mux_div_get_src_div(cpuclk, &src, &div); + if (ret) + return ret; + + cpuclk->src = src; + cpuclk->div = div; + + for (i = 0; i < num_parents; i++) { + if (src == cpuclk->parent_map[i].cfg) { + parent = clk_hw_get_parent_by_index(hw, i); + parent_rate = clk_hw_get_rate(parent); + return clk_rcg2_calc_rate(parent_rate, 0, 0, 0, div); + } + } + pr_err("%s: Can't find parent %d\n", name, src); + + return ret; +} + +static int cpucc_clk_enable(struct clk_hw *hw) +{ + return clk_regmap_mux_div_ops.enable(hw); +} + +static void cpucc_clk_disable(struct clk_hw *hw) +{ + clk_regmap_mux_div_ops.disable(hw); +} + +static u8 cpucc_clk_get_parent(struct clk_hw *hw) +{ + return clk_regmap_mux_div_ops.get_parent(hw); +} + +static void spm_event(struct pll_spm_ctrl *apcs_pll_spm, bool enable) +{ + void __iomem *base = apcs_pll_spm->spm_base; + u32 offset, force_event_offset, bit, val; + + if (!apcs_pll_spm) + return; + + offset = apcs_pll_spm->offset; + force_event_offset = apcs_pll_spm->force_event_offset; + bit = apcs_pll_spm->event_bit; + + if (enable) { + /* L2_SPM_FORCE_EVENT_EN */ + val = readl_relaxed(base + offset); + val |= BIT(bit); + writel_relaxed(val, (base + offset)); + /* Ensure that the write above goes through. */ + mb(); + + /* L2_SPM_FORCE_EVENT */ + val = readl_relaxed(base + offset + force_event_offset); + val |= BIT(bit); + writel_relaxed(val, (base + offset + force_event_offset)); + /* Ensure that the write above goes through. */ + mb(); + } else { + /* L2_SPM_FORCE_EVENT */ + val = readl_relaxed(base + offset + force_event_offset); + val &= ~BIT(bit); + writel_relaxed(val, (base + offset + force_event_offset)); + /* Ensure that the write above goes through. */ + mb(); + + /* L2_SPM_FORCE_EVENT_EN */ + val = readl_relaxed(base + offset); + val &= ~BIT(bit); + writel_relaxed(val, (base + offset)); + /* Ensure that the write above goes through. */ + mb(); + } +} + +/* + * We use the notifier function for switching to a temporary safe configuration + * (mux and divider), while the APSS pll is reconfigured. + */ +static int cpucc_notifier_cb(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct clk_regmap_mux_div *cpuclk = container_of(nb, + struct clk_regmap_mux_div, clk_nb); + int ret = 0, safe_src = cpuclk->safe_src; + + switch (event) { + case PRE_RATE_CHANGE: + /* set the mux to safe source gpll0_ao_out & div */ + ret = __mux_div_set_src_div(cpuclk, safe_src, 1); + spm_event(&apcs_pll_spm, true); + break; + case POST_RATE_CHANGE: + if (cpuclk->src != safe_src) + spm_event(&apcs_pll_spm, false); + break; + case ABORT_RATE_CHANGE: + pr_err("Error in configuring PLL - stay at safe src only\n"); + } + + return notifier_from_errno(ret); +} + +static const struct clk_ops cpucc_clk_ops = { + .enable = cpucc_clk_enable, + .disable = cpucc_clk_disable, + .get_parent = cpucc_clk_get_parent, + .set_rate = cpucc_clk_set_rate, + .set_parent = cpucc_clk_set_parent, + .set_rate_and_parent = cpucc_clk_set_rate_and_parent, + .determine_rate = cpucc_clk_determine_rate, + .recalc_rate = cpucc_clk_recalc_rate, + .debug_init = clk_debug_measure_add, + .list_registers = cpucc_clk_list_registers, +}; + +/* Initial configuration for 1305.6MHz */ +static const struct pll_config apcs_cpu_pll_config = { + .l = 0x44, + .m = 0, + .n = 1, + .pre_div_val = 0x0, + .pre_div_mask = 0x7 << 12, + .post_div_val = 0x0, + .post_div_mask = 0x3 << 8, + .main_output_mask = BIT(0), + .aux_output_mask = BIT(1), +}; + +static struct clk_pll apcs_cpu_pll = { + .mode_reg = 0x0, + .l_reg = 0x4, + .m_reg = 0x8, + .n_reg = 0xc, + .config_reg = 0x10, + .status_reg = 0x1c, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "apcs_cpu_pll", + .parent_names = (const char *[]){ "bi_tcxo_ao" }, + .num_parents = 1, + .ops = &clk_pll_hf_ops, + .vdd_class = &vdd_hf_pll, + .rate_max = (unsigned long[VDD_HF_PLL_NUM]) { + [VDD_HF_PLL_SVS] = 1000000000, + [VDD_HF_PLL_NOM] = 2020000000, + }, + .num_rate_max = VDD_HF_PLL_NUM, + }, +}; + +static struct clk_regmap_mux_div apcs_mux_c1_clk = { + .reg_offset = 0x0, + .hid_width = 5, + .hid_shift = 0, + .src_width = 3, + .src_shift = 8, + .safe_src = 4, + .safe_div = 1, + .parent_map = apcs_mux_clk_parent_map0, + .clk_nb.notifier_call = cpucc_notifier_cb, + .clkr.hw.init = &(struct clk_init_data) { + .name = "apcs_mux_c1_clk", + .parent_names = apcs_mux_clk_parent_name0, + .num_parents = 3, + .vdd_class = &vdd_cpu_c1, + .flags = CLK_SET_RATE_PARENT, + .ops = &cpucc_clk_ops, + }, +}; + +static struct clk_regmap_mux_div apcs_mux_cci_clk = { + .reg_offset = 0x0, + .hid_width = 5, + .hid_shift = 0, + .src_width = 3, + .src_shift = 8, + .safe_src = 4, + .safe_div = 1, + .parent_map = apcs_mux_clk_parent_map1, + .clkr.hw.init = &(struct clk_init_data) { + .name = "apcs_mux_cci_clk", + .parent_names = apcs_mux_clk_parent_name1, + .num_parents = 2, + .vdd_class = &vdd_cpu_cci, + .flags = CLK_SET_RATE_PARENT, + .ops = &cpucc_clk_ops, + }, +}; + +static const struct of_device_id match_table[] = { + { .compatible = "qcom,cpu-clock-sdm" }, + {} +}; + +static struct regmap_config cpu_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x34, + .fast_io = true, +}; + +static struct clk_hw *cpu_clks_hws[] = { + [APCS_CPU_PLL] = &apcs_cpu_pll.clkr.hw, + [APCS_MUX_C1_CLK] = &apcs_mux_c1_clk.clkr.hw, + [APCS_MUX_CCI_CLK] = &apcs_mux_cci_clk.clkr.hw, +}; + +static void cpucc_clk_get_speed_bin(struct platform_device *pdev, int *bin, + int *version) +{ + struct resource *res; + void __iomem *base; + u32 pte_efuse; + + *bin = 0; + *version = 0; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse"); + if (!res) { + dev_info(&pdev->dev, + "No speed/PVS binning available. Defaulting to 0!\n"); + return; + } + + base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!base) { + dev_info(&pdev->dev, + "Unable to read efuse data. Defaulting to 0!\n"); + return; + } + + pte_efuse = readl_relaxed(base); + devm_iounmap(&pdev->dev, base); + + *bin = (pte_efuse >> 2) & 0x7; + + dev_info(&pdev->dev, "PVS version: %d speed bin: %d\n", *version, *bin); +} + +static int cpucc_clk_get_fmax_vdd_class(struct platform_device *pdev, + struct clk_init_data *clk_intd, char *prop_name) +{ + struct device_node *of = pdev->dev.of_node; + struct clk_vdd_class *vdd = clk_intd->vdd_class; + u32 *array; + int prop_len, i, j, ret; + int num = vdd->num_regulators + 1; + + if (!of_find_property(of, prop_name, &prop_len)) { + dev_err(&pdev->dev, "missing %s\n", prop_name); + return -EINVAL; + } + + prop_len /= sizeof(u32); + if (prop_len % num) { + dev_err(&pdev->dev, "bad length %d\n", prop_len); + return -EINVAL; + } + + prop_len /= num; + vdd->level_votes = devm_kzalloc(&pdev->dev, prop_len * sizeof(int), + GFP_KERNEL); + if (!vdd->level_votes) + return -ENOMEM; + + vdd->vdd_uv = devm_kzalloc(&pdev->dev, + prop_len * sizeof(int) * (num - 1), GFP_KERNEL); + if (!vdd->vdd_uv) + return -ENOMEM; + + clk_intd->rate_max = devm_kzalloc(&pdev->dev, + prop_len * sizeof(unsigned long), GFP_KERNEL); + if (!clk_intd->rate_max) + return -ENOMEM; + + array = devm_kzalloc(&pdev->dev, + prop_len * sizeof(u32) * num, GFP_KERNEL); + if (!array) + return -ENOMEM; + + ret = of_property_read_u32_array(of, prop_name, array, prop_len * num); + if (ret) + return -ENOMEM; + + for (i = 0; i < prop_len; i++) { + clk_intd->rate_max[i] = array[num * i]; + for (j = 1; j < num; j++) { + vdd->vdd_uv[(num - 1) * i + (j - 1)] = + array[num * i + j]; + } + } + + devm_kfree(&pdev->dev, array); + vdd->num_levels = prop_len; + vdd->cur_level = prop_len; + clk_intd->num_rate_max = prop_len; + + return 0; +} + +static int find_vdd_level(struct clk_init_data *clk_intd, unsigned long rate) +{ + int level; + + for (level = 0; level < clk_intd->num_rate_max; level++) + if (rate <= clk_intd->rate_max[level]) + break; + + if (level == clk_intd->num_rate_max) { + pr_err("Rate %lu for %s is greater than highest Fmax\n", rate, + clk_intd->name); + return -EINVAL; + } + + return level; +} + +static int +cpucc_clk_add_opp(struct clk_hw *hw, struct device *dev, unsigned long max_rate) +{ + struct clk_init_data *clk_intd = (struct clk_init_data *)hw->init; + struct clk_vdd_class *vdd = clk_intd->vdd_class; + int level, uv, j = 1; + unsigned long rate = 0; + long ret; + + if (IS_ERR_OR_NULL(dev)) { + pr_err("%s: Invalid parameters\n", __func__); + return -EINVAL; + } + + while (1) { + rate = clk_intd->rate_max[j++]; + level = find_vdd_level(clk_intd, rate); + if (level <= 0) { + pr_warn("clock-cpu: no corner for %lu.\n", rate); + return -EINVAL; + } + + uv = vdd->vdd_uv[level]; + if (uv < 0) { + pr_warn("clock-cpu: no uv for %lu.\n", rate); + return -EINVAL; + } + + ret = dev_pm_opp_add(dev, rate, uv); + if (ret) { + pr_warn("clock-cpu: failed to add OPP for %lu\n", rate); + return rate; + } + + if (rate >= max_rate) + break; + } + + return 0; +} + +static void cpucc_clk_print_opp_table(int cpu) +{ + struct dev_pm_opp *oppfmax, *oppfmin; + unsigned long apc_c1_fmax, apc_c1_fmin; + u32 max_index = apcs_mux_c1_clk.clkr.hw.init->num_rate_max; + + apc_c1_fmax = apcs_mux_c1_clk.clkr.hw.init->rate_max[max_index - 1]; + apc_c1_fmin = apcs_mux_c1_clk.clkr.hw.init->rate_max[1]; + + oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(cpu), + apc_c1_fmax, true); + oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(cpu), + apc_c1_fmin, true); + pr_info("Clock_cpu:(cpu %d) OPP voltage for %lu: %ld\n", cpu, + apc_c1_fmin, dev_pm_opp_get_voltage(oppfmin)); + pr_info("Clock_cpu:(cpu %d) OPP voltage for %lu: %ld\n", cpu, + apc_c1_fmax, dev_pm_opp_get_voltage(oppfmax)); + +} + +static void cpucc_clk_populate_opp_table(struct platform_device *pdev) +{ + unsigned long apc_c1_fmax; + u32 max_index = apcs_mux_c1_clk.clkr.hw.init->num_rate_max; + int cpu, sdm_cpu = 0; + + apc_c1_fmax = apcs_mux_c1_clk.clkr.hw.init->rate_max[max_index - 1]; + + for_each_possible_cpu(cpu) { + sdm_cpu = cpu; + WARN(cpucc_clk_add_opp(&apcs_mux_c1_clk.clkr.hw, + get_cpu_device(cpu), apc_c1_fmax), + "Failed to add OPP levels for apcs_mux_c1_clk\n"); + } + cpucc_clk_print_opp_table(sdm_cpu); +} + +static int clock_pm_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + switch (event) { + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + clk_unprepare(apcs_mux_c1_clk.clkr.hw.clk); + clk_unprepare(apcs_mux_cci_clk.clkr.hw.clk); + break; + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + clk_prepare(apcs_mux_c1_clk.clkr.hw.clk); + clk_prepare(apcs_mux_cci_clk.clkr.hw.clk); + break; + default: + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block clock_pm_notifier = { + .notifier_call = clock_pm_event, +}; + +static int cpucc_driver_probe(struct platform_device *pdev) +{ + struct resource *res; + struct clk_hw_onecell_data *data; + struct device *dev = &pdev->dev; + struct clk *clk; + int i, ret, speed_bin, version, cpu; + char prop_name[] = "qcom,speedX-bin-vX-XXX"; + void __iomem *base; + + clk = devm_clk_get(dev, "xo_ao"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(dev, "Unable to get xo clock\n"); + return PTR_ERR(clk); + } + + clk = devm_clk_get(dev, "gpll0_ao"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(dev, "Unable to get GPLL0 clock\n"); + return PTR_ERR(clk); + } + + /* Rail Regulator for apcs_pll */ + vdd_hf_pll.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_hf_pll"); + if (IS_ERR(vdd_hf_pll.regulator[0])) { + if (!(PTR_ERR(vdd_hf_pll.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_hf_pll regulator\n"); + return PTR_ERR(vdd_hf_pll.regulator[0]); + } + + vdd_hf_pll.regulator[1] = devm_regulator_get(&pdev->dev, "vdd_dig_ao"); + if (IS_ERR(vdd_hf_pll.regulator[1])) { + if (!(PTR_ERR(vdd_hf_pll.regulator[1]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_dig_ao regulator\n"); + return PTR_ERR(vdd_hf_pll.regulator[1]); + } + + /* Rail Regulator for APCS C1 mux */ + vdd_cpu_c1.regulator[0] = devm_regulator_get(&pdev->dev, "cpu-vdd"); + if (IS_ERR(vdd_cpu_c1.regulator[0])) { + if (!(PTR_ERR(vdd_cpu_c1.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get cpu-vdd regulator\n"); + return PTR_ERR(vdd_cpu_c1.regulator[0]); + } + + /* Rail Regulator for APCS CCI mux */ + vdd_cpu_cci.regulator[0] = devm_regulator_get(&pdev->dev, "cpu-vdd"); + if (IS_ERR(vdd_cpu_cci.regulator[0])) { + if (!(PTR_ERR(vdd_cpu_cci.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get cpu-vdd regulator\n"); + return PTR_ERR(vdd_cpu_cci.regulator[0]); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_pll"); + if (res == NULL) { + dev_err(&pdev->dev, "Failed to get apcs_pll resources\n"); + return -EINVAL; + } + + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed map apcs_cpu_pll register base\n"); + return PTR_ERR(base); + } + + cpu_regmap_config.name = "apcs_pll"; + apcs_cpu_pll.clkr.regmap = devm_regmap_init_mmio(dev, base, + &cpu_regmap_config); + if (IS_ERR(apcs_cpu_pll.clkr.regmap)) { + dev_err(&pdev->dev, "Couldn't get regmap for apcs_cpu_pll\n"); + return PTR_ERR(apcs_cpu_pll.clkr.regmap); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "apcs-c1-rcg-base"); + if (res == NULL) { + dev_err(&pdev->dev, "Failed to get apcs-c1 resources\n"); + return -EINVAL; + } + + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed map apcs-c1-rcg register base\n"); + return PTR_ERR(base); + } + + cpu_regmap_config.name = "apcs-c1-rcg-base"; + apcs_mux_c1_clk.clkr.regmap = devm_regmap_init_mmio(dev, base, + &cpu_regmap_config); + if (IS_ERR(apcs_mux_c1_clk.clkr.regmap)) { + dev_err(&pdev->dev, "Couldn't get regmap for apcs-c1-rcg\n"); + return PTR_ERR(apcs_mux_c1_clk.clkr.regmap); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "apcs-cci-rcg-base"); + if (res == NULL) { + dev_err(&pdev->dev, "Failed to get apcs-cci resources\n"); + return -EINVAL; + } + + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed map apcs-cci-rcg register base\n"); + return PTR_ERR(base); + } + + cpu_regmap_config.name = "apcs-cci-rcg-base"; + apcs_mux_cci_clk.clkr.regmap = devm_regmap_init_mmio(dev, base, + &cpu_regmap_config); + if (IS_ERR(apcs_mux_cci_clk.clkr.regmap)) { + dev_err(&pdev->dev, "Couldn't get regmap for apcs-cci-rcg\n"); + return PTR_ERR(apcs_mux_cci_clk.clkr.regmap); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "spm_c1_base"); + if (res == NULL) { + dev_err(&pdev->dev, "Failed to get spm-c1 resources\n"); + return -EINVAL; + } + + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed to ioremap c1 spm registers\n"); + return -ENOMEM; + } + + apcs_pll_spm.spm_base = base; + + /* Get speed bin information */ + cpucc_clk_get_speed_bin(pdev, &speed_bin, &version); + + snprintf(prop_name, ARRAY_SIZE(prop_name), + "qcom,speed%d-bin-v%d-%s", speed_bin, version, "c1"); + + ret = cpucc_clk_get_fmax_vdd_class(pdev, + (struct clk_init_data *)apcs_mux_c1_clk.clkr.hw.init, + prop_name); + if (ret) { + dev_err(&pdev->dev, "Didn't get c1 speed bin\n"); + ret = cpucc_clk_get_fmax_vdd_class(pdev, + (struct clk_init_data *) + apcs_mux_c1_clk.clkr.hw.init, + prop_name); + if (ret) { + dev_err(&pdev->dev, "Unable to get vdd class for c1\n"); + return ret; + } + } + + snprintf(prop_name, ARRAY_SIZE(prop_name), + "qcom,speed%d-bin-v%d-%s", speed_bin, version, "cci"); + + ret = cpucc_clk_get_fmax_vdd_class(pdev, + (struct clk_init_data *)apcs_mux_cci_clk.clkr.hw.init, + prop_name); + if (ret) { + dev_err(&pdev->dev, "Didn't get cci speed bin\n"); + ret = cpucc_clk_get_fmax_vdd_class(pdev, + (struct clk_init_data *) + apcs_mux_cci_clk.clkr.hw.init, + prop_name); + if (ret) { + dev_err(&pdev->dev, "Unable get vdd class for cci\n"); + return ret; + } + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->num = ARRAY_SIZE(cpu_clks_hws); + + for (i = 0; i < ARRAY_SIZE(cpu_clks_hws); i++) { + ret = devm_clk_hw_register(dev, cpu_clks_hws[i]); + if (ret) { + dev_err(&pdev->dev, "Failed to register clock\n"); + return ret; + } + data->hws[i] = cpu_clks_hws[i]; + } + + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, data); + if (ret) { + dev_err(&pdev->dev, "CPU clock driver registeration failed\n"); + return ret; + } + + /* For safe freq switching during rate change */ + ret = clk_notifier_register(apcs_mux_c1_clk.clkr.hw.clk, + &apcs_mux_c1_clk.clk_nb); + if (ret) { + dev_err(dev, "failed to register clock notifier: %d\n", ret); + return ret; + } + + /* + * To increase the enable count for the clocks so + * that they dont get disabled during late init. + */ + get_online_cpus(); + for_each_online_cpu(cpu) { + WARN(clk_prepare_enable(apcs_mux_c1_clk.clkr.hw.clk), + "Unable to turn on CPU clock\n"); + clk_prepare_enable(apcs_mux_cci_clk.clkr.hw.clk); + } + put_online_cpus(); + + register_pm_notifier(&clock_pm_notifier); + + cpucc_clk_populate_opp_table(pdev); + dev_info(dev, "CPU clock Driver probed successfully\n"); + + return ret; +} + +static struct platform_driver cpu_clk_driver = { + .probe = cpucc_driver_probe, + .driver = { + .name = "qcom-cpu-sdm", + .of_match_table = match_table, + }, +}; + +static int __init cpu_clk_init(void) +{ + return platform_driver_register(&cpu_clk_driver); +} +subsys_initcall(cpu_clk_init); + +static void __exit cpu_clk_exit(void) +{ + platform_driver_unregister(&cpu_clk_driver); +} +module_exit(cpu_clk_exit); + +#define REG_OFFSET 0x4 +#define APCS_PLL 0x0b016000 +#define A53SS_MUX_C1 0x0b011050 + +static void config_enable_hf_pll(void __iomem *base) +{ + /* Configure USER_CTL value */ + writel_relaxed(0xf, base + apcs_cpu_pll.config_reg); + + /* Enable the pll */ + writel_relaxed(0x2, base + apcs_cpu_pll.mode_reg); + udelay(2); + writel_relaxed(0x6, base + apcs_cpu_pll.mode_reg); + udelay(50); + writel_relaxed(0x7, base + apcs_cpu_pll.mode_reg); + /* Ensure that the writes go through before enabling PLL */ + mb(); +} + +static int __init cpu_clock_init(void) +{ + struct device_node *dev; + void __iomem *base; + int count, regval = 0; + unsigned long enable_mask = GENMASK(2, 0); + + dev = of_find_compatible_node(NULL, NULL, "qcom,cpu-clock-sdm"); + if (!dev) { + pr_debug("device node not initialized\n"); + return -ENOMEM; + } + + base = ioremap_nocache(APCS_PLL, SZ_64); + if (!base) + return -ENOMEM; + + regval = readl_relaxed(base); + if (!((regval & enable_mask) == enable_mask)) + config_enable_hf_pll(base); + + iounmap(base); + + base = ioremap_nocache(A53SS_MUX_C1, SZ_8); + if (!base) + return -ENOMEM; + + writel_relaxed(0x501, base + REG_OFFSET); + + /* Update bit */ + regval = readl_relaxed(base); + regval |= BIT(0); + writel_relaxed(regval, base); + + /* Wait for update to take effect */ + for (count = 500; count > 0; count--) { + if ((!(readl_relaxed(base))) & BIT(0)) + break; + udelay(1); + } + + /* Update bit */ + regval = readl_relaxed(base); + regval |= BIT(0); + writel_relaxed(regval, base); + + /* Wait for update to take effect */ + for (count = 500; count > 0; count--) { + if ((!(readl_relaxed(base))) & BIT(0)) + break; + udelay(1); + } + + return 0; +} +early_initcall(cpu_clock_init); + +MODULE_ALIAS("platform:cpu"); +MODULE_DESCRIPTION("SDM CPU clock Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 29e7034a1db3928b3af5e58929b1b06693270947..9fc98819321a4f00e0c21aed3fcb66f657ad3fb1 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1472,7 +1472,11 @@ static int clk_gfx3d_src_determine_rate(struct clk_hw *hw, } f = qcom_find_freq(rcg->freq_tbl, req->rate); - if (!f || (req->rate != f->freq)) + + if (!f) + return -EINVAL; + + if (req->rate != f->freq) req->rate = f->freq; /* Indexes of source from the parent map */ diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 96e09c8ab74f17c601a99b54cdff28a328bdf75e..6d3b3b548ec2a2ba00a22bfc55e5248c249d31fb 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -1003,7 +1003,7 @@ DEFINE_CLK_SMD_RPM(sdm429w, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); DEFINE_CLK_SMD_RPM(sdm429w, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0); DEFINE_CLK_SMD_RPM(sdm429w, sysmmnoc_clk, sysmmnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, - 0); + 2); DEFINE_CLK_SMD_RPM_QDSS(sdm429w, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1); @@ -1038,6 +1038,10 @@ static struct clk_hw *sdm429w_clks[] = { [RPM_SMD_BB_CLK1_A] = &sdm429w_bb_clk1_a.hw, [RPM_SMD_BB_CLK2] = &sdm429w_bb_clk2.hw, [RPM_SMD_BB_CLK2_A] = &sdm429w_bb_clk2_a.hw, + [RPM_SMD_BB_CLK1_PIN] = &sdm429w_bb_clk1_pin.hw, + [RPM_SMD_BB_CLK1_A_PIN] = &sdm429w_bb_clk1_a_pin.hw, + [RPM_SMD_BB_CLK2_PIN] = &sdm429w_bb_clk2_pin.hw, + [RPM_SMD_BB_CLK2_A_PIN] = &sdm429w_bb_clk2_a_pin.hw, [RPM_SMD_RF_CLK2] = &sdm429w_rf_clk2.hw, [RPM_SMD_RF_CLK2_A] = &sdm429w_rf_clk2_a.hw, [RPM_SMD_DIV_CLK2] = &sdm429w_div_clk2.hw, diff --git a/drivers/clk/qcom/debugcc-sdm429w.c b/drivers/clk/qcom/debugcc-sdm429w.c index f733209fdcbacec21bf964d50aa78f6d0f962c41..52d560dde9270490beda6782821485805820ddfa 100644 --- a/drivers/clk/qcom/debugcc-sdm429w.c +++ b/drivers/clk/qcom/debugcc-sdm429w.c @@ -223,7 +223,7 @@ static struct clk_debug_mux gcc_debug_mux = { 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp2_uart1_apps_clk", 0x9C, 1, GCC, 0x9C, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, - { "gcc_blsp2_uart2_apps_clk", 0x9A, 1, GCC, 0x9A, 0x1FF, 0, 0xF, + { "gcc_blsp2_uart2_apps_clk", 0xA1, 1, GCC, 0xA1, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_boot_rom_ahb_clk", 0xF8, 1, GCC, 0xF8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, @@ -333,9 +333,9 @@ static struct clk_debug_mux gcc_debug_mux = { 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_byte1_clk", 0x1FC, 1, GCC, 0x1FC, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, - { "gcc_mdss_esc0_clk", 0x1E5, 1, GCC, 0x1E5, 0x1FF, 0, 0xF, 12, + { "gcc_mdss_esc0_clk", 0x1FD, 1, GCC, 0x1FD, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, - { "gcc_mdss_esc1_clk", 0x1FD, 1, GCC, 0x1FD, 0x1FF, 0, 0xF, 12, + { "gcc_mdss_esc1_clk", 0x1E5, 1, GCC, 0x1E5, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_mdp_clk", 0x1F9, 1, GCC, 0x1F9, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 7ddec886fcd35b05fed2d1a5e3920bcf302d4557..c0b043b1bd248ad5b47bb7aa59a877f045a11d56 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -140,22 +140,6 @@ static const char * const gcc_xo_gpll0_gpll4_gpll0_early_div[] = { "gpll0_early_div" }; -static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div_map[] = { - { P_XO, 0 }, - { P_GPLL0, 1 }, - { P_GPLL2, 2 }, - { P_GPLL3, 3 }, - { P_GPLL0_EARLY_DIV, 6 } -}; - -static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div[] = { - "xo", - "gpll0", - "gpll2", - "gpll3", - "gpll0_early_div" -}; - static const struct parent_map gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div_map[] = { { P_XO, 0 }, { P_GPLL0, 1 }, @@ -194,26 +178,6 @@ static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early "gpll0_early_div" }; -static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div_map[] = { - { P_XO, 0 }, - { P_GPLL0, 1 }, - { P_GPLL2, 2 }, - { P_GPLL3, 3 }, - { P_GPLL1, 4 }, - { P_GPLL4, 5 }, - { P_GPLL0_EARLY_DIV, 6 } -}; - -static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div[] = { - "xo", - "gpll0", - "gpll2", - "gpll3", - "gpll1", - "gpll4", - "gpll0_early_div" -}; - static struct clk_fixed_factor xo = { .mult = 1, .div = 1, diff --git a/drivers/clk/qcom/gcc-sdm429w.c b/drivers/clk/qcom/gcc-sdm429w.c index d49b5c4e5762098217bf32511cc0bde69fccb28c..61239022ab85fc863c88a100187b5737564010bb 100644 --- a/drivers/clk/qcom/gcc-sdm429w.c +++ b/drivers/clk/qcom/gcc-sdm429w.c @@ -65,7 +65,7 @@ static const char * const gcc_parent_names_0[] = { }; static const char * const gcc_parent_names_ao_0[] = { - "bi_tcxo_a", + "bi_tcxo_ao", "gpll0_ao_out_main", "core_bi_pll_test_se", }; @@ -415,7 +415,7 @@ static struct clk_alpha_pll gpll0_ao_out_main = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gpll0_ao_out_main", - .parent_names = (const char *[]){ "bi_tcxo_a" }, + .parent_names = (const char *[]){ "bi_tcxo_ao" }, .num_parents = 1, .ops = &clk_alpha_pll_ops, }, @@ -455,6 +455,7 @@ static struct clk_alpha_pll gpll3_out_main = { .vdd_class = &vdd_cx, .num_rate_max = VDD_NUM, .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW_L1] = 800000000, [VDD_NOMINAL] = 1400000000}, }, }, @@ -478,7 +479,7 @@ static struct clk_alpha_pll gpll4_out_main = { }, }; -static struct clk_pll gpll6_out_main = { +static struct clk_pll gpll6 = { .l_reg = 0x37004, .m_reg = 0x37008, .n_reg = 0x3700C, @@ -487,10 +488,21 @@ static struct clk_pll gpll6_out_main = { .status_reg = 0x3701C, .status_bit = 17, .clkr.hw.init = &(struct clk_init_data){ - .name = "gpll6", - .parent_names = (const char *[]){ "bi_tcxo" }, + .name = "gpll6", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct clk_regmap gpll6_out_main = { + .enable_reg = 0x45000, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gpll6_out_main", + .parent_names = (const char *[]){ "gpll6" }, .num_parents = 1, - .ops = &clk_pll_ops, + .ops = &clk_pll_vote_ops, }, }; @@ -499,7 +511,7 @@ static struct clk_regmap gpll6_out_aux = { .enable_mask = BIT(7), .hw.init = &(struct clk_init_data){ .name = "gpll6_out_aux", - .parent_names = (const char *[]){ "gpll6_out_main" }, + .parent_names = (const char *[]){ "gpll6" }, .num_parents = 1, .ops = &clk_pll_vote_ops, }, @@ -960,7 +972,7 @@ static const struct freq_tbl ftbl_cpp_clk_src[] = { F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0), F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0), - F(308570000, P_GPLL6_OUT_MAIN, 3.5, 0, 0), + F(308571428, P_GPLL6_OUT_MAIN, 3.5, 0, 0), F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), F(360000000, P_GPLL6_OUT_MAIN, 3, 0, 0), { } @@ -1086,7 +1098,7 @@ static const struct freq_tbl ftbl_jpeg0_clk_src[] = { F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0), F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0), - F(308570000, P_GPLL6_OUT_AUX, 3.5, 0, 0), + F(308571428, P_GPLL6_OUT_AUX, 3.5, 0, 0), F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), { } }; @@ -1267,7 +1279,7 @@ static const struct freq_tbl ftbl_vfe0_clk_src[] = { F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0), F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0), - F(308570000, P_GPLL6_OUT_MAIN, 3.5, 0, 0), + F(308571428, P_GPLL6_OUT_MAIN, 3.5, 0, 0), F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), F(360000000, P_GPLL6_OUT_MAIN, 3, 0, 0), F(400000000, P_GPLL0_OUT_MAIN, 2, 0, 0), @@ -1371,12 +1383,10 @@ static struct clk_rcg2 camss_gp0_clk_src = { .parent_map = gcc_parent_map_20, .freq_tbl = ftbl_camss_gp0_clk_src, .enable_safe_config = true, - .flags = HW_CLK_CTRL_MODE, .clkr.hw.init = &(struct clk_init_data){ .name = "camss_gp0_clk_src", .parent_names = gcc_parent_names_20, .num_parents = 5, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, .vdd_class = &vdd_cx, .num_rate_max = VDD_NUM, @@ -1394,12 +1404,10 @@ static struct clk_rcg2 camss_gp1_clk_src = { .parent_map = gcc_parent_map_20, .freq_tbl = ftbl_camss_gp0_clk_src, .enable_safe_config = true, - .flags = HW_CLK_CTRL_MODE, .clkr.hw.init = &(struct clk_init_data){ .name = "camss_gp1_clk_src", .parent_names = gcc_parent_names_20, .num_parents = 5, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, .vdd_class = &vdd_cx, .num_rate_max = VDD_NUM, @@ -1648,7 +1656,6 @@ static const struct freq_tbl ftbl_gfx3d_clk_src[] = { F_SLEW(216000000, P_GPLL6_OUT_AUX, 5, 0, 0, FIXED_FREQ_SRC), F_SLEW(228571429, P_GPLL0_OUT_MAIN, 3.5, 0, 0, FIXED_FREQ_SRC), F_SLEW(240000000, P_GPLL6_OUT_AUX, 4.5, 0, 0, FIXED_FREQ_SRC), - F_SLEW(259200000, P_GPLL3_OUT_MAIN, 2.5, 0, 0, 1296000000), F_SLEW(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0, FIXED_FREQ_SRC), F_SLEW(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0, FIXED_FREQ_SRC), F_SLEW(355200000, P_GPLL3_OUT_MAIN, 1, 0, 0, 710400000), @@ -1673,7 +1680,6 @@ static struct clk_rcg2 gfx3d_clk_src = { .name = "gfx3d_clk_src", .parent_names = gcc_parent_names_14, .num_parents = 6, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, }, }; @@ -1931,10 +1937,10 @@ static struct clk_branch gcc_mss_q6_bimc_axi_clk = { static struct clk_branch gcc_blsp1_ahb_clk = { .halt_reg = 0x1008, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0x1008, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(10), .hw.init = &(struct clk_init_data){ .name = "gcc_blsp1_ahb_clk", .ops = &clk_branch2_ops, @@ -2196,10 +2202,10 @@ static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = { static struct clk_branch gcc_blsp2_ahb_clk = { .halt_reg = 0xb008, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0xb008, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(20), .hw.init = &(struct clk_init_data){ .name = "gcc_blsp2_ahb_clk", .ops = &clk_branch2_ops, @@ -2317,10 +2323,10 @@ static struct clk_branch gcc_blsp2_uart2_apps_clk = { static struct clk_branch gcc_boot_rom_ahb_clk = { .halt_reg = 0x1300c, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0x1300c, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(7), .hw.init = &(struct clk_init_data){ .name = "gcc_boot_rom_ahb_clk", .ops = &clk_branch2_ops, @@ -2330,9 +2336,9 @@ static struct clk_branch gcc_boot_rom_ahb_clk = { static struct clk_branch gcc_crypto_ahb_clk = { .halt_reg = 0x16024, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0x16024, + .enable_reg = 0x45004, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_crypto_ahb_clk", @@ -2343,10 +2349,10 @@ static struct clk_branch gcc_crypto_ahb_clk = { static struct clk_branch gcc_crypto_axi_clk = { .halt_reg = 0x16020, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0x16020, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(1), .hw.init = &(struct clk_init_data){ .name = "gcc_crypto_axi_clk", .ops = &clk_branch2_ops, @@ -2356,10 +2362,10 @@ static struct clk_branch gcc_crypto_axi_clk = { static struct clk_branch gcc_crypto_clk = { .halt_reg = 0x1601c, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0x1601c, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(2), .hw.init = &(struct clk_init_data){ .name = "gcc_crypto_clk", .parent_names = (const char *[]){ @@ -2461,8 +2467,8 @@ static struct clk_branch gcc_prng_ahb_clk = { .halt_reg = 0x13004, .halt_check = BRANCH_HALT, .clkr = { - .enable_reg = 0x13004, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(8), .hw.init = &(struct clk_init_data){ .name = "gcc_prng_ahb_clk", .ops = &clk_branch2_ops, @@ -2558,7 +2564,6 @@ static struct clk_branch gcc_usb2a_phy_sleep_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_usb2a_phy_sleep_clk", - .num_parents = 1, .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, @@ -3540,6 +3545,14 @@ static struct clk_branch gcc_oxili_aon_clk = { .num_parents = 1, .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 320000000, + [VDD_LOW_L1] = 400000000, + [VDD_NOMINAL] = 510000000, + [VDD_NOMINAL_L1] = 560000000, + [VDD_HIGH] = 650000000}, }, }, }; @@ -3558,6 +3571,14 @@ static struct clk_branch gcc_oxili_gfx3d_clk = { .num_parents = 1, .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 320000000, + [VDD_LOW_L1] = 400000000, + [VDD_NOMINAL] = 510000000, + [VDD_NOMINAL_L1] = 560000000, + [VDD_HIGH] = 650000000}, }, }, }; @@ -3845,7 +3866,8 @@ static struct clk_regmap *gcc_sdm429w_clocks[] = { [GPLL0_SLEEP_CLK_SRC] = &gpll0_sleep_clk_src.clkr, [GPLL3_OUT_MAIN] = &gpll3_out_main.clkr, [GPLL4_OUT_MAIN] = &gpll4_out_main.clkr, - [GPLL6_OUT_MAIN] = &gpll6_out_main.clkr, + [GPLL6_OUT_MAIN] = &gpll6_out_main, + [GPLL6] = &gpll6.clkr, [GPLL6_OUT_AUX] = &gpll6_out_aux, [JPEG0_CLK_SRC] = &jpeg0_clk_src.clkr, [PDM2_CLK_SRC] = &pdm2_clk_src.clkr, diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c index b922842328db155907cb55a540ed1032026f3429..ecc5b248350ede30f83556cabdabcf5419ed62ca 100644 --- a/drivers/clk/qcom/gcc-sdm660.c +++ b/drivers/clk/qcom/gcc-sdm660.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, 2019-2020, 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 @@ -2974,281 +2974,361 @@ static struct clk_debug_mux gcc_debug_mux = { .priv = &debug_mux_priv, .en_mask = BIT(16), .debug_offset = 0x62000, - .post_div_offset = 0x62004, - .cbcr_offset = 0x62008, + .post_div_offset = 0x62000, + .cbcr_offset = 0x62000, .src_sel_mask = 0x3FF, .src_sel_shift = 0, .post_div_mask = 0xF, - .post_div_shift = 0, - .period_offset = 0x50, + .post_div_shift = 12, MUX_SRC_LIST( - { "snoc_clk", 0x000 }, - { "cnoc_clk", 0x00E }, - { "cnoc_periph_clk", 0x198 }, - { "bimc_clk", 0x19D }, - { "ce1_clk", 0x097 }, - { "ipa_clk", 0x11b }, - { "gcc_aggre2_ufs_axi_clk", 0x10B }, - { "gcc_aggre2_usb3_axi_clk", 0x10A }, - { "gcc_bimc_gfx_clk", 0x0AC }, - { "gcc_bimc_hmss_axi_clk", 0x0BB }, - { "gcc_bimc_mss_q6_axi_clk", 0x0A3 }, - { "gcc_blsp1_ahb_clk", 0x04A }, - { "gcc_blsp1_qup1_i2c_apps_clk", 0x04D }, - { "gcc_blsp1_qup1_spi_apps_clk", 0x04C }, - { "gcc_blsp1_qup2_i2c_apps_clk", 0x051 }, - { "gcc_blsp1_qup2_spi_apps_clk", 0x050 }, - { "gcc_blsp1_qup3_i2c_apps_clk", 0x055 }, - { "gcc_blsp1_qup3_spi_apps_clk", 0x054 }, - { "gcc_blsp1_qup4_i2c_apps_clk", 0x059 }, - { "gcc_blsp1_qup4_spi_apps_clk", 0x058 }, - { "gcc_blsp1_uart1_apps_clk", 0x04E }, - { "gcc_blsp1_uart2_apps_clk", 0x052 }, - { "gcc_blsp2_ahb_clk", 0x05E }, - { "gcc_blsp2_qup1_i2c_apps_clk", 0x061 }, - { "gcc_blsp2_qup1_spi_apps_clk", 0x060 }, - { "gcc_blsp2_qup2_i2c_apps_clk", 0x065 }, - { "gcc_blsp2_qup2_spi_apps_clk", 0x064 }, - { "gcc_blsp2_qup3_i2c_apps_clk", 0x069 }, - { "gcc_blsp2_qup3_spi_apps_clk", 0x068 }, - { "gcc_blsp2_qup4_i2c_apps_clk", 0x06D }, - { "gcc_blsp2_qup4_spi_apps_clk", 0x06C }, - { "gcc_blsp2_uart1_apps_clk", 0x062 }, - { "gcc_blsp2_uart2_apps_clk", 0x066 }, - { "gcc_boot_rom_ahb_clk", 0x07A }, - { "gcc_ce1_ahb_m_clk", 0x099 }, - { "gcc_ce1_axi_m_clk", 0x098 }, - { "gcc_cfg_noc_usb2_axi_clk", 0x168 }, - { "gcc_cfg_noc_usb3_axi_clk", 0x014 }, - { "gcc_dcc_ahb_clk", 0x119 }, - { "gcc_gp1_clk", 0x0DF }, - { "gcc_gp2_clk", 0x0E0 }, - { "gcc_gp3_clk", 0x0E1 }, - { "gcc_gpu_bimc_gfx_clk", 0x13F }, - { "gcc_gpu_cfg_ahb_clk", 0x13B }, - { "gcc_hmss_dvm_bus_clk", 0x0BF }, - { "gcc_hmss_rbcpr_clk", 0x0BC }, - { "gcc_mmss_noc_cfg_ahb_clk", 0x020 }, - { "gcc_mmss_sys_noc_axi_clk", 0x01F }, - { "gcc_mss_cfg_ahb_clk", 0x11F }, - { "gcc_mss_mnoc_bimc_axi_clk", 0x120 }, - { "gcc_mss_q6_bimc_axi_clk", 0x124 }, - { "gcc_mss_snoc_axi_clk", 0x123 }, - { "gcc_pdm2_clk", 0x074 }, - { "gcc_pdm_ahb_clk", 0x072 }, - { "gcc_prng_ahb_clk", 0x075 }, - { "gcc_qspi_ahb_clk", 0x172 }, - { "gcc_qspi_ser_clk", 0x173 }, - { "gcc_sdcc1_ahb_clk", 0x16E }, - { "gcc_sdcc1_apps_clk", 0x16D }, - { "gcc_sdcc1_ice_core_clk", 0x16F }, - { "gcc_sdcc2_ahb_clk", 0x047 }, - { "gcc_sdcc2_apps_clk", 0x046 }, - { "gcc_ufs_ahb_clk", 0x0EB }, - { "gcc_ufs_axi_clk", 0x0EA }, - { "gcc_ufs_ice_core_clk", 0x0F1 }, - { "gcc_ufs_phy_aux_clk", 0x0F2 }, - { "gcc_ufs_unipro_core_clk", 0x0F0 }, - { "gcc_usb20_master_clk", 0x169 }, - { "gcc_usb20_mock_utmi_clk", 0x16B }, - { "gcc_usb20_sleep_clk", 0x16A }, - { "gcc_usb30_master_clk", 0x03C }, - { "gcc_usb30_mock_utmi_clk", 0x03E }, - { "gcc_usb30_sleep_clk", 0x03D }, - { "gcc_usb3_phy_aux_clk", 0x03F }, - { "gcc_usb_phy_cfg_ahb2phy_clk", 0x045 }, - { "gcc_ufs_rx_symbol_0_clk", 0x0ED }, - { "gcc_ufs_rx_symbol_1_clk", 0x162 }, - { "gcc_ufs_tx_symbol_0_clk", 0x0EC }, - { "gcc_usb3_phy_pipe_clk", 0x040 }, - { "mmssnoc_axi_clk", 0x22, CAM_CC, - 0x004, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_bimc_smmu_ahb_clk", 0x22, CAM_CC, - 0x00C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_bimc_smmu_axi_clk", 0x22, CAM_CC, - 0x00D, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_ahb_clk", 0x22, CAM_CC, - 0x037, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cci_ahb_clk", 0x22, CAM_CC, - 0x02E, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cci_clk", 0x22, CAM_CC, - 0x02D, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cphy_csid0_clk", 0x22, CAM_CC, - 0x08D, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cphy_csid1_clk", 0x22, CAM_CC, - 0x08E, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cphy_csid2_clk", 0x22, CAM_CC, - 0x08F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cphy_csid3_clk", 0x22, CAM_CC, - 0x090, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cpp_ahb_clk", 0x22, CAM_CC, - 0x03B, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cpp_axi_clk", 0x22, CAM_CC, - 0x07A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cpp_clk", 0x22, CAM_CC, - 0x03A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cpp_vbif_ahb_clk", 0x22, CAM_CC, - 0x073, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi0_ahb_clk", 0x22, CAM_CC, - 0x042, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi0_clk", 0x22, CAM_CC, - 0x041, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi0phytimer_clk", 0x22, CAM_CC, - 0x02F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi0pix_clk", 0x22, CAM_CC, - 0x045, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi0rdi_clk", 0x22, CAM_CC, - 0x044, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi1_ahb_clk", 0x22, CAM_CC, - 0x047, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi1_clk", 0x22, CAM_CC, - 0x046, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi1phytimer_clk", 0x22, CAM_CC, - 0x030, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi1pix_clk", 0x22, CAM_CC, - 0x04A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi1rdi_clk", 0x22, CAM_CC, - 0x049, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi2_ahb_clk", 0x22, CAM_CC, - 0x04C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi2_clk", 0x22, CAM_CC, - 0x04B, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi2phytimer_clk", 0x22, CAM_CC, - 0x031, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi2pix_clk", 0x22, CAM_CC, - 0x04F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi2rdi_clk", 0x22, CAM_CC, - 0x04E, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi3_ahb_clk", 0x22, CAM_CC, - 0x051, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi3_clk", 0x22, CAM_CC, - 0x050, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi3pix_clk", 0x22, CAM_CC, - 0x054, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi3rdi_clk", 0x22, CAM_CC, - 0x053, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi_vfe0_clk", 0x22, CAM_CC, - 0x03F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi_vfe1_clk", 0x22, CAM_CC, - 0x040, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csiphy0_clk", 0x22, CAM_CC, - 0x043, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csiphy1_clk", 0x22, CAM_CC, - 0x085, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csiphy2_clk", 0x22, CAM_CC, - 0x088, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_gp0_clk", 0x22, CAM_CC, - 0x027, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_gp1_clk", 0x22, CAM_CC, - 0x028, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_ispif_ahb_clk", 0x22, CAM_CC, - 0x033, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_jpeg0_clk", 0x22, CAM_CC, - 0x032, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_jpeg_ahb_clk", 0x22, CAM_CC, - 0x035, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_jpeg_axi_clk", 0x22, CAM_CC, - 0x036, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_mclk0_clk", 0x22, CAM_CC, - 0x029, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_mclk1_clk", 0x22, CAM_CC, - 0x02A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_mclk2_clk", 0x22, CAM_CC, - 0x02B, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_mclk3_clk", 0x22, CAM_CC, - 0x02C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_micro_ahb_clk", 0x22, CAM_CC, - 0x026, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_top_ahb_clk", 0x22, CAM_CC, - 0x025, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe0_ahb_clk", 0x22, CAM_CC, - 0x086, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe0_clk", 0x22, CAM_CC, - 0x038, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe0_stream_clk", 0x22, CAM_CC, - 0x071, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe1_ahb_clk", 0x22, CAM_CC, - 0x087, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe1_clk", 0x22, CAM_CC, - 0x039, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe1_stream_clk", 0x22, CAM_CC, - 0x072, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe_vbif_ahb_clk", 0x22, CAM_CC, - 0x03C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe_vbif_axi_clk", 0x22, CAM_CC, - 0x03D, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_csiphy_ahb2crif_clk", 0x22, CAM_CC, - 0x0B8, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_ahb_clk", 0x22, CAM_CC, - 0x022, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_axi_clk", 0x22, CAM_CC, - 0x024, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_byte0_clk", 0x22, CAM_CC, - 0x01E, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_byte0_intf_clk", 0x22, CAM_CC, - 0x0AD, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_byte1_clk", 0x22, CAM_CC, - 0x01F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_byte1_intf_clk", 0x22, CAM_CC, - 0x0B6, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_aux_clk", 0x22, CAM_CC, - 0x09C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_crypto_clk", 0x22, CAM_CC, - 0x09A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_gtc_clk", 0x22, CAM_CC, - 0x09D, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_link_clk", 0x22, CAM_CC, - 0x098, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_link_intf_clk", 0x22, CAM_CC, - 0x099, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_pixel_clk", 0x22, CAM_CC, - 0x09B, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_esc0_clk", 0x22, CAM_CC, - 0x020, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_esc1_clk", 0x22, CAM_CC, - 0x021, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_hdmi_dp_ahb_clk", 0x22, CAM_CC, - 0x023, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_mdp_clk", 0x22, CAM_CC, - 0x014, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_pclk0_clk", 0x22, CAM_CC, - 0x016, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_pclk1_clk", 0x22, CAM_CC, - 0x017, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_rot_clk", 0x22, CAM_CC, - 0x012, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_vsync_clk", 0x22, CAM_CC, - 0x01C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_misc_ahb_clk", 0x22, CAM_CC, - 0x003, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_misc_cxo_clk", 0x22, CAM_CC, - 0x077, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mnoc_ahb_clk", 0x22, CAM_CC, - 0x001, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_snoc_dvm_axi_clk", 0x22, CAM_CC, - 0x013, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_video_ahb_clk", 0x22, CAM_CC, - 0x011, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_video_axi_clk", 0x22, CAM_CC, - 0x00F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_video_core_clk", 0x22, CAM_CC, - 0x00E, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_video_subcore0_clk", 0x22, CAM_CC, - 0x01A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_throttle_camss_axi_clk", 0x22, CAM_CC, - 0x0AA, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_throttle_mdss_axi_clk", 0x22, CAM_CC, - 0x0AB, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_throttle_video_axi_clk", 0x22, CAM_CC, - 0x0AC, 0, 0, 0x1000, BM(14, 13) }, - { "gpucc_gfx3d_clk", 0x13d, GPU_CC, - 0x008, 0, 0, 0, BM(18, 17) }, - { "gpucc_rbbmtimer_clk", 0x13d, GPU_CC, - 0x005, 0, 0, 0, BM(18, 17) }, - { "gpucc_rbcpr_clk", 0x13d, GPU_CC, - 0x003, 0, 0, 0, BM(18, 17) }, - { "pwrcl_clk", 0x0c0, CPU_CC, 0x000, 0x3, 8, 0x0FF }, - { "perfcl_clk", 0x0c0, CPU_CC, 0x100, 0x3, 8, 0x0FF }, + { "snoc_clk", 0x000, 1, GCC, 0x000, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "cnoc_clk", 0x00E, 1, GCC, 0x00E, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "cnoc_periph_clk", 0x198, 1, GCC, 0x198, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "bimc_clk", 0x19D, 1, GCC, 0x19D, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "ce1_clk", 0x097, 1, GCC, 0x097, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "ipa_clk", 0x11b, 1, GCC, 0x11b, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_aggre2_ufs_axi_clk", 0x10B, 1, GCC, 0x10B, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_aggre2_usb3_axi_clk", 0x10A, 1, GCC, 0x10A, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_bimc_gfx_clk", 0x0AC, 1, GCC, 0x0AC, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_bimc_hmss_axi_clk", 0x0BB, 1, GCC, 0x0BB, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_bimc_mss_q6_axi_clk", 0x0A3, 1, GCC, 0x0A3, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_ahb_clk", 0x04A, 1, GCC, 0x04A, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup1_i2c_apps_clk", 0x04D, 1, GCC, 0x04D, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup1_spi_apps_clk", 0x04C, 1, GCC, 0x04C, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup2_i2c_apps_clk", 0x051, 1, GCC, 0x051, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup2_spi_apps_clk", 0x050, 1, GCC, 0x050, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup3_i2c_apps_clk", 0x055, 1, GCC, 0x055, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup3_spi_apps_clk", 0x054, 1, GCC, 0x054, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup4_i2c_apps_clk", 0x059, 1, GCC, 0x059, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup4_spi_apps_clk", 0x058, 1, GCC, 0x058, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_uart1_apps_clk", 0x04E, 1, GCC, 0x04E, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_uart2_apps_clk", 0x052, 1, GCC, 0x052, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_ahb_clk", 0x05E, 1, GCC, 0x05E, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup1_i2c_apps_clk", 0x061, 1, GCC, 0x061, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup1_spi_apps_clk", 0x060, 1, GCC, 0x060, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup2_i2c_apps_clk", 0x065, 1, GCC, 0x065, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup2_spi_apps_clk", 0x064, 1, GCC, 0x064, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup3_i2c_apps_clk", 0x069, 1, GCC, 0x069, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup3_spi_apps_clk", 0x068, 1, GCC, 0x068, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup4_i2c_apps_clk", 0x06D, 1, GCC, 0x06D, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup4_spi_apps_clk", 0x06C, 1, GCC, 0x06C, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_uart1_apps_clk", 0x062, 1, GCC, 0x062, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_uart2_apps_clk", 0x066, 1, GCC, 0x066, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_boot_rom_ahb_clk", 0x07A, 1, GCC, 0x07A, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ce1_ahb_m_clk", 0x099, 1, GCC, 0x099, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ce1_axi_m_clk", 0x098, 1, GCC, 0x098, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_cfg_noc_usb2_axi_clk", 0x168, 1, GCC, 0x168, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_cfg_noc_usb3_axi_clk", 0x014, 1, GCC, 0x014, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_dcc_ahb_clk", 0x119, 1, GCC, 0x119, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_gp1_clk", 0x0DF, 1, GCC, 0x0DF, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_gp2_clk", 0x0E0, 1, GCC, 0x0E0, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_gp3_clk", 0x0E1, 1, GCC, 0x0E1, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_gpu_bimc_gfx_clk", 0x13F, 1, GCC, 0x13F, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_gpu_cfg_ahb_clk", 0x13B, 1, GCC, 0x13B, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_hmss_dvm_bus_clk", 0x0BF, 1, GCC, 0x0BF, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_hmss_rbcpr_clk", 0x0BC, 1, GCC, 0x0BC, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mmss_noc_cfg_ahb_clk", 0x020, 1, GCC, 0x020, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mmss_sys_noc_axi_clk", 0x01F, 1, GCC, 0x01F, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mss_cfg_ahb_clk", 0x11F, 1, GCC, 0x11F, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mss_mnoc_bimc_axi_clk", 0x120, 1, GCC, 0x120, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mss_q6_bimc_axi_clk", 0x124, 1, GCC, 0x124, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mss_snoc_axi_clk", 0x123, 1, GCC, 0x123, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_pdm2_clk", 0x074, 1, GCC, 0x074, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_pdm_ahb_clk", 0x072, 1, GCC, 0x072, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_prng_ahb_clk", 0x075, 1, GCC, 0x075, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_qspi_ahb_clk", 0x172, 1, GCC, 0x172, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_qspi_ser_clk", 0x173, 1, GCC, 0x173, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_sdcc1_ahb_clk", 0x16E, 1, GCC, 0x16E, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_sdcc1_apps_clk", 0x16D, 1, GCC, 0x16D, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_sdcc1_ice_core_clk", 0x16F, 1, GCC, 0x16F, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_sdcc2_ahb_clk", 0x047, 1, GCC, 0x047, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_sdcc2_apps_clk", 0x046, 1, GCC, 0x046, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_ahb_clk", 0x0EB, 1, GCC, 0x0EB, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_axi_clk", 0x0EA, 1, GCC, 0x0EA, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_ice_core_clk", 0x0F1, 1, GCC, 0x0F1, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_phy_aux_clk", 0x0F2, 1, GCC, 0x0F2, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_unipro_core_clk", 0x0F0, 1, GCC, 0x0F0, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb20_master_clk", 0x169, 1, GCC, 0x169, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb20_mock_utmi_clk", 0x16B, 1, GCC, 0x16B, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb20_sleep_clk", 0x16A, 1, GCC, 0x16A, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb30_master_clk", 0x03C, 1, GCC, 0x03C, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb30_mock_utmi_clk", 0x03E, 1, GCC, 0x03E, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb30_sleep_clk", 0x03D, 1, GCC, 0x03D, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb3_phy_aux_clk", 0x03F, 1, GCC, 0x03F, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb_phy_cfg_ahb2phy_clk", 0x045, 1, GCC, 0x045, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_rx_symbol_0_clk", 0x0ED, 1, GCC, 0x0ED, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_rx_symbol_1_clk", 0x162, 1, GCC, 0x162, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_tx_symbol_0_clk", 0x0EC, 1, GCC, 0x0EC, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb3_phy_pipe_clk", 0x040, 1, GCC, 0x040, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "mmssnoc_axi_clk", 0x22, 1, CAM_CC, 0x004, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_bimc_smmu_ahb_clk", 0x22, 1, CAM_CC, 0x00C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_bimc_smmu_axi_clk", 0x22, 1, CAM_CC, 0x00D, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_ahb_clk", 0x22, 1, CAM_CC, 0x037, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cci_ahb_clk", 0x22, 1, CAM_CC, 0x02E, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cci_clk", 0x22, 1, CAM_CC, 0x02D, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cphy_csid0_clk", 0x22, 1, CAM_CC, 0x08D, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cphy_csid1_clk", 0x22, 1, CAM_CC, 0x08E, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cphy_csid2_clk", 0x22, 1, CAM_CC, 0x08F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cphy_csid3_clk", 0x22, 1, CAM_CC, 0x090, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cpp_ahb_clk", 0x22, 1, CAM_CC, 0x03B, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cpp_axi_clk", 0x22, 1, CAM_CC, 0x07A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cpp_clk", 0x22, 1, CAM_CC, 0x03A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cpp_vbif_ahb_clk", 0x22, 1, CAM_CC, 0x073, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi0_ahb_clk", 0x22, 1, CAM_CC, 0x042, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi0_clk", 0x22, 1, CAM_CC, 0x041, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi0phytimer_clk", 0x22, 1, CAM_CC, 0x02F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi0pix_clk", 0x22, 1, CAM_CC, 0x045, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi0rdi_clk", 0x22, 1, CAM_CC, 0x044, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi1_ahb_clk", 0x22, 1, CAM_CC, 0x047, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi1_clk", 0x22, 1, CAM_CC, 0x046, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi1phytimer_clk", 0x22, 1, CAM_CC, 0x030, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi1pix_clk", 0x22, 1, CAM_CC, 0x04A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi1rdi_clk", 0x22, 1, CAM_CC, 0x049, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi2_ahb_clk", 0x22, 1, CAM_CC, 0x04C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi2_clk", 0x22, 1, CAM_CC, 0x04B, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi2phytimer_clk", 0x22, 1, CAM_CC, 0x031, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi2pix_clk", 0x22, 1, CAM_CC, 0x04F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi2rdi_clk", 0x22, 1, CAM_CC, 0x04E, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi3_ahb_clk", 0x22, 1, CAM_CC, 0x051, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi3_clk", 0x22, 1, CAM_CC, 0x050, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi3pix_clk", 0x22, 1, CAM_CC, 0x054, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi3rdi_clk", 0x22, 1, CAM_CC, 0x053, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi_vfe0_clk", 0x22, 1, CAM_CC, 0x03F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi_vfe1_clk", 0x22, 1, CAM_CC, 0x040, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csiphy0_clk", 0x22, 1, CAM_CC, 0x043, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csiphy1_clk", 0x22, 1, CAM_CC, 0x085, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csiphy2_clk", 0x22, 1, CAM_CC, 0x088, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_gp0_clk", 0x22, 1, CAM_CC, 0x027, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_gp1_clk", 0x22, 1, CAM_CC, 0x028, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_ispif_ahb_clk", 0x22, 1, CAM_CC, 0x033, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_jpeg0_clk", 0x22, 1, CAM_CC, 0x032, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_jpeg_ahb_clk", 0x22, 1, CAM_CC, 0x035, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_jpeg_axi_clk", 0x22, 1, CAM_CC, 0x036, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_mclk0_clk", 0x22, 1, CAM_CC, 0x029, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_mclk1_clk", 0x22, 1, CAM_CC, 0x02A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_mclk2_clk", 0x22, 1, CAM_CC, 0x02B, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_mclk3_clk", 0x22, 1, CAM_CC, 0x02C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_micro_ahb_clk", 0x22, 1, CAM_CC, 0x026, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_top_ahb_clk", 0x22, 1, CAM_CC, 0x025, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe0_ahb_clk", 0x22, 1, CAM_CC, 0x086, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe0_clk", 0x22, 1, CAM_CC, 0x038, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe0_stream_clk", 0x22, 1, CAM_CC, 0x071, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe1_ahb_clk", 0x22, 1, CAM_CC, 0x087, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe1_clk", 0x22, 1, CAM_CC, 0x039, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe1_stream_clk", 0x22, 1, CAM_CC, 0x072, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe_vbif_ahb_clk", 0x22, 1, CAM_CC, 0x03C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe_vbif_axi_clk", 0x22, 1, CAM_CC, 0x03D, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_csiphy_ahb2crif_clk", 0x22, 1, CAM_CC, 0x0B8, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_ahb_clk", 0x22, 1, CAM_CC, 0x022, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_axi_clk", 0x22, 1, CAM_CC, 0x024, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_byte0_clk", 0x22, 1, CAM_CC, 0x01E, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_byte0_intf_clk", 0x22, 1, CAM_CC, 0x0AD, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_byte1_clk", 0x22, 1, CAM_CC, 0x01F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_byte1_intf_clk", 0x22, 1, CAM_CC, 0x0B6, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_aux_clk", 0x22, 1, CAM_CC, 0x09C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_crypto_clk", 0x22, 1, CAM_CC, 0x09A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_gtc_clk", 0x22, 1, CAM_CC, 0x09D, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_link_clk", 0x22, 1, CAM_CC, 0x098, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_link_intf_clk", 0x22, 1, CAM_CC, 0x099, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_pixel_clk", 0x22, 1, CAM_CC, 0x09B, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_esc0_clk", 0x22, 1, CAM_CC, 0x020, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_esc1_clk", 0x22, 1, CAM_CC, 0x021, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_hdmi_dp_ahb_clk", 0x22, 1, CAM_CC, 0x023, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_mdp_clk", 0x22, 1, CAM_CC, 0x014, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_pclk0_clk", 0x22, 1, CAM_CC, 0x016, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_pclk1_clk", 0x22, 1, CAM_CC, 0x017, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_rot_clk", 0x22, 1, CAM_CC, 0x012, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_vsync_clk", 0x22, 1, CAM_CC, 0x01C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_misc_ahb_clk", 0x22, 1, CAM_CC, 0x003, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_misc_cxo_clk", 0x22, 1, CAM_CC, 0x077, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mnoc_ahb_clk", 0x22, 1, CAM_CC, 0x001, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_snoc_dvm_axi_clk", 0x22, 1, CAM_CC, 0x013, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_video_ahb_clk", 0x22, 1, CAM_CC, 0x011, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_video_axi_clk", 0x22, 1, CAM_CC, 0x00F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_video_core_clk", 0x22, 1, CAM_CC, 0x00E, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_video_subcore0_clk", 0x22, 1, CAM_CC, 0x01A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_throttle_camss_axi_clk", 0x22, 1, CAM_CC, 0x0AA, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_throttle_mdss_axi_clk", 0x22, 1, CAM_CC, 0x0AB, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_throttle_video_axi_clk", 0x22, 1, CAM_CC, 0x0AC, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "gpucc_gfx3d_clk", 0x13d, 1, GPU_CC, 0x008, + 0xF, 0, 0, 0, 0, 0, 0, 0x10000, 1 }, + { "gpucc_rbbmtimer_clk", 0x13d, 1, GPU_CC, 0x005, + 0xF, 0, 0, 0, 0, 0, 0, 0x10000, 1 }, + { "gpucc_rbcpr_clk", 0x13d, 1, GPU_CC, 0x003, + 0xF, 0, 0, 0, 0, 0, 0, 0x10000, 1 }, + { "pwrcl_clk", 0x0c0, 1, CPU_CC, 0x000, + 0x3, 8, 0xF, 11, 1, 0, 0, U32_MAX, 1 }, + { "perfcl_clk", 0x0c0, 1, CPU_CC, 0x001, + 0x3, 8, 0xF, 11, 1, 0, 0, U32_MAX, 1 }, ), .hw.init = &(struct clk_init_data){ .name = "gcc_debug_mux", diff --git a/drivers/clk/qcom/gpucc-sdm660.c b/drivers/clk/qcom/gpucc-sdm660.c index 29db382aa144d381b30ed770671f9bbe894781b9..3dd8073966920cf019c18236499b42e47c8dc07d 100644 --- a/drivers/clk/qcom/gpucc-sdm660.c +++ b/drivers/clk/qcom/gpucc-sdm660.c @@ -209,6 +209,7 @@ static struct clk_rcg2 gfx3d_clk_src = { .freq_tbl = ftbl_gfx3d_clk_src, .parent_map = gpucc_parent_map_1, .flags = FORCE_ENABLE_RCG, + .enable_safe_config = true, .clkr.hw.init = &gpu_clks_init[0], }; diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c index ab44b3964f71555a35ceba706a0f48c864150460..e549ef13f578cbc097109cf08821fc394643c805 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c @@ -470,7 +470,7 @@ static void dsi_pll_config_slave(struct mdss_pll_resources *rsc) rsc->slave = NULL; if (!orsc) { - pr_warn("slave PLL unavilable, assuming standalone config\n"); + pr_debug("slave PLL unavilable, assuming standalone config\n"); return; } diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm-util.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm-util.c index 944b1dbad781cae38a85a05a5bd338d576362bd2..f67d5a0e7765655101d541ab369c55b67d2e0113 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm-util.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm-util.c @@ -24,17 +24,31 @@ #define DSI_PLL_POLL_MAX_READS 15 #define DSI_PLL_POLL_TIMEOUT_US 1000 +static void __mdss_dsi_get_pll_vco_cntrl(u64 target_freq, u32 post_div_mux, + u32 *vco_cntrl, u32 *cpbias_cntrl); + int pixel_div_set_div(void *context, unsigned int reg, unsigned int div) { struct mdss_pll_resources *pll = context; + void __iomem *pll_base = pll->pll_base; + int rc; + char data = 0; struct dsi_pll_db *pdb; pdb = (struct dsi_pll_db *)pll->priv; + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } /* Programming during vco_prepare. Keep this value */ - pdb->param.pixel_divhf = (div - 1); + data = ((div - 1) & 0x7f); + MDSS_PLL_REG_W(pll_base, DSIPHY_SSC9, data); + pdb->param.pixel_divhf = data; + mdss_pll_resource_enable(pll, false); pr_debug("ndx=%d div=%d divhf=%d\n", pll->index, div, pdb->param.pixel_divhf); @@ -46,6 +60,7 @@ int pixel_div_get_div(void *context, unsigned int reg, { int rc; struct mdss_pll_resources *pll = context; + u32 val = 0; if (is_gdsc_disabled(pll)) return 0; @@ -56,8 +71,9 @@ int pixel_div_get_div(void *context, unsigned int reg, return rc; } - *div = (MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SSC9) & 0x7F); - pr_debug("pixel_div = %d\n", (*div+1)); + val = (MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SSC9) & 0x7F); + *div = val + 1; + pr_debug("pixel_div = %d\n", (*div)); mdss_pll_resource_enable(pll, false); @@ -68,13 +84,30 @@ int set_post_div_mux_sel(void *context, unsigned int reg, unsigned int sel) { struct mdss_pll_resources *pll = context; + void __iomem *pll_base = pll->pll_base; struct dsi_pll_db *pdb; + u64 target_freq = 0; + u32 vco_cntrl = 0, cpbias_cntrl = 0; + char data = 0; pdb = (struct dsi_pll_db *)pll->priv; /* Programming during vco_prepare. Keep this value */ pdb->param.post_div_mux = sel; + target_freq = div_u64(pll->vco_current_rate, + BIT(pdb->param.post_div_mux)); + __mdss_dsi_get_pll_vco_cntrl(target_freq, pdb->param.post_div_mux, + &vco_cntrl, &cpbias_cntrl); + + data = ((vco_cntrl & 0x3f) | BIT(6)); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_CTRL, data); + pr_debug("%s: vco_cntrl 0x%x\n", __func__, vco_cntrl); + + data = ((cpbias_cntrl & 0x1) << 6) | BIT(4); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL, data); + pr_debug("%s: cpbias_cntrl 0x%x\n", __func__, cpbias_cntrl); + pr_debug("ndx=%d post_div_mux_sel=%d p_div=%d\n", pll->index, sel, (u32) BIT(sel)); @@ -99,6 +132,7 @@ int get_post_div_mux_sel(void *context, unsigned int reg, vco_cntrl = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_PLL_VCO_CTRL); vco_cntrl &= 0x30; + pr_debug("%s: vco_cntrl 0x%x\n", __func__, vco_cntrl); cpbias_cntrl = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL); @@ -121,6 +155,7 @@ int get_post_div_mux_sel(void *context, unsigned int reg, } mdss_pll_resource_enable(pll, false); + pr_debug("%s: sel = %d\n", __func__, *sel); return 0; } @@ -129,16 +164,24 @@ int set_gp_mux_sel(void *context, unsigned int reg, unsigned int sel) { struct mdss_pll_resources *pll = context; - struct dsi_pll_db *pdb; + void __iomem *pll_base = pll->pll_base; + char data = 0; + int rc; - pdb = (struct dsi_pll_db *)pll->priv; + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } /* Programming during vco_prepare. Keep this value */ - pdb->param.gp_div_mux = sel; + data = ((sel & 0x7) << 5) | 0x5; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, data); pr_debug("ndx=%d gp_div_mux_sel=%d gp_cntrl=%d\n", pll->index, sel, (u32) BIT(sel)); + mdss_pll_resource_enable(pll, false); return 0; } @@ -184,7 +227,9 @@ static bool pll_is_pll_locked_12nm(struct mdss_pll_resources *pll, pr_err("DSI PLL ndx=%d status=%x failed to Lock\n", pll->index, status); pll_locked = false; + pr_debug("%s: not locked\n", __func__); } else { + pr_debug("%s: locked\n", __func__); pll_locked = true; } @@ -551,13 +596,13 @@ static void mdss_dsi_pll_12nm_calc_reg(struct mdss_pll_resources *pll, { struct dsi_pll_param *param = &pdb->param; u64 target_freq = 0; + u32 post_div_mux = 0; + get_post_div_mux_sel(pll, 0, &post_div_mux); target_freq = div_u64(pll->vco_current_rate, - BIT(pdb->param.post_div_mux)); + BIT(post_div_mux)); param->hsfreqrange = __mdss_dsi_get_hsfreqrange(target_freq); - __mdss_dsi_get_pll_vco_cntrl(target_freq, param->post_div_mux, - ¶m->vco_cntrl, ¶m->cpbias_cntrl); param->osc_freq_target = __mdss_dsi_get_osc_freq_target(target_freq); param->m_div = (u32) __mdss_dsi_pll_get_m_div(pll->vco_current_rate); param->fsm_ovr_ctrl = __mdss_dsi_get_fsm_ovr_ctrl(target_freq); @@ -716,9 +761,6 @@ static void pll_db_commit_12nm(struct mdss_pll_resources *pll, data = ((param->hsfreqrange & 0x7f) | BIT(7)); MDSS_PLL_REG_W(pll_base, DSIPHY_HS_FREQ_RAN_SEL, data); - data = ((param->vco_cntrl & 0x3f) | BIT(6)); - MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_CTRL, data); - data = (param->osc_freq_target & 0x7f); MDSS_PLL_REG_W(pll_base, DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_0, data); @@ -742,15 +784,6 @@ static void pll_db_commit_12nm(struct mdss_pll_resources *pll, data = ((param->gmp_cntrl & 0x3) << 4); MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_GMP_CTRL_DIG_TST, data); - data = ((param->cpbias_cntrl & 0x1) << 6) | BIT(4); - MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL, data); - - data = ((param->gp_div_mux & 0x7) << 5) | 0x5; - MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, data); - - data = (param->pixel_divhf & 0x7f); - MDSS_PLL_REG_W(pll_base, DSIPHY_SSC9, data); - MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_ANA_PROG_CTRL, 0x03); MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_ANA_TST_LOCK_ST_OVR_CTRL, 0x50); MDSS_PLL_REG_W(pll_base, @@ -788,6 +821,14 @@ int pll_vco_set_rate_12nm(struct clk_hw *hw, unsigned long rate, pll->vco_current_rate = rate; pll->vco_ref_clk_rate = vco->ref_clk_rate; + + mdss_dsi_pll_12nm_calc_reg(pll, pdb); + if (pll->ssc_en) + mdss_dsi_pll_12nm_calc_ssc(pll, pdb); + + /* commit DSI vco */ + pll_db_commit_12nm(pll, pdb); + error: return rc; } @@ -800,9 +841,13 @@ static unsigned long pll_vco_get_rate_12nm(struct clk_hw *hw) u64 ref_clk = vco->ref_clk_rate; int rc; struct mdss_pll_resources *pll = vco->priv; + u32 post_div_mux; + u32 cpbias_cntrl = 0; - if (is_gdsc_disabled(pll)) + if (is_gdsc_disabled(pll)) { + pr_err("%s:gdsc disabled\n", __func__); return 0; + } rc = mdss_pll_resource_enable(pll, true); if (rc) { @@ -820,6 +865,16 @@ static unsigned long pll_vco_get_rate_12nm(struct clk_hw *hw) m_div_11_6 &= 0x3f; pr_debug("m_div_11_6 = 0x%x\n", m_div_11_6); + post_div_mux = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_VCO_CTRL); + + pr_debug("post_div_mux = 0x%x\n", post_div_mux); + + cpbias_cntrl = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL); + cpbias_cntrl = ((cpbias_cntrl >> 6) & 0x1); + pr_debug("cpbias_cntrl = 0x%x\n", cpbias_cntrl); + m_div = ((m_div_11_6 << 6) | (m_div_5_0)); vco_rate = div_u64((ref_clk * m_div), 4); @@ -854,12 +909,22 @@ unsigned long vco_12nm_recalc_rate(struct clk_hw *hw, struct mdss_pll_resources *pll = vco->priv; unsigned long rate = 0; int rc; + struct dsi_pll_db *pdb; + + pdb = (struct dsi_pll_db *)pll->priv; if (!pll && is_gdsc_disabled(pll)) { pr_err("gdsc disabled\n"); return 0; } + if (pll->vco_current_rate != 0) { + rate = pll_vco_get_rate_12nm(hw); + pr_debug("%s:returning vco rate = %lld\n", __func__, + pll->vco_current_rate); + return rate; + } + rc = mdss_pll_resource_enable(pll, true); if (rc) { pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); @@ -870,6 +935,7 @@ unsigned long vco_12nm_recalc_rate(struct clk_hw *hw, pll->handoff_resources = true; pll->pll_on = true; rate = pll_vco_get_rate_12nm(hw); + pr_debug("%s: pll locked. rate %lu\n", __func__, rate); } else { mdss_pll_resource_enable(pll, false); } @@ -930,15 +996,7 @@ int pll_vco_prepare_12nm(struct clk_hw *hw) goto end; } - mdss_dsi_pll_12nm_calc_reg(pll, pdb); - if (pll->ssc_en) - mdss_dsi_pll_12nm_calc_ssc(pll, pdb); - - /* commit DSI vco */ - pll_db_commit_12nm(pll, pdb); - rc = dsi_pll_enable(hw); - error: if (rc) { mdss_pll_resource_enable(pll, false); diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm.c index 21561941dcd5596c93263538660d2bec7b91db53..9f8767455338c66b3241553104c148c811966c4d 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm.c @@ -37,6 +37,7 @@ static const struct clk_ops clk_ops_vco_12nm = { .round_rate = pll_vco_round_rate_12nm, .prepare = pll_vco_prepare_12nm, .unprepare = pll_vco_unprepare_12nm, + .enable = pll_vco_enable_12nm, }; static struct regmap_bus pclk_div_regmap_bus = { @@ -216,8 +217,8 @@ static struct clk_fixed_factor dsi0pll_post_div32 = { static struct clk_regmap_mux dsi0pll_post_div_mux = { .reg = DSIPHY_PLL_VCO_CTRL, - .shift = 4, - .width = 2, + .shift = 0, + .width = 3, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi0pll_post_div_mux", @@ -308,8 +309,8 @@ static struct clk_fixed_factor dsi1pll_post_div32 = { static struct clk_regmap_mux dsi1pll_post_div_mux = { .reg = DSIPHY_PLL_VCO_CTRL, - .shift = 4, - .width = 2, + .shift = 0, + .width = 3, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi1pll_post_div_mux", @@ -400,7 +401,7 @@ static struct clk_fixed_factor dsi0pll_gp_div32 = { static struct clk_regmap_mux dsi0pll_gp_div_mux = { .reg = DSIPHY_PLL_CTRL, - .shift = 5, + .shift = 0, .width = 3, .clkr = { .hw.init = &(struct clk_init_data){ @@ -492,7 +493,7 @@ static struct clk_fixed_factor dsi1pll_gp_div32 = { static struct clk_regmap_mux dsi1pll_gp_div_mux = { .reg = DSIPHY_PLL_CTRL, - .shift = 5, + .shift = 0, .width = 3, .clkr = { .hw.init = &(struct clk_init_data){ @@ -516,11 +517,12 @@ static struct clk_regmap_div dsi0pll_pclk_src = { .width = 6, .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_pclk_src", + .name = "dsi0_phy_pll_out_dsiclk", .parent_names = (const char *[]){ "dsi0pll_gp_div_mux"}, .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_regmap_div_ops, }, }, @@ -532,11 +534,12 @@ static struct clk_regmap_div dsi1pll_pclk_src = { .width = 6, .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_pclk_src", + .name = "dsi1_phy_pll_out_dsiclk", .parent_names = (const char *[]){ "dsi1pll_gp_div_mux"}, .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_regmap_div_ops, }, }, @@ -546,10 +549,11 @@ static struct clk_fixed_factor dsi0pll_byte_clk_src = { .div = 4, .mult = 1, .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_byte_clk_src", + .name = "dsi0_phy_pll_out_byteclk", .parent_names = (const char *[]){"dsi0pll_post_div_mux"}, .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_fixed_factor_ops, }, }; @@ -558,15 +562,15 @@ static struct clk_fixed_factor dsi1pll_byte_clk_src = { .div = 4, .mult = 1, .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_byte_clk_src", + .name = "dsi1_phy_pll_out_byteclk", .parent_names = (const char *[]){"dsi1pll_post_div_mux"}, .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_fixed_factor_ops, }, }; - static struct clk_hw *mdss_dsi_pllcc_12nm[] = { [VCO_CLK_0] = &dsi0pll_vco_clk.hw, [POST_DIV1_0_CLK] = &dsi0pll_post_div1.hw, @@ -608,14 +612,14 @@ int dsi_pll_clock_register_12nm(struct platform_device *pdev, struct mdss_pll_resources *pll_res) { int rc = 0, ndx, i; - struct clk *clk; + struct clk *clk = NULL; struct clk_onecell_data *clk_data; int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_12nm); struct regmap *rmap; struct dsi_pll_db *pdb; if (!pdev || !pdev->dev.of_node || - !pll_res || !pll_res->pll_base || !pll_res->phy_base) { + !pll_res || !pll_res->pll_base) { pr_err("Invalid params\n"); return -EINVAL; } @@ -649,7 +653,7 @@ int dsi_pll_clock_register_12nm(struct platform_device *pdev, clk_data->clk_num = num_clks; /* Establish client data */ - if (ndx == 0) { + if (pll_res->index == 0) { rmap = devm_regmap_init(&pdev->dev, &post_div_mux_regmap_bus, pll_res, &dsi_pll_12nm_config); dsi0pll_post_div_mux.clkr.regmap = rmap; @@ -712,7 +716,8 @@ int dsi_pll_clock_register_12nm(struct platform_device *pdev, of_clk_src_onecell_get, clk_data); } if (!rc) { - pr_info("Registered DSI PLL ndx=%d, clocks successfully", ndx); + pr_info("Registered DSI PLL ndx=%d, clocks successfully", + pll_res->index); return rc; } diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c index 8a948250b2003c58b36f9602b230f30153552cc0..f99070ec9c3dfc308398de2de53be21bad7b2ab1 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.c +++ b/drivers/clk/qcom/mdss/mdss-pll.c @@ -136,6 +136,8 @@ static int mdss_pll_resource_parse(struct platform_device *pdev, pll_res->pll_interface_type = MDSS_DSI_PLL_7NM; else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_7nm_v2")) pll_res->pll_interface_type = MDSS_DSI_PLL_7NM_V2; + else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_12nm")) + pll_res->pll_interface_type = MDSS_DSI_PLL_12NM; else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_28lpm")) pll_res->pll_interface_type = MDSS_DSI_PLL_28LPM; else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_14nm")) diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h index d7e1e2c538517b3e8c9c71c8fe0b536ece0755b9..4e3af2f03b8bc7d0eec97036c6cffb344778bab5 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.h +++ b/drivers/clk/qcom/mdss/mdss-pll.h @@ -219,12 +219,8 @@ static inline bool is_gdsc_disabled(struct mdss_pll_resources *pll_res) WARN(1, "gdsc_base register is not defined\n"); return true; } - if (pll_res->target_id == MDSS_PLL_TARGET_SDM660) - ret = ((readl_relaxed(pll_res->gdsc_base + 0x4) & BIT(31)) && + ret = ((readl_relaxed(pll_res->gdsc_base + 0x4) & BIT(31)) && (!(readl_relaxed(pll_res->gdsc_base) & BIT(0)))) ? false : true; - else - ret = readl_relaxed(pll_res->gdsc_base) & BIT(31) ? - false : true; return ret; } diff --git a/drivers/clk/qcom/vdd-level-cpu.h b/drivers/clk/qcom/vdd-level-cpu.h new file mode 100644 index 0000000000000000000000000000000000000000..5937dde697752067c41eaefe59158f3ed82dadf4 --- /dev/null +++ b/drivers/clk/qcom/vdd-level-cpu.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020, 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. + */ + +#ifndef __DRIVERS_CLK_QCOM_VDD_LEVEL_CPU_H +#define __DRIVERS_CLK_QCOM_VDD_LEVEL_CPU_H + +#include +#include + +enum vdd_hf_pll_levels { + VDD_HF_PLL_OFF, + VDD_HF_PLL_SVS, + VDD_HF_PLL_NOM, + VDD_HF_PLL_TUR, + VDD_HF_PLL_NUM, +}; + +static int vdd_hf_levels[] = { + 0, RPM_REGULATOR_LEVEL_NONE, /* VDD_HF_PLL_OFF */ + 1800000, RPM_REGULATOR_LEVEL_SVS, /* VDD_HF_PLL_SVS */ + 1800000, RPM_REGULATOR_LEVEL_NOM, /* VDD_HF_PLL_NOM */ + 1800000, RPM_REGULATOR_LEVEL_TURBO, /* VDD_HF_PLL_TUR */ +}; + +#endif diff --git a/drivers/clk/qcom/virtio_clk_sm8150.c b/drivers/clk/qcom/virtio_clk_sm8150.c index 7ccab3d24a5573899fa941050d28a9a0e7019953..8f2ca94308585a9837c9827b8054e5f2f9975e80 100644 --- a/drivers/clk/qcom/virtio_clk_sm8150.c +++ b/drivers/clk/qcom/virtio_clk_sm8150.c @@ -67,8 +67,16 @@ static const char * const sm8150_gcc_virtio_clocks[] = { [GCC_PCIE_0_SLV_AXI_CLK] = "gcc_pcie_0_slv_axi_clk", [GCC_PCIE_0_CLKREF_CLK] = "gcc_pcie_0_clkref_en", [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = "gcc_pcie_0_slv_q2a_axi_clk", + [GCC_PCIE_1_PIPE_CLK] = "gcc_pcie_1_pipe_clk", + [GCC_PCIE_1_AUX_CLK] = "gcc_pcie_1_aux_clk", + [GCC_PCIE_1_CFG_AHB_CLK] = "gcc_pcie_1_cfg_ahb_clk", + [GCC_PCIE_1_MSTR_AXI_CLK] = "gcc_pcie_1_mstr_axi_clk", + [GCC_PCIE_1_SLV_AXI_CLK] = "gcc_pcie_1_slv_axi_clk", + [GCC_PCIE_1_CLKREF_CLK] = "gcc_pcie_1_clkref_en", + [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = "gcc_pcie_1_slv_q2a_axi_clk", [GCC_AGGRE_NOC_PCIE_TBU_CLK] = "gcc_aggre_noc_pcie_tbu_clk", [GCC_PCIE0_PHY_REFGEN_CLK] = "gcc_pcie0_phy_refgen_clk", + [GCC_PCIE1_PHY_REFGEN_CLK] = "gcc_pcie1_phy_refgen_clk", [GCC_PCIE_PHY_AUX_CLK] = "gcc_pcie_phy_aux_clk", [GCC_SDCC2_AHB_CLK] = "gcc_sdcc2_ahb_clk", [GCC_SDCC2_APPS_CLK] = "gcc_sdcc2_apps_clk", @@ -86,6 +94,8 @@ static const char * const sm8150_gcc_virtio_resets[] = { [GCC_USB30_SEC_BCR] = "gcc_usb30_sec_master_clk", [GCC_PCIE_0_BCR] = "gcc_pcie_0_mstr_axi_clk", [GCC_PCIE_0_PHY_BCR] = "gcc_pcie_0_phy_bcr", + [GCC_PCIE_1_BCR] = "gcc_pcie_1_mstr_axi_clk", + [GCC_PCIE_1_PHY_BCR] = "gcc_pcie_1_phy_bcr", }; const struct clk_virtio_desc clk_virtio_sm8150_gcc = { diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index d8d3cb67b4029ac58c905fcae097a2c6957a9f22..3d30262219275194c573fe35e35e661f7822a692 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1240,6 +1240,7 @@ static unsigned long __init exynos4_get_xom(void) xom = readl(chipid_base + 8); iounmap(chipid_base); + of_node_put(np); } return xom; diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 47a14f93f8693e68c401bb3d8e09746b2c844429..2f54df5bef8e58470846ac5585e4a5b5d064f591 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -170,6 +170,8 @@ static const unsigned long exynos5x_clk_regs[] __initconst = { GATE_BUS_CPU, GATE_SCLK_CPU, CLKOUT_CMU_CPU, + APLL_CON0, + KPLL_CON0, CPLL_CON0, DPLL_CON0, EPLL_CON0, diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c index 35fabe1a32c30e4b400a77205c892f150b3f5f7c..269467e8e07e13a38399899c75194a347873c658 100644 --- a/drivers/clk/socfpga/clk-pll-a10.c +++ b/drivers/clk/socfpga/clk-pll-a10.c @@ -95,6 +95,7 @@ static struct clk * __init __socfpga_pll_init(struct device_node *node, clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); clk_mgr_a10_base_addr = of_iomap(clkmgr_np, 0); + of_node_put(clkmgr_np); BUG_ON(!clk_mgr_a10_base_addr); pll_clk->hw.reg = clk_mgr_a10_base_addr + reg; diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c index c7f463172e4b93d0cec4b46e45558a301aa16234..b4b44e9b5901132a4849261d1563a6f3a797a469 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -100,6 +100,7 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node, clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); clk_mgr_base_addr = of_iomap(clkmgr_np, 0); + of_node_put(clkmgr_np); BUG_ON(!clk_mgr_base_addr); pll_clk->hw.reg = clk_mgr_base_addr + reg; diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c index d93b452f0df9752aa348323821a5de0e20cd51c3..1cef040ebe82990027c3b21b1f3f1711faf43d44 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -132,7 +132,7 @@ static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_mipi_clk, "pll-mipi", 8, 4, /* N */ 4, 2, /* K */ 0, 4, /* M */ - BIT(31), /* gate */ + BIT(31) | BIT(23) | BIT(22), /* gate */ BIT(28), /* lock */ CLK_SET_RATE_UNGATE); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c index 9e3f4088724b430f111c2996e8d5e51cf368877b..c7f9d974b10d55366df9af45843610f1f2f5e32f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c @@ -84,7 +84,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", BIT(28), /* lock */ 0); -static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr", +static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr0_clk, "pll-ddr0", "osc24M", 0x020, 8, 5, /* N */ 4, 2, /* K */ @@ -123,6 +123,14 @@ static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph1_clk, "pll-periph1", 2, /* post-div */ 0); +static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_ddr1_clk, "pll-ddr1", + "osc24M", 0x04c, + 8, 7, /* N */ + 0, 2, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + static const char * const cpu_parents[] = { "osc32k", "osc24M", "pll-cpu", "pll-cpu" }; static SUNXI_CCU_MUX(cpu_clk, "cpu", cpu_parents, @@ -310,7 +318,8 @@ static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M", 0x0cc, BIT(16), 0); -static const char * const dram_parents[] = { "pll-ddr", "pll-periph0-2x" }; +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1", + "pll-periph0-2x" }; static SUNXI_CCU_M_WITH_MUX(dram_clk, "dram", dram_parents, 0x0f4, 0, 4, 20, 2, CLK_IS_CRITICAL); @@ -369,10 +378,11 @@ static struct ccu_common *sun8i_v3s_ccu_clks[] = { &pll_audio_base_clk.common, &pll_video_clk.common, &pll_ve_clk.common, - &pll_ddr_clk.common, + &pll_ddr0_clk.common, &pll_periph0_clk.common, &pll_isp_clk.common, &pll_periph1_clk.common, + &pll_ddr1_clk.common, &cpu_clk.common, &axi_clk.common, &ahb1_clk.common, @@ -457,11 +467,12 @@ static struct clk_hw_onecell_data sun8i_v3s_hw_clks = { [CLK_PLL_AUDIO_8X] = &pll_audio_8x_clk.hw, [CLK_PLL_VIDEO] = &pll_video_clk.common.hw, [CLK_PLL_VE] = &pll_ve_clk.common.hw, - [CLK_PLL_DDR] = &pll_ddr_clk.common.hw, + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, [CLK_PLL_ISP] = &pll_isp_clk.common.hw, [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, + [CLK_PLL_DDR1] = &pll_ddr1_clk.common.hw, [CLK_CPU] = &cpu_clk.common.hw, [CLK_AXI] = &axi_clk.common.hw, [CLK_AHB1] = &ahb1_clk.common.hw, diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.h b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.h index 4a4d36fdad9601b2d9139a3a55339f704402d387..a091b7217dfd5806d36008139fc5ad07d05b37a9 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.h +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.h @@ -29,7 +29,7 @@ #define CLK_PLL_AUDIO_8X 5 #define CLK_PLL_VIDEO 6 #define CLK_PLL_VE 7 -#define CLK_PLL_DDR 8 +#define CLK_PLL_DDR0 8 #define CLK_PLL_PERIPH0 9 #define CLK_PLL_PERIPH0_2X 10 #define CLK_PLL_ISP 11 @@ -58,6 +58,8 @@ /* And the GPU module clock is exported */ -#define CLK_NUMBER (CLK_MIPI_CSI + 1) +#define CLK_PLL_DDR1 74 + +#define CLK_NUMBER (CLK_PLL_DDR1 + 1) #endif /* _CCU_SUN8I_H3_H_ */ diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index aaf5bfa9bd9c915efdca1b2ac5fba58d86199a01..e3ae041ac30e1af4472c26fdfce517bd38d12cc7 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -563,7 +563,19 @@ static int __init exynos4_timer_resources(struct device_node *np, void __iomem * return 0; out_irq: - free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); + if (mct_int_type == MCT_INT_PPI) { + free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); + } else { + for_each_possible_cpu(cpu) { + struct mct_clock_event_device *pcpu_mevt = + per_cpu_ptr(&percpu_mct_tick, cpu); + + if (pcpu_mevt->evt.irq != -1) { + free_irq(pcpu_mevt->evt.irq, pcpu_mevt); + pcpu_mevt->evt.irq = -1; + } + } + } return err; } diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 2a3fe83ec3377cc160570fc9ed6e0e5375f57f7a..6f4a9a8faccc2a4f4504ce892443410c06681db8 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -202,6 +202,11 @@ static int __init sun5i_setup_clocksource(struct device_node *node, } rate = clk_get_rate(clk); + if (!rate) { + pr_err("Couldn't get parent clock rate\n"); + ret = -EINVAL; + goto err_disable_clk; + } cs->timer.base = base; cs->timer.clk = clk; @@ -275,6 +280,11 @@ static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem } rate = clk_get_rate(clk); + if (!rate) { + pr_err("Couldn't get parent clock rate\n"); + ret = -EINVAL; + goto err_disable_clk; + } ce->timer.base = base; ce->timer.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c index 7281a2c19c362177a57a962f8d587ef40764b92e..39c462711eae04ea23da4481ed9d5f376c86c783 100644 --- a/drivers/cpufreq/brcmstb-avs-cpufreq.c +++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c @@ -468,12 +468,12 @@ static int brcm_avs_set_pstate(struct private_data *priv, unsigned int pstate) return __issue_avs_command(priv, AVS_CMD_SET_PSTATE, true, args); } -static unsigned long brcm_avs_get_voltage(void __iomem *base) +static u32 brcm_avs_get_voltage(void __iomem *base) { return readl(base + AVS_MBOX_VOLTAGE1); } -static unsigned long brcm_avs_get_frequency(void __iomem *base) +static u32 brcm_avs_get_frequency(void __iomem *base) { return readl(base + AVS_MBOX_FREQUENCY) * 1000; /* in kHz */ } @@ -762,8 +762,8 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv) rc = brcm_avs_get_pmap(priv, NULL); magic = readl(priv->base + AVS_MBOX_MAGIC); - return (magic == AVS_FIRMWARE_MAGIC) && (rc != -ENOTSUPP) && - (rc != -EINVAL); + return (magic == AVS_FIRMWARE_MAGIC) && ((rc != -ENOTSUPP) || + (rc != -EINVAL)); } static unsigned int brcm_avs_cpufreq_get(unsigned int cpu) @@ -973,14 +973,14 @@ static ssize_t show_brcm_avs_voltage(struct cpufreq_policy *policy, char *buf) { struct private_data *priv = policy->driver_data; - return sprintf(buf, "0x%08lx\n", brcm_avs_get_voltage(priv->base)); + return sprintf(buf, "0x%08x\n", brcm_avs_get_voltage(priv->base)); } static ssize_t show_brcm_avs_frequency(struct cpufreq_policy *policy, char *buf) { struct private_data *priv = policy->driver_data; - return sprintf(buf, "0x%08lx\n", brcm_avs_get_frequency(priv->base)); + return sprintf(buf, "0x%08x\n", brcm_avs_get_frequency(priv->base)); } cpufreq_freq_attr_ro(brcm_avs_pstate); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 16d123001b5c92d4a6ec64e06967bbc3f96dc45e..21b919bfaeccf7f32e11ca523008afe434802e2f 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -27,7 +27,7 @@ struct cpufreq_stats { unsigned int *trans_table; }; -static int cpufreq_stats_update(struct cpufreq_stats *stats) +static void cpufreq_stats_update(struct cpufreq_stats *stats) { unsigned long long cur_time = get_jiffies_64(); unsigned long flags; @@ -36,7 +36,6 @@ static int cpufreq_stats_update(struct cpufreq_stats *stats) stats->time_in_state[stats->last_index] += cur_time - stats->last_time; stats->last_time = cur_time; spin_unlock_irqrestore(&cpufreq_stats_lock, flags); - return 0; } static void cpufreq_stats_clear_table(struct cpufreq_stats *stats) @@ -113,8 +112,11 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) break; len += snprintf(buf + len, PAGE_SIZE - len, "\n"); } - if (len >= PAGE_SIZE) - return PAGE_SIZE; + + if (len >= PAGE_SIZE) { + pr_warn_once("cpufreq transition table exceeds PAGE_SIZE. Disabling\n"); + return -EFBIG; + } return len; } cpufreq_freq_attr_ro(trans_table); diff --git a/drivers/crypto/amcc/crypto4xx_trng.h b/drivers/crypto/amcc/crypto4xx_trng.h index 931d22531f51590749c803d0dd694e820cab87d8..7bbda51b7337c3a0f5df5d3b9427c75e2d30908f 100644 --- a/drivers/crypto/amcc/crypto4xx_trng.h +++ b/drivers/crypto/amcc/crypto4xx_trng.h @@ -26,9 +26,9 @@ void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev); void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev); #else static inline void ppc4xx_trng_probe( - struct crypto4xx_device *dev __maybe_unused) { } + struct crypto4xx_core_device *dev __maybe_unused) { } static inline void ppc4xx_trng_remove( - struct crypto4xx_device *dev __maybe_unused) { } + struct crypto4xx_core_device *dev __maybe_unused) { } #endif #endif diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index 84422435f39b4aa42c6f9f8c413047880b5fc3d0..279e907590e9887819dc2f53da3a6d0c63402b08 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -718,7 +718,7 @@ static int handle_ahash_req(struct iproc_reqctx_s *rctx) */ unsigned int new_data_len; - unsigned int chunk_start = 0; + unsigned int __maybe_unused chunk_start = 0; u32 db_size; /* Length of data field, incl gcm and hash padding */ int pad_len = 0; /* total pad len, including gcm, hash, stat padding */ u32 data_pad_len = 0; /* length of GCM/CCM padding */ @@ -1676,8 +1676,6 @@ static void spu_rx_callback(struct mbox_client *cl, void *msg) struct spu_hw *spu = &iproc_priv.spu; struct brcm_message *mssg = msg; struct iproc_reqctx_s *rctx; - struct iproc_ctx_s *ctx; - struct crypto_async_request *areq; int err = 0; rctx = mssg->ctx; @@ -1687,8 +1685,6 @@ static void spu_rx_callback(struct mbox_client *cl, void *msg) err = -EFAULT; goto cb_finish; } - areq = rctx->parent; - ctx = rctx->ctx; /* process the SPU status */ err = spu->spu_status_process(rctx->msg_buf.rx_stat); diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index fde07d4ff0190efcc229fd0a561681fcd5c07b28..ff6718a11e9ec74d9409cf8c4c1cbf54d22456da 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -353,7 +353,10 @@ static int __init caam_rng_init(void) goto free_rng_ctx; dev_info(dev, "registering rng-caam\n"); - return hwrng_register(&caam_rng); + + err = hwrng_register(&caam_rng); + if (!err) + return err; free_rng_ctx: kfree(rng_ctx); diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index 8da88beb1abbe1def7582add0e49e88023c430dd..832ba2afdcd57f0e42cfddedbfcccad07a4cdd1b 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -22,7 +22,7 @@ void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, size_t len; void *buf; - for (it = sg; it && tlen > 0 ; it = sg_next(sg)) { + for (it = sg; it && tlen > 0 ; it = sg_next(it)) { /* * make sure the scatterlist's page * has a valid virtual memory mapping diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c index 89291c15015cd3eb0218ec20747273db310a9dd4..3f768699332ba230d7518dee75ae7ada6b357d3a 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes.c +++ b/drivers/crypto/ccp/ccp-crypto-aes.c @@ -1,7 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * AMD Cryptographic Coprocessor (CCP) AES crypto API support * - * Copyright (C) 2013,2016 Advanced Micro Devices, Inc. + * Copyright (C) 2013-2019 Advanced Micro Devices, Inc. * * Author: Tom Lendacky * @@ -79,8 +80,7 @@ static int ccp_aes_crypt(struct ablkcipher_request *req, bool encrypt) return -EINVAL; if (((ctx->u.aes.mode == CCP_AES_MODE_ECB) || - (ctx->u.aes.mode == CCP_AES_MODE_CBC) || - (ctx->u.aes.mode == CCP_AES_MODE_CFB)) && + (ctx->u.aes.mode == CCP_AES_MODE_CBC)) && (req->nbytes & (AES_BLOCK_SIZE - 1))) return -EINVAL; @@ -291,7 +291,7 @@ static struct ccp_aes_def aes_algs[] = { .version = CCP_VERSION(3, 0), .name = "cfb(aes)", .driver_name = "cfb-aes-ccp", - .blocksize = AES_BLOCK_SIZE, + .blocksize = 1, .ivsize = AES_BLOCK_SIZE, .alg_defaults = &ccp_aes_defaults, }, diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index 1e2e42106dee070d92ac543c8e1448327caffb8a..330853a2702f027ac82b5bab4a098ab4f2e8d0d7 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -458,8 +458,8 @@ static int ccp_copy_from_sb(struct ccp_cmd_queue *cmd_q, return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, true); } -static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_aes_engine *aes = &cmd->u.aes; struct ccp_dm_workarea key, ctx; @@ -614,8 +614,8 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_aes_engine *aes = &cmd->u.aes; struct ccp_dm_workarea key, ctx, final_wa, tag; @@ -897,7 +897,8 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_aes_engine *aes = &cmd->u.aes; struct ccp_dm_workarea key, ctx; @@ -907,12 +908,6 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) bool in_place = false; int ret; - if (aes->mode == CCP_AES_MODE_CMAC) - return ccp_run_aes_cmac_cmd(cmd_q, cmd); - - if (aes->mode == CCP_AES_MODE_GCM) - return ccp_run_aes_gcm_cmd(cmd_q, cmd); - if (!((aes->key_len == AES_KEYSIZE_128) || (aes->key_len == AES_KEYSIZE_192) || (aes->key_len == AES_KEYSIZE_256))) @@ -1080,8 +1075,8 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_xts_aes_engine *xts = &cmd->u.xts; struct ccp_dm_workarea key, ctx; @@ -1280,7 +1275,8 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_des3_engine *des3 = &cmd->u.des3; @@ -1293,6 +1289,9 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) int ret; /* Error checks */ + if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0)) + return -EINVAL; + if (!cmd_q->ccp->vdata->perform->des3) return -EINVAL; @@ -1375,8 +1374,6 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) * passthru option to convert from big endian to little endian. */ if (des3->mode != CCP_DES3_MODE_ECB) { - u32 load_mode; - op.sb_ctx = cmd_q->sb_ctx; ret = ccp_init_dm_workarea(&ctx, cmd_q, @@ -1392,12 +1389,8 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) if (ret) goto e_ctx; - if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) - load_mode = CCP_PASSTHRU_BYTESWAP_NOOP; - else - load_mode = CCP_PASSTHRU_BYTESWAP_256BIT; ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx, - load_mode); + CCP_PASSTHRU_BYTESWAP_256BIT); if (ret) { cmd->engine_error = cmd_q->cmd_error; goto e_ctx; @@ -1459,10 +1452,6 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) } /* ...but we only need the last DES3_EDE_BLOCK_SIZE bytes */ - if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) - dm_offset = CCP_SB_BYTES - des3->iv_len; - else - dm_offset = 0; ccp_get_dm_area(&ctx, dm_offset, des3->iv, 0, DES3_EDE_BLOCK_SIZE); } @@ -1483,7 +1472,8 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_sha_engine *sha = &cmd->u.sha; struct ccp_dm_workarea ctx; @@ -1827,7 +1817,8 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_rsa_engine *rsa = &cmd->u.rsa; struct ccp_dm_workarea exp, src, dst; @@ -1958,8 +1949,8 @@ static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_passthru_engine *pt = &cmd->u.passthru; struct ccp_dm_workarea mask; @@ -2090,7 +2081,8 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q, +static noinline_for_stack int +ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_passthru_nomap_engine *pt = &cmd->u.passthru_nomap; @@ -2431,7 +2423,8 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_ecc_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_ecc_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_ecc_engine *ecc = &cmd->u.ecc; @@ -2468,7 +2461,17 @@ int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) switch (cmd->engine) { case CCP_ENGINE_AES: - ret = ccp_run_aes_cmd(cmd_q, cmd); + switch (cmd->u.aes.mode) { + case CCP_AES_MODE_CMAC: + ret = ccp_run_aes_cmac_cmd(cmd_q, cmd); + break; + case CCP_AES_MODE_GCM: + ret = ccp_run_aes_gcm_cmd(cmd_q, cmd); + break; + default: + ret = ccp_run_aes_cmd(cmd_q, cmd); + break; + } break; case CCP_ENGINE_XTS_AES_128: ret = ccp_run_xts_aes_cmd(cmd_q, cmd); diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index bb7b59fc5c08b0b5417ccac58af879aab6edce5b..8d39f3a07bf8605cbe65fcdeea2bd5379bbbd4ba 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -2693,9 +2693,6 @@ static int chcr_gcm_setauthsize(struct crypto_aead *tfm, unsigned int authsize) aeadctx->mayverify = VERIFY_SW; break; default: - - crypto_tfm_set_flags((struct crypto_tfm *) tfm, - CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } return crypto_aead_setauthsize(aeadctx->sw_cipher, authsize); @@ -2720,8 +2717,6 @@ static int chcr_4106_4309_setauthsize(struct crypto_aead *tfm, aeadctx->mayverify = VERIFY_HW; break; default: - crypto_tfm_set_flags((struct crypto_tfm *)tfm, - CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } return crypto_aead_setauthsize(aeadctx->sw_cipher, authsize); @@ -2762,8 +2757,6 @@ static int chcr_ccm_setauthsize(struct crypto_aead *tfm, aeadctx->mayverify = VERIFY_HW; break; default: - crypto_tfm_set_flags((struct crypto_tfm *)tfm, - CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } return crypto_aead_setauthsize(aeadctx->sw_cipher, authsize); @@ -2790,8 +2783,7 @@ static int chcr_ccm_common_setkey(struct crypto_aead *aead, ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; mk_size = CHCR_KEYCTX_MAC_KEY_SIZE_256; } else { - crypto_tfm_set_flags((struct crypto_tfm *)aead, - CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); aeadctx->enckey_len = 0; return -EINVAL; } @@ -2831,8 +2823,7 @@ static int chcr_aead_rfc4309_setkey(struct crypto_aead *aead, const u8 *key, int error; if (keylen < 3) { - crypto_tfm_set_flags((struct crypto_tfm *)aead, - CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); aeadctx->enckey_len = 0; return -EINVAL; } @@ -2883,8 +2874,7 @@ static int chcr_gcm_setkey(struct crypto_aead *aead, const u8 *key, } else if (keylen == AES_KEYSIZE_256) { ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; } else { - crypto_tfm_set_flags((struct crypto_tfm *)aead, - CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); pr_err("GCM: Invalid key length %d\n", keylen); ret = -EINVAL; goto out; diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c index 1a724263761bc52c5f2a518f8e9560e5262c9474..2d178e013535c3bdf7872147be8cae6a347b98bf 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c @@ -179,7 +179,7 @@ static int sun4i_hash(struct ahash_request *areq) */ unsigned int i = 0, end, fill, min_fill, nwait, nbw = 0, j = 0, todo; unsigned int in_i = 0; - u32 spaces, rx_cnt = SS_RX_DEFAULT, bf[32] = {0}, wb = 0, v, ivmode = 0; + u32 spaces, rx_cnt = SS_RX_DEFAULT, bf[32] = {0}, v, ivmode = 0; struct sun4i_req_ctx *op = ahash_request_ctx(areq); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct sun4i_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); @@ -188,6 +188,7 @@ static int sun4i_hash(struct ahash_request *areq) struct sg_mapping_iter mi; int in_r, err = 0; size_t copied = 0; + __le32 wb = 0; dev_dbg(ss->dev, "%s %s bc=%llu len=%u mode=%x wl=%u h0=%0x", __func__, crypto_tfm_alg_name(areq->base.tfm), @@ -399,7 +400,7 @@ static int sun4i_hash(struct ahash_request *areq) nbw = op->len - 4 * nwait; if (nbw) { - wb = *(u32 *)(op->buf + nwait * 4); + wb = cpu_to_le32(*(u32 *)(op->buf + nwait * 4)); wb &= GENMASK((nbw * 8) - 1, 0); op->byte_count += nbw; @@ -408,7 +409,7 @@ static int sun4i_hash(struct ahash_request *areq) /* write the remaining bytes of the nbw buffer */ wb |= ((1 << 7) << (nbw * 8)); - bf[j++] = wb; + bf[j++] = le32_to_cpu(wb); /* * number of space to pad to obtain 64o minus 8(size) minus 4 (final 1) @@ -427,13 +428,13 @@ static int sun4i_hash(struct ahash_request *areq) /* write the length of data */ if (op->mode == SS_OP_SHA1) { - __be64 bits = cpu_to_be64(op->byte_count << 3); - bf[j++] = lower_32_bits(bits); - bf[j++] = upper_32_bits(bits); + __be64 *bits = (__be64 *)&bf[j]; + *bits = cpu_to_be64(op->byte_count << 3); + j += 2; } else { - __le64 bits = op->byte_count << 3; - bf[j++] = lower_32_bits(bits); - bf[j++] = upper_32_bits(bits); + __le64 *bits = (__le64 *)&bf[j]; + *bits = cpu_to_le64(op->byte_count << 3); + j += 2; } writesl(ss->base + SS_RXFIFO, bf, j); @@ -475,7 +476,7 @@ static int sun4i_hash(struct ahash_request *areq) } } else { for (i = 0; i < 4; i++) { - v = readl(ss->base + SS_MD0 + i * 4); + v = cpu_to_le32(readl(ss->base + SS_MD0 + i * 4)); memcpy(areq->result + i * 4, &v, 4); } } diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 0d6256d2ce5844f4f6c7ceba6150168cc8ac4723..e66ea89537923a3b8232a568e150d173b33f4cc6 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -944,6 +944,14 @@ int devfreq_remove_governor(struct devfreq_governor *governor) } EXPORT_SYMBOL(devfreq_remove_governor); +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct devfreq *devfreq = to_devfreq(dev); + return sprintf(buf, "%s\n", dev_name(devfreq->dev.parent)); +} +static DEVICE_ATTR_RO(name); + static ssize_t governor_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1272,6 +1280,7 @@ static ssize_t trans_stat_show(struct device *dev, static DEVICE_ATTR_RO(trans_stat); static struct attribute *devfreq_attrs[] = { + &dev_attr_name.attr, &dev_attr_governor.attr, &dev_attr_available_governors.attr, &dev_attr_cur_freq.attr, diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 75db633cbe88635bcd79db12fa02fcf1bf53934b..4e8bcd708bffba8279de74bfddece50a850beb89 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -69,18 +70,34 @@ struct dma_proc { static struct dma_buf_list db_list; +static void dmabuf_dent_put(struct dma_buf *dmabuf) +{ + if (atomic_dec_and_test(&dmabuf->dent_count)) { + kfree(dmabuf->name); + kfree(dmabuf); + } +} + + static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen) { struct dma_buf *dmabuf; char name[DMA_BUF_NAME_LEN]; size_t ret = 0; + spin_lock(&dentry->d_lock); dmabuf = dentry->d_fsdata; + if (!dmabuf || !atomic_add_unless(&dmabuf->dent_count, 1, 0)) { + spin_unlock(&dentry->d_lock); + goto out; + } + spin_unlock(&dentry->d_lock); mutex_lock(&dmabuf->lock); if (dmabuf->name) ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN); mutex_unlock(&dmabuf->lock); - + dmabuf_dent_put(dmabuf); +out: return dynamic_dname(dentry, buffer, buflen, "/%s:%s", dentry->d_name.name, ret > 0 ? name : ""); } @@ -107,12 +124,16 @@ static struct file_system_type dma_buf_fs_type = { static int dma_buf_release(struct inode *inode, struct file *file) { struct dma_buf *dmabuf; + struct dentry *dentry = file->f_path.dentry; if (!is_dma_buf_file(file)) return -EINVAL; dmabuf = file->private_data; + spin_lock(&dentry->d_lock); + dentry->d_fsdata = NULL; + spin_unlock(&dentry->d_lock); BUG_ON(dmabuf->vmapping_counter); /* @@ -137,8 +158,7 @@ static int dma_buf_release(struct inode *inode, struct file *file) reservation_object_fini(dmabuf->resv); module_put(dmabuf->owner); - kfree(dmabuf->buf_name); - kfree(dmabuf); + dmabuf_dent_put(dmabuf); return 0; } @@ -609,6 +629,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) dmabuf->buf_name = bufname; dmabuf->name = bufname; dmabuf->ktime = ktime_get(); + atomic_set(&dmabuf->dent_count, 1); if (!resv) { resv = (struct reservation_object *)&dmabuf[1]; diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index 7f0b9aa158679aca780d86890426339f48586f4b..9887f2a14aa9885a4211444cf09acd0c9bbe931b 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -451,7 +451,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_interleaved( if (chan->hw_2d) { if (!axi_dmac_check_len(chan, xt->sgl[0].size) || - !axi_dmac_check_len(chan, xt->numf)) + xt->numf == 0) return NULL; if (xt->sgl[0].size + dst_icg > chan->max_length || xt->sgl[0].size + src_icg > chan->max_length) diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 46a519e07195c73846a7672f04fc19417b948301..b408c07662f594a0c5c9a809b402a0bcda90a912 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -87,13 +87,20 @@ static void dw_dma_acpi_controller_register(struct dw_dma *dw) dma_cap_set(DMA_SLAVE, info->dma_cap); info->filter_fn = dw_dma_acpi_filter; - ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate, - info); + ret = acpi_dma_controller_register(dev, acpi_dma_simple_xlate, info); if (ret) dev_err(dev, "could not register acpi_dma_controller\n"); } + +static void dw_dma_acpi_controller_free(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + + acpi_dma_controller_free(dev); +} #else /* !CONFIG_ACPI */ static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {} +static inline void dw_dma_acpi_controller_free(struct dw_dma *dw) {} #endif /* !CONFIG_ACPI */ #ifdef CONFIG_OF @@ -249,6 +256,9 @@ static int dw_remove(struct platform_device *pdev) { struct dw_dma_chip *chip = platform_get_drvdata(pdev); + if (ACPI_HANDLE(&pdev->dev)) + dw_dma_acpi_controller_free(chip->dw); + if (pdev->dev.of_node) of_dma_controller_free(pdev->dev.of_node); diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 519c24465dea4cd12992ecfbc9fb2bc6352e7c9f..57a49fe713fdcfebf0ab4c372b2472ec4474bbe1 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -2340,8 +2340,10 @@ static int edma_probe(struct platform_device *pdev) ecc->tc_list = devm_kcalloc(dev, ecc->num_tc, sizeof(*ecc->tc_list), GFP_KERNEL); - if (!ecc->tc_list) - return -ENOMEM; + if (!ecc->tc_list) { + ret = -ENOMEM; + goto err_reg1; + } for (i = 0;; i++) { ret = of_parse_phandle_with_fixed_args(node, "ti,tptcs", diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index 29d04ca71d52ed05e47435a869fd7826ae93aa08..15525a2b8ebd71429ab64378721f1e9eb8da592c 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -64,10 +64,10 @@ static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc) if (hsuc->direction == DMA_MEM_TO_DEV) { bsr = config->dst_maxburst; - mtsr = config->src_addr_width; + mtsr = config->dst_addr_width; } else if (hsuc->direction == DMA_DEV_TO_MEM) { bsr = config->src_maxburst; - mtsr = config->dst_addr_width; + mtsr = config->src_addr_width; } hsu_chan_disable(hsuc); diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 0fc12a8783e39456dcac63c7392b5c92349ef0cb..99f3f22ed6476ac1a125b3106d813a1658bc624d 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1441,6 +1441,14 @@ static void sdma_add_scripts(struct sdma_engine *sdma, if (!sdma->script_number) sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; + if (sdma->script_number > sizeof(struct sdma_script_start_addrs) + / sizeof(s32)) { + dev_err(sdma->dev, + "SDMA script number %d not match with firmware.\n", + sdma->script_number); + return; + } + for (i = 0; i < sdma->script_number; i++) if (addr_arr[i] > 0) saddr_arr[i] = addr_arr[i]; diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index f70cc74032eaa9fd1d8da9b4203839e25befd1f6..e3899ae429e0ff18960dd4e37b73462454fd6fbe 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -388,10 +388,11 @@ ioat_alloc_ring(struct dma_chan *c, int order, gfp_t flags) descs->virt = dma_alloc_coherent(to_dev(ioat_chan), SZ_2M, &descs->hw, flags); - if (!descs->virt && (i > 0)) { + if (!descs->virt) { int idx; for (idx = 0; idx < i; idx++) { + descs = &ioat_chan->descs[idx]; dma_free_coherent(to_dev(ioat_chan), SZ_2M, descs->virt, descs->hw); descs->virt = NULL; diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 219ae3b545dbab035d20ce628c7a025159f9e9bb..803045c92f3ba5dd723e236fee0ae4bed235260b 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -222,9 +222,11 @@ static irqreturn_t k3_dma_int_handler(int irq, void *dev_id) c = p->vchan; if (c && (tc1 & BIT(i))) { spin_lock_irqsave(&c->vc.lock, flags); - vchan_cookie_complete(&p->ds_run->vd); - p->ds_done = p->ds_run; - p->ds_run = NULL; + if (p->ds_run != NULL) { + vchan_cookie_complete(&p->ds_run->vd); + p->ds_done = p->ds_run; + p->ds_run = NULL; + } spin_unlock_irqrestore(&c->vc.lock, flags); } if (c && (tc2 & BIT(i))) { @@ -264,6 +266,10 @@ static int k3_dma_start_txd(struct k3_dma_chan *c) if (BIT(c->phy->idx) & k3_dma_get_chan_stat(d)) return -EAGAIN; + /* Avoid losing track of ds_run if a transaction is in flight */ + if (c->phy->ds_run) + return -EAGAIN; + if (vd) { struct k3_dma_desc_sw *ds = container_of(vd, struct k3_dma_desc_sw, vd); diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 1993889003fd11d51d80090daf32737d740a5b4b..1c57577f49fea23cd1aa73c7df850effe2b88d1b 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1059,6 +1059,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev, mv_chan->op_in_desc = XOR_MODE_IN_DESC; dma_dev = &mv_chan->dmadev; + dma_dev->dev = &pdev->dev; mv_chan->xordev = xordev; /* @@ -1091,7 +1092,6 @@ mv_xor_channel_add(struct mv_xor_device *xordev, dma_dev->device_free_chan_resources = mv_xor_free_chan_resources; dma_dev->device_tx_status = mv_xor_status; dma_dev->device_issue_pending = mv_xor_issue_pending; - dma_dev->dev = &pdev->dev; /* set prep routines based on capability */ if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask)) diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index 09b6756366c30ec70c0976850abbfd9c703be0a8..4f4733d831a1ac9fc3043c4d8b8d6b5b2fd0ac8e 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -98,6 +98,7 @@ struct tegra_adma_chan_regs { unsigned int src_addr; unsigned int trg_addr; unsigned int fifo_ctrl; + unsigned int cmd; unsigned int tc; }; @@ -127,6 +128,7 @@ struct tegra_adma_chan { enum dma_transfer_direction sreq_dir; unsigned int sreq_index; bool sreq_reserved; + struct tegra_adma_chan_regs ch_regs; /* Transfer count and position info */ unsigned int tx_buf_count; @@ -635,8 +637,30 @@ static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec, static int tegra_adma_runtime_suspend(struct device *dev) { struct tegra_adma *tdma = dev_get_drvdata(dev); + struct tegra_adma_chan_regs *ch_reg; + struct tegra_adma_chan *tdc; + int i; tdma->global_cmd = tdma_read(tdma, ADMA_GLOBAL_CMD); + if (!tdma->global_cmd) + goto clk_disable; + + for (i = 0; i < tdma->nr_channels; i++) { + tdc = &tdma->channels[i]; + ch_reg = &tdc->ch_regs; + ch_reg->cmd = tdma_ch_read(tdc, ADMA_CH_CMD); + /* skip if channel is not active */ + if (!ch_reg->cmd) + continue; + ch_reg->tc = tdma_ch_read(tdc, ADMA_CH_TC); + ch_reg->src_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_SRC_ADDR); + ch_reg->trg_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_TRG_ADDR); + ch_reg->ctrl = tdma_ch_read(tdc, ADMA_CH_CTRL); + ch_reg->fifo_ctrl = tdma_ch_read(tdc, ADMA_CH_FIFO_CTRL); + ch_reg->config = tdma_ch_read(tdc, ADMA_CH_CONFIG); + } + +clk_disable: clk_disable_unprepare(tdma->ahub_clk); return 0; @@ -645,7 +669,9 @@ static int tegra_adma_runtime_suspend(struct device *dev) static int tegra_adma_runtime_resume(struct device *dev) { struct tegra_adma *tdma = dev_get_drvdata(dev); - int ret; + struct tegra_adma_chan_regs *ch_reg; + struct tegra_adma_chan *tdc; + int ret, i; ret = clk_prepare_enable(tdma->ahub_clk); if (ret) { @@ -654,6 +680,24 @@ static int tegra_adma_runtime_resume(struct device *dev) } tdma_write(tdma, ADMA_GLOBAL_CMD, tdma->global_cmd); + if (!tdma->global_cmd) + return 0; + + for (i = 0; i < tdma->nr_channels; i++) { + tdc = &tdma->channels[i]; + ch_reg = &tdc->ch_regs; + /* skip if channel was not active earlier */ + if (!ch_reg->cmd) + continue; + tdma_ch_write(tdc, ADMA_CH_TC, ch_reg->tc); + tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR, ch_reg->src_addr); + tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR, ch_reg->trg_addr); + tdma_ch_write(tdc, ADMA_CH_CTRL, ch_reg->ctrl); + tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_reg->fifo_ctrl); + tdma_ch_write(tdc, ADMA_CH_CONFIG, ch_reg->config); + tdma_ch_write(tdc, ADMA_CH_CMD, ch_reg->cmd); + } + return 0; } @@ -700,16 +744,6 @@ static int tegra_adma_probe(struct platform_device *pdev) return PTR_ERR(tdma->ahub_clk); } - pm_runtime_enable(&pdev->dev); - - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) - goto rpm_disable; - - ret = tegra_adma_init(tdma); - if (ret) - goto rpm_put; - INIT_LIST_HEAD(&tdma->dma_dev.channels); for (i = 0; i < tdma->nr_channels; i++) { struct tegra_adma_chan *tdc = &tdma->channels[i]; @@ -727,6 +761,16 @@ static int tegra_adma_probe(struct platform_device *pdev) tdc->tdma = tdma; } + pm_runtime_enable(&pdev->dev); + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) + goto rpm_disable; + + ret = tegra_adma_init(tdma); + if (ret) + goto rpm_put; + dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask); dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask); dma_cap_set(DMA_CYCLIC, tdma->dma_dev.cap_mask); @@ -768,13 +812,13 @@ static int tegra_adma_probe(struct platform_device *pdev) dma_remove: dma_async_device_unregister(&tdma->dma_dev); -irq_dispose: - while (--i >= 0) - irq_dispose_mapping(tdma->channels[i].irq); rpm_put: pm_runtime_put_sync(&pdev->dev); rpm_disable: pm_runtime_disable(&pdev->dev); +irq_dispose: + while (--i >= 0) + irq_dispose_mapping(tdma->channels[i].irq); return ret; } diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index f7fa05fee45a1c803fe85b286b4096957ffb89ab..329021189c38bc2a343ee78882cf53289f93720f 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -680,22 +680,18 @@ static int del_mc_from_global_list(struct mem_ctl_info *mci) struct mem_ctl_info *edac_mc_find(int idx) { - struct mem_ctl_info *mci = NULL; + struct mem_ctl_info *mci; struct list_head *item; mutex_lock(&mem_ctls_mutex); list_for_each(item, &mc_devices) { mci = list_entry(item, struct mem_ctl_info, link); - - if (mci->mc_idx >= idx) { - if (mci->mc_idx == idx) { - goto unlock; - } - break; - } + if (mci->mc_idx == idx) + goto unlock; } + mci = NULL; unlock: mutex_unlock(&mem_ctls_mutex); return mci; diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c index 24c461dea7afb146a509e097b581aa2fdaede132..fd8053f9556e72090d595a736621333aa5be546a 100644 --- a/drivers/firmware/efi/libstub/gop.c +++ b/drivers/firmware/efi/libstub/gop.c @@ -85,30 +85,6 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, } } -static efi_status_t -__gop_query32(efi_system_table_t *sys_table_arg, - struct efi_graphics_output_protocol_32 *gop32, - struct efi_graphics_output_mode_info **info, - unsigned long *size, u64 *fb_base) -{ - struct efi_graphics_output_protocol_mode_32 *mode; - efi_graphics_output_protocol_query_mode query_mode; - efi_status_t status; - unsigned long m; - - m = gop32->mode; - mode = (struct efi_graphics_output_protocol_mode_32 *)m; - query_mode = (void *)(unsigned long)gop32->query_mode; - - status = __efi_call_early(query_mode, (void *)gop32, mode->mode, size, - info); - if (status != EFI_SUCCESS) - return status; - - *fb_base = mode->frame_buffer_base; - return status; -} - static efi_status_t setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, efi_guid_t *proto, unsigned long size, void **gop_handle) @@ -121,7 +97,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, u64 fb_base; struct efi_pixel_bitmask pixel_info; int pixel_format; - efi_status_t status = EFI_NOT_FOUND; + efi_status_t status; u32 *handles = (u32 *)(unsigned long)gop_handle; int i; @@ -130,6 +106,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, nr_gops = size / sizeof(u32); for (i = 0; i < nr_gops; i++) { + struct efi_graphics_output_protocol_mode_32 *mode; struct efi_graphics_output_mode_info *info = NULL; efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; bool conout_found = false; @@ -147,9 +124,11 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, if (status == EFI_SUCCESS) conout_found = true; - status = __gop_query32(sys_table_arg, gop32, &info, &size, - ¤t_fb_base); - if (status == EFI_SUCCESS && (!first_gop || conout_found) && + mode = (void *)(unsigned long)gop32->mode; + info = (void *)(unsigned long)mode->info; + current_fb_base = mode->frame_buffer_base; + + if ((!first_gop || conout_found) && info->pixel_format != PIXEL_BLT_ONLY) { /* * Systems that use the UEFI Console Splitter may @@ -177,7 +156,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, /* Did we find any GOPs? */ if (!first_gop) - goto out; + return EFI_NOT_FOUND; /* EFI framebuffer */ si->orig_video_isVGA = VIDEO_TYPE_EFI; @@ -199,32 +178,8 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, si->lfb_size = si->lfb_linelength * si->lfb_height; si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; -out: - return status; -} - -static efi_status_t -__gop_query64(efi_system_table_t *sys_table_arg, - struct efi_graphics_output_protocol_64 *gop64, - struct efi_graphics_output_mode_info **info, - unsigned long *size, u64 *fb_base) -{ - struct efi_graphics_output_protocol_mode_64 *mode; - efi_graphics_output_protocol_query_mode query_mode; - efi_status_t status; - unsigned long m; - - m = gop64->mode; - mode = (struct efi_graphics_output_protocol_mode_64 *)m; - query_mode = (void *)(unsigned long)gop64->query_mode; - - status = __efi_call_early(query_mode, (void *)gop64, mode->mode, size, - info); - if (status != EFI_SUCCESS) - return status; - *fb_base = mode->frame_buffer_base; - return status; + return EFI_SUCCESS; } static efi_status_t @@ -239,7 +194,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, u64 fb_base; struct efi_pixel_bitmask pixel_info; int pixel_format; - efi_status_t status = EFI_NOT_FOUND; + efi_status_t status; u64 *handles = (u64 *)(unsigned long)gop_handle; int i; @@ -248,6 +203,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, nr_gops = size / sizeof(u64); for (i = 0; i < nr_gops; i++) { + struct efi_graphics_output_protocol_mode_64 *mode; struct efi_graphics_output_mode_info *info = NULL; efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; bool conout_found = false; @@ -265,9 +221,11 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, if (status == EFI_SUCCESS) conout_found = true; - status = __gop_query64(sys_table_arg, gop64, &info, &size, - ¤t_fb_base); - if (status == EFI_SUCCESS && (!first_gop || conout_found) && + mode = (void *)(unsigned long)gop64->mode; + info = (void *)(unsigned long)mode->info; + current_fb_base = mode->frame_buffer_base; + + if ((!first_gop || conout_found) && info->pixel_format != PIXEL_BLT_ONLY) { /* * Systems that use the UEFI Console Splitter may @@ -295,7 +253,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, /* Did we find any GOPs? */ if (!first_gop) - goto out; + return EFI_NOT_FOUND; /* EFI framebuffer */ si->orig_video_isVGA = VIDEO_TYPE_EFI; @@ -317,8 +275,8 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, si->lfb_size = si->lfb_linelength * si->lfb_height; si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; -out: - return status; + + return EFI_SUCCESS; } /* diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index f8d3dd338506ae2dcb22e68cc3b51cdd92719b9b..f0887b823b8405df79a5c21a6c088421633fde85 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -328,6 +328,7 @@ static struct tzdbg tzdbg = { static struct tzdbg_log_t *g_qsee_log; static dma_addr_t coh_pmem; static uint32_t debug_rw_buf_size; +static bool restore_from_hibernation; /* * Debugfs data structure and functions @@ -718,6 +719,15 @@ static int _disp_tz_log_stats(size_t count) { static struct tzdbg_log_pos_t log_start = {0}; struct tzdbg_log_t *log_ptr; + /* wrap and offset are initialized to zero since tz is coldboot + * during restoration from hibernation.the reason to initialise + * the wrap and offset to zero since it contains previous boot + * values and which are invalid now. + */ + if (restore_from_hibernation) { + log_start.wrap = log_start.offset = 0; + return 0; + } log_ptr = (struct tzdbg_log_t *)((unsigned char *)tzdbg.diag_buf + tzdbg.diag_buf->ring_off - @@ -743,6 +753,16 @@ static int _disp_qsee_log_stats(size_t count) { static struct tzdbg_log_pos_t log_start = {0}; + /* wrap and offset are initialized to zero since tz is coldboot + * during restoration from hibernation. The reason to initialise + * the wrap and offset to zero since it contains previous values + * and which are invalid now. + */ + if (restore_from_hibernation) { + log_start.wrap = log_start.offset = 0; + return 0; + } + return _disp_log_stats(g_qsee_log, &log_start, QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t), count, TZDBG_QSEE_LOG); @@ -1144,20 +1164,34 @@ static int tz_log_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int tz_log_freeze(struct device *dev) { - dma_free_coherent(dev, QSEE_LOG_BUF_SIZE, (void *)g_qsee_log, - coh_pmem); - + /* This Boolean variable is maintained to initialise the ring buffer + * log pointer to zero during restoration from hibernation + */ + restore_from_hibernation = 1; + if (g_qsee_log) + dma_free_coherent(dev, QSEE_LOG_BUF_SIZE, (void *)g_qsee_log, + coh_pmem); return 0; } static int tz_log_restore(struct device *dev) { + /* ring buffer log pointer needs to be re initialized + * during restoration from hibernation. + */ + if (restore_from_hibernation) { + _disp_tz_log_stats(0); + _disp_qsee_log_stats(0); + } /* Register the log bugger at TZ during hibernation resume. * After hibernation the log buffer is with HLOS as TZ encountered * a coldboot sequence. */ tzdbg_register_qsee_log_buf(to_platform_device(dev)); - + /* This is set back to zero after successful restoration + * from hibernation. + */ + restore_from_hibernation = 0; return 0; } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b3d1ddd546a54406d4add87f30e7a63af3be6f93..8f230c9dadd1b544373b89ee90f0b5a89939296b 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -989,6 +989,7 @@ config GPIO_LP87565 config GPIO_MAX77620 tristate "GPIO support for PMIC MAX77620 and MAX20024" depends on MFD_MAX77620 + select GPIOLIB_IRQCHIP help GPIO driver for MAX77620 and MAX20024 PMIC from Maxim Semiconductor. MAX77620 PMIC has 8 pins that can be configured as GPIOs. The diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index e7783b852d69716bf6b885e0ca7672605be863d0..d5f735ce0dd4c07599ae0dad8ced25f3cfdc769e 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -306,6 +306,7 @@ static int mpc8xxx_probe(struct platform_device *pdev) return -ENOMEM; gc = &mpc8xxx_gc->gc; + gc->parent = &pdev->dev; if (of_property_read_bool(np, "little-endian")) { ret = bgpio_init(gc, &pdev->dev, 4, diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index b3cc948a2d8b4e80af6c7b6d81c63e5eb8c78d10..f1d7066b6637e395e6c164940dfdc4a02653dcbf 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -639,6 +639,8 @@ static void zynq_gpio_restore_context(struct zynq_gpio *gpio) unsigned int bank_num; for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) { + writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr + + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); writel_relaxed(gpio->context.datalsw[bank_num], gpio->base_addr + ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num)); @@ -648,9 +650,6 @@ static void zynq_gpio_restore_context(struct zynq_gpio *gpio) writel_relaxed(gpio->context.dirm[bank_num], gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); - writel_relaxed(gpio->context.int_en[bank_num], - gpio->base_addr + - ZYNQ_GPIO_INTEN_OFFSET(bank_num)); writel_relaxed(gpio->context.int_type[bank_num], gpio->base_addr + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); @@ -660,6 +659,9 @@ static void zynq_gpio_restore_context(struct zynq_gpio *gpio) writel_relaxed(gpio->context.int_any[bank_num], gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); + writel_relaxed(~(gpio->context.int_en[bank_num]), + gpio->base_addr + + ZYNQ_GPIO_INTEN_OFFSET(bank_num)); } } diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 3aa7fe6baf2a6a6908736618886384024d94ce14..c7b9125c8ec229e7b9871c63665751177fd54bdc 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -24,11 +24,19 @@ #include "gpiolib.h" +#define QUIRK_NO_EDGE_EVENTS_ON_BOOT 0x01l +#define QUIRK_NO_WAKEUP 0x02l + static int run_edge_events_on_boot = -1; module_param(run_edge_events_on_boot, int, 0444); MODULE_PARM_DESC(run_edge_events_on_boot, "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto"); +static int honor_wakeup = -1; +module_param(honor_wakeup, int, 0444); +MODULE_PARM_DESC(honor_wakeup, + "Honor the ACPI wake-capable flag: 0=no, 1=yes, -1=auto"); + /** * struct acpi_gpio_event - ACPI GPIO event handler data * @@ -339,7 +347,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, event->handle = evt_handle; event->handler = handler; event->irq = irq; - event->irq_is_wake = agpio->wake_capable == ACPI_WAKE_CAPABLE; + event->irq_is_wake = honor_wakeup && agpio->wake_capable == ACPI_WAKE_CAPABLE; event->pin = pin; event->desc = desc; @@ -1312,7 +1320,7 @@ static int acpi_gpio_handle_deferred_request_irqs(void) /* We must use _sync so that this runs after the first deferred_probe run */ late_initcall_sync(acpi_gpio_handle_deferred_request_irqs); -static const struct dmi_system_id run_edge_events_on_boot_blacklist[] = { +static const struct dmi_system_id gpiolib_acpi_quirks[] = { { /* * The Minix Neo Z83-4 has a micro-USB-B id-pin handler for @@ -1322,7 +1330,8 @@ static const struct dmi_system_id run_edge_events_on_boot_blacklist[] = { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MINIX"), DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"), - } + }, + .driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT, }, { /* @@ -1334,20 +1343,52 @@ static const struct dmi_system_id run_edge_events_on_boot_blacklist[] = { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"), DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"), - } + }, + .driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT, + }, + { + /* + * Various HP X2 10 Cherry Trail models use an external + * embedded-controller connected via I2C + an ACPI GPIO + * event handler. The embedded controller generates various + * spurious wakeup events when suspended. So disable wakeup + * for its handler (it uses the only ACPI GPIO event handler). + * This breaks wakeup when opening the lid, the user needs + * to press the power-button to wakeup the system. The + * alternative is suspend simply not working, which is worse. + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"), + }, + .driver_data = (void *)QUIRK_NO_WAKEUP, }, {} /* Terminating entry */ }; static int acpi_gpio_setup_params(void) { + const struct dmi_system_id *id; + long quirks = 0; + + id = dmi_first_match(gpiolib_acpi_quirks); + if (id) + quirks = (long)id->driver_data; + if (run_edge_events_on_boot < 0) { - if (dmi_check_system(run_edge_events_on_boot_blacklist)) + if (quirks & QUIRK_NO_EDGE_EVENTS_ON_BOOT) run_edge_events_on_boot = 0; else run_edge_events_on_boot = 1; } + if (honor_wakeup < 0) { + if (quirks & QUIRK_NO_WAKEUP) + honor_wakeup = 0; + else + honor_wakeup = 1; + } + return 0; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f5a25fae927c24b35f74aa72cedd6bb2f3889570..d5b42cc86d718865d4682c778fd938159ced0baf 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3150,8 +3150,9 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, if (chip->ngpio <= p->chip_hwnum) { dev_err(dev, - "requested GPIO %d is out of range [0..%d] for chip %s\n", - idx, chip->ngpio, chip->label); + "requested GPIO %u (%u) is out of range [0..%u] for chip %s\n", + idx, p->chip_hwnum, chip->ngpio - 1, + chip->label); return ERR_PTR(-EINVAL); } diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 41b3252feba7fc51265ce27e57b197497e44a74c..c635e13e92b92f699da3458ba3a6e897da91c986 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -270,7 +270,7 @@ static void drm_dp_encode_sideband_req(struct drm_dp_sideband_msg_req_body *req, memcpy(&buf[idx], req->u.i2c_read.transactions[i].bytes, req->u.i2c_read.transactions[i].num_bytes); idx += req->u.i2c_read.transactions[i].num_bytes; - buf[idx] = (req->u.i2c_read.transactions[i].no_stop_bit & 0x1) << 5; + buf[idx] = (req->u.i2c_read.transactions[i].no_stop_bit & 0x1) << 4; buf[idx] |= (req->u.i2c_read.transactions[i].i2c_transaction_delay & 0xf); idx++; } @@ -1019,9 +1019,20 @@ static struct drm_dp_mst_port *drm_dp_mst_get_port_ref_locked(struct drm_dp_mst_ static struct drm_dp_mst_port *drm_dp_get_validated_port_ref(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { struct drm_dp_mst_port *rport = NULL; + mutex_lock(&mgr->lock); - if (mgr->mst_primary) - rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, port); + /* + * Port may or may not be 'valid' but we don't care about that when + * destroying the port and we are guaranteed that the port pointer + * will be valid until we've finished + */ + if (current_work() == &mgr->destroy_connector_work) { + kref_get(&port->kref); + rport = port; + } else if (mgr->mst_primary) { + rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, + port); + } mutex_unlock(&mgr->lock); return rport; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index f1259a0c2883da105109a8ee2530a0e33cc5b1e3..eb6bf881c465a51be98e4b10e2aea428704e707d 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1590,7 +1590,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, * Changes struct fb_var_screeninfo are currently not pushed back * to KMS, hence fail if different settings are requested. */ - if (var->bits_per_pixel != fb->format->cpp[0] * 8 || + if (var->bits_per_pixel > fb->format->cpp[0] * 8 || var->xres > fb->width || var->yres > fb->height || var->xres_virtual > fb->width || var->yres_virtual > fb->height) { DRM_DEBUG("fb requested width/height/bpp can't fit in current fb " @@ -1615,6 +1615,11 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, drm_fb_helper_fill_pixel_fmt(var, fb->format->depth); } + /* + * Likewise, bits_per_pixel should be rounded up to a supported value. + */ + var->bits_per_pixel = fb->format->cpp[0] * 8; + /* * drm fbdev emulation doesn't support changing the pixel format at all, * so reject all pixel format changing requests. diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c index 2d955d7d7b6d83ecdfae58e5bf26084f28a98999..e154e6fb64dacca169c7994b92b4eb9d50d25e6b 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c @@ -207,7 +207,7 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) mutex_lock(&obj->lock); pages = etnaviv_gem_get_pages(obj); mutex_unlock(&obj->lock); - if (pages) { + if (!IS_ERR(pages)) { int j; iter.hdr->data[0] = bomap - bomap_start; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c index ae884723e9b1b7a59c3f38a4518d6a804be6b074..880b95511b987dda481acf14a2c38f92391b56eb 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c @@ -26,7 +26,7 @@ struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj) int npages = obj->size >> PAGE_SHIFT; if (WARN_ON(!etnaviv_obj->pages)) /* should have already pinned! */ - return NULL; + return ERR_PTR(-EINVAL); return drm_prime_pages_to_sg(etnaviv_obj->pages, npages); } diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c index 8bd29075ae4ebb9c0d865d00b92d7f5a7be9e163..edcca17615001cb4ba37e7ac3601d731189f36c8 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c @@ -71,7 +71,6 @@ static int hibmc_drm_fb_create(struct drm_fb_helper *helper, DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n", sizes->surface_width, sizes->surface_height, sizes->surface_bpp); - sizes->surface_depth = 32; bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 3925a63c1661fcc250fd38871b7f88aec28aa2ff..cdb67889817cbdc5055fe38ce2c5c3835cbaf363 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -993,18 +993,19 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, if (args->ctx_id == DEFAULT_CONTEXT_HANDLE) return -ENOENT; + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + ctx = i915_gem_context_lookup(file_priv, args->ctx_id); - if (!ctx) + if (!ctx) { + mutex_unlock(&dev->struct_mutex); return -ENOENT; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - goto out; + } __destroy_hw_context(ctx, file_priv); mutex_unlock(&dev->struct_mutex); -out: i915_gem_context_put(ctx); return 0; } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index e0483c068d2310d96ea6952c575d5440eeb6b3e2..baff1f01bfc799ce69bcd1bfdf5cea59b3c4ad88 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1101,17 +1101,14 @@ static u32 *gen9_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) *batch++ = MI_NOOP; - /* WaClearSlmSpaceAtContextSwitch:kbl */ - /* Actual scratch location is at 128 bytes offset */ - if (IS_KBL_REVID(engine->i915, 0, KBL_REVID_A0)) { - batch = gen8_emit_pipe_control(batch, - PIPE_CONTROL_FLUSH_L3 | - PIPE_CONTROL_GLOBAL_GTT_IVB | - PIPE_CONTROL_CS_STALL | - PIPE_CONTROL_QW_WRITE, - i915_ggtt_offset(engine->scratch) - + 2 * CACHELINE_BYTES); - } + /* WaClearSlmSpaceAtContextSwitch:skl,bxt,kbl,glk,cfl */ + batch = gen8_emit_pipe_control(batch, + PIPE_CONTROL_FLUSH_L3 | + PIPE_CONTROL_GLOBAL_GTT_IVB | + PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_QW_WRITE, + i915_ggtt_offset(engine->scratch) + + 2 * CACHELINE_BYTES); /* WaMediaPoolStateCmdInWABB:bxt,glk */ if (HAS_POOLED_EU(engine->i915)) { diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 7791313405b5fc26d7d5954aa8cff6483c25c907..c8671b1578c6627a2132389ac901c99262517659 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -394,19 +394,17 @@ static const unsigned int a3xx_registers[] = { 0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e, 0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8, 0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7, - 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356, - 0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d, - 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472, - 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef, - 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511, - 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed, - 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a, - 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce, - 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec, - 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749, - 0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d, - 0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036, - 0x303c, 0x303c, 0x305e, 0x305f, + 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2440, 0x2440, 0x2444, 0x2444, + 0x2448, 0x244d, 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, + 0x2472, 0x2472, 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, + 0x24e4, 0x24ef, 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, + 0x2510, 0x2511, 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, + 0x25ec, 0x25ed, 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, + 0x261a, 0x261a, 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, + 0x26c4, 0x26ce, 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, + 0x26ec, 0x26ec, 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, + 0x300c, 0x300e, 0x301c, 0x301d, 0x302a, 0x302a, 0x302c, 0x302d, + 0x3030, 0x3031, 0x3034, 0x3036, 0x303c, 0x303c, 0x305e, 0x305f, ~0 /* sentinel */ }; diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index aeafe9738e104ac24a65377b367d1abbbe6e1949..1c7105f77c4da191f1d393cbbc7237621912762f 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -34,6 +34,8 @@ #include "dsi_cfg.h" #include "msm_kms.h" +#define DSI_RESET_TOGGLE_DELAY_MS 20 + static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) { u32 ver; @@ -906,7 +908,7 @@ static void dsi_sw_reset(struct msm_dsi_host *msm_host) wmb(); /* clocks need to be enabled before reset */ dsi_write(msm_host, REG_DSI_RESET, 1); - wmb(); /* make sure reset happen */ + msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */ dsi_write(msm_host, REG_DSI_RESET, 0); } @@ -1287,7 +1289,7 @@ static void dsi_sw_reset_restore(struct msm_dsi_host *msm_host) /* dsi controller can only be reset while clocks are running */ dsi_write(msm_host, REG_DSI_RESET, 1); - wmb(); /* make sure reset happen */ + msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */ dsi_write(msm_host, REG_DSI_RESET, 0); wmb(); /* controller out of reset */ dsi_write(msm_host, REG_DSI_CTRL, data0); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c index 824067d2d4277d36699b1f15c6d58f74a97fe23f..42f0ecb0cf35fd406a4115355c81aac93f7310af 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c @@ -635,7 +635,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, if (cfg_handler) mdp5_cfg_destroy(cfg_handler); - return NULL; + return ERR_PTR(ret); } static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c index 60ece0a8a2e1bc1e5acd5753fe3d37f08323ed8e..1d2d6bae73cd1f57aef57a31ed6ce80dfc57e3f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c @@ -87,7 +87,7 @@ nvkm_gddr3_calc(struct nvkm_ram *ram) WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16; /* XXX: Get these values from the VBIOS instead */ DLL = !(ram->mr[1] & 0x1); - RON = !(ram->mr[1] & 0x300) >> 8; + RON = !((ram->mr[1] & 0x300) >> 8); break; default: return -ENOSYS; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c index 11b28b086a062f7ba2cea541fb391095ea2cec43..7b052879af7287a33c7ce0585f9c46e5f9d99403 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c @@ -88,10 +88,10 @@ nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec) if (exec) { nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC, memx->base, finish); + nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n", + reply[0], reply[1]); } - nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n", - reply[0], reply[1]); kfree(memx); return 0; } diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index ce8b353b5753ab81f1033972bc005c0ba716a13f..ba31c7674fcdd0f206d4e052743b6f51a2a1f114 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -7012,8 +7012,8 @@ static int cik_irq_init(struct radeon_device *rdev) } /* setup interrupt control */ - /* XXX this should actually be a bus address, not an MC address. same on older asics */ - WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8); + /* set dummy read address to dummy page address */ + WREG32(INTERRUPT_CNTL2, rdev->dummy_page.addr >> 8); interrupt_cntl = RREG32(INTERRUPT_CNTL); /* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index e06e2d8feab397822361ba18a3e4b420cc2f0c4d..a724bb87cfad7f1dd043f5b51ecc61dc415d746b 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3690,8 +3690,8 @@ int r600_irq_init(struct radeon_device *rdev) } /* setup interrupt control */ - /* set dummy read address to ring address */ - WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8); + /* set dummy read address to dummy page address */ + WREG32(INTERRUPT_CNTL2, rdev->dummy_page.addr >> 8); interrupt_cntl = RREG32(INTERRUPT_CNTL); /* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 1907c950d76f05ef32811685baaee9f7d4db83b9..1144cafea9acd403bdc8ed23512e674ae2cbcca6 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -5993,8 +5993,8 @@ static int si_irq_init(struct radeon_device *rdev) } /* setup interrupt control */ - /* set dummy read address to ring address */ - WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8); + /* set dummy read address to dummy page address */ + WREG32(INTERRUPT_CNTL2, rdev->dummy_page.addr >> 8); interrupt_cntl = RREG32(INTERRUPT_CNTL); /* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 592572554eb0ea1c102432af051bd72356e614b8..58d8a98c749b43e1f7ef554d4aeefae3459c4c51 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -233,8 +233,8 @@ static int shmob_drm_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); sdev->mmio = devm_ioremap_resource(&pdev->dev, res); - if (sdev->mmio == NULL) - return -ENOMEM; + if (IS_ERR(sdev->mmio)) + return PTR_ERR(sdev->mmio); ret = shmob_drm_setup_clocks(sdev, pdata->clk_source); if (ret < 0) diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index cf65e32b5090a00991e06a583a31214b951a8eff..0399bb18d3872b7adad83de601e099d6dd6f8eac 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -721,7 +721,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) return 0; err_sysfs: - drm_bridge_remove(bridge); return -EINVAL; } diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 30f02d2fdd034ccffc89fa95aa8d94ff5edecb5e..bbb195a92e93f3648302f2aee55ad04a81cea6e8 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -1314,7 +1314,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) return 0; err_sysfs: - drm_bridge_remove(bridge); hdmi->drm_connector = NULL; return -EINVAL; } diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c index 5cf2527bffc86cdcc7e43054d28eebc06baf6437..d7a8fea945574d5524cb9726b5373f5e31ca7625 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c @@ -50,7 +50,7 @@ static unsigned long sun4i_tmds_calc_divider(unsigned long rate, (rate - tmp_rate) < (rate - best_rate)) { best_rate = tmp_rate; best_m = m; - is_double = d; + is_double = (d == 2) ? true : false; } } } diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index 9385734b3e66834d4cdeb4cdadcbb934de07107f..645f10d2a6e2e2f661a09a90aa488f58660bdb99 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, 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 @@ -201,6 +201,20 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .max_power = 5448, .regfw_name = "a530v3_seq.fw2", }, + { + .gpurev = ADRENO_REV_A504, + .core = 5, + .major = 0, + .minor = 4, + .patchid = ANY_ID, + .features = ADRENO_PREEMPTION | ADRENO_64BIT, + .pm4fw_name = "a530_pm4.fw", + .pfpfw_name = "a530_pfp.fw", + .gpudev = &adreno_a5xx_gpudev, + .gmem_size = (SZ_128K + SZ_8K), + .num_protected_regs = 0x20, + .busy_mask = 0xFFFFFFFE, + }, { .gpurev = ADRENO_REV_A505, .core = 5, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 11f7ec68beeeb7c81857d80cc784a8caa9e44f97..905dd4009a7e723c87007bfbab278fbc886d7e77 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2020, 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 @@ -212,6 +212,7 @@ enum adreno_gpurev { ADRENO_REV_A418 = 418, ADRENO_REV_A420 = 420, ADRENO_REV_A430 = 430, + ADRENO_REV_A504 = 504, ADRENO_REV_A505 = 505, ADRENO_REV_A506 = 506, ADRENO_REV_A508 = 508, @@ -1274,6 +1275,7 @@ static inline int adreno_is_a5xx(struct adreno_device *adreno_dev) ADRENO_GPUREV(adreno_dev) < 600; } +ADRENO_TARGET(a504, ADRENO_REV_A504) ADRENO_TARGET(a505, ADRENO_REV_A505) ADRENO_TARGET(a506, ADRENO_REV_A506) ADRENO_TARGET(a508, ADRENO_REV_A508) @@ -1300,9 +1302,9 @@ static inline int adreno_is_a530v3(struct adreno_device *adreno_dev) (ADRENO_CHIPID_PATCH(adreno_dev->chipid) == 2); } -static inline int adreno_is_a505_or_a506(struct adreno_device *adreno_dev) +static inline int adreno_is_a504_to_a506(struct adreno_device *adreno_dev) { - return ADRENO_GPUREV(adreno_dev) >= 505 && + return ADRENO_GPUREV(adreno_dev) >= 504 && ADRENO_GPUREV(adreno_dev) <= 506; } diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 671d23691dfa8c07adee237244061bb149a119ca..ba46bd46d450af996c48d23a8c165d8dd20b21d9 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -56,6 +56,7 @@ static const struct adreno_vbif_platform a5xx_vbif_platforms[] = { { adreno_is_a512, a540_vbif }, { adreno_is_a510, a530_vbif }, { adreno_is_a508, a530_vbif }, + { adreno_is_a504, a530_vbif }, { adreno_is_a505, a530_vbif }, { adreno_is_a506, a530_vbif }, }; @@ -127,6 +128,7 @@ static const struct { } a5xx_efuse_funcs[] = { { adreno_is_a530, a530_efuse_leakage }, { adreno_is_a530, a530_efuse_speed_bin }, + { adreno_is_a504, a530_efuse_speed_bin }, { adreno_is_a505, a530_efuse_speed_bin }, { adreno_is_a512, a530_efuse_speed_bin }, { adreno_is_a508, a530_efuse_speed_bin }, @@ -152,7 +154,7 @@ static void a5xx_platform_setup(struct adreno_device *adreno_dev) uint64_t addr; struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - if (adreno_is_a505_or_a506(adreno_dev) || adreno_is_a508(adreno_dev)) { + if (adreno_is_a504_to_a506(adreno_dev) || adreno_is_a508(adreno_dev)) { gpudev->snapshot_data->sect_sizes->cp_meq = 32; gpudev->snapshot_data->sect_sizes->cp_merciu = 1024; gpudev->snapshot_data->sect_sizes->roq = 256; @@ -1181,6 +1183,7 @@ static const struct { { adreno_is_a530, a530_hwcg_regs, ARRAY_SIZE(a530_hwcg_regs) }, { adreno_is_a512, a512_hwcg_regs, ARRAY_SIZE(a512_hwcg_regs) }, { adreno_is_a510, a510_hwcg_regs, ARRAY_SIZE(a510_hwcg_regs) }, + { adreno_is_a504, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) }, { adreno_is_a505, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) }, { adreno_is_a506, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) }, { adreno_is_a508, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) }, @@ -1930,7 +1933,7 @@ static void a5xx_start(struct adreno_device *adreno_dev) * Below CP registers are 0x0 by default, program init * values based on a5xx flavor. */ - if (adreno_is_a505_or_a506(adreno_dev) || adreno_is_a508(adreno_dev)) { + if (adreno_is_a504_to_a506(adreno_dev) || adreno_is_a508(adreno_dev)) { kgsl_regwrite(device, A5XX_CP_MEQ_THRESHOLDS, 0x20); kgsl_regwrite(device, A5XX_CP_MERCIU_SIZE, 0x400); kgsl_regwrite(device, A5XX_CP_ROQ_THRESHOLDS_2, 0x40000030); @@ -1956,7 +1959,7 @@ static void a5xx_start(struct adreno_device *adreno_dev) * vtxFifo and primFifo thresholds default values * are different. */ - if (adreno_is_a505_or_a506(adreno_dev) || adreno_is_a508(adreno_dev)) + if (adreno_is_a504_to_a506(adreno_dev) || adreno_is_a508(adreno_dev)) kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL, (0x100 << 11 | 0x100 << 22)); else if (adreno_is_a510(adreno_dev) || adreno_is_a512(adreno_dev)) @@ -2264,6 +2267,7 @@ static int _me_init_ucode_workarounds(struct adreno_device *adreno_dev) switch (ADRENO_GPUREV(adreno_dev)) { case ADRENO_REV_A510: return 0x00000001; /* Ucode workaround for token end syncs */ + case ADRENO_REV_A504: case ADRENO_REV_A505: case ADRENO_REV_A506: case ADRENO_REV_A530: diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index d39420b0c9edcd237d8657c8efac041516d9fcb2..760cef5891af79e16aac51b423975d1c0cd69659 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -36,6 +36,7 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) struct adreno_ringbuffer *rb = adreno_dev->cur_rb; unsigned long flags; int ret = 0; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); spin_lock_irqsave(&rb->preempt_lock, flags); @@ -45,11 +46,30 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) * dispatcher context. Do it now. */ if (rb->skip_inline_wptr) { + /* + * There could be a situation where GPU comes out of + * ifpc after a fenced write transaction but before + * reading AHB_FENCE_STATUS from KMD, it goes back to + * ifpc due to inactivity (kernel scheduler plays a + * role here). Thus, the GPU could technically be + * re-collapsed between subsequent register writes + * leading to a prolonged preemption sequence. The + * keepalive bit prevents any further power collapse + * while it is set. + */ + if (gmu_core_isenabled(device)) + gmu_core_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, + 0x0, 0x2); ret = adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr, FENCE_STATUS_WRITEDROPPED0_MASK); + /* Clear the keep alive */ + if (gmu_core_isenabled(device)) + gmu_core_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, + 0x2, 0x0); + reset_timer = true; rb->skip_inline_wptr = false; } diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 12ebc174bf1664287dc1162d6ae539c2d8faf3ef..2ee57e9a5ce6d0574d716ab1c2474f2c1e4d79f4 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, 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 @@ -89,6 +89,7 @@ static void adreno_get_submit_time(struct adreno_device *adreno_dev, static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb) { + struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); unsigned long flags; int ret = 0; @@ -102,6 +103,17 @@ static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, */ kgsl_pwrscale_busy(KGSL_DEVICE(adreno_dev)); + /* + * There could be a situation where GPU comes out of + * ifpc after a fenced write transaction but before + * reading AHB_FENCE_STATUS from KMD, it goes back to + * ifpc due to inactivity (kernel scheduler plays a + * role here). Put a keep alive vote to avoid such + * unlikely scenario. + */ + if (gpudev->gpu_keepalive) + gpudev->gpu_keepalive(adreno_dev, true); + /* * Ensure the write posted after a possible * GMU wakeup (write could have dropped during wakeup) @@ -110,6 +122,9 @@ static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->_wptr, FENCE_STATUS_WRITEDROPPED0_MASK); rb->skip_inline_wptr = false; + if (gpudev->gpu_keepalive) + gpudev->gpu_keepalive(adreno_dev, false); + } } else { /* diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c index ea9e52354f5600449d59ec6aec5029c71df9e891..b3ad32257cde7e141157276031faebc6fbccd9f2 100644 --- a/drivers/gpu/msm/kgsl_pool.c +++ b/drivers/gpu/msm/kgsl_pool.c @@ -265,12 +265,20 @@ void kgsl_pool_free_pages(struct page **pages, unsigned int pcount) if (pages == NULL || pcount == 0) return; + if (WARN(!kern_addr_valid((unsigned long)pages), + "Address of pages=%pK is not valid\n", pages)) + return; + for (i = 0; i < pcount;) { /* * Free each page or compound page group individually. */ struct page *p = pages[i]; + if (WARN(!kern_addr_valid((unsigned long)p), + "Address of page=%pK is not valid\n", p)) + return; + i += 1 << compound_order(p); kgsl_pool_free_page(p); } diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 9746d15163a4ecf4232e284323fe3cb50e3589eb..f96baacb78428cb6c5b71ef9a146e3ba933d026c 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, 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 @@ -1053,8 +1053,11 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc) kfree(memdesc->sgt); } + memdesc->page_count = 0; if (memdesc->pages) kgsl_free(memdesc->pages); + memdesc->pages = NULL; + } EXPORT_SYMBOL(kgsl_sharedmem_free); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 1a1bafe100ec31c078d44d452ec546b9c1beb19d..36f2e25f50cb1bf7f2ec536b9871a2f9d38897ec 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -268,6 +268,12 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign offset = report->size; report->size += parser->global.report_size * parser->global.report_count; + /* Total size check: Allow for possible report index byte */ + if (report->size > (HID_MAX_BUFFER_SIZE - 1) << 3) { + hid_err(parser->device, "report is too long\n"); + return -1; + } + if (!parser->local.usage_index) /* Ignore padding fields */ return 0; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 5bcf7c2e3171dd39556479b6d86314ea2fd0cb65..e25a5e2c2ecac8e6abf7e8ed8972231728abd162 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1029,6 +1029,7 @@ #define USB_DEVICE_ID_SYNAPTICS_LTS2 0x1d10 #define USB_DEVICE_ID_SYNAPTICS_HD 0x0ac3 #define USB_DEVICE_ID_SYNAPTICS_QUAD_HD 0x1ac3 +#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012 0x2968 #define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710 #define USB_VENDOR_ID_TEXAS_INSTRUMENTS 0x2047 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 9d24fb0715ba3f25d98e023cc13bf4658c6cfc8b..14e4003fde4dd939878cdc2b98d25f5134faf2cf 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1116,9 +1116,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel } mapped: - if (device->driver->input_mapped && device->driver->input_mapped(device, - hidinput, field, usage, &bit, &max) < 0) - goto ignore; + if (device->driver->input_mapped && + device->driver->input_mapped(device, hidinput, field, usage, + &bit, &max) < 0) { + /* + * The driver indicated that no further generic handling + * of the usage is desired. + */ + return; + } set_bit(usage->type, input->evbit); @@ -1176,9 +1182,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel set_bit(MSC_SCAN, input->mscbit); } -ignore: return; +ignore: + usage->type = 0; + usage->code = 0; } void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c index 98b059d79bc891948695fe53a6a774bf171376c8..2ce1eb0c9212531814055177e6820fcdc18eb947 100644 --- a/drivers/hid/hid-ite.c +++ b/drivers/hid/hid-ite.c @@ -43,6 +43,9 @@ static int ite_event(struct hid_device *hdev, struct hid_field *field, static const struct hid_device_id ite_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) }, { HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) }, + /* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */ + { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, + USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) }, { } }; MODULE_DEVICE_TABLE(hid, ite_devices); diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 5652bd0ffb4d610a8249aa591536fdeb851f5243..5243c412081917e2f452e48bd01d48539595ef4a 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -257,13 +257,14 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t static unsigned int hidraw_poll(struct file *file, poll_table *wait) { struct hidraw_list *list = file->private_data; + unsigned int mask = POLLOUT | POLLWRNORM; /* hidraw is always writable */ poll_wait(file, &list->hidraw->wait, wait); if (list->head != list->tail) - return POLLIN | POLLRDNORM; + mask |= POLLIN | POLLRDNORM; if (!list->hidraw->exist) - return POLLERR | POLLHUP; - return 0; + mask |= POLLERR | POLLHUP; + return mask; } static int hidraw_open(struct inode *inode, struct file *file) diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 6f67d73b184e52814342834c965f181244f6b43a..c749f449c7cb357e65b9c588c8039904badd35d3 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -25,6 +25,7 @@ #include #include #include +#include #define UHID_NAME "uhid" #define UHID_BUFSIZE 32 @@ -768,13 +769,14 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer, static unsigned int uhid_char_poll(struct file *file, poll_table *wait) { struct uhid_device *uhid = file->private_data; + unsigned int mask = POLLOUT | POLLWRNORM; /* uhid is always writable */ poll_wait(file, &uhid->waitq, wait); if (uhid->head != uhid->tail) - return POLLIN | POLLRDNORM; + mask |= POLLIN | POLLRDNORM; - return 0; + return mask; } static const struct file_operations uhid_fops = { diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index ce342fd0457e9e81f11f631a0b54af3691896a5a..bccd97cdc53f9fc5bb8052a978b73f7035717e1e 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -254,12 +254,51 @@ static int hiddev_release(struct inode * inode, struct file * file) return 0; } +static int __hiddev_open(struct hiddev *hiddev, struct file *file) +{ + struct hiddev_list *list; + int error; + + lockdep_assert_held(&hiddev->existancelock); + + list = vzalloc(sizeof(*list)); + if (!list) + return -ENOMEM; + + mutex_init(&list->thread_lock); + list->hiddev = hiddev; + + if (!hiddev->open++) { + error = hid_hw_power(hiddev->hid, PM_HINT_FULLON); + if (error < 0) + goto err_drop_count; + + error = hid_hw_open(hiddev->hid); + if (error < 0) + goto err_normal_power; + } + + spin_lock_irq(&hiddev->list_lock); + list_add_tail(&list->node, &hiddev->list); + spin_unlock_irq(&hiddev->list_lock); + + file->private_data = list; + + return 0; + +err_normal_power: + hid_hw_power(hiddev->hid, PM_HINT_NORMAL); +err_drop_count: + hiddev->open--; + vfree(list); + return error; +} + /* * open file op */ static int hiddev_open(struct inode *inode, struct file *file) { - struct hiddev_list *list; struct usb_interface *intf; struct hid_device *hid; struct hiddev *hiddev; @@ -268,66 +307,14 @@ static int hiddev_open(struct inode *inode, struct file *file) intf = usbhid_find_interface(iminor(inode)); if (!intf) return -ENODEV; + hid = usb_get_intfdata(intf); hiddev = hid->hiddev; - if (!(list = vzalloc(sizeof(struct hiddev_list)))) - return -ENOMEM; - mutex_init(&list->thread_lock); - list->hiddev = hiddev; - file->private_data = list; - - /* - * no need for locking because the USB major number - * is shared which usbcore guards against disconnect - */ - if (list->hiddev->exist) { - if (!list->hiddev->open++) { - res = hid_hw_open(hiddev->hid); - if (res < 0) - goto bail; - } - } else { - res = -ENODEV; - goto bail; - } - - spin_lock_irq(&list->hiddev->list_lock); - list_add_tail(&list->node, &hiddev->list); - spin_unlock_irq(&list->hiddev->list_lock); - mutex_lock(&hiddev->existancelock); - /* - * recheck exist with existance lock held to - * avoid opening a disconnected device - */ - if (!list->hiddev->exist) { - res = -ENODEV; - goto bail_unlock; - } - if (!list->hiddev->open++) - if (list->hiddev->exist) { - struct hid_device *hid = hiddev->hid; - res = hid_hw_power(hid, PM_HINT_FULLON); - if (res < 0) - goto bail_unlock; - res = hid_hw_open(hid); - if (res < 0) - goto bail_normal_power; - } - mutex_unlock(&hiddev->existancelock); - return 0; -bail_normal_power: - hid_hw_power(hid, PM_HINT_NORMAL); -bail_unlock: + res = hiddev->exist ? __hiddev_open(hiddev, file) : -ENODEV; mutex_unlock(&hiddev->existancelock); - spin_lock_irq(&list->hiddev->list_lock); - list_del(&list->node); - spin_unlock_irq(&list->hiddev->list_lock); -bail: - file->private_data = NULL; - vfree(list); return res; } diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 37db2eb66ed790624b0da69355d4414e24587269..d7d1f24671009a4e72240e5a887b879ca699527a 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -297,9 +297,10 @@ static inline u16 volt2reg(int channel, long volt, u8 bypass_attn) long reg; if (bypass_attn & (1 << channel)) - reg = (volt * 1024) / 2250; + reg = DIV_ROUND_CLOSEST(volt * 1024, 2250); else - reg = (volt * r[1] * 1024) / ((r[0] + r[1]) * 2250); + reg = DIV_ROUND_CLOSEST(volt * r[1] * 1024, + (r[0] + r[1]) * 2250); return clamp_val(reg, 0, 1023) & (0xff << 2); } diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 7b53065e98828119ba874439c50a6acabe0684e4..652973d83a07ecd595e2ac7b7ec343ceaa170f2a 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -51,6 +51,7 @@ struct hwmon_device_attribute { #define to_hwmon_attr(d) \ container_of(d, struct hwmon_device_attribute, dev_attr) +#define to_dev_attr(a) container_of(a, struct device_attribute, attr) /* * Thermal zone information @@ -58,7 +59,7 @@ struct hwmon_device_attribute { * also provides the sensor index. */ struct hwmon_thermal_data { - struct hwmon_device *hwdev; /* Reference to hwmon device */ + struct device *dev; /* Reference to hwmon device */ int index; /* sensor index */ }; @@ -95,9 +96,27 @@ static const struct attribute_group *hwmon_dev_attr_groups[] = { NULL }; +static void hwmon_free_attrs(struct attribute **attrs) +{ + int i; + + for (i = 0; attrs[i]; i++) { + struct device_attribute *dattr = to_dev_attr(attrs[i]); + struct hwmon_device_attribute *hattr = to_hwmon_attr(dattr); + + kfree(hattr); + } + kfree(attrs); +} + static void hwmon_dev_release(struct device *dev) { - kfree(to_hwmon_device(dev)); + struct hwmon_device *hwdev = to_hwmon_device(dev); + + if (hwdev->group.attrs) + hwmon_free_attrs(hwdev->group.attrs); + kfree(hwdev->groups); + kfree(hwdev); } static struct class hwmon_class = { @@ -121,11 +140,11 @@ static DEFINE_IDA(hwmon_ida); static int hwmon_thermal_get_temp(void *data, int *temp) { struct hwmon_thermal_data *tdata = data; - struct hwmon_device *hwdev = tdata->hwdev; + struct hwmon_device *hwdev = to_hwmon_device(tdata->dev); int ret; long t; - ret = hwdev->chip->ops->read(&hwdev->dev, hwmon_temp, hwmon_temp_input, + ret = hwdev->chip->ops->read(tdata->dev, hwmon_temp, hwmon_temp_input, tdata->index, &t); if (ret < 0) return ret; @@ -139,26 +158,31 @@ static const struct thermal_zone_of_device_ops hwmon_thermal_ops = { .get_temp = hwmon_thermal_get_temp, }; -static int hwmon_thermal_add_sensor(struct device *dev, - struct hwmon_device *hwdev, int index) +static int hwmon_thermal_add_sensor(struct device *dev, int index) { struct hwmon_thermal_data *tdata; + struct thermal_zone_device *tzd; tdata = devm_kzalloc(dev, sizeof(*tdata), GFP_KERNEL); if (!tdata) return -ENOMEM; - tdata->hwdev = hwdev; + tdata->dev = dev; tdata->index = index; - devm_thermal_zone_of_sensor_register(&hwdev->dev, index, tdata, - &hwmon_thermal_ops); + tzd = devm_thermal_zone_of_sensor_register(dev, index, tdata, + &hwmon_thermal_ops); + /* + * If CONFIG_THERMAL_OF is disabled, this returns -ENODEV, + * so ignore that error but forward any other error. + */ + if (IS_ERR(tzd) && (PTR_ERR(tzd) != -ENODEV)) + return PTR_ERR(tzd); return 0; } #else -static int hwmon_thermal_add_sensor(struct device *dev, - struct hwmon_device *hwdev, int index) +static int hwmon_thermal_add_sensor(struct device *dev, int index) { return 0; } @@ -235,8 +259,7 @@ static bool is_string_attr(enum hwmon_sensor_types type, u32 attr) (type == hwmon_fan && attr == hwmon_fan_label); } -static struct attribute *hwmon_genattr(struct device *dev, - const void *drvdata, +static struct attribute *hwmon_genattr(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int index, @@ -264,7 +287,7 @@ static struct attribute *hwmon_genattr(struct device *dev, if ((mode & S_IWUGO) && !ops->write) return ERR_PTR(-EINVAL); - hattr = devm_kzalloc(dev, sizeof(*hattr), GFP_KERNEL); + hattr = kzalloc(sizeof(*hattr), GFP_KERNEL); if (!hattr) return ERR_PTR(-ENOMEM); @@ -467,8 +490,7 @@ static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info) return n; } -static int hwmon_genattrs(struct device *dev, - const void *drvdata, +static int hwmon_genattrs(const void *drvdata, struct attribute **attrs, const struct hwmon_ops *ops, const struct hwmon_channel_info *info) @@ -494,7 +516,7 @@ static int hwmon_genattrs(struct device *dev, attr_mask &= ~BIT(attr); if (attr >= template_size) return -EINVAL; - a = hwmon_genattr(dev, drvdata, info->type, attr, i, + a = hwmon_genattr(drvdata, info->type, attr, i, templates[attr], ops); if (IS_ERR(a)) { if (PTR_ERR(a) != -ENOENT) @@ -508,8 +530,7 @@ static int hwmon_genattrs(struct device *dev, } static struct attribute ** -__hwmon_create_attrs(struct device *dev, const void *drvdata, - const struct hwmon_chip_info *chip) +__hwmon_create_attrs(const void *drvdata, const struct hwmon_chip_info *chip) { int ret, i, aindex = 0, nattrs = 0; struct attribute **attrs; @@ -520,15 +541,17 @@ __hwmon_create_attrs(struct device *dev, const void *drvdata, if (nattrs == 0) return ERR_PTR(-EINVAL); - attrs = devm_kcalloc(dev, nattrs + 1, sizeof(*attrs), GFP_KERNEL); + attrs = kcalloc(nattrs + 1, sizeof(*attrs), GFP_KERNEL); if (!attrs) return ERR_PTR(-ENOMEM); for (i = 0; chip->info[i]; i++) { - ret = hwmon_genattrs(dev, drvdata, &attrs[aindex], chip->ops, + ret = hwmon_genattrs(drvdata, &attrs[aindex], chip->ops, chip->info[i]); - if (ret < 0) + if (ret < 0) { + hwmon_free_attrs(attrs); return ERR_PTR(ret); + } aindex += ret; } @@ -570,14 +593,13 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, for (i = 0; groups[i]; i++) ngroups++; - hwdev->groups = devm_kcalloc(dev, ngroups, sizeof(*groups), - GFP_KERNEL); + hwdev->groups = kcalloc(ngroups, sizeof(*groups), GFP_KERNEL); if (!hwdev->groups) { err = -ENOMEM; goto free_hwmon; } - attrs = __hwmon_create_attrs(dev, drvdata, chip); + attrs = __hwmon_create_attrs(drvdata, chip); if (IS_ERR(attrs)) { err = PTR_ERR(attrs); goto free_hwmon; @@ -621,8 +643,13 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, if (!chip->ops->is_visible(drvdata, hwmon_temp, hwmon_temp_input, j)) continue; - if (info[i]->config[j] & HWMON_T_INPUT) - hwmon_thermal_add_sensor(dev, hwdev, j); + if (info[i]->config[j] & HWMON_T_INPUT) { + err = hwmon_thermal_add_sensor(hdev, j); + if (err) { + device_unregister(hdev); + goto ida_remove; + } + } } } } @@ -630,7 +657,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, return hdev; free_hwmon: - kfree(hwdev); + hwmon_dev_release(hdev); ida_remove: ida_simple_remove(&hwmon_ida, id); return ERR_PTR(err); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 005ffb5ffa92dacd91aed181b5b6bd6b1e26d225..1737bb5fbaafe6491a7cb7ea3f999b58459458da 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -165,7 +165,7 @@ static int lm75_write(struct device *dev, enum hwmon_sensor_types type, temp = DIV_ROUND_CLOSEST(temp << (resolution - 8), 1000) << (16 - resolution); - return regmap_write(data->regmap, reg, temp); + return regmap_write(data->regmap, reg, (u16)temp); } static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 38ffbdb0a85fba288cdcac8e76cc7ff3eadec65d..779ec8fdfae082b640046bc36f4b2eb416e3b128 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -32,8 +32,8 @@ static const u8 REG_VOLTAGE[5] = { 0x09, 0x0a, 0x0c, 0x0d, 0x0e }; static const u8 REG_VOLTAGE_LIMIT_LSB[2][5] = { - { 0x40, 0x00, 0x42, 0x44, 0x46 }, - { 0x3f, 0x00, 0x41, 0x43, 0x45 }, + { 0x46, 0x00, 0x40, 0x42, 0x44 }, + { 0x45, 0x00, 0x3f, 0x41, 0x43 }, }; static const u8 REG_VOLTAGE_LIMIT_MSB[5] = { 0x48, 0x00, 0x47, 0x47, 0x48 }; diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 85b515cd9df0ee804775d9610d68f8d927525475..2bc352c5357f446d1d7b9f34a779a610a25cb4cd 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -80,7 +80,14 @@ static struct pmbus_driver_info tps53679_info = { static int tps53679_probe(struct i2c_client *client, const struct i2c_device_id *id) { - return pmbus_do_probe(client, id, &tps53679_info); + struct pmbus_driver_info *info; + + info = devm_kmemdup(&client->dev, &tps53679_info, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + return pmbus_do_probe(client, id, info); } static const struct i2c_device_id tps53679_id[] = { diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c index decd7df995abfa2b40381b7b1be251051b6023e5..2a18539591eaffec4f6e2c70e0a0a313ca77ad4f 100644 --- a/drivers/hwmon/shtc1.c +++ b/drivers/hwmon/shtc1.c @@ -38,7 +38,7 @@ static const unsigned char shtc1_cmd_read_id_reg[] = { 0xef, 0xc8 }; /* constants for reading the ID register */ #define SHTC1_ID 0x07 -#define SHTC1_ID_REG_MASK 0x1f +#define SHTC1_ID_REG_MASK 0x3f /* delays for non-blocking i2c commands, both in us */ #define SHTC1_NONBLOCKING_WAIT_TIME_HPM 14400 diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 8ac89d0781ccc68336eff6f13270063ed69a3ee9..a575e1cdb81a80206a97ca2057c738ed7be17802 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -130,17 +130,23 @@ superio_select(struct w83627hf_sio_data *sio, int ld) outb(ld, sio->sioaddr + 1); } -static inline void +static inline int superio_enter(struct w83627hf_sio_data *sio) { + if (!request_muxed_region(sio->sioaddr, 2, DRVNAME)) + return -EBUSY; + outb(0x87, sio->sioaddr); outb(0x87, sio->sioaddr); + + return 0; } static inline void superio_exit(struct w83627hf_sio_data *sio) { outb(0xAA, sio->sioaddr); + release_region(sio->sioaddr, 2); } #define W627_DEVID 0x52 @@ -1278,7 +1284,7 @@ static DEVICE_ATTR_RO(name); static int __init w83627hf_find(int sioaddr, unsigned short *addr, struct w83627hf_sio_data *sio_data) { - int err = -ENODEV; + int err; u16 val; static __initconst char *const names[] = { @@ -1290,7 +1296,11 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr, }; sio_data->sioaddr = sioaddr; - superio_enter(sio_data); + err = superio_enter(sio_data); + if (err) + return err; + + err = -ENODEV; val = force_id ? force_id : superio_inb(sio_data, DEVID); switch (val) { case W627_DEVID: @@ -1644,9 +1654,21 @@ static int w83627thf_read_gpio5(struct platform_device *pdev) struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev); int res = 0xff, sel; - superio_enter(sio_data); + if (superio_enter(sio_data)) { + /* + * Some other driver reserved the address space for itself. + * We don't want to fail driver instantiation because of that, + * so display a warning and keep going. + */ + dev_warn(&pdev->dev, + "Can not read VID data: Failed to enable SuperIO access\n"); + return res; + } + superio_select(sio_data, W83627HF_LD_GPIO5); + res = 0xff; + /* Make sure these GPIO pins are enabled */ if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) { dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n"); @@ -1677,7 +1699,17 @@ static int w83687thf_read_vid(struct platform_device *pdev) struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev); int res = 0xff; - superio_enter(sio_data); + if (superio_enter(sio_data)) { + /* + * Some other driver reserved the address space for itself. + * We don't want to fail driver instantiation because of that, + * so display a warning and keep going. + */ + dev_warn(&pdev->dev, + "Can not read VID data: Failed to enable SuperIO access\n"); + return res; + } + superio_select(sio_data, W83627HF_LD_HWM); /* Make sure these GPIO pins are enabled */ diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c index fa6880b8060a050cf2ef01d8a79b762e1cb2272c..b0511d7a801774757a34a04b88af951e11627ca6 100644 --- a/drivers/hwspinlock/qcom_hwspinlock.c +++ b/drivers/hwspinlock/qcom_hwspinlock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013,2020, The Linux Foundation. All rights reserved. * Copyright (c) 2015, Sony Mobile Communications AB * * This software is licensed under the terms of the GNU General Public @@ -28,13 +28,19 @@ #define QCOM_MUTEX_APPS_PROC_ID 1 #define QCOM_MUTEX_NUM_LOCKS 32 +/** + * setting default mutex id as QCOM_MUTEX_APPS_PROC_ID + * and will override this value if dt entry is found + */ +static u32 qcom_mutex_lock_id = QCOM_MUTEX_APPS_PROC_ID; + static int qcom_hwspinlock_trylock(struct hwspinlock *lock) { struct regmap_field *field = lock->priv; u32 lock_owner; int ret; - ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID); + ret = regmap_field_write(field, qcom_mutex_lock_id); if (ret) return ret; @@ -42,7 +48,7 @@ static int qcom_hwspinlock_trylock(struct hwspinlock *lock) if (ret) return ret; - return lock_owner == QCOM_MUTEX_APPS_PROC_ID; + return lock_owner == qcom_mutex_lock_id; } static void qcom_hwspinlock_unlock(struct hwspinlock *lock) @@ -57,7 +63,7 @@ static void qcom_hwspinlock_unlock(struct hwspinlock *lock) return; } - if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) { + if (lock_owner != qcom_mutex_lock_id) { pr_err("%s: spinlock not owned by us (actual owner is %d)\n", __func__, lock_owner); } @@ -88,6 +94,7 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev) size_t array_size; u32 stride; u32 base; + u32 mutex_id; int ret; int i; @@ -114,6 +121,10 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev) return -EINVAL; } + ret = of_property_read_u32(pdev->dev.of_node, "mutex-id", &mutex_id); + if (!ret) + qcom_mutex_lock_id = mutex_id; + array_size = QCOM_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock); bank = devm_kzalloc(&pdev->dev, sizeof(*bank) + array_size, GFP_KERNEL); if (!bank) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 7aee00fdaa4b7410f0107b98db3f90e0174e8eaa..e1132524f4c8e7461abf5fa8412075f45943424f 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -366,9 +366,7 @@ static void *etb_alloc_buffer(struct coresight_device *csdev, int node, cpu = event->cpu; struct cs_buffers *buf; - if (cpu == -1) - cpu = smp_processor_id(); - node = cpu_to_node(cpu); + node = (cpu == -1) ? NUMA_NO_NODE : cpu_to_node(cpu); buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node); if (!buf) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 3ba6d904ae80aa60130b6efa32d4cb61a5c26e06..03cb7721e13a98539701e9b823aa662640306afd 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -145,6 +145,9 @@ static void free_sink_buffer(struct etm_event_data *event_data) cpu = cpumask_first(mask); sink = coresight_get_sink(etm_event_cpu_path(event_data, cpu)); + if (!sink) + return; + sink_ops(sink)->free_buffer(event_data->snk_config); } diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index 19d33fbdb6f659248a4f02e6b34e01a5a5a35bc8..7d79f0dfd01dfcf4ffe8bb78f6698a6f36691f16 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -964,8 +964,11 @@ static ssize_t addr_range_show(struct device *dev, spin_lock(&drvdata->spinlock); idx = config->addr_idx; - if (idx >= ETM_MAX_SINGLE_ADDR_CMP) + if (idx >= ETM_MAX_SINGLE_ADDR_CMP) { + spin_unlock(&drvdata->spinlock); return -EINVAL; + } + if (idx % 2 != 0) { spin_unlock(&drvdata->spinlock); return -EPERM; @@ -1002,8 +1005,11 @@ static ssize_t addr_range_store(struct device *dev, spin_lock(&drvdata->spinlock); idx = config->addr_idx; - if (idx >= ETM_MAX_SINGLE_ADDR_CMP) + if (idx >= ETM_MAX_SINGLE_ADDR_CMP) { + spin_unlock(&drvdata->spinlock); return -EINVAL; + } + if (idx % 2 != 0) { spin_unlock(&drvdata->spinlock); return -EPERM; diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index e747a6c3b57ec0a227c9622c9645288d107f3f72..6d0cb43361bc6097727fc0faea0381667d963a59 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -392,9 +392,7 @@ static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int node, cpu = event->cpu; struct cs_buffers *buf; - if (cpu == -1) - cpu = smp_processor_id(); - node = cpu_to_node(cpu); + node = (cpu == -1) ? NUMA_NO_NODE : cpu_to_node(cpu); /* Allocate memory structure for interaction with Perf */ buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node); diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 3baf2c8cf0dc53576ae093285f9d9fd314c88422..04ec9c38d98f65fe2f76cc897c589f6c9df4887a 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -883,7 +883,9 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata, static void tmc_free_etr_buf(struct etr_buf *etr_buf) { - WARN_ON(!etr_buf->ops || !etr_buf->ops->free); + if (WARN_ON(!etr_buf->ops || !etr_buf->ops->free)) + return; + etr_buf->ops->free(etr_buf); kfree(etr_buf); } @@ -947,7 +949,8 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata) etr_buf->full = status & TMC_STS_FULL; - WARN_ON(!etr_buf->ops || !etr_buf->ops->sync); + if (WARN_ON(!etr_buf->ops || !etr_buf->ops->sync)) + return; etr_buf->ops->sync(etr_buf, rrp, rwp); } @@ -1164,13 +1167,13 @@ static int tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) return 0; } -static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) +static int __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; uint32_t axictl; if (drvdata->enable_to_bam) - return; + return 0; /* Configure and enable required CSR registers */ msm_qdss_csr_enable_bam_to_usb(drvdata->csr); @@ -1179,7 +1182,13 @@ static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) CS_UNLOCK(drvdata->base); - writel_relaxed(bamdata->data_fifo.size / 4, drvdata->base + TMC_RSZ); + if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) + writel_relaxed(bamdata->data_fifo.size / 4, + drvdata->base + TMC_RSZ); + else if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) + writel_relaxed(bamdata->connect.data.size / 4, + drvdata->base + TMC_RSZ); + writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); axictl = readl_relaxed(drvdata->base + TMC_AXICTL); @@ -1190,15 +1199,33 @@ static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) axictl = (axictl & ~0x3) | 0x2; writel_relaxed(axictl, drvdata->base + TMC_AXICTL); - if (bamdata->props.options & SPS_BAM_SMMU_EN) { - writel_relaxed((uint32_t)bamdata->data_fifo.iova, - drvdata->base + TMC_DBALO); - writel_relaxed((((uint64_t)bamdata->data_fifo.iova) >> 32) - & 0xFF, drvdata->base + TMC_DBAHI); - } else { - writel_relaxed((uint32_t)bamdata->data_fifo.phys_base, - drvdata->base + TMC_DBALO); - writel_relaxed((((uint64_t)bamdata->data_fifo.phys_base) >> 32) + if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) { + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + writel_relaxed((uint32_t)bamdata->data_fifo.iova, + drvdata->base + TMC_DBALO); + writel_relaxed( + (((uint64_t)bamdata->data_fifo.iova) >> 32) + & 0xFF, drvdata->base + TMC_DBAHI); + } else { + writel_relaxed((uint32_t)bamdata->data_fifo.phys_base, + drvdata->base + TMC_DBALO); + writel_relaxed( + (((uint64_t)bamdata->data_fifo.phys_base) >> 32) + & 0xFF, drvdata->base + TMC_DBAHI); + } + } + + if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + CS_LOCK(drvdata->base); + dev_err(drvdata->dev, "PCIE mode doesn't support smmu.\n"); + return -EINVAL; + } + + writel_relaxed((uint32_t)bamdata->connect.data.phys_base, + drvdata->base + TMC_DBALO); + writel_relaxed( + (((uint64_t)bamdata->connect.data.phys_base) >> 32) & 0xFF, drvdata->base + TMC_DBAHI); } /* Set FOnFlIn for periodic flush */ @@ -1210,6 +1237,7 @@ static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) msm_qdss_csr_enable_flush(drvdata->csr); drvdata->enable_to_bam = true; + return 0; } static int get_usb_bam_iova(struct device *dev, unsigned long usb_bam_handle, @@ -1259,19 +1287,57 @@ static int tmc_etr_bam_enable(struct tmc_drvdata *drvdata) bamdata->connect.source = bamdata->handle; bamdata->connect.event_thresh = 0x4; bamdata->connect.src_pipe_index = TMC_ETR_BAM_PIPE_INDEX; - bamdata->connect.options = SPS_O_AUTO_ENABLE; + if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) { + bamdata->connect.options = SPS_O_AUTO_ENABLE; + + bamdata->connect.destination = bamdata->dest; + bamdata->connect.dest_pipe_index = bamdata->dest_pipe_idx; + bamdata->connect.desc = bamdata->desc_fifo; + bamdata->connect.data = bamdata->data_fifo; + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + ret = get_usb_bam_iova(drvdata->dev, + bamdata->dest, &iova); + if (ret) + goto err1; + bamdata->connect.dest_iova = iova; + } + } else if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + dev_err(drvdata->dev, "PCIE mode doesn't support smmu.\n"); + ret = -EINVAL; + goto err1; + } - bamdata->connect.destination = bamdata->dest; - bamdata->connect.dest_pipe_index = bamdata->dest_pipe_idx; - bamdata->connect.desc = bamdata->desc_fifo; - bamdata->connect.data = bamdata->data_fifo; + bamdata->connect.options = SPS_O_AUTO_ENABLE | SPS_O_DUMMY_PEER; + + bamdata->connect.destination = + drvdata->ipa_data->ipa_qdss_out.ipa_rx_db_pa; + bamdata->connect.dest_pipe_index = 0; + bamdata->connect.desc.phys_base = + drvdata->ipa_data->ipa_qdss_in.desc_fifo_base_addr; + bamdata->connect.desc.size = + drvdata->ipa_data->ipa_qdss_in.desc_fifo_size; + bamdata->connect.desc.base = + ioremap(bamdata->connect.desc.phys_base, + bamdata->connect.desc.size); + if (!bamdata->connect.desc.base) { + ret = -ENOMEM; + goto err1; + } - if (bamdata->props.options & SPS_BAM_SMMU_EN) { - ret = get_usb_bam_iova(drvdata->dev, bamdata->dest, &iova); - if (ret) + bamdata->connect.data.phys_base = + drvdata->ipa_data->ipa_qdss_in.data_fifo_base_addr; + bamdata->connect.data.size = + drvdata->ipa_data->ipa_qdss_in.data_fifo_size; + bamdata->connect.data.base = + ioremap(bamdata->connect.data.phys_base, + bamdata->connect.data.size); + if (!bamdata->connect.data.base) { + ret = -ENOMEM; goto err1; - bamdata->connect.dest_iova = iova; + } } + ret = sps_connect(bamdata->pipe, &bamdata->connect); if (ret) goto err1; @@ -1337,6 +1403,14 @@ void usb_notifier(void *priv, unsigned int event, struct qdss_request *d_req, int ret = 0; mutex_lock(&drvdata->mem_lock); + if (drvdata->out_mode != TMC_ETR_OUT_MODE_USB + || drvdata->mode == CS_MODE_DISABLED) { + dev_err(&drvdata->csdev->dev, + "%s: ETR is not USB mode, or ETR is disabled.\n", __func__); + mutex_unlock(&drvdata->mem_lock); + return; + } + if (event == USB_QDSS_CONNECT) { ret = tmc_etr_fill_usb_bam_data(drvdata); if (ret) @@ -1395,6 +1469,77 @@ int tmc_etr_bam_init(struct amba_device *adev, return sps_register_bam_device(&bamdata->props, &bamdata->handle); } +int tmc_etr_ipa_init(struct amba_device *adev, + struct tmc_drvdata *drvdata) +{ + int ret; + struct device *dev = &adev->dev; + struct device_node *node = adev->dev.of_node; + struct tmc_etr_ipa_data *ipa_data; + u32 value = 0; + + ipa_data = devm_kzalloc(dev, sizeof(*ipa_data), GFP_KERNEL); + if (!ipa_data) + return -ENOMEM; + + drvdata->ipa_data = ipa_data; + + ret = of_property_read_u32(node, "ipa-conn-data-base-pa", &value); + if (ret) { + pr_err("%s: Invalid ipa data base address property\n", + __func__); + return -EINVAL; + } + ipa_data->ipa_qdss_in.data_fifo_base_addr = value; + + ret = of_property_read_u32(node, "ipa-conn-data-size", &value); + if (ret) { + pr_err("%s: Invalid ipa data base size\n", __func__); + return -EINVAL; + } + ipa_data->ipa_qdss_in.data_fifo_size = value; + + ret = of_property_read_u32(node, "ipa-conn-desc-base-pa", &value); + if (ret) { + pr_err("%s: Invalid ipa desc base address property\n", + __func__); + return -EINVAL; + } + ipa_data->ipa_qdss_in.desc_fifo_base_addr = value; + + ret = of_property_read_u32(node, "ipa-conn-desc-size", &value); + if (ret) { + pr_err("%s: Invalid ipa desc size property\n", __func__); + return -EINVAL; + } + ipa_data->ipa_qdss_in.desc_fifo_size = value; + + ret = of_property_read_u32(node, "ipa-peer-evt-reg-pa", &value); + if (ret) { + pr_err("%s: Invalid ipa peer reg pa property\n", __func__); + return -EINVAL; + } + ipa_data->ipa_qdss_in.bam_p_evt_dest_addr = value; + + ipa_data->ipa_qdss_in.bam_p_evt_threshold = 0x4; + ipa_data->ipa_qdss_in.override_eot = 0x1; + return 0; +} + +static int tmc_etr_ipa_conn(struct tmc_drvdata *drvdata) +{ + if (!drvdata->ipa_data) + return -ENOMEM; + + return ipa_qdss_conn_pipes(&drvdata->ipa_data->ipa_qdss_in, + &drvdata->ipa_data->ipa_qdss_out); +} + +static int tmc_etr_ipa_disconn(void) +{ + return ipa_qdss_disconn_pipes(); +} + static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) { int ret = 0; @@ -1419,7 +1564,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) spin_unlock_irqrestore(&drvdata->spinlock, flags); if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM || - drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { + (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE && + drvdata->pcie_path == TMC_ETR_PCIE_SW_PATH)) { /* * ETR DDR memory is not allocated until user enables * tmc at least once. If user specifies different ETR @@ -1441,6 +1587,32 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) coresight_cti_map_trigout(drvdata->cti_flush, 3, 0); coresight_cti_map_trigin(drvdata->cti_reset, 2, 0); + } else if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE && + drvdata->pcie_path == TMC_ETR_PCIE_HW_PATH) { + ret = tmc_etr_ipa_conn(drvdata); + if (ret) { + mutex_unlock(&drvdata->mem_lock); + return ret; + } + + ret = tmc_etr_bam_enable(drvdata); + if (ret) { + tmc_etr_ipa_disconn(); + mutex_unlock(&drvdata->mem_lock); + return ret; + } + + spin_lock_irqsave(&drvdata->spinlock, flags); + ret = __tmc_etr_enable_to_bam(drvdata); + if (ret) { + spin_unlock_irqrestore(&drvdata->spinlock, + flags); + tmc_etr_ipa_disconn(); + mutex_unlock(&drvdata->mem_lock); + return ret; + } + spin_unlock_irqrestore(&drvdata->spinlock, flags); + } else { drvdata->usbch = usb_qdss_open("qdss", drvdata, usb_notifier); @@ -1480,7 +1652,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) } if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM || - drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { + (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE && + drvdata->pcie_path == TMC_ETR_PCIE_SW_PATH)) { ret = tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf); if (ret) goto out; @@ -1501,7 +1674,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) tmc_etr_byte_cntr_start(drvdata->byte_cntr); - if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) + if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE + && drvdata->pcie_path == TMC_ETR_PCIE_SW_PATH) etr_pcie_start(drvdata->byte_cntr); dev_info(drvdata->dev, "TMC-ETR enabled\n"); @@ -1968,6 +2142,14 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) drvdata->usbch = NULL; drvdata->mode = CS_MODE_DISABLED; goto out; + } else if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE + && drvdata->pcie_path == TMC_ETR_PCIE_HW_PATH) { + __tmc_etr_disable_to_bam(drvdata); + spin_unlock_irqrestore(&drvdata->spinlock, flags); + tmc_etr_bam_disable(drvdata); + tmc_etr_ipa_disconn(); + drvdata->mode = CS_MODE_DISABLED; + goto out; } else { tmc_etr_disable_hw(drvdata); } @@ -1989,7 +2171,8 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) spin_unlock_irqrestore(&drvdata->spinlock, flags); if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM || - drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { + (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE + && drvdata->pcie_path == TMC_ETR_PCIE_SW_PATH)) { if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { etr_pcie_stop(drvdata->byte_cntr); flush_workqueue(drvdata->byte_cntr->pcie_wq); @@ -2016,7 +2199,9 @@ static void tmc_abort_etr_sink(struct coresight_device *csdev) if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) tmc_etr_disable_hw(drvdata); - else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) + else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB + || (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE && + drvdata->pcie_path == TMC_ETR_PCIE_HW_PATH)) __tmc_etr_disable_to_bam(drvdata); out0: drvdata->enable = false; @@ -2090,7 +2275,8 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) goto out; } - if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) { + if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB || + drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { ret = -EINVAL; goto out; } diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index fab4feed93883630fdd1b8a6463429578cddabc4..96e50fd70f2c7ec34f8d794e01bdea505d217407 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -434,6 +434,46 @@ static ssize_t out_mode_store(struct device *dev, } static DEVICE_ATTR_RW(out_mode); +static ssize_t pcie_path_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + str_tmc_etr_pcie_path[drvdata->pcie_path]); +} + +static ssize_t pcie_path_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + char str[10] = ""; + + if (strlen(buf) >= 10) + return -EINVAL; + if (sscanf(buf, "%10s", str) != 1) + return -EINVAL; + + mutex_lock(&drvdata->mem_lock); + if (drvdata->enable) { + mutex_unlock(&drvdata->mem_lock); + pr_err("ETR is in use, disable it to switch the pcie path\n"); + return -EINVAL; + } + + if (!strcmp(str, str_tmc_etr_pcie_path[TMC_ETR_PCIE_SW_PATH])) + drvdata->pcie_path = TMC_ETR_PCIE_SW_PATH; + else if (!strcmp(str, str_tmc_etr_pcie_path[TMC_ETR_PCIE_HW_PATH])) + drvdata->pcie_path = TMC_ETR_PCIE_HW_PATH; + else + size = -EINVAL; + + mutex_unlock(&drvdata->mem_lock); + return size; +} +static DEVICE_ATTR_RW(pcie_path); + static ssize_t available_out_modes_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -586,6 +626,7 @@ static struct attribute *coresight_tmc_etr_attrs[] = { &dev_attr_block_size.attr, &dev_attr_out_mode.attr, &dev_attr_available_out_modes.attr, + &dev_attr_pcie_path.attr, NULL, }; @@ -724,6 +765,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) drvdata->size = SZ_1M; drvdata->out_mode = TMC_ETR_OUT_MODE_MEM; + drvdata->pcie_path = TMC_ETR_PCIE_HW_PATH; } else { drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; } @@ -793,6 +835,12 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) goto out_iommu_deinit; idr_init(&drvdata->idr); mutex_init(&drvdata->idr_mutex); + + if (of_property_read_bool(drvdata->dev->of_node, + "qcom,qdss-ipa-support")) + ret = tmc_etr_ipa_init(adev, drvdata); + if (ret) + goto out_iommu_deinit; break; case TMC_CONFIG_TYPE_ETF: desc.type = CORESIGHT_DEV_TYPE_LINKSINK; diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 92f725e2ea3186df64098ae44a9ab8ce3a36bbeb..b24f30a80f27072316e8fa4e3718a892839dd8ba 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "coresight-byte-cntr.h" @@ -158,6 +159,16 @@ enum tmc_mem_intf_width { #define CORESIGHT_SOC_600_ETR_CAPS \ (TMC_ETR_SAVE_RESTORE | TMC_ETR_AXI_ARCACHE) +enum tmc_etr_pcie_path { + TMC_ETR_PCIE_SW_PATH, + TMC_ETR_PCIE_HW_PATH, +}; + +static const char * const str_tmc_etr_pcie_path[] = { + [TMC_ETR_PCIE_SW_PATH] = "sw", + [TMC_ETR_PCIE_HW_PATH] = "hw", +}; + enum tmc_etr_out_mode { TMC_ETR_OUT_MODE_NONE, TMC_ETR_OUT_MODE_MEM, @@ -172,6 +183,11 @@ static const char * const str_tmc_etr_out_mode[] = { [TMC_ETR_OUT_MODE_PCIE] = "pcie", }; +struct tmc_etr_ipa_data { + struct ipa_qdss_conn_out_params ipa_qdss_out; + struct ipa_qdss_conn_in_params ipa_qdss_in; +}; + struct tmc_etr_bam_data { struct sps_bam_props props; unsigned long handle; @@ -264,6 +280,7 @@ struct tmc_drvdata { u32 etr_caps; u32 delta_bottom; enum tmc_etr_out_mode out_mode; + enum tmc_etr_pcie_path pcie_path; struct usb_qdss_ch *usbch; struct tmc_etr_bam_data *bamdata; bool sticky_enable; @@ -279,6 +296,7 @@ struct tmc_drvdata { struct mutex idr_mutex; struct etr_buf *sysfs_buf; struct etr_buf *perf_buf; + struct tmc_etr_ipa_data *ipa_data; }; struct etr_buf_operations { @@ -346,6 +364,8 @@ void usb_notifier(void *priv, unsigned int event, struct qdss_request *d_req, struct usb_qdss_ch *ch); int tmc_etr_bam_init(struct amba_device *adev, struct tmc_drvdata *drvdata); +int tmc_etr_ipa_init(struct amba_device *adev, + struct tmc_drvdata *drvdata); extern struct byte_cntr *byte_cntr_init(struct amba_device *adev, struct tmc_drvdata *drvdata); extern void tmc_etr_free_mem(struct tmc_drvdata *drvdata); diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index 3d9f7b925457bde0eb15b0cb6f1113f6cb9478df..69c4a71826c0df949bdcbbe5375ff07c9ce6788e 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, 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 @@ -3037,7 +3037,7 @@ static int i2c_msm_init(void) { return platform_driver_register(&i2c_msm_driver); } -subsys_initcall(i2c_msm_init); +module_init(i2c_msm_init); static void i2c_msm_exit(void) { diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 255074d7ef76e7750280e08cfa77062e60c2315c..8eeea7f722612d5eeedb63d07618748559c63262 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -29,6 +29,7 @@ #include #include #include +#include #define SE_I2C_TX_TRANS_LEN (0x26C) #define SE_I2C_RX_TRANS_LEN (0x270) @@ -82,6 +83,8 @@ #define I2C_TIMEOUT_MIN_USEC 500000 +#define MAX_SE 20 + enum i2c_se_mode { UNINITIALIZED, FIFO_SE_DMA, @@ -101,6 +104,11 @@ struct geni_i2c_ssr { bool is_ssr_down; }; +struct dbg_buf_ctxt { + void *virt_buf; + void *map_buf; +}; + struct geni_i2c_dev { struct device *dev; void __iomem *base; @@ -137,11 +145,16 @@ struct geni_i2c_dev { bool cmd_done; struct geni_i2c_clk_fld geni_i2c_clk_param; struct geni_i2c_ssr i2c_ssr; + u32 dbg_num; + struct dbg_buf_ctxt *dbg_buf_ptr; }; static void ssr_i2c_force_suspend(struct device *dev); static void ssr_i2c_force_resume(struct device *dev); +static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; +static int arr_idx; + struct geni_i2c_err_log { int err; const char *msg; @@ -219,12 +232,6 @@ static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c) static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) { - if (gi2c->cur) - GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, - "len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n", - gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags, - gi2c->xfer_timeout); - if (err == I2C_NACK || err == GENI_ABORT_DONE) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", gi2c_log[err].msg); @@ -233,8 +240,6 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n", gi2c_log[err].msg); } - GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s: se-mode:%d\n", __func__, - gi2c->se_mode); geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); err_ret: gi2c->err = gi2c_log[err].err; @@ -261,7 +266,13 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) dm_rx_st = readl_relaxed(gi2c->base + SE_DMA_RX_IRQ_STAT); dma = readl_relaxed(gi2c->base + SE_GENI_DMA_MODE_EN); - if (!cur || (m_stat & M_CMD_FAILURE_EN) || + if (!cur) { + geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); + GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "Spurious irq\n"); + goto irqret; + } + + if ((m_stat & M_CMD_FAILURE_EN) || (dm_rx_st & (DM_I2C_CB_ERR)) || (m_stat & M_CMD_CANCEL_EN) || (m_stat & M_CMD_ABORT_EN)) { @@ -288,12 +299,6 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) goto irqret; } - if (dma) { - dev_dbg(gi2c->dev, "i2c dma tx:0x%x, dma rx:0x%x\n", dm_tx_st, - dm_rx_st); - goto irqret; - } - if (((m_stat & M_RX_FIFO_WATERMARK_EN) || (m_stat & M_RX_FIFO_LAST_EN)) && (cur->flags & I2C_M_RD)) { u32 rxcnt = rx_st & RX_FIFO_WC_MSK; @@ -486,6 +491,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], goto geni_i2c_gsi_xfer_out; } } + if (!gi2c->rx_c) { gi2c->rx_c = dma_request_slave_channel(gi2c->dev, "rx"); if (!gi2c->rx_c) { @@ -564,6 +570,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], sizeof(gi2c->go_t)); if (msgs[i].flags & I2C_M_RD) { + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msg[%d].len:%d R\n", i, gi2c->cur->len); sg_init_table(&gi2c->rx_sg, 1); ret = geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, msgs[i].buf, msgs[i].len, @@ -574,6 +582,11 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], ret); goto geni_i2c_gsi_xfer_out; + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)msgs[i].buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&gi2c->rx_ph; } gi2c->rx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph); @@ -604,6 +617,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], rx_cookie = dmaengine_submit(gi2c->rx_desc); dma_async_issue_pending(gi2c->rx_c); } else { + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msg[%d].len:%d W\n", i, gi2c->cur->len); ret = geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, msgs[i].buf, msgs[i].len, DMA_TO_DEVICE); @@ -613,7 +628,13 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], ret); goto geni_i2c_gsi_xfer_out; + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)msgs[i].buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&gi2c->tx_ph; } + gi2c->tx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph); gi2c->tx_t.dword[1] = @@ -649,8 +670,11 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, - "GSI Txn timed out: %u len: %d\n", - gi2c->xfer_timeout, gi2c->cur->len); + "I2C gsi xfer timeout:%u flags:%d addr:0x%x\n", + gi2c->xfer_timeout, gi2c->cur->flags, + gi2c->cur->addr); + geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, + gi2c->ipcl); gi2c->err = -ETIMEDOUT; } geni_i2c_err_prep_sg: @@ -684,7 +708,6 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, int i, ret = 0, timeout = 0; gi2c->err = 0; - gi2c->cur = &msgs[0]; reinit_completion(&gi2c->xfer); mutex_lock(&gi2c->i2c_ssr.ssr_lock); if (gi2c->i2c_ssr.is_ssr_down) { @@ -693,6 +716,12 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mutex_unlock(&gi2c->i2c_ssr.ssr_lock); return -EINVAL; } + /* Client to respect system suspend */ + if (!pm_runtime_enabled(gi2c->dev)) { + GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, + "%s: System suspended\n", __func__); + return -EACCES; + } ret = pm_runtime_get_sync(gi2c->dev); if (ret < 0) { @@ -704,14 +733,23 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mutex_unlock(&gi2c->i2c_ssr.ssr_lock); return ret; } + + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "n:%d addr:0x%x\n", num, msgs[0].addr); + + gi2c->dbg_num = num; + kfree(gi2c->dbg_buf_ptr); + gi2c->dbg_buf_ptr = + kcalloc(num, sizeof(struct dbg_buf_ctxt), GFP_KERNEL); + if (!gi2c->dbg_buf_ptr) + GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, + "Buf logging pointer not available\n"); + if (gi2c->se_mode == GSI_ONLY) { ret = geni_i2c_gsi_xfer(adap, msgs, num); goto geni_i2c_txn_ret; } - qcom_geni_i2c_conf(gi2c, 0); - dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n", - num, msgs[0].len, msgs[0].flags); for (i = 0; i < num; i++) { int stretch = (i < (num - 1)); u32 m_param = 0; @@ -734,9 +772,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, break; } if (msgs[i].flags & I2C_M_RD) { - dev_dbg(gi2c->dev, - "READ,n:%d,i:%d len:%d, stretch:%d\n", - num, i, msgs[i].len, stretch); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msgs[%d].len:%d R\n", i, msgs[i].len); geni_write_reg(msgs[i].len, gi2c->base, SE_I2C_RX_TRANS_LEN); m_cmd = I2C_READ; @@ -749,12 +786,16 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mode = FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)msgs[i].buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&rx_dma; } } } else { - dev_dbg(gi2c->dev, - "WRITE:n:%d,i:%d len:%d, stretch:%d, m_param:0x%x\n", - num, i, msgs[i].len, stretch, m_param); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msgs[%d].len:%d W\n", i, msgs[i].len); geni_write_reg(msgs[i].len, gi2c->base, SE_I2C_TX_TRANS_LEN); m_cmd = I2C_WRITE; @@ -767,6 +808,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mode = FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)msgs[i].buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&tx_dma; } } if (mode == FIFO_MODE) /* Get FIFO IRQ */ @@ -785,12 +831,14 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, "%s: SSR Down\n", __func__); goto geni_i2c_txn_ret; } - if (!timeout) + if (!timeout) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "I2C xfer timeout: %d\n", gi2c->xfer_timeout); geni_i2c_err(gi2c, GENI_TIMEOUT); + } if (gi2c->err) { reinit_completion(&gi2c->xfer); - gi2c->cur = NULL; geni_cancel_m_cmd(gi2c->base); mutex_unlock(&gi2c->i2c_ssr.ssr_lock); timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); @@ -802,8 +850,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, goto geni_i2c_txn_ret; } - if (!timeout) + if (!timeout) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "Abort\n"); geni_abort_m_cmd(gi2c->base); + } } gi2c->cur_wr = 0; @@ -824,9 +875,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, geni_se_tx_dma_unprep(gi2c->wrapper_dev, tx_dma, msgs[i].len); } + ret = gi2c->err; if (gi2c->err) { - dev_err(gi2c->dev, "i2c error :%d\n", gi2c->err); + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "i2c error :%d\n", gi2c->err); break; } } @@ -836,9 +889,12 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, pm_runtime_mark_last_busy(gi2c->dev); pm_runtime_put_autosuspend(gi2c->dev); + gi2c->cur_wr = 0; + gi2c->cur_rd = 0; gi2c->cur = NULL; gi2c->err = 0; - dev_dbg(gi2c->dev, "i2c txn ret:%d\n", ret); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "i2c txn ret:%d\n", ret); mutex_unlock(&gi2c->i2c_ssr.ssr_lock); return ret; } @@ -867,6 +923,10 @@ static int geni_i2c_probe(struct platform_device *pdev) if (!gi2c) return -ENOMEM; + if (arr_idx++ < MAX_SE) + /* Debug purpose */ + gi2c_dev_dbg[arr_idx] = gi2c; + gi2c->dev = &pdev->dev; snprintf(boot_marker, sizeof(boot_marker), "M - DRIVER GENI_I2C Init"); @@ -906,14 +966,12 @@ static int geni_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret); return ret; } - gi2c->i2c_rsc.m_ahb_clk = devm_clk_get(&pdev->dev, "m-ahb"); if (IS_ERR(gi2c->i2c_rsc.m_ahb_clk)) { ret = PTR_ERR(gi2c->i2c_rsc.m_ahb_clk); dev_err(&pdev->dev, "Err getting M AHB clk %d\n", ret); return ret; } - gi2c->i2c_rsc.s_ahb_clk = devm_clk_get(&pdev->dev, "s-ahb"); if (IS_ERR(gi2c->i2c_rsc.s_ahb_clk)) { ret = PTR_ERR(gi2c->i2c_rsc.s_ahb_clk); @@ -998,6 +1056,7 @@ static int geni_i2c_probe(struct platform_device *pdev) gi2c->irq, ret); return ret; } + disable_irq(gi2c->irq); i2c_set_adapdata(&gi2c->adap, gi2c); gi2c->adap.dev.parent = gi2c->dev; @@ -1012,7 +1071,11 @@ static int geni_i2c_probe(struct platform_device *pdev) gi2c->i2c_rsc.rsc_ssr.force_suspend = ssr_i2c_force_suspend; gi2c->i2c_rsc.rsc_ssr.force_resume = ssr_i2c_force_resume; mutex_init(&gi2c->i2c_ssr.ssr_lock); - i2c_add_adapter(&gi2c->adap); + ret = i2c_add_adapter(&gi2c->adap); + if (ret) { + dev_err(gi2c->dev, "Add adapter failed\n"); + return ret; + } snprintf(boot_marker, sizeof(boot_marker), "M - DRIVER GENI_I2C_%d Ready", gi2c->adap.nr); @@ -1034,6 +1097,9 @@ static int geni_i2c_remove(struct platform_device *pdev) static int geni_i2c_resume_noirq(struct device *device) { + struct geni_i2c_dev *gi2c = dev_get_drvdata(device); + + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } @@ -1064,6 +1130,7 @@ static int geni_i2c_runtime_suspend(struct device *dev) GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s failed ret:%d\n", __func__, ret); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return ret; } @@ -1103,23 +1170,27 @@ static int geni_i2c_runtime_resume(struct device *dev) gi2c->se_mode = GSI_ONLY; geni_se_select_mode(gi2c->base, GSI_DMA); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, - "i2c in GSI ONLY mode\n"); + "i2c GSI mode\n"); } else { int gi2c_tx_depth = get_tx_fifo_depth(gi2c->base); gi2c->se_mode = FIFO_SE_DMA; - gi2c->tx_wm = gi2c_tx_depth - 1; geni_se_init(gi2c->base, gi2c->tx_wm, gi2c_tx_depth); se_config_packing(gi2c->base, 8, 4, true); + qcom_geni_i2c_conf(gi2c, 0); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "i2c fifo/se-dma mode. fifo depth:%d\n", gi2c_tx_depth); } + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "i2c-%d: %s\n", + gi2c->adap.nr, dev_name(gi2c->dev)); } + if (gi2c->se_mode == FIFO_SE_DMA) enable_irq(gi2c->irq); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } @@ -1136,6 +1207,8 @@ static int geni_i2c_suspend_noirq(struct device *device) return -EBUSY; } if (!pm_runtime_status_suspended(device)) { + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "%s\n", __func__); geni_i2c_runtime_suspend(device); pm_runtime_disable(device); pm_runtime_set_suspended(device); diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 97d2c5111f4389b7804bab5253262f5532b80271..8bf7fc626a9d4c974c7004ac88da87effea21acd 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -221,7 +221,7 @@ static int ad5380_read_raw(struct iio_dev *indio_dev, if (ret) return ret; *val >>= chan->scan_type.shift; - val -= (1 << chan->scan_type.realbits) / 2; + *val -= (1 << chan->scan_type.realbits) / 2; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 2 * st->vref; diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index c950aa10d0ae0ec9b6a1e2ef43eec256b98c9696..5abe095901c83dbb0c98b045c44c49fabd1867f0 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -372,12 +372,14 @@ static int adis16480_get_calibbias(struct iio_dev *indio_dev, case IIO_MAGN: case IIO_PRESSURE: ret = adis_read_reg_16(&st->adis, reg, &val16); - *bias = sign_extend32(val16, 15); + if (ret == 0) + *bias = sign_extend32(val16, 15); break; case IIO_ANGL_VEL: case IIO_ACCEL: ret = adis_read_reg_32(&st->adis, reg, &val32); - *bias = sign_extend32(val32, 31); + if (ret == 0) + *bias = sign_extend32(val32, 31); break; default: ret = -EINVAL; diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index d501257660937187280dcc106a93e5c9ab379bff..c3badf6343782ea6201591cfd5c93983a1234608 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -570,7 +570,7 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const unsigned long *mask, bool timestamp) { unsigned bytes = 0; - int length, i; + int length, i, largest = 0; /* How much space will the demuxed element take? */ for_each_set_bit(i, mask, @@ -578,13 +578,17 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, length = iio_storage_bytes_for_si(indio_dev, i); bytes = ALIGN(bytes, length); bytes += length; + largest = max(largest, length); } if (timestamp) { length = iio_storage_bytes_for_timestamp(indio_dev); bytes = ALIGN(bytes, length); bytes += length; + largest = max(largest, length); } + + bytes = ALIGN(bytes, largest); return bytes; } diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index fc4630e4acdd6bcd938439bc3abd9bf424610fe8..1614f6f3677c0b50560d1be5b61d7d84e8f349a2 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2789,7 +2789,7 @@ static void addr_handler(int status, struct sockaddr *src_addr, if (status) pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n", status); - } else { + } else if (status) { pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to resolve IP. status %d\n", status); } diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index e8afc47f8949649546e83813815f4107083c743c..908803fe8276dc56434715cd6b9a372c6da533ee 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -2024,13 +2024,13 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, bnxt_qplib_mark_qp_error(qp); bnxt_qplib_unlock_buddy_cq(qp, cq); } else { + /* Before we complete, do WA 9060 */ + if (do_wa9060(qp, cq, cq_cons, sw_sq_cons, + cqe_sq_cons)) { + *lib_qp = qp; + goto out; + } if (swq->flags & SQ_SEND_FLAGS_SIGNAL_COMP) { - /* Before we complete, do WA 9060 */ - if (do_wa9060(qp, cq, cq_cons, sw_sq_cons, - cqe_sq_cons)) { - *lib_qp = qp; - goto out; - } cqe->status = CQ_REQ_STATUS_OK; cqe++; (*budget)--; diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index bb36cdf82a8d6c76d884f0ddb00f09f6488b2a2b..7eb1cc1b1aa04626af7ba6a9a4d4fafcf8195d4d 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -2056,7 +2056,7 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip, } else { pdev = get_real_dev(n->dev); ep->l2t = cxgb4_l2t_get(cdev->rdev.lldi.l2t, - n, pdev, 0); + n, pdev, rt_tos2priority(tos)); if (!ep->l2t) goto out; ep->mtu = dst_mtu(dst); @@ -2147,7 +2147,8 @@ static int c4iw_reconnect(struct c4iw_ep *ep) laddr6->sin6_addr.s6_addr, raddr6->sin6_addr.s6_addr, laddr6->sin6_port, - raddr6->sin6_port, 0, + raddr6->sin6_port, + ep->com.cm_id->tos, raddr6->sin6_scope_id); iptype = 6; ra = (__u8 *)&raddr6->sin6_addr; @@ -2923,15 +2924,18 @@ static int terminate(struct c4iw_dev *dev, struct sk_buff *skb) ep = get_ep_from_tid(dev, tid); BUG_ON(!ep); - if (ep && ep->com.qp) { - pr_warn("TERM received tid %u qpid %u\n", - tid, ep->com.qp->wq.sq.qid); - attrs.next_state = C4IW_QP_STATE_TERMINATE; - c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, - C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); + if (ep) { + if (ep->com.qp) { + pr_warn("TERM received tid %u qpid %u\n", tid, + ep->com.qp->wq.sq.qid); + attrs.next_state = C4IW_QP_STATE_TERMINATE; + c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, + C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); + } + + c4iw_put_ep(&ep->com); } else pr_warn("TERM received tid %u no ep/qp\n", tid); - c4iw_put_ep(&ep->com); return 0; } @@ -3295,7 +3299,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) laddr6->sin6_addr.s6_addr, raddr6->sin6_addr.s6_addr, laddr6->sin6_port, - raddr6->sin6_port, 0, + raddr6->sin6_port, cm_id->tos, raddr6->sin6_scope_id); } if (!ep->dst) { diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 9f78bb07744c79d07c2c21a400df590befb5b114..4a0b7c00347718db316989f8c5331ff652e322d3 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -10552,12 +10552,29 @@ void set_link_down_reason(struct hfi1_pportdata *ppd, u8 lcl_reason, } } -/* - * Verify if BCT for data VLs is non-zero. +/** + * data_vls_operational() - Verify if data VL BCT credits and MTU + * are both set. + * @ppd: pointer to hfi1_pportdata structure + * + * Return: true - Ok, false -otherwise. */ static inline bool data_vls_operational(struct hfi1_pportdata *ppd) { - return !!ppd->actual_vls_operational; + int i; + u64 reg; + + if (!ppd->actual_vls_operational) + return false; + + for (i = 0; i < ppd->vls_supported; i++) { + reg = read_csr(ppd->dd, SEND_CM_CREDIT_VL + (8 * i)); + if ((reg && !ppd->dd->vld[i].mtu) || + (!reg && ppd->dd->vld[i].mtu)) + return false; + } + + return true; } /* @@ -10662,7 +10679,8 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state) if (!data_vls_operational(ppd)) { dd_dev_err(dd, - "%s: data VLs not operational\n", __func__); + "%s: Invalid data VL credits or mtu\n", + __func__); ret = -EINVAL; break; } diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 3a37d26889df169a61cd785cb455fb47d3863019..281e9987ffc831727c97d5f8ff4436d787e4e2c0 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -241,7 +241,6 @@ void hns_roce_qp_free(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) if ((hr_qp->ibqp.qp_type) != IB_QPT_GSI) { hns_roce_table_put(hr_dev, &qp_table->irrl_table, hr_qp->qpn); - hns_roce_table_put(hr_dev, &qp_table->qp_table, hr_qp->qpn); } } diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index cfddca850cb4d385ed05242e73649e48f1223bb1..fb45bfa4f845e9f488b886ebd07b3a839d784cec 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -460,7 +460,7 @@ struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev, int entry) if (entry < 0 || entry >= MAX_MR_CACHE_ENTRIES) { mlx5_ib_err(dev, "cache entry %d is out of range\n", entry); - return NULL; + return ERR_PTR(-EINVAL); } ent = &cache->ent[entry]; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 5a7dcb5afe6e3ad4f5f2ececb3609085637027b0..84c962820aa2a891d6c3c1655eddc3536f1e398c 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2357,6 +2357,11 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX | MLX5_QP_OPTPAR_Q_KEY | MLX5_QP_OPTPAR_PRI_PORT, + [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RRE | + MLX5_QP_OPTPAR_RAE | + MLX5_QP_OPTPAR_RWE | + MLX5_QP_OPTPAR_PKEY_INDEX | + MLX5_QP_OPTPAR_PRI_PORT, }, [MLX5_QP_STATE_RTR] = { [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | @@ -2390,6 +2395,12 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q MLX5_QP_OPTPAR_RWE | MLX5_QP_OPTPAR_PM_STATE, [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY, + [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | + MLX5_QP_OPTPAR_RRE | + MLX5_QP_OPTPAR_RAE | + MLX5_QP_OPTPAR_RWE | + MLX5_QP_OPTPAR_PM_STATE | + MLX5_QP_OPTPAR_RNR_TIMEOUT, }, }, [MLX5_QP_STATE_RTS] = { @@ -2406,6 +2417,12 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY | MLX5_QP_OPTPAR_SRQN | MLX5_QP_OPTPAR_CQN_RCV, + [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RRE | + MLX5_QP_OPTPAR_RAE | + MLX5_QP_OPTPAR_RWE | + MLX5_QP_OPTPAR_RNR_TIMEOUT | + MLX5_QP_OPTPAR_PM_STATE | + MLX5_QP_OPTPAR_ALT_ADDR_PATH, }, }, [MLX5_QP_STATE_SQER] = { @@ -2417,6 +2434,10 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q MLX5_QP_OPTPAR_RWE | MLX5_QP_OPTPAR_RAE | MLX5_QP_OPTPAR_RRE, + [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RNR_TIMEOUT | + MLX5_QP_OPTPAR_RWE | + MLX5_QP_OPTPAR_RAE | + MLX5_QP_OPTPAR_RRE, }, }, }; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index 27d5e8d9f08d38a6a5358885b4315d35cab949ae..7683d13dad3d571bb12fab3c63c012d9bcff70d3 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -55,7 +55,7 @@ int ocrdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) { - if (index > 1) + if (index > 0) return -EINVAL; *pkey = 0xffff; diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 656e7c1a4449f8f95ed68206c0e6e65df0d36064..6ae72accae3db37f2c0ca3a75e06e4d9b02cf5ec 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -63,7 +63,7 @@ static inline int qedr_ib_copy_to_udata(struct ib_udata *udata, void *src, int qedr_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) { - if (index > QEDR_ROCE_PKEY_TABLE_LEN) + if (index >= QEDR_ROCE_PKEY_TABLE_LEN) return -EINVAL; *pkey = QEDR_ROCE_PKEY_DEFAULT; @@ -178,54 +178,47 @@ int qedr_query_device(struct ib_device *ibdev, return 0; } -#define QEDR_SPEED_SDR (1) -#define QEDR_SPEED_DDR (2) -#define QEDR_SPEED_QDR (4) -#define QEDR_SPEED_FDR10 (8) -#define QEDR_SPEED_FDR (16) -#define QEDR_SPEED_EDR (32) - static inline void get_link_speed_and_width(int speed, u8 *ib_speed, u8 *ib_width) { switch (speed) { case 1000: - *ib_speed = QEDR_SPEED_SDR; + *ib_speed = IB_SPEED_SDR; *ib_width = IB_WIDTH_1X; break; case 10000: - *ib_speed = QEDR_SPEED_QDR; + *ib_speed = IB_SPEED_QDR; *ib_width = IB_WIDTH_1X; break; case 20000: - *ib_speed = QEDR_SPEED_DDR; + *ib_speed = IB_SPEED_DDR; *ib_width = IB_WIDTH_4X; break; case 25000: - *ib_speed = QEDR_SPEED_EDR; + *ib_speed = IB_SPEED_EDR; *ib_width = IB_WIDTH_1X; break; case 40000: - *ib_speed = QEDR_SPEED_QDR; + *ib_speed = IB_SPEED_QDR; *ib_width = IB_WIDTH_4X; break; case 50000: - *ib_speed = QEDR_SPEED_QDR; - *ib_width = IB_WIDTH_4X; + *ib_speed = IB_SPEED_HDR; + *ib_width = IB_WIDTH_1X; break; case 100000: - *ib_speed = QEDR_SPEED_EDR; + *ib_speed = IB_SPEED_EDR; *ib_width = IB_WIDTH_4X; break; default: /* Unsupported */ - *ib_speed = QEDR_SPEED_SDR; + *ib_speed = IB_SPEED_SDR; *ib_width = IB_WIDTH_1X; } } diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c index fdfa25059723d8efcd607cf26e9c0c283309aeb4..2602c7375d5859d3700c93e9d6a052ea7ee68a0a 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c @@ -423,7 +423,7 @@ struct net_device *usnic_get_netdev(struct ib_device *device, u8 port_num) int usnic_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) { - if (index > 1) + if (index > 0) return -EINVAL; *pkey = 0xffff; diff --git a/drivers/infiniband/sw/rxe/rxe_cq.c b/drivers/infiniband/sw/rxe/rxe_cq.c index c4aabf78dc90f525d0e9a4da78fc0dc5b96bcd15..f6e036ded046ee0818ea8f2d529773b7d3911a14 100644 --- a/drivers/infiniband/sw/rxe/rxe_cq.c +++ b/drivers/infiniband/sw/rxe/rxe_cq.c @@ -30,7 +30,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - +#include #include "rxe.h" #include "rxe_loc.h" #include "rxe_queue.h" @@ -97,7 +97,7 @@ int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe, err = do_mmap_info(rxe, udata, false, context, cq->queue->buf, cq->queue->buf_size, &cq->queue->ip); if (err) { - kvfree(cq->queue->buf); + vfree(cq->queue->buf); kfree(cq->queue); return err; } diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c index b4a8acc7bb7d62fb479473df7ec6aaacde86e533..0e2425f2823351778c1b63bd135864c59b32d4af 100644 --- a/drivers/infiniband/sw/rxe/rxe_pool.c +++ b/drivers/infiniband/sw/rxe/rxe_pool.c @@ -112,6 +112,18 @@ static inline struct kmem_cache *pool_cache(struct rxe_pool *pool) return rxe_type_info[pool->type].cache; } +static void rxe_cache_clean(size_t cnt) +{ + int i; + struct rxe_type_info *type; + + for (i = 0; i < cnt; i++) { + type = &rxe_type_info[i]; + kmem_cache_destroy(type->cache); + type->cache = NULL; + } +} + int rxe_cache_init(void) { int err; @@ -136,24 +148,14 @@ int rxe_cache_init(void) return 0; err1: - while (--i >= 0) { - kmem_cache_destroy(type->cache); - type->cache = NULL; - } + rxe_cache_clean(i); return err; } void rxe_cache_exit(void) { - int i; - struct rxe_type_info *type; - - for (i = 0; i < RXE_NUM_TYPES; i++) { - type = &rxe_type_info[i]; - kmem_cache_destroy(type->cache); - type->cache = NULL; - } + rxe_cache_clean(RXE_NUM_TYPES); } static int rxe_pool_init_index(struct rxe_pool *pool, u32 max, u32 min) diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index aeea994b04c43752311fd2f593c63ef41cb38d65..25055a68a2c07937407d968d885d02d894d95844 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "rxe.h" #include "rxe_loc.h" @@ -255,7 +256,7 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, qp->sq.queue->buf_size, &qp->sq.queue->ip); if (err) { - kvfree(qp->sq.queue->buf); + vfree(qp->sq.queue->buf); kfree(qp->sq.queue); return err; } @@ -308,7 +309,7 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp, qp->rq.queue->buf_size, &qp->rq.queue->ip); if (err) { - kvfree(qp->rq.queue->buf); + vfree(qp->rq.queue->buf); kfree(qp->rq.queue); return err; } diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index c1ae4aeae2f90e5a9c1376a296529d912d77d457..46dfc6ae9d1c1597e18e677a99a6f32c84b4c138 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -197,7 +197,7 @@ struct iser_data_buf { struct scatterlist *sg; int size; unsigned long data_len; - unsigned int dma_nents; + int dma_nents; }; /* fwd declarations */ diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 322209d5ff5829b6dfd5f4de54f4d11fe141c63d..19883169e7b763cf6ebd92103f165026f6068c54 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -240,8 +240,8 @@ int iser_fast_reg_fmr(struct iscsi_iser_task *iser_task, page_vec->npages = 0; page_vec->fake_mr.page_size = SIZE_4K; plen = ib_sg_to_pages(&page_vec->fake_mr, mem->sg, - mem->size, NULL, iser_set_page); - if (unlikely(plen < mem->size)) { + mem->dma_nents, NULL, iser_set_page); + if (unlikely(plen < mem->dma_nents)) { iser_err("page vec too short to hold this SG\n"); iser_data_buf_dump(mem, device->ib_device); iser_dump_page_vec(page_vec); @@ -450,10 +450,10 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); - n = ib_map_mr_sg(mr, mem->sg, mem->size, NULL, SIZE_4K); - if (unlikely(n != mem->size)) { + n = ib_map_mr_sg(mr, mem->sg, mem->dma_nents, NULL, SIZE_4K); + if (unlikely(n != mem->dma_nents)) { iser_err("failed to map sg (%d/%d)\n", - n, mem->size); + n, mem->dma_nents); return n < 0 ? n : -EINVAL; } diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index ee3f630c92179dac8d4a7351bd43e459d9d72fc2..9b5691f306a230262103bc25ada8d897838ae14d 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -2582,17 +2582,6 @@ isert_wait4logout(struct isert_conn *isert_conn) } } -static void -isert_wait4cmds(struct iscsi_conn *conn) -{ - isert_info("iscsi_conn %p\n", conn); - - if (conn->sess) { - target_sess_cmd_list_set_waiting(conn->sess->se_sess); - target_wait_for_sess_cmds(conn->sess->se_sess); - } -} - /** * isert_put_unsol_pending_cmds() - Drop commands waiting for * unsolicitate dataout @@ -2640,7 +2629,6 @@ static void isert_wait_conn(struct iscsi_conn *conn) ib_drain_qp(isert_conn->qp); isert_put_unsol_pending_cmds(conn); - isert_wait4cmds(conn); isert_wait4logout(isert_conn); queue_work(isert_release_wq, &isert_conn->release_work); diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 181deb6f05b0cf86d6a8f811918b92d39a3f1244..5f1055c94d662a25e4ea12808b59e76bf357be35 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1246,9 +1246,11 @@ static int srpt_build_cmd_rsp(struct srpt_rdma_ch *ch, struct srpt_send_ioctx *ioctx, u64 tag, int status) { + struct se_cmd *cmd = &ioctx->cmd; struct srp_rsp *srp_rsp; const u8 *sense_data; int sense_data_len, max_sense_len; + u32 resid = cmd->residual_count; /* * The lowest bit of all SAM-3 status codes is zero (see also @@ -1270,6 +1272,28 @@ static int srpt_build_cmd_rsp(struct srpt_rdma_ch *ch, srp_rsp->tag = tag; srp_rsp->status = status; + if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { + if (cmd->data_direction == DMA_TO_DEVICE) { + /* residual data from an underflow write */ + srp_rsp->flags = SRP_RSP_FLAG_DOUNDER; + srp_rsp->data_out_res_cnt = cpu_to_be32(resid); + } else if (cmd->data_direction == DMA_FROM_DEVICE) { + /* residual data from an underflow read */ + srp_rsp->flags = SRP_RSP_FLAG_DIUNDER; + srp_rsp->data_in_res_cnt = cpu_to_be32(resid); + } + } else if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { + if (cmd->data_direction == DMA_TO_DEVICE) { + /* residual data from an overflow write */ + srp_rsp->flags = SRP_RSP_FLAG_DOOVER; + srp_rsp->data_out_res_cnt = cpu_to_be32(resid); + } else if (cmd->data_direction == DMA_FROM_DEVICE) { + /* residual data from an overflow read */ + srp_rsp->flags = SRP_RSP_FLAG_DIOVER; + srp_rsp->data_in_res_cnt = cpu_to_be32(resid); + } + } + if (sense_data_len) { BUILD_BUG_ON(MIN_MAX_RSP_SIZE <= sizeof(*srp_rsp)); max_sense_len = ch->max_ti_iu_len - sizeof(*srp_rsp); diff --git a/drivers/input/input.c b/drivers/input/input.c index 50d425fe6706faf84596851a730a0e62b860d1cb..cadb368be8eff68fea2e4396ef3e8217c73efc1e 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -858,16 +858,18 @@ static int input_default_setkeycode(struct input_dev *dev, } } - __clear_bit(*old_keycode, dev->keybit); - __set_bit(ke->keycode, dev->keybit); - - for (i = 0; i < dev->keycodemax; i++) { - if (input_fetch_keycode(dev, i) == *old_keycode) { - __set_bit(*old_keycode, dev->keybit); - break; /* Setting the bit twice is useless, so break */ + if (*old_keycode <= KEY_MAX) { + __clear_bit(*old_keycode, dev->keybit); + for (i = 0; i < dev->keycodemax; i++) { + if (input_fetch_keycode(dev, i) == *old_keycode) { + __set_bit(*old_keycode, dev->keybit); + /* Setting the bit twice is useless, so break */ + break; + } } } + __set_bit(ke->keycode, dev->keybit); return 0; } @@ -923,9 +925,13 @@ int input_set_keycode(struct input_dev *dev, * Simulate keyup event if keycode is not present * in the keymap anymore */ - if (test_bit(EV_KEY, dev->evbit) && - !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && - __test_and_clear_bit(old_keycode, dev->key)) { + if (old_keycode > KEY_MAX) { + dev_warn(dev->dev.parent ?: &dev->dev, + "%s: got too big old keycode %#x\n", + __func__, old_keycode); + } else if (test_bit(EV_KEY, dev->evbit) && + !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && + __test_and_clear_bit(old_keycode, dev->key)) { struct input_value vals[] = { { EV_KEY, old_keycode, 0 }, input_value_sync diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 8567ee47761e111b31f7c8270bdc6414de6668a1..ae3b04557074010bc708c48db877c486f9d1cd0a 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -100,7 +100,7 @@ static int __init ske_keypad_chip_init(struct ske_keypad *keypad) while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--) cpu_relax(); - if (!timeout) + if (timeout == -1) return -EINVAL; /* diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c index 77c47d6325fe91dca54f5b18d6c2a43c561b7f4c..a9ee813eef10f83e7f4de3c46bcfbc24ef8817c5 100644 --- a/drivers/input/misc/keyspan_remote.c +++ b/drivers/input/misc/keyspan_remote.c @@ -344,7 +344,8 @@ static int keyspan_setup(struct usb_device* dev) int retval = 0; retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0); + 0x11, 0x40, 0x5601, 0x0, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (retval) { dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n", __func__, retval); @@ -352,7 +353,8 @@ static int keyspan_setup(struct usb_device* dev) } retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x44, 0x40, 0x0, 0x0, NULL, 0, 0); + 0x44, 0x40, 0x0, 0x0, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (retval) { dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n", __func__, retval); @@ -360,7 +362,8 @@ static int keyspan_setup(struct usb_device* dev) } retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x22, 0x40, 0x0, 0x0, NULL, 0, 0); + 0x22, 0x40, 0x0, 0x0, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (retval) { dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n", __func__, retval); diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 7dd1c1fbe42a8d1079995f7ff1acb36974864fe9..27b3db154a33f542d82c9f8f61b1971da1d47e7e 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -98,7 +98,7 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) if (regs->enable_mask) rc = regmap_update_bits(vib->regmap, regs->enable_addr, - on ? regs->enable_mask : 0, val); + regs->enable_mask, on ? ~0 : 0); return rc; } diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index df9fa421072f1c4367eed70b7033dd701b5377b4..d930b6b451b950c351ae0147f11b7b0c5ebf0176 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -242,6 +242,7 @@ struct qpnp_pon { bool resin_pon_reset; ktime_t kpdpwr_last_release_time; struct notifier_block pon_nb; + bool legacy_hard_reset_offset; }; static int pon_ship_mode_en; @@ -423,7 +424,7 @@ int qpnp_pon_set_restart_reason(enum pon_restart_reason reason) if (!pon->store_hard_reset_reason) return 0; - if (is_pon_gen2(pon)) + if (is_pon_gen2(pon) && !pon->legacy_hard_reset_offset) rc = qpnp_pon_masked_write(pon, QPNP_PON_SOFT_RB_SPARE(pon), GENMASK(7, 1), (reason << 1)); else @@ -2416,6 +2417,9 @@ static int qpnp_pon_probe(struct platform_device *pdev) pon->store_hard_reset_reason = of_property_read_bool(dev->of_node, "qcom,store-hard-reset-reason"); + pon->legacy_hard_reset_offset = of_property_read_bool(pdev->dev.of_node, + "qcom,use-legacy-hard-reset-offset"); + if (of_property_read_bool(dev->of_node, "qcom,secondary-pon-reset")) { if (sys_reset) { dev_err(dev, "qcom,system-reset property shouldn't be used along with qcom,secondary-pon-reset property\n"); diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index 4b2466cf2fb1c9181ce6038750a9586f10ee983a..b6ccf39c6a7bb46bc67bf086952a799e27f4f930 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -166,6 +166,7 @@ static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, /* prepare to write next block of bytes */ cur_len -= SMB_MAX_COUNT; databuff += SMB_MAX_COUNT; + rmiaddr += SMB_MAX_COUNT; } exit: mutex_unlock(&rmi_smb->page_mutex); @@ -217,6 +218,7 @@ static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr, /* prepare to read next block of bytes */ cur_len -= SMB_MAX_COUNT; databuff += SMB_MAX_COUNT; + rmiaddr += SMB_MAX_COUNT; } retval = 0; diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 0b55e1f375b397627915790e1876a509ae1d5276..fbe2df91aad3a3957a0bbb94175a7617be5ff7f4 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -1822,14 +1822,14 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); /* Verify that a device really has an endpoint */ - if (intf->altsetting[0].desc.bNumEndpoints < 1) { + if (intf->cur_altsetting->desc.bNumEndpoints < 1) { dev_err(&intf->dev, "interface has %d endpoints, but must have minimum 1\n", - intf->altsetting[0].desc.bNumEndpoints); + intf->cur_altsetting->desc.bNumEndpoints); err = -EINVAL; goto fail3; } - endpoint = &intf->altsetting[0].endpoint[0].desc; + endpoint = &intf->cur_altsetting->endpoint[0].desc; /* Go set up our URB, which is called when the tablet receives * input. diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 35031228a6d076cf0dd91dab411f049ec679df6b..799c94dda651aacf7acc76e6e38995d48c32ffb4 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -875,18 +875,14 @@ static int gtco_probe(struct usb_interface *usbinterface, } /* Sanity check that a device has an endpoint */ - if (usbinterface->altsetting[0].desc.bNumEndpoints < 1) { + if (usbinterface->cur_altsetting->desc.bNumEndpoints < 1) { dev_err(&usbinterface->dev, "Invalid number of endpoints\n"); error = -EINVAL; goto err_free_urb; } - /* - * The endpoint is always altsetting 0, we know this since we know - * this device only has one interrupt endpoint - */ - endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + endpoint = &usbinterface->cur_altsetting->endpoint[0].desc; /* Some debug */ dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting); @@ -973,7 +969,7 @@ static int gtco_probe(struct usb_interface *usbinterface, input_dev->dev.parent = &usbinterface->dev; /* Setup the URB, it will be posted later on open of input device */ - endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + endpoint = &usbinterface->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(gtco->urbinfo, udev, diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c index 47de5a81172f65a24a656361afdf244f2f61ff4e..2319144802c93ab08a1251eecf8bdde644884a43 100644 --- a/drivers/input/tablet/pegasus_notetaker.c +++ b/drivers/input/tablet/pegasus_notetaker.c @@ -260,7 +260,7 @@ static int pegasus_probe(struct usb_interface *intf, return -ENODEV; /* Sanity check that the device has an endpoint */ - if (intf->altsetting[0].desc.bNumEndpoints < 1) { + if (intf->cur_altsetting->desc.bNumEndpoints < 1) { dev_err(&intf->dev, "Invalid number of endpoints\n"); return -EINVAL; } diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index d2e14d9e59753288168d50de4d8e2e880ed40ce3..ab44eb0352d060e7f7953924b069dd20fad6144f 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -246,6 +246,7 @@ static int sun4i_ts_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct device *hwmon; + struct thermal_zone_device *thermal; int error; u32 reg; bool ts_attached; @@ -365,7 +366,10 @@ static int sun4i_ts_probe(struct platform_device *pdev) if (IS_ERR(hwmon)) return PTR_ERR(hwmon); - devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, &sun4i_ts_tz_ops); + thermal = devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, + &sun4i_ts_tz_ops); + if (IS_ERR(thermal)) + return PTR_ERR(thermal); writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index f16f8358c70aab09da0cda18a4fa623f7d8a027a..98e03d0ca03cbad73569063e71f4307b100560b0 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -537,7 +537,7 @@ static int sur40_probe(struct usb_interface *interface, int error; /* Check if we really have the right interface. */ - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; if (iface_desc->desc.bInterfaceClass != 0xFF) return -ENODEV; diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index d09c24825734eb2cfc288418f22139066efedcb4..778f167be2d3517656799bd609f84d53765457a3 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2160,6 +2160,8 @@ static int attach_device(struct device *dev, */ domain_flush_tlb_pde(domain); + domain_flush_complete(domain); + return ret; } diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 6a3cf4d0bd5e358e91417eae1224ba55c5fadd06..4d2920988d6074c4bdb386bacbd88e3aa306f802 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -420,6 +420,9 @@ static void iommu_enable(struct amd_iommu *iommu) static void iommu_disable(struct amd_iommu *iommu) { + if (!iommu->mmio_base) + return; + /* Disable command buffer */ iommu_feature_disable(iommu, CONTROL_CMDBUF_EN); diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 523d0889c2a4ecb52e18e896c31b793fb6687e8e..b48666849dbedaff02bbf812647a865cbd0c0ac0 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -442,7 +442,6 @@ struct dmar_rmrr_unit { u64 end_address; /* reserved end address */ struct dmar_dev_scope *devices; /* target devices */ int devices_cnt; /* target device count */ - struct iommu_resv_region *resv; /* reserved region handle */ }; struct dmar_atsr_unit { @@ -3361,9 +3360,12 @@ static int __init init_dmars(void) iommu_identity_mapping |= IDENTMAP_ALL; #ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA - iommu_identity_mapping |= IDENTMAP_GFX; + dmar_map_gfx = 0; #endif + if (!dmar_map_gfx) + iommu_identity_mapping |= IDENTMAP_GFX; + check_tylersburg_isoch(); if (iommu_identity_mapping) { @@ -4168,7 +4170,6 @@ static inline void init_iommu_pm_ops(void) {} int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) { struct acpi_dmar_reserved_memory *rmrr; - int prot = DMA_PTE_READ|DMA_PTE_WRITE; struct dmar_rmrr_unit *rmrru; size_t length; @@ -4182,22 +4183,16 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) rmrru->end_address = rmrr->end_address; length = rmrr->end_address - rmrr->base_address + 1; - rmrru->resv = iommu_alloc_resv_region(rmrr->base_address, length, prot, - IOMMU_RESV_DIRECT); - if (!rmrru->resv) - goto free_rmrru; rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1), ((void *)rmrr) + rmrr->header.length, &rmrru->devices_cnt); if (rmrru->devices_cnt && rmrru->devices == NULL) - goto free_all; + goto free_rmrru; list_add(&rmrru->list, &dmar_rmrr_units); return 0; -free_all: - kfree(rmrru->resv); free_rmrru: kfree(rmrru); out: @@ -4415,7 +4410,6 @@ static void intel_iommu_free_dmars(void) list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) { list_del(&rmrru->list); dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt); - kfree(rmrru->resv); kfree(rmrru); } @@ -5183,22 +5177,33 @@ static void intel_iommu_remove_device(struct device *dev) static void intel_iommu_get_resv_regions(struct device *device, struct list_head *head) { + int prot = DMA_PTE_READ | DMA_PTE_WRITE; struct iommu_resv_region *reg; struct dmar_rmrr_unit *rmrr; struct device *i_dev; int i; - rcu_read_lock(); + down_read(&dmar_global_lock); for_each_rmrr_units(rmrr) { for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, i, i_dev) { + struct iommu_resv_region *resv; + size_t length; + if (i_dev != device) continue; - list_add_tail(&rmrr->resv->list, head); + length = rmrr->end_address - rmrr->base_address + 1; + resv = iommu_alloc_resv_region(rmrr->base_address, + length, prot, + IOMMU_RESV_DIRECT); + if (!resv) + break; + + list_add_tail(&resv->list, head); } } - rcu_read_unlock(); + up_read(&dmar_global_lock); reg = iommu_alloc_resv_region(IOAPIC_RANGE_START, IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1, @@ -5213,10 +5218,8 @@ static void intel_iommu_put_resv_regions(struct device *dev, { struct iommu_resv_region *entry, *next; - list_for_each_entry_safe(entry, next, head, list) { - if (entry->type == IOMMU_RESV_MSI) - kfree(entry); - } + list_for_each_entry_safe(entry, next, head, list) + kfree(entry); } #ifdef CONFIG_INTEL_IOMMU_SVM diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c index 8f26083ba76a4124bab8a62f6a97a7becb7ebf66..5a5d597a00a690832eab56757f5f198be9e5d4e4 100644 --- a/drivers/iommu/io-pgtable-fast.c +++ b/drivers/iommu/io-pgtable-fast.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, 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 @@ -150,7 +150,7 @@ struct av8l_fast_io_pgtable { #define AV8L_FAST_PAGE_SHIFT 12 #define PTE_MAIR_IDX(pte) \ - ((pte >> AV8L_FAST_PTE_ATTRINDX_SHIFT) && \ + ((pte >> AV8L_FAST_PTE_ATTRINDX_SHIFT) & \ AV8L_FAST_PTE_ATTRINDX_MASK) #define PTE_SH_IDX(pte) (pte & AV8L_FAST_PTE_SH_MASK) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index ef7629844de3955152e5f4dad9485dd12e07c67e..ddd71248902235b2dac945cb68fd6e36273762e8 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -617,6 +617,7 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev) mutex_unlock(&group->mutex); dev->iommu_group = NULL; kobject_put(group->devices_kobj); + sysfs_remove_link(group->devices_kobj, device->name); err_free_name: kfree(device->name); err_remove_link: @@ -1959,9 +1960,9 @@ int iommu_request_dm_for_dev(struct device *dev) int ret; /* Device must already be in a group before calling this function */ - group = iommu_group_get_for_dev(dev); - if (IS_ERR(group)) - return PTR_ERR(group); + group = iommu_group_get(dev); + if (!group) + return -EINVAL; mutex_lock(&group->mutex); diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index c30f6270043152bf6304821863dc8e45722c22d6..0f99e95a1a73934aaba4ea2d8ae9a73a65263b0c 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -115,6 +115,30 @@ struct mtk_iommu_domain { static struct iommu_ops mtk_iommu_ops; +/* + * In M4U 4GB mode, the physical address is remapped as below: + * + * CPU Physical address: + * ==================== + * + * 0 1G 2G 3G 4G 5G + * |---A---|---B---|---C---|---D---|---E---| + * +--I/O--+------------Memory-------------+ + * + * IOMMU output physical address: + * ============================= + * + * 4G 5G 6G 7G 8G + * |---E---|---B---|---C---|---D---| + * +------------Memory-------------+ + * + * The Region 'A'(I/O) can NOT be mapped by M4U; For Region 'B'/'C'/'D', the + * bit32 of the CPU physical address always is needed to set, and for Region + * 'E', the CPU physical address keep as is. + * Additionally, The iommu consumers always use the CPU phyiscal address. + */ +#define MTK_IOMMU_4GB_MODE_REMAP_BASE 0x40000000 + static LIST_HEAD(m4ulist); /* List all the M4U HWs */ #define for_each_m4u(data) list_for_each_entry(data, &m4ulist, list) @@ -404,7 +428,7 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain, pa = dom->iop->iova_to_phys(dom->iop, iova); spin_unlock_irqrestore(&dom->pgtlock, flags); - if (data->enable_4GB) + if (data->enable_4GB && pa < MTK_IOMMU_4GB_MODE_REMAP_BASE) pa |= BIT_ULL(32); return pa; diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c index c0dd17a821709d8959a06e2ca3674b4e733da806..73de2deaba673481d02603f0093c0d03250b2a49 100644 --- a/drivers/lightnvm/pblk-rb.c +++ b/drivers/lightnvm/pblk-rb.c @@ -825,8 +825,8 @@ int pblk_rb_tear_down_check(struct pblk_rb *rb) } out: - spin_unlock(&rb->w_lock); spin_unlock_irq(&rb->s_lock); + spin_unlock(&rb->w_lock); return ret; } diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index cb2ecf417ffee9d1ef2232c38246a07a2dfc1f31..c9ef797d423bc94f0f407231d84c6a15343b6a2c 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -132,6 +132,16 @@ config QCOM_APCS_IPC providing an interface for invoking the inter-process communication signals from the application processor to other masters. +config QCOM_GVM_IPC + tristate "Qualcomm Technologies, Inc. GVM IPC driver" + depends on ARCH_QCOM + help + Say y here to enable support for the GVM IPC mailbox driver, + This driver will providing an interface for invoking the communication + between GVM and primary host through virtual IRQ line. It signals from + the GVM to primary host and primary host will send different signal to + remote sub system. + config TEGRA_HSP_MBOX bool "Tegra HSP (Hardware Synchronization Primitives) Driver" depends on ARCH_TEGRA_186_SOC diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 7650057c4cfbf4336879609a7c7f9a6f6ba97559..2f4f8d614640c8364e520dd625542a80a9da2c97 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -35,6 +35,8 @@ obj-$(CONFIG_BCM_FLEXRM_MBOX) += bcm-flexrm-mailbox.o obj-$(CONFIG_QCOM_APCS_IPC) += qcom-apcs-ipc-mailbox.o +obj-$(CONFIG_QCOM_GVM_IPC) += qcom-gvm-ipc-mailbox.o + obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o obj-$(CONFIG_QTI_RPMH_MBOX) += qcom-rpmh-mailbox.o diff --git a/drivers/mailbox/qcom-gvm-ipc-mailbox.c b/drivers/mailbox/qcom-gvm-ipc-mailbox.c new file mode 100644 index 0000000000000000000000000000000000000000..ee080a292b492cd9f47fa4196918bbe12e29e89c --- /dev/null +++ b/drivers/mailbox/qcom-gvm-ipc-mailbox.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2020, The Linux Foundation, All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define QCOM_GVM_CHNL 32 + +struct qcom_gvm_ipc { + struct mbox_controller mbox; + struct mbox_chan mbox_chans[QCOM_GVM_CHNL]; + + void __iomem *reg; + unsigned long offset; +}; + +static int qcom_gvm_ipc_send_data(struct mbox_chan *chan, void *data) +{ + struct qcom_gvm_ipc *gvm_ipc = container_of(chan->mbox, + struct qcom_gvm_ipc, mbox); + + __raw_writel(1, gvm_ipc->reg); + + return 0; +} + +static const struct mbox_chan_ops qcom_gvm_ipc_ops = { + .send_data = qcom_gvm_ipc_send_data, +}; + +static int qcom_gvm_ipc_probe(struct platform_device *pdev) +{ + struct qcom_gvm_ipc *gvm_ipc; + struct resource *res; + void __iomem *base; + unsigned long i; + int ret; + + gvm_ipc = devm_kzalloc(&pdev->dev, sizeof(*gvm_ipc), GFP_KERNEL); + if (!gvm_ipc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (IS_ERR(base)) + return PTR_ERR(base); + + gvm_ipc->reg = base; + /* Initialize channel identifiers */ + for (i = 0; i < ARRAY_SIZE(gvm_ipc->mbox_chans); i++) + gvm_ipc->mbox_chans[i].con_priv = (void *)i; + + gvm_ipc->mbox.dev = &pdev->dev; + gvm_ipc->mbox.ops = &qcom_gvm_ipc_ops; + gvm_ipc->mbox.chans = gvm_ipc->mbox_chans; + gvm_ipc->mbox.num_chans = ARRAY_SIZE(gvm_ipc->mbox_chans); + + ret = mbox_controller_register(&gvm_ipc->mbox); + if (ret) { + dev_err(&pdev->dev, "failed to register GVM IPC controller\n"); + return ret; + } + + platform_set_drvdata(pdev, gvm_ipc); + + return 0; +} + +static int qcom_gvm_ipc_remove(struct platform_device *pdev) +{ + struct qcom_gvm_ipc *gvm_ipc = platform_get_drvdata(pdev); + + mbox_controller_unregister(&gvm_ipc->mbox); + + return 0; +} + +/* .data is the offset of the ipc register within the global block */ +static const struct of_device_id qcom_gvm_ipc_of_match[] = { + { .compatible = "qcom,sm8150-apcs-hmss-global" }, + {} +}; +MODULE_DEVICE_TABLE(of, qcom_gvm_ipc_of_match); + +static struct platform_driver qcom_gvm_ipc_driver = { + .probe = qcom_gvm_ipc_probe, + .remove = qcom_gvm_ipc_remove, + .driver = { + .name = "qcom_gvm_ipc", + .of_match_table = qcom_gvm_ipc_of_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init qcom_gvm_ipc_init(void) +{ + return platform_driver_register(&qcom_gvm_ipc_driver); +} +postcore_initcall(qcom_gvm_ipc_init); + +static void __exit qcom_gvm_ipc_exit(void) +{ + platform_driver_unregister(&qcom_gvm_ipc_driver); +} +module_exit(qcom_gvm_ipc_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. GVM IPC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 0cabf31fb163a3fa582035ecc77be37d56a949b6..7eb76a1a25053477c69afe6cb9806f8c7d5b9f27 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1729,7 +1729,7 @@ void bitmap_flush(struct mddev *mddev) /* * free memory that was allocated */ -void bitmap_free(struct bitmap *bitmap) +void md_bitmap_free(struct bitmap *bitmap) { unsigned long k, pages; struct bitmap_page *bp; @@ -1763,7 +1763,7 @@ void bitmap_free(struct bitmap *bitmap) kfree(bp); kfree(bitmap); } -EXPORT_SYMBOL(bitmap_free); +EXPORT_SYMBOL(md_bitmap_free); void bitmap_wait_behind_writes(struct mddev *mddev) { @@ -1796,7 +1796,7 @@ void bitmap_destroy(struct mddev *mddev) if (mddev->thread) mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; - bitmap_free(bitmap); + md_bitmap_free(bitmap); } /* @@ -1887,7 +1887,7 @@ struct bitmap *bitmap_create(struct mddev *mddev, int slot) return bitmap; error: - bitmap_free(bitmap); + md_bitmap_free(bitmap); return ERR_PTR(err); } @@ -1958,7 +1958,7 @@ struct bitmap *get_bitmap_from_slot(struct mddev *mddev, int slot) rv = bitmap_init_from_disk(bitmap, 0); if (rv) { - bitmap_free(bitmap); + md_bitmap_free(bitmap); return ERR_PTR(rv); } diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index 5df35ca90f58b5b9156913a478d1f51f561a0a7a..dd53a978c5f26769c2af827484367430a42fcf62 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -271,7 +271,7 @@ int bitmap_resize(struct bitmap *bitmap, sector_t blocks, struct bitmap *get_bitmap_from_slot(struct mddev *mddev, int slot); int bitmap_copy_from_slot(struct mddev *mddev, int slot, sector_t *lo, sector_t *hi, bool clear_bits); -void bitmap_free(struct bitmap *bitmap); +void md_bitmap_free(struct bitmap *bitmap); void bitmap_wait_behind_writes(struct mddev *mddev); #endif diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index c5534d294773fc0267a1b4c7438a3316e74d417a..00025569e80714fb404df653d4fcaae9bec49433 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -17,7 +17,7 @@ #include "dm-bufio.h" #define DM_MSG_PREFIX "persistent snapshot" -#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */ +#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32U /* 16KB */ #define DM_PREFETCH_CHUNKS 12 diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 717aaffc227dfa942821bebf4133670dbc684d95..10057ac85476ec099aef71bacf718bdc41a621c5 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -1128,7 +1128,7 @@ int cluster_check_sync_size(struct mddev *mddev) bm_lockres = lockres_init(mddev, str, NULL, 1); if (!bm_lockres) { pr_err("md-cluster: Cannot initialize %s\n", str); - bitmap_free(bitmap); + md_bitmap_free(bitmap); return -1; } bm_lockres->flags |= DLM_LKF_NOQUEUE; @@ -1142,11 +1142,11 @@ int cluster_check_sync_size(struct mddev *mddev) sync_size = sb->sync_size; else if (sync_size != sb->sync_size) { kunmap_atomic(sb); - bitmap_free(bitmap); + md_bitmap_free(bitmap); return -1; } kunmap_atomic(sb); - bitmap_free(bitmap); + md_bitmap_free(bitmap); } return (my_sync_size == sync_size) ? 0 : -1; diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 204adde004a3c36f3ecb92aa624c20e98fcd38ab..cdafa5e0ea6dbf772e2daa43079a6d8d767d9a15 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -94,7 +94,7 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) char b[BDEVNAME_SIZE]; char b2[BDEVNAME_SIZE]; struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL); - unsigned short blksize = 512; + unsigned blksize = 512; *private_conf = ERR_PTR(-ENOMEM); if (!conf) diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 44b0584eb8a6cc9137bdd55ba60da6963193691b..e7768ed1ff9c24b121058a0354c620cfee854d94 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1136,7 +1136,7 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; #else - return -ENOTTY; + ret = -ENOTTY; #endif } else { s64 val; diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 348296be492585b64d50e972e1cdf6c7b48fc749..4f67a515bdd81e6523ae6449d4b9069b2e78bb9e 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -203,7 +203,6 @@ struct ov6650 { unsigned long pclk_max; /* from resolution and format */ struct v4l2_fract tpf; /* as requested with s_parm */ u32 code; - enum v4l2_colorspace colorspace; }; @@ -216,6 +215,17 @@ static u32 ov6650_codes[] = { MEDIA_BUS_FMT_Y8_1X8, }; +static const struct v4l2_mbus_framefmt ov6650_def_fmt = { + .width = W_CIF, + .height = H_CIF, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .field = V4L2_FIELD_NONE, + .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, + .quantization = V4L2_QUANTIZATION_DEFAULT, + .xfer_func = V4L2_XFER_FUNC_DEFAULT, +}; + /* read a register */ static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) { @@ -517,12 +527,20 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd, if (format->pad) return -EINVAL; - mf->width = priv->rect.width >> priv->half_scale; - mf->height = priv->rect.height >> priv->half_scale; - mf->code = priv->code; - mf->colorspace = priv->colorspace; - mf->field = V4L2_FIELD_NONE; + /* initialize response with default media bus frame format */ + *mf = ov6650_def_fmt; + /* update media bus format code and frame size */ + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + mf->width = cfg->try_fmt.width; + mf->height = cfg->try_fmt.height; + mf->code = cfg->try_fmt.code; + + } else { + mf->width = priv->rect.width >> priv->half_scale; + mf->height = priv->rect.height >> priv->half_scale; + mf->code = priv->code; + } return 0; } @@ -627,11 +645,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) priv->pclk_max = 8000000; } - if (code == MEDIA_BUS_FMT_SBGGR8_1X8) - priv->colorspace = V4L2_COLORSPACE_SRGB; - else if (code != 0) - priv->colorspace = V4L2_COLORSPACE_JPEG; - if (half_scale) { dev_dbg(&client->dev, "max resolution: QCIF\n"); coma_set |= COMA_QCIF; @@ -665,11 +678,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) if (!ret) priv->code = code; - if (!ret) { - mf->colorspace = priv->colorspace; - mf->width = priv->rect.width >> half_scale; - mf->height = priv->rect.height >> half_scale; - } return ret; } @@ -688,8 +696,6 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, v4l_bound_align_image(&mf->width, 2, W_CIF, 1, &mf->height, 2, H_CIF, 1, 0); - mf->field = V4L2_FIELD_NONE; - switch (mf->code) { case MEDIA_BUS_FMT_Y10_1X10: mf->code = MEDIA_BUS_FMT_Y8_1X8; @@ -699,20 +705,39 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; break; default: mf->code = MEDIA_BUS_FMT_SBGGR8_1X8; /* fall through */ case MEDIA_BUS_FMT_SBGGR8_1X8: - mf->colorspace = V4L2_COLORSPACE_SRGB; break; } - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return ov6650_s_fmt(sd, mf); - cfg->try_fmt = *mf; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + /* store media bus format code and frame size in pad config */ + cfg->try_fmt.width = mf->width; + cfg->try_fmt.height = mf->height; + cfg->try_fmt.code = mf->code; + /* return default mbus frame format updated with pad config */ + *mf = ov6650_def_fmt; + mf->width = cfg->try_fmt.width; + mf->height = cfg->try_fmt.height; + mf->code = cfg->try_fmt.code; + + } else { + /* apply new media bus format code and frame size */ + int ret = ov6650_s_fmt(sd, mf); + + if (ret) + return ret; + + /* return default format updated with active size and code */ + *mf = ov6650_def_fmt; + mf->width = priv->rect.width >> priv->half_scale; + mf->height = priv->rect.height >> priv->half_scale; + mf->code = priv->code; + } return 0; } @@ -1020,7 +1045,6 @@ static int ov6650_probe(struct i2c_client *client, priv->rect.height = H_CIF; priv->half_scale = false; priv->code = MEDIA_BUS_FMT_YUYV8_2X8; - priv->colorspace = V4L2_COLORSPACE_JPEG; ret = ov6650_video_probe(client); if (ret) diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index 98467b2089fa8e837134d8e73fd0ccc584de4a4e..099d59b992c1b22568bf3647bd67afdcab6f3d46 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -484,7 +484,7 @@ static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) - pos += rc; + *pos += rc; return rc; } diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index e795ddeb7fe28a016a05ff876e987cf01f0634af..60f122edaefb30cc688b48ec90df94184408428a 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1460,8 +1460,9 @@ static int dvb_register(struct cx23885_tsport *port) if (fe0->dvb.frontend != NULL) { struct i2c_adapter *tun_i2c; - fe0->dvb.frontend->sec_priv = kmalloc(sizeof(dib7000p_ops), GFP_KERNEL); - memcpy(fe0->dvb.frontend->sec_priv, &dib7000p_ops, sizeof(dib7000p_ops)); + fe0->dvb.frontend->sec_priv = kmemdup(&dib7000p_ops, sizeof(dib7000p_ops), GFP_KERNEL); + if (!fe0->dvb.frontend->sec_priv) + return -ENOMEM; tun_i2c = dib7000p_ops.get_i2c_master(fe0->dvb.frontend, DIBX000_I2C_INTERFACE_TUNER, 1); if (!dvb_attach(dib0070_attach, fe0->dvb.frontend, tun_i2c, &dib7070p_dib0070_config)) return -ENODEV; diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index c9bd018e53de607f63cfe1367404be228ec90806..e2b19c3eaa87633e8109d2da8c9571e7d95ab4a8 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -420,7 +420,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) - pos += rc; + *pos += rc; return rc; } diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c index e7bd2b8484e3dea151da347a9c369eedbabacfe5..ee1230440b397e3b2e55f1f59e04e461dd6f0efc 100644 --- a/drivers/media/pci/tw5864/tw5864-video.c +++ b/drivers/media/pci/tw5864/tw5864-video.c @@ -1395,13 +1395,13 @@ static void tw5864_handle_frame(struct tw5864_h264_frame *frame) input->vb = NULL; spin_unlock_irqrestore(&input->slock, flags); - v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf); - if (!vb) { /* Gone because of disabling */ dev_dbg(&dev->pci->dev, "vb is empty, dropping frame\n"); return; } + v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf); + /* * Check for space. * Mind the overhead of startcode emulation prevention. diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 891fa2505efa0a67d64330f979ad184b8c59c855..2f962a3418f630c06e230f01c51fe7be418c74bb 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -496,7 +496,7 @@ static void stop_streaming(struct vb2_queue *vq) spin_unlock_irq(&isi->irqlock); if (!isi->enable_preview_path) { - timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; + timeout = jiffies + (FRAME_INTERVAL_MILLI_SEC * HZ) / 1000; /* Wait until the end of the current frame. */ while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && time_before(jiffies, timeout)) diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index 90d0f13283ae932f1cd969f2df2f20ce261f4c85..12065ad1ac4579b7c35513696d6116f79db02e36 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -886,9 +886,7 @@ static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) static int isif_config_ycbcr(void) { struct isif_ycbcr_config *params = &isif_cfg.ycbcr; - struct vpss_pg_frame_size frame_size; u32 modeset = 0, ccdcfg = 0; - struct vpss_sync_pol sync; dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); @@ -976,13 +974,6 @@ static int isif_config_ycbcr(void) /* two fields are interleaved in memory */ regw(0x00000249, SDOFST); - /* Setup test pattern if enabled */ - if (isif_cfg.bayer.config_params.test_pat_gen) { - sync.ccdpg_hdpol = params->hd_pol; - sync.ccdpg_vdpol = params->vd_pol; - dm365_vpss_set_sync_pol(sync); - dm365_vpss_set_pg_frame_size(frame_size); - } return 0; } diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 1d3c13e369044bbcdeb42823628fd0ee7005056f..915af9ca471113239fa5b931c2eccd9baafcab3a 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -126,7 +126,7 @@ static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, struct v4l2_output *output) { struct vpbe_config *cfg = vpbe_dev->cfg; - int temp_index = output->index; + unsigned int temp_index = output->index; if (temp_index >= cfg->num_outputs) return -EINVAL; diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index a920164f53f1f0ab9de8a9947af72ac6cf653c95..39340abefd14de6540bff7013135809ee03731bf 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -316,7 +316,7 @@ static int isp_video_release(struct file *file) ivc->streaming = 0; } - vb2_fop_release(file); + _vb2_fop_release(file, NULL); if (v4l2_fh_is_singular_file(file)) { fimc_pipeline_call(&ivc->ve, close); diff --git a/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c b/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c index dcdf3671faf43919806a02673074c0f0b034b70a..eaf983776cb010edb94a385843aa328c80eb3b4f 100644 --- a/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c +++ b/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c @@ -570,6 +570,7 @@ static int ais_ife_csid_config_rdi_path( path_cfg->end_line = res->in_cfg.crop_bottom; path_cfg->decode_fmt = res->in_cfg.decode_format; path_cfg->plain_fmt = res->in_cfg.pack_type; + path_cfg->init_frame_drop = res->in_cfg.init_frame_drop; if (path_cfg->decode_fmt == 0xF) path_cfg->pix_enable = false; @@ -677,10 +678,17 @@ static int ais_ife_csid_config_rdi_path( struct ais_ife_csid_path_cfg *tmp = &csid_hw->rdi_cfg[i]; + /* + * doesn't compare with itself and + * not INIT/STREAMING rdi + */ + if (id == i || + tmp->state < AIS_ISP_RESOURCE_STATE_INIT_HW) + continue; + /*checking for multiple streams of same VC*/ - if (i != id && - tmp->vc == path_cfg->vc && - tmp->decode_fmt == path_cfg->decode_fmt) { + if (tmp->vc == path_cfg->vc && + tmp->decode_fmt == path_cfg->decode_fmt) { val = path_cfg->decode_fmt << csid_reg->cmn_reg->fmt_shift_val; @@ -784,9 +792,12 @@ static int ais_ife_csid_deinit_rdi_path( struct ais_ife_csid_path_cfg *tmp = &csid_hw->rdi_cfg[i]; - if (i != id && - tmp->vc == path_cfg->vc && - tmp->decode_fmt == path_cfg->decode_fmt) + if (i == id || + tmp->state == AIS_ISP_RESOURCE_STATE_AVAILABLE) + continue; + + if (tmp->vc == path_cfg->vc && + tmp->decode_fmt == path_cfg->decode_fmt) check_cnt++; } @@ -812,8 +823,6 @@ static int ais_ife_csid_enable_rdi_path( csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; path_data = &csid_hw->rdi_cfg[id]; - - path_data->init_frame_drop = 1; path_data->sof_cnt = 0; /* Enable the required RDI interrupts */ diff --git a/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h b/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h index c75e0b5685c2d9222e5e4641a2c8daee00143465..e09030b2196f4f55a50a7b289654051be9df19a5 100644 --- a/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h +++ b/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h @@ -270,6 +270,7 @@ struct ais_ife_rdi_in_cfg { uint32_t crop_bottom; uint32_t crop_left; uint32_t crop_right; + uint32_t init_frame_drop; uint32_t reserved; }; diff --git a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c index 2cee173d29028584d55e8328525a62c946b5b51d..73a57ca7ae650687e3a95f841879dde0ccf81fd3 100644 --- a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c +++ b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c @@ -1137,7 +1137,7 @@ static int ais_vfe_dispatch_irq(struct cam_hw_info *vfe_hw, core_info = (struct ais_vfe_hw_core_info *)vfe_hw->core_info; CAM_DBG(CAM_ISP, "VFE[%d] event %d", - core_info->vfe_idx, work_data->evt_type); + core_info->vfe_idx, p_work->evt_type); task = cam_req_mgr_workq_get_task(core_info->workq); if (!task) { diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c index f30c9e49b0ab306d72dfab8887f0a5d80fda016f..45eb1f449d35412a362708dc6d0dfe1d9a9551b7 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1513,14 +1513,16 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, } else { //If rd_done is complete with NACK wait until RESET_ACK //is received. + rc = 0; if (cci_dev->cci_master_info[master].status == -EINVAL) { rc = wait_for_completion_timeout( &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); - } - if (rc <= 0) { - CAM_ERR(CAM_CCI, - "wait_for_completion_timeout rc = %d, rc"); + if (rc <= 0) { + CAM_ERR(CAM_CCI, + "wait_for_completion_timeout rc = %d, rc"); + } else + rc = 0; } } diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_soc.c index f3aec629159502a036d2342cb75442b58e1974e1..3a81905a234f455647f4a9cb11d5cd5e59e096c5 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -27,8 +27,7 @@ int cam_cci_init(struct v4l2_subdev *sd, cci_dev = v4l2_get_subdevdata(sd); if (!cci_dev || !c_ctrl) { - CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", - cci_dev, c_ctrl); + CAM_ERR(CAM_CCI, "failed: invalid params"); rc = -EINVAL; return rc; } @@ -37,47 +36,15 @@ int cam_cci_init(struct v4l2_subdev *sd, base = soc_info->reg_map[0].mem_base; if (!soc_info || !base) { - CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", - soc_info, base); + CAM_ERR(CAM_CCI, "failed: invalid params"); rc = -EINVAL; return rc; } - CAM_DBG(CAM_CCI, "Base address %pK", base); - - if (cci_dev->ref_count++) { - CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); - CAM_DBG(CAM_CCI, "master %d", master); - if (master < MASTER_MAX && master >= 0) { - mutex_lock(&cci_dev->cci_master_info[master].mutex); - flush_workqueue(cci_dev->write_wq[master]); - /* Re-initialize the completion */ - reinit_completion( - &cci_dev->cci_master_info[master].reset_complete); - reinit_completion( - &cci_dev->cci_master_info[master].rd_done); - for (i = 0; i < NUM_QUEUES; i++) - reinit_completion( - &cci_dev->cci_master_info[master].report_q[i]); - /* Set reset pending flag to TRUE */ - cci_dev->cci_master_info[master].reset_pending = TRUE; - /* Set proper mask to RESET CMD address */ - if (master == MASTER_0) - cam_io_w_mb(CCI_M0_RESET_RMSK, - base + CCI_RESET_CMD_ADDR); - else - cam_io_w_mb(CCI_M1_RESET_RMSK, - base + CCI_RESET_CMD_ADDR); - /* wait for reset done irq */ - rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, - CCI_TIMEOUT); - if (rc <= 0) - CAM_ERR(CAM_CCI, "wait failed %d", rc); - mutex_unlock(&cci_dev->cci_master_info[master].mutex); - } + CAM_DBG(CAM_CCI, "ref_count %d master %d", cci_dev->ref_count, master); + + if (cci_dev->ref_count++) return 0; - } /* Enable Regulators and IRQ*/ rc = cam_soc_util_enable_platform_resource(soc_info, true, diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index f855ad1b498e404710c887ebf354a27f8ad5a295..2ac164251e0127ac3245601050aa3b84a8ddb745 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -340,6 +340,23 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp, } } +static void __cam_isp_ctx_dequeue_request(struct cam_context *ctx, + struct cam_ctx_request *req) +{ + struct cam_ctx_request *req_current; + struct cam_ctx_request *req_prev; + + spin_lock_bh(&ctx->lock); + list_for_each_entry_safe_reverse(req_current, req_prev, + &ctx->pending_req_list, list) { + if (req->request_id == req_current->request_id) { + list_del_init(&req_current->list); + break; + } + } + spin_unlock_bh(&ctx->lock); +} + static int __cam_isp_ctx_enqueue_request_in_order( struct cam_context *ctx, struct cam_ctx_request *req) { @@ -2527,13 +2544,20 @@ static int __cam_isp_ctx_flush_req_in_top_state( if (rc) goto end; + /* + * As HW is stopped already No request will move from + * one list to other good time to flush reqs. + */ spin_lock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "try to flush pending list"); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, + flush_req); CAM_DBG(CAM_ISP, "try to flush wait list"); rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list, - flush_req); + flush_req); CAM_DBG(CAM_ISP, "try to flush active list"); rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list, - flush_req); + flush_req); ctx_isp->active_req_cnt = 0; spin_unlock_bh(&ctx->lock); @@ -3409,13 +3433,12 @@ static int __cam_isp_ctx_config_dev_in_top_state( add_req.dev_hdl = ctx->dev_hdl; add_req.req_id = req->request_id; add_req.skip_before_applying = 0; + __cam_isp_ctx_enqueue_request_in_order(ctx, req); rc = ctx->ctx_crm_intf->add_req(&add_req); if (rc) { CAM_ERR(CAM_ISP, "Add req failed: req id=%llu", req->request_id); - } else { - __cam_isp_ctx_enqueue_request_in_order( - ctx, req); + __cam_isp_ctx_dequeue_request(ctx, req); } } else { rc = -EINVAL; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index 35790fd06405f0884f79d568234dada17b68f290..dfbc9b07e4a483ede4f1ec3205874d0ef278391a 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -2494,7 +2494,6 @@ static int cam_req_mgr_cb_notify_trigger( struct crm_task_payload *task_data; bool send_sof = true; int i = 0; - int64_t sof_time_diff = 0; if (!trigger_data) { CAM_ERR(CAM_CRM, "sof_data is NULL"); @@ -2514,10 +2513,6 @@ static int cam_req_mgr_cb_notify_trigger( if (link->dev_sof_evt[i].dev_hdl == trigger_data->dev_hdl) { if (link->dev_sof_evt[i].sof_done == false) { link->dev_sof_evt[i].sof_done = true; - link->dev_sof_evt[i].frame_id = - trigger_data->frame_id; - link->dev_sof_evt[i].timestamp = - trigger_data->sof_timestamp_val; } else CAM_INFO(CAM_CRM, "Received Spurious SOF"); } else if (link->dev_sof_evt[i].sof_done == false) { @@ -2527,23 +2522,6 @@ static int cam_req_mgr_cb_notify_trigger( if (!send_sof) return 0; - if (link->num_sof_src > 1) { - for (i = 0; i < (link->num_sof_src - 1); i++) { - if (link->dev_sof_evt[i].timestamp >= - link->dev_sof_evt[i+1].timestamp) { - sof_time_diff = link->dev_sof_evt[i].timestamp - - link->dev_sof_evt[i+1].timestamp; - } else { - sof_time_diff = - link->dev_sof_evt[i+1].timestamp - - link->dev_sof_evt[i].timestamp; - } - if ((link->dev_sof_evt[i].frame_id != - link->dev_sof_evt[i+1].frame_id) || - sof_time_diff > TIMESTAMP_DIFF_THRESHOLD) - return 0; - } - } for (i = 0; i < link->num_sof_src; i++) link->dev_sof_evt[i].sof_done = false; diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h index d5463443068e69070d39145ad40e00bfec88aa7a..d145c0945eaa63d1bf5c11621d3f8507a97a6b2c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 2018, 2020, 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 @@ -49,7 +49,7 @@ static struct csid_reg_parms_t csid_v3_5 = { 0xB8, 0xBC, 11, - 0x7FFF, + 0x7FFFF, 0x4, 17, 0x30050000, diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c index 851bb261ca1ba3e4c7decca107100eeb2cab486f..9f0bd6f9e4f0c074b17a4fc109b4d637dd061b17 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2020, 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 @@ -854,6 +854,14 @@ static int msm_csid_release(struct csid_device *csid_dev) msm_camera_enable_irq(csid_dev->irq, false); + if (msm_camera_tz_is_secured( + MSM_CAMERA_TZ_IO_REGION_CSIDCORE0 + csid_dev->pdev->id) == 0) { + msm_camera_vio_w(csid_dev->ctrl_reg->csid_reg.csid_rst_stb_all, + csid_dev->base, + csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr, + csid_dev->pdev->id); + } + msm_camera_clk_enable(&csid_dev->pdev->dev, csid_dev->csid_clk_info, csid_dev->csid_clk, diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h index 68f8ea37b080b8fe7784e98488bd201138d8da12..216bfccd87d0edfa3a94e4e7d6499a70070df80e 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 2018-2020, 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 @@ -26,7 +26,7 @@ static struct csiphy_reg_parms_t csiphy_v3_5 = { static struct csiphy_reg_3ph_parms_t csiphy_v3_5_3ph = { /*MIPI CSI PHY registers*/ - {0x814, 0x0}, + {0x814, 0xD5}, {0x818, 0x1}, {0x188, 0x7F}, {0x18C, 0x7F}, @@ -80,15 +80,15 @@ static struct csiphy_reg_3ph_parms_t csiphy_v3_5_3ph = { {0x4, 0x8}, {0x8, 0x0}, {0xC, 0xA5}, - {0x10, 0x52}, + {0x10, 0x50}, {0x2C, 0x1}, {0x30, 0x2}, - {0x34, 0x3}, + {0x34, 0x1}, {0x38, 0x1}, {0x3C, 0xB8}, {0x1C, 0xA}, {0x14, 0x0}, - {0x0, 0x0}, + {0x0, 0xD7}, {0x700, 0xC0}, }; #endif diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c index 539cf843872f4aee4e6eab2a2c260e99e6f9f613..d29212635d1c6d74632b1554dd90be40c9f154ca 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.c +++ b/drivers/media/platform/msm/npu/npu_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, 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 @@ -32,7 +32,7 @@ #define LOG_MSG_TOTAL_SIZE_INDEX 0 #define LOG_MSG_MSG_ID_INDEX 1 -#define NPU_FW_TIMEOUT_POLL_INTERVAL_MS 20 +#define NPU_FW_TIMEOUT_POLL_INTERVAL_MS 10 #define NPU_FW_TIMEOUT_MS 1000 /* ------------------------------------------------------------------------- @@ -43,7 +43,7 @@ static void host_irq_wq(struct work_struct *work); static void fw_deinit_wq(struct work_struct *work); static void turn_off_fw_logging(struct npu_device *npu_dev); static int wait_for_status_ready(struct npu_device *npu_dev, - uint32_t status_reg, uint32_t status_bits); + uint32_t status_reg, uint32_t status_bits, bool poll); static struct npu_network *alloc_network(struct npu_host_ctx *ctx, struct npu_client *client); static struct npu_network *get_network_by_hdl(struct npu_host_ctx *ctx, @@ -158,7 +158,7 @@ int fw_init(struct npu_device *npu_dev) pr_debug("waiting for status ready from fw\n"); if (wait_for_status_ready(npu_dev, REG_NPU_FW_CTRL_STATUS, - FW_CTRL_STATUS_MAIN_THREAD_READY_VAL)) { + FW_CTRL_STATUS_MAIN_THREAD_READY_VAL, true)) { ret = -EPERM; need_retry = true; goto wait_fw_ready_fail; @@ -255,7 +255,7 @@ void fw_deinit(struct npu_device *npu_dev, bool ssr, bool fw_alive) pr_debug("waiting for shutdown status from fw\n"); if (wait_for_status_ready(npu_dev, REG_NPU_FW_CTRL_STATUS, - FW_CTRL_STATUS_SHUTDOWN_DONE_VAL)) { + FW_CTRL_STATUS_SHUTDOWN_DONE_VAL, true)) { pr_err("wait for fw shutdown timedout\n"); ret = -ETIMEDOUT; } @@ -468,7 +468,7 @@ static void turn_off_fw_logging(struct npu_device *npu_dev) } static int wait_for_status_ready(struct npu_device *npu_dev, - uint32_t status_reg, uint32_t status_bits) + uint32_t status_reg, uint32_t status_bits, bool poll) { uint32_t ctrl_sts = 0; uint32_t wait_cnt = 0, max_wait_ms; @@ -476,20 +476,36 @@ static int wait_for_status_ready(struct npu_device *npu_dev, max_wait_ms = (host_ctx->fw_dbg_mode & FW_DBG_MODE_INC_TIMEOUT) ? NW_DEBUG_TIMEOUT_MS : NPU_FW_TIMEOUT_MS; + if (poll) + wait_cnt = max_wait_ms * 10; + else + wait_cnt = max_wait_ms / NPU_FW_TIMEOUT_POLL_INTERVAL_MS; /* keep reading status register until bits are set */ - while ((ctrl_sts & status_bits) != status_bits) { + do { ctrl_sts = REGR(npu_dev, status_reg); - msleep(NPU_FW_TIMEOUT_POLL_INTERVAL_MS); - wait_cnt += NPU_FW_TIMEOUT_POLL_INTERVAL_MS; - if (wait_cnt >= max_wait_ms) { + if ((ctrl_sts & status_bits) == status_bits) { + pr_debug("status %x[reg %x] ready received\n", + status_bits, status_reg); + break; + } + + if (!wait_cnt) { pr_err("timeout wait for status %x[%x] in reg %x\n", status_bits, ctrl_sts, status_reg); - return -EPERM; + return -ETIMEDOUT; } - } - pr_debug("status %x[reg %x] ready received\n", status_bits, status_reg); + + if (poll) + udelay(100); + else + msleep(NPU_FW_TIMEOUT_POLL_INTERVAL_MS); + + wait_cnt--; + } while (1); + return 0; + } static int npu_notify_dsp(struct npu_device *npu_dev, bool pwr_up) @@ -513,7 +529,7 @@ static int npu_notify_dsp(struct npu_device *npu_dev, bool pwr_up) INTERRUPT_RAISE_DSP(npu_dev); ret = wait_for_status_ready(npu_dev, REG_HOST_DSP_CTRL_STATUS, - ack_val); + ack_val, true); if (ret) pr_warn("No response from dsp\n"); diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 8ba90efd6811220369f19666b68362a26a219e93..bb97ecb25431da64375dc2436f78268aef660eba 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, 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 @@ -542,7 +542,7 @@ struct msm_vidc_format vdec_formats[] = { .type = OUTPUT_PORT, .defer_outputs = true, .input_min_count = 4, - .output_min_count = 11, + .output_min_count = 9, }, }; diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 4d29860d27b42006c1c664d0330ecb7ea77bb421..18604b608ab2ec8f11afd4bd03e9543b61510ae7 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -1527,23 +1527,20 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) unsigned long size; struct videobuf_buffer *vb; - vb = q->bufs[b->index]; - if (!vout->streaming) return -EINVAL; - if (file->f_flags & O_NONBLOCK) - /* Call videobuf_dqbuf for non blocking mode */ - ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1); - else - /* Call videobuf_dqbuf for blocking mode */ - ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0); + ret = videobuf_dqbuf(q, b, !!(file->f_flags & O_NONBLOCK)); + if (ret) + return ret; + + vb = q->bufs[b->index]; addr = (unsigned long) vout->buf_phy_addr[vb->i]; size = (unsigned long) vb->size; dma_unmap_single(vout->vid_dev->v4l2_dev.dev, addr, size, DMA_TO_DEVICE); - return ret; + return 0; } static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 4568e68e15fa65f2f6074367f806e06374dcccfa..85a5e33600c03851f281071c30b79cd01755366e 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2005,7 +2005,7 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, V4L2_CID_JPEG_RESTART_INTERVAL, - 0, 3, 0xffff, 0); + 0, 0xffff, 1, 0); if (ctx->jpeg->variant->version == SJPEG_S5P) mask = ~0x06; /* 422, 420 */ } diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c index bdc380b14e0c47e73461ded4b16d01cbf484ed2d..a95b7c56569e38c65308498093101e5585295d36 100644 --- a/drivers/media/platform/vivid/vivid-osd.c +++ b/drivers/media/platform/vivid/vivid-osd.c @@ -167,7 +167,7 @@ static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev * var->nonstd = 0; var->vmode &= ~FB_VMODE_MASK; - var->vmode = FB_VMODE_NONINTERLACED; + var->vmode |= FB_VMODE_NONINTERLACED; /* Dummy values */ var->hsync_len = 24; diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index b60fb6ed5aeb548c18a1ae618024ee21904977ba..5275356143429c289a045feb041e39677ee59123 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -453,10 +453,10 @@ static int si470x_i2c_remove(struct i2c_client *client) free_irq(client->irq, radio); video_unregister_device(&radio->videodev); - kfree(radio); v4l2_ctrl_handler_free(&radio->hdl); v4l2_device_unregister(&radio->v4l2_dev); + kfree(radio); return 0; } diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 26895ae42fcf41ecb73e731389c445ff64b20ea2..2d20d908e2803c4bf0dc2603e8ba63dc9c8a81de 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -1271,8 +1271,9 @@ static int fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) switch (action->type) { case ACTION_SEND_COMMAND: /* Send */ - if (fmc_send_cmd(fmdev, 0, 0, action->data, - action->size, NULL, NULL)) + ret = fmc_send_cmd(fmdev, 0, 0, action->data, + action->size, NULL, NULL); + if (ret) goto rel_fw; cmd_cnt++; diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c index c047a0bdf91f926af4656fb8a710e1209ee32127..66990a193bc50d3c605df457c948819f09b0a26e 100644 --- a/drivers/media/usb/dvb-usb/af9005.c +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -563,7 +563,7 @@ static int af9005_boot_packet(struct usb_device *udev, int type, u8 *reply, u8 *buf, int size) { u16 checksum; - int act_len, i, ret; + int act_len = 0, i, ret; memset(buf, 0, size); buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c index 475a3c0cdee7f88a9630f337cd9d0aaf59f2e177..20d33f0544ed209020f23dcbacc9abd7c50cfbee 100644 --- a/drivers/media/usb/dvb-usb/digitv.c +++ b/drivers/media/usb/dvb-usb/digitv.c @@ -233,18 +233,22 @@ static struct rc_map_table rc_map_digitv_table[] = { static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { - int i; + int ret, i; u8 key[5]; u8 b[4] = { 0 }; *event = 0; *state = REMOTE_NO_KEY_PRESSED; - digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4); + ret = digitv_ctrl_msg(d, USB_READ_REMOTE, 0, NULL, 0, &key[1], 4); + if (ret) + return ret; /* Tell the device we've read the remote. Not sure how necessary this is, but the Nebula SDK does it. */ - digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); + ret = digitv_ctrl_msg(d, USB_WRITE_REMOTE, 0, b, 4, NULL, 0); + if (ret) + return ret; /* if something is inside the buffer, simulate key press */ if (key[1] != 0) diff --git a/drivers/media/usb/dvb-usb/dvb-usb-urb.c b/drivers/media/usb/dvb-usb/dvb-usb-urb.c index c1b4e94a37f8d774291c546d62073f91cd21b2e8..2aabf90d869769144184465414d9da1cb3925352 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-urb.c @@ -12,7 +12,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen, int delay_ms) { - int actlen,ret = -ENOMEM; + int actlen = 0, ret = -ENOMEM; if (!d || wbuf == NULL || wlen == 0) return -EINVAL; diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 0f141762abf17c6d2c8c703863bb82dbee757094..87582be4a39d2627d6f146729a2e802dcfdc7a6d 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -2038,7 +2038,7 @@ int gspca_dev_probe2(struct usb_interface *intf, pr_err("couldn't kzalloc gspca struct\n"); return -ENOMEM; } - gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); + gspca_dev->usb_buf = kzalloc(USB_BUF_SZ, GFP_KERNEL); if (!gspca_dev->usb_buf) { pr_err("out of memory\n"); ret = -ENOMEM; diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 4ff8d0aed015ce992e1b1f25dcac605153fafb6f..d30f129a9db75daf8807634a550771d3b26da870 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -706,7 +706,8 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv, struct zr364xx_camera *cam = video_drvdata(file); strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver)); - strlcpy(cap->card, cam->udev->product, sizeof(cap->card)); + if (cam->udev->product) + strlcpy(cap->card, cam->udev->product, sizeof(cap->card)); strlcpy(cap->bus_info, dev_name(&cam->udev->dev), sizeof(cap->bus_info)); cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 4b478e8c7dfb249b35f68ed1045799e18c8c501b..30d8f6a60557b7da59615645657dbd5508a2fda3 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1589,12 +1589,12 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_s_fmt_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_vid_out)) @@ -1617,22 +1617,22 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_s_fmt_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_sdr_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_s_fmt_sdr_cap(file, fh, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_sdr_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_s_fmt_sdr_out(file, fh, arg); case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_meta_cap)) @@ -1676,12 +1676,12 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_try_fmt_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_vid_out)) @@ -1704,22 +1704,22 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_try_fmt_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_sdr_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_try_fmt_sdr_cap(file, fh, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_sdr_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_try_fmt_sdr_out(file, fh, arg); case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_meta_cap)) diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index cf6ce9f600ca84a099aa9f698aa86109d8bfe91a..f9b2e652c399c54f2ec2f422f988491bd7628bc6 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -100,19 +100,19 @@ struct buflist { * Function prototypes. Called from OS entry point mptctl_ioctl. * arg contents specific to function. */ -static int mptctl_fw_download(unsigned long arg); -static int mptctl_getiocinfo(unsigned long arg, unsigned int cmd); -static int mptctl_gettargetinfo(unsigned long arg); -static int mptctl_readtest(unsigned long arg); -static int mptctl_mpt_command(unsigned long arg); -static int mptctl_eventquery(unsigned long arg); -static int mptctl_eventenable(unsigned long arg); -static int mptctl_eventreport(unsigned long arg); -static int mptctl_replace_fw(unsigned long arg); - -static int mptctl_do_reset(unsigned long arg); -static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd); -static int mptctl_hp_targetinfo(unsigned long arg); +static int mptctl_fw_download(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_getiocinfo(MPT_ADAPTER *iocp, unsigned long arg, unsigned int cmd); +static int mptctl_gettargetinfo(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_readtest(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_mpt_command(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_eventquery(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_eventenable(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_eventreport(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_replace_fw(MPT_ADAPTER *iocp, unsigned long arg); + +static int mptctl_do_reset(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_hp_hostinfo(MPT_ADAPTER *iocp, unsigned long arg, unsigned int cmd); +static int mptctl_hp_targetinfo(MPT_ADAPTER *iocp, unsigned long arg); static int mptctl_probe(struct pci_dev *, const struct pci_device_id *); static void mptctl_remove(struct pci_dev *); @@ -123,8 +123,8 @@ static long compat_mpctl_ioctl(struct file *f, unsigned cmd, unsigned long arg); /* * Private function calls. */ -static int mptctl_do_mpt_command(struct mpt_ioctl_command karg, void __user *mfPtr); -static int mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen); +static int mptctl_do_mpt_command(MPT_ADAPTER *iocp, struct mpt_ioctl_command karg, void __user *mfPtr); +static int mptctl_do_fw_download(MPT_ADAPTER *iocp, char __user *ufwbuf, size_t fwlen); static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags, struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, @@ -656,19 +656,19 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) * by TM and FW reloads. */ if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) { - return mptctl_getiocinfo(arg, _IOC_SIZE(cmd)); + return mptctl_getiocinfo(iocp, arg, _IOC_SIZE(cmd)); } else if (cmd == MPTTARGETINFO) { - return mptctl_gettargetinfo(arg); + return mptctl_gettargetinfo(iocp, arg); } else if (cmd == MPTTEST) { - return mptctl_readtest(arg); + return mptctl_readtest(iocp, arg); } else if (cmd == MPTEVENTQUERY) { - return mptctl_eventquery(arg); + return mptctl_eventquery(iocp, arg); } else if (cmd == MPTEVENTENABLE) { - return mptctl_eventenable(arg); + return mptctl_eventenable(iocp, arg); } else if (cmd == MPTEVENTREPORT) { - return mptctl_eventreport(arg); + return mptctl_eventreport(iocp, arg); } else if (cmd == MPTFWREPLACE) { - return mptctl_replace_fw(arg); + return mptctl_replace_fw(iocp, arg); } /* All of these commands require an interrupt or @@ -678,15 +678,15 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return ret; if (cmd == MPTFWDOWNLOAD) - ret = mptctl_fw_download(arg); + ret = mptctl_fw_download(iocp, arg); else if (cmd == MPTCOMMAND) - ret = mptctl_mpt_command(arg); + ret = mptctl_mpt_command(iocp, arg); else if (cmd == MPTHARDRESET) - ret = mptctl_do_reset(arg); + ret = mptctl_do_reset(iocp, arg); else if ((cmd & ~IOCSIZE_MASK) == (HP_GETHOSTINFO & ~IOCSIZE_MASK)) - ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd)); + ret = mptctl_hp_hostinfo(iocp, arg, _IOC_SIZE(cmd)); else if (cmd == HP_GETTARGETINFO) - ret = mptctl_hp_targetinfo(arg); + ret = mptctl_hp_targetinfo(iocp, arg); else ret = -EINVAL; @@ -705,11 +705,10 @@ mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return ret; } -static int mptctl_do_reset(unsigned long arg) +static int mptctl_do_reset(MPT_ADAPTER *iocp, unsigned long arg) { struct mpt_ioctl_diag_reset __user *urinfo = (void __user *) arg; struct mpt_ioctl_diag_reset krinfo; - MPT_ADAPTER *iocp; if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) { printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - " @@ -718,12 +717,6 @@ static int mptctl_do_reset(unsigned long arg) return -EFAULT; } - if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) { - printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n", - __FILE__, __LINE__, krinfo.hdr.iocnum); - return -ENODEV; /* (-6) No such device or address */ - } - dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_reset called.\n", iocp->name)); @@ -754,7 +747,7 @@ static int mptctl_do_reset(unsigned long arg) * -ENOMSG if FW upload returned bad status */ static int -mptctl_fw_download(unsigned long arg) +mptctl_fw_download(MPT_ADAPTER *iocp, unsigned long arg) { struct mpt_fw_xfer __user *ufwdl = (void __user *) arg; struct mpt_fw_xfer kfwdl; @@ -766,7 +759,7 @@ mptctl_fw_download(unsigned long arg) return -EFAULT; } - return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen); + return mptctl_do_fw_download(iocp, kfwdl.bufp, kfwdl.fwlen); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -784,11 +777,10 @@ mptctl_fw_download(unsigned long arg) * -ENOMSG if FW upload returned bad status */ static int -mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) +mptctl_do_fw_download(MPT_ADAPTER *iocp, char __user *ufwbuf, size_t fwlen) { FWDownload_t *dlmsg; MPT_FRAME_HDR *mf; - MPT_ADAPTER *iocp; FWDownloadTCSGE_t *ptsge; MptSge_t *sgl, *sgIn; char *sgOut; @@ -808,17 +800,10 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) pFWDownloadReply_t ReplyMsg = NULL; unsigned long timeleft; - if (mpt_verify_adapter(ioc, &iocp) < 0) { - printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", - ioc); - return -ENODEV; /* (-6) No such device or address */ - } else { - - /* Valid device. Get a message frame and construct the FW download message. - */ - if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL) - return -EAGAIN; - } + /* Valid device. Get a message frame and construct the FW download message. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL) + return -EAGAIN; dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_fwdl called. mptctl_id = %xh.\n", iocp->name, mptctl_id)); @@ -826,8 +811,6 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) iocp->name, ufwbuf)); dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.fwlen = %d\n", iocp->name, (int)fwlen)); - dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.ioc = %04xh\n", - iocp->name, ioc)); dlmsg = (FWDownload_t*) mf; ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL; @@ -1238,13 +1221,11 @@ kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTE * -ENODEV if no such device/adapter */ static int -mptctl_getiocinfo (unsigned long arg, unsigned int data_size) +mptctl_getiocinfo (MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size) { struct mpt_ioctl_iocinfo __user *uarg = (void __user *) arg; struct mpt_ioctl_iocinfo *karg; - MPT_ADAPTER *ioc; struct pci_dev *pdev; - int iocnum; unsigned int port; int cim_rev; struct scsi_device *sdev; @@ -1272,14 +1253,6 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) return PTR_ERR(karg); } - if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - kfree(karg); - return -ENODEV; - } - /* Verify the data transfer size is correct. */ if (karg->hdr.maxDataSize != data_size) { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - " @@ -1385,15 +1358,13 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) * -ENODEV if no such device/adapter */ static int -mptctl_gettargetinfo (unsigned long arg) +mptctl_gettargetinfo (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg; struct mpt_ioctl_targetinfo karg; - MPT_ADAPTER *ioc; VirtDevice *vdevice; char *pmem; int *pdata; - int iocnum; int numDevices = 0; int lun; int maxWordsLeft; @@ -1408,13 +1379,6 @@ mptctl_gettargetinfo (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_gettargetinfo called.\n", ioc->name)); /* Get the port number and set the maximum number of bytes @@ -1510,12 +1474,10 @@ mptctl_gettargetinfo (unsigned long arg) * -ENODEV if no such device/adapter */ static int -mptctl_readtest (unsigned long arg) +mptctl_readtest (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_test __user *uarg = (void __user *) arg; struct mpt_ioctl_test karg; - MPT_ADAPTER *ioc; - int iocnum; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) { printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - " @@ -1524,13 +1486,6 @@ mptctl_readtest (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_readtest called.\n", ioc->name)); /* Fill in the data and return the structure to the calling @@ -1571,12 +1526,10 @@ mptctl_readtest (unsigned long arg) * -ENODEV if no such device/adapter */ static int -mptctl_eventquery (unsigned long arg) +mptctl_eventquery (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_eventquery __user *uarg = (void __user *) arg; struct mpt_ioctl_eventquery karg; - MPT_ADAPTER *ioc; - int iocnum; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) { printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - " @@ -1585,13 +1538,6 @@ mptctl_eventquery (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n", ioc->name)); karg.eventEntries = MPTCTL_EVENT_LOG_SIZE; @@ -1610,12 +1556,10 @@ mptctl_eventquery (unsigned long arg) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int -mptctl_eventenable (unsigned long arg) +mptctl_eventenable (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_eventenable __user *uarg = (void __user *) arg; struct mpt_ioctl_eventenable karg; - MPT_ADAPTER *ioc; - int iocnum; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) { printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - " @@ -1624,13 +1568,6 @@ mptctl_eventenable (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n", ioc->name)); if (ioc->events == NULL) { @@ -1658,12 +1595,10 @@ mptctl_eventenable (unsigned long arg) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int -mptctl_eventreport (unsigned long arg) +mptctl_eventreport (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_eventreport __user *uarg = (void __user *) arg; struct mpt_ioctl_eventreport karg; - MPT_ADAPTER *ioc; - int iocnum; int numBytes, maxEvents, max; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) { @@ -1673,12 +1608,6 @@ mptctl_eventreport (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n", ioc->name)); @@ -1712,12 +1641,10 @@ mptctl_eventreport (unsigned long arg) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int -mptctl_replace_fw (unsigned long arg) +mptctl_replace_fw (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_replace_fw __user *uarg = (void __user *) arg; struct mpt_ioctl_replace_fw karg; - MPT_ADAPTER *ioc; - int iocnum; int newFwSize; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) { @@ -1727,13 +1654,6 @@ mptctl_replace_fw (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n", ioc->name)); /* If caching FW, Free the old FW image @@ -1780,12 +1700,10 @@ mptctl_replace_fw (unsigned long arg) * -ENOMEM if memory allocation error */ static int -mptctl_mpt_command (unsigned long arg) +mptctl_mpt_command (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_command __user *uarg = (void __user *) arg; struct mpt_ioctl_command karg; - MPT_ADAPTER *ioc; - int iocnum; int rc; @@ -1796,14 +1714,7 @@ mptctl_mpt_command (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - - rc = mptctl_do_mpt_command (karg, &uarg->MF); + rc = mptctl_do_mpt_command (ioc, karg, &uarg->MF); return rc; } @@ -1821,9 +1732,8 @@ mptctl_mpt_command (unsigned long arg) * -EPERM if SCSI I/O and target is untagged */ static int -mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) +mptctl_do_mpt_command (MPT_ADAPTER *ioc, struct mpt_ioctl_command karg, void __user *mfPtr) { - MPT_ADAPTER *ioc; MPT_FRAME_HDR *mf = NULL; MPIHeader_t *hdr; char *psge; @@ -1832,7 +1742,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) dma_addr_t dma_addr_in; dma_addr_t dma_addr_out; int sgSize = 0; /* Num SG elements */ - int iocnum, flagsLength; + int flagsLength; int sz, rc = 0; int msgContext; u16 req_idx; @@ -1847,13 +1757,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) bufIn.kptr = bufOut.kptr = NULL; bufIn.len = bufOut.len = 0; - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - spin_lock_irqsave(&ioc->taskmgmt_lock, flags); if (ioc->ioc_reset_in_progress) { spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); @@ -2418,17 +2321,15 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) * -ENOMEM if memory allocation error */ static int -mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) +mptctl_hp_hostinfo(MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size) { hp_host_info_t __user *uarg = (void __user *) arg; - MPT_ADAPTER *ioc; struct pci_dev *pdev; char *pbuf=NULL; dma_addr_t buf_dma; hp_host_info_t karg; CONFIGPARMS cfg; ConfigPageHeader_t hdr; - int iocnum; int rc, cim_rev; ToolboxIstwiReadWriteRequest_t *IstwiRWRequest; MPT_FRAME_HDR *mf = NULL; @@ -2452,12 +2353,6 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n", ioc->name)); @@ -2670,15 +2565,13 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) * -ENOMEM if memory allocation error */ static int -mptctl_hp_targetinfo(unsigned long arg) +mptctl_hp_targetinfo(MPT_ADAPTER *ioc, unsigned long arg) { hp_target_info_t __user *uarg = (void __user *) arg; SCSIDevicePage0_t *pg0_alloc; SCSIDevicePage3_t *pg3_alloc; - MPT_ADAPTER *ioc; MPT_SCSI_HOST *hd = NULL; hp_target_info_t karg; - int iocnum; int data_sz; dma_addr_t page_dma; CONFIGPARMS cfg; @@ -2692,12 +2585,6 @@ mptctl_hp_targetinfo(unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } if (karg.hdr.id >= MPT_MAX_FC_DEVICES) return -EINVAL; dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n", @@ -2865,7 +2752,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd, kfw.fwlen = kfw32.fwlen; kfw.bufp = compat_ptr(kfw32.bufp); - ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); + ret = mptctl_do_fw_download(iocp, kfw.bufp, kfw.fwlen); mutex_unlock(&iocp->ioctl_cmds.mutex); @@ -2919,7 +2806,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd, /* Pass new structure to do_mpt_command */ - ret = mptctl_do_mpt_command (karg, &uarg->MF); + ret = mptctl_do_mpt_command (iocp, karg, &uarg->MF); mutex_unlock(&iocp->ioctl_cmds.mutex); diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 2b7e8eeaa59e9f8471d4d354d1739bbe7032c8fa..0504761516f7b3c97b10d73b571813af1cee058a 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -126,6 +126,18 @@ static const struct intel_lpss_platform_info apl_i2c_info = { .properties = apl_i2c_properties, }; +static struct property_entry glk_i2c_properties[] = { + PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 313), + PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), + PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 290), + { }, +}; + +static const struct intel_lpss_platform_info glk_i2c_info = { + .clk_rate = 133000000, + .properties = glk_i2c_properties, +}; + static const struct intel_lpss_platform_info cnl_i2c_info = { .clk_rate = 216000000, .properties = spt_i2c_properties, @@ -165,14 +177,14 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info }, /* GLK */ - { PCI_VDEVICE(INTEL, 0x31ac), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31ae), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31b0), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31b2), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31b4), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31b6), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31b8), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31ba), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31ac), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31ae), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b0), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b2), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b4), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b6), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b8), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31ba), (kernel_ulong_t)&glk_i2c_info }, { PCI_VDEVICE(INTEL, 0x31bc), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x31be), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x31c0), (kernel_ulong_t)&bxt_uart_info }, diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index b5c4f8f974aa75882f6e64dc0d7a7b6ac193210c..9ed573e232c0026744412b67b6f2b025ad9e9906 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -541,6 +541,7 @@ module_init(intel_lpss_init); static void __exit intel_lpss_exit(void) { + ida_destroy(&intel_lpss_devid_ida); debugfs_remove(intel_lpss_debugfs); } module_exit(intel_lpss_exit); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 08c3204947254ba2b69037da024d8fe75d1f7b5e..2d4c9718efc87f4488a35737f2b29478537a88fb 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -490,6 +490,14 @@ config QSEECOM Manager (SCM) interface. It exposes APIs for both userspace and kernel clients. +config PROFILER + tristate "Qualcomm Technologies, Inc. trustzone Communicator driver" + help + Provides a communication interface between userspace and + trustzone using Secure Channel Manager (SCM) interface. + It exposes APIs for userspace to get system profiling + information. + config VEXPRESS_SYSCFG bool "Versatile Express System Configuration driver" depends on VEXPRESS_CONFIG diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 63dbe5f03e1e357b4a599520de0e414e5c6fe908..553ddb0d58e7dba74c36ca32e3b0191b581bba51 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_HDCP_QSEECOM) += hdcp_qseecom.o obj-$(CONFIG_HDCP_QSEECOM) += msm_hdcp.o obj-$(CONFIG_QSEECOM) += qseecom.o +obj-$(CONFIG_PROFILER) += profiler.o obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index eb29113e0bac2437f1714af1e4189b74fe992b6f..b11737f7bdca32124d75ff150d1f56cf50706486 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -419,10 +419,9 @@ int enclosure_remove_device(struct enclosure_device *edev, struct device *dev) cdev = &edev->component[i]; if (cdev->dev == dev) { enclosure_remove_links(cdev); - device_del(&cdev->cdev); put_device(dev); cdev->dev = NULL; - return device_add(&cdev->cdev); + return 0; } } return -ENODEV; diff --git a/drivers/misc/mic/card/mic_x100.c b/drivers/misc/mic/card/mic_x100.c index b9f0710ffa6b0f80f256994c968d783242723243..4007adc666f377d0ef4ddbf4f8bbdcb773abfa39 100644 --- a/drivers/misc/mic/card/mic_x100.c +++ b/drivers/misc/mic/card/mic_x100.c @@ -249,6 +249,9 @@ static int __init mic_probe(struct platform_device *pdev) mdrv->dev = &pdev->dev; snprintf(mdrv->name, sizeof(mic_driver_name), mic_driver_name); + /* FIXME: use dma_set_mask_and_coherent() and check result */ + dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + mdev->mmio.pa = MIC_X100_MMIO_BASE; mdev->mmio.len = MIC_X100_MMIO_LEN; mdev->mmio.va = devm_ioremap(&pdev->dev, MIC_X100_MMIO_BASE, @@ -294,18 +297,6 @@ static void mic_platform_shutdown(struct platform_device *pdev) mic_remove(pdev); } -static u64 mic_dma_mask = DMA_BIT_MASK(64); - -static struct platform_device mic_platform_dev = { - .name = mic_driver_name, - .id = 0, - .num_resources = 0, - .dev = { - .dma_mask = &mic_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(64), - }, -}; - static struct platform_driver __refdata mic_platform_driver = { .probe = mic_probe, .remove = mic_remove, @@ -315,6 +306,8 @@ static struct platform_driver __refdata mic_platform_driver = { }, }; +static struct platform_device *mic_platform_dev; + static int __init mic_init(void) { int ret; @@ -328,9 +321,12 @@ static int __init mic_init(void) request_module("mic_x100_dma"); mic_init_card_debugfs(); - ret = platform_device_register(&mic_platform_dev); + + mic_platform_dev = platform_device_register_simple(mic_driver_name, + 0, NULL, 0); + ret = PTR_ERR_OR_ZERO(mic_platform_dev); if (ret) { - pr_err("platform_device_register ret %d\n", ret); + pr_err("platform_device_register_full ret %d\n", ret); goto cleanup_debugfs; } ret = platform_driver_register(&mic_platform_driver); @@ -341,7 +337,7 @@ static int __init mic_init(void) return ret; device_unregister: - platform_device_unregister(&mic_platform_dev); + platform_device_unregister(mic_platform_dev); cleanup_debugfs: mic_exit_card_debugfs(); done: @@ -351,7 +347,7 @@ static int __init mic_init(void) static void __exit mic_exit(void) { platform_driver_unregister(&mic_platform_driver); - platform_device_unregister(&mic_platform_dev); + platform_device_unregister(mic_platform_dev); mic_exit_card_debugfs(); } diff --git a/drivers/misc/profiler.c b/drivers/misc/profiler.c new file mode 100644 index 0000000000000000000000000000000000000000..49ebd2516bb5f4642d7c7f5181669dce9e04a49a --- /dev/null +++ b/drivers/misc/profiler.c @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2017-2018, 2020 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) "PROFILER: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PROFILER_DEV "profiler" + +static struct class *driver_class; +static dev_t profiler_device_no; + +struct profiler_control { + struct device *pdev; + struct cdev cdev; +}; + +static struct profiler_control profiler; + +struct profiler_dev_handle { + bool released; + int abort; + atomic_t ioctl_count; +}; + + +static int profiler_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, + const void *req_buf, void *resp_buf) +{ + int ret = 0; + uint32_t qseos_cmd_id = 0; + struct scm_desc desc = {0}; + + if (!req_buf || !resp_buf) { + pr_err("Invalid buffer pointer\n"); + return -EINVAL; + } + qseos_cmd_id = *(uint32_t *)req_buf; + + switch (svc_id) { + + case SCM_SVC_BW: + switch (qseos_cmd_id) { + case TZ_BW_SVC_START_ID: + case TZ_BW_SVC_GET_ID: + case TZ_BW_SVC_STOP_ID: + /* Send the command to TZ */ + desc.arginfo = SCM_ARGS(4, SCM_RW, SCM_VAL, + SCM_RW, SCM_VAL); + desc.args[0] = virt_to_phys(& + (((struct tz_bw_svc_buf *) + req_buf)->bwreq)); + desc.args[1] = ((struct tz_bw_svc_buf *) + req_buf)->req_size; + desc.args[2] = virt_to_phys(& + ((struct tz_bw_svc_buf *) + req_buf)->bwresp); + desc.args[3] = sizeof(struct tz_bw_svc_resp); + + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, + TZ_SVC_BW_PROF_ID), &desc); + break; + default: + pr_err("cmd_id %d is not supported by scm_call2.\n", + qseos_cmd_id); + ret = -EINVAL; + } /*end of switch (qsee_cmd_id) */ + break; + default: + pr_err("svc_id 0x%x is not supported by armv8 scm_call2.\n", + svc_id); + ret = -EINVAL; + break; + } /*end of switch svc_id */ + return ret; +} + + +static int profiler_scm_call(u32 svc_id, u32 tz_cmd_id, const void *cmd_buf, + size_t cmd_len, void *resp_buf, size_t resp_len) +{ + if (!is_scm_armv8()) + return scm_call(svc_id, tz_cmd_id, cmd_buf, cmd_len, + resp_buf, resp_len); + else + return profiler_scm_call2(svc_id, tz_cmd_id, cmd_buf, resp_buf); +} + +static int bw_profiling_command(void *req) +{ + struct tz_bw_svc_resp *bw_resp = NULL; + uint32_t cmd_id = 0; + int ret; + + cmd_id = *(uint32_t *)req; + bw_resp = &((struct tz_bw_svc_buf *)req)->bwresp; + /* Flush buffers from cache to memory. */ + dmac_flush_range(req, req + + PAGE_ALIGN(sizeof(union tz_bw_svc_req))); + dmac_flush_range((void *)bw_resp, ((void *)bw_resp) + + sizeof(struct tz_bw_svc_resp)); + ret = profiler_scm_call(SCM_SVC_BW, TZ_SVC_BW_PROF_ID, req, + sizeof(struct tz_bw_svc_buf), + bw_resp, sizeof(struct tz_bw_svc_resp)); + if (ret) { + pr_err("profiler_scm_call failed with err: %d\n", ret); + return -EINVAL; + } + /* Invalidate cache. */ + dmac_inv_range((void *)bw_resp, ((void *)bw_resp) + + sizeof(struct tz_bw_svc_resp)); + /* Verify cmd id and Check that request succeeded.*/ + if ((bw_resp->status != E_BW_SUCCESS) || + (cmd_id != bw_resp->cmd_id)) { + ret = -1; + pr_err("Status: %d,Cmd: %d\n", + bw_resp->status, + bw_resp->cmd_id); + } + return ret; +} + +static int bw_profiling_start(struct tz_bw_svc_buf *bwbuf) +{ + struct tz_bw_svc_start_req *bwstartreq = NULL; + + bwstartreq = (struct tz_bw_svc_start_req *) &bwbuf->bwreq; + /* Populate request data */ + bwstartreq->cmd_id = TZ_BW_SVC_START_ID; + bwstartreq->version = TZ_BW_SVC_VERSION; + bwbuf->req_size = sizeof(struct tz_bw_svc_start_req); + return bw_profiling_command(bwbuf); +} + +static int bw_profiling_get(void __user *argp, struct tz_bw_svc_buf *bwbuf) +{ + struct tz_bw_svc_get_req *bwgetreq = NULL; + int ret; + char *buf = NULL; + const int bufsize = sizeof(struct profiler_bw_cntrs_req) + - sizeof(uint32_t); + struct profiler_bw_cntrs_req cnt_buf; + + memset(&cnt_buf, 0, sizeof(cnt_buf)); + bwgetreq = (struct tz_bw_svc_get_req *) &bwbuf->bwreq; + /* Allocate memory for get buffer */ + buf = kzalloc(PAGE_ALIGN(bufsize), GFP_KERNEL); + if (buf == NULL) { + ret = -ENOMEM; + pr_err(" Failed to allocate memory\n"); + return ret; + } + /* Populate request data */ + bwgetreq->cmd_id = TZ_BW_SVC_GET_ID; + bwgetreq->buf_ptr = (uint64_t) virt_to_phys(buf); + bwgetreq->buf_size = bufsize; + bwbuf->req_size = sizeof(struct tz_bw_svc_get_req); + dmac_flush_range(buf, ((void *)buf) + PAGE_ALIGN(bwgetreq->buf_size)); + ret = bw_profiling_command(bwbuf); + if (ret) { + pr_err("bw_profiling_command failed\n"); + return ret; + } + dmac_inv_range(buf, ((void *)buf) + PAGE_ALIGN(bwgetreq->buf_size)); + memcpy(&cnt_buf, buf, bufsize); + if (copy_to_user(argp, &cnt_buf, sizeof(struct profiler_bw_cntrs_req))) + pr_err("copy_to_user failed\n"); + /* Free memory for response */ + if (buf != NULL) { + kfree(buf); + buf = NULL; + } + return ret; +} + +static int bw_profiling_stop(struct tz_bw_svc_buf *bwbuf) +{ + struct tz_bw_svc_stop_req *bwstopreq = NULL; + + bwstopreq = (struct tz_bw_svc_stop_req *) &bwbuf->bwreq; + /* Populate request data */ + bwstopreq->cmd_id = TZ_BW_SVC_STOP_ID; + bwbuf->req_size = sizeof(struct tz_bw_svc_stop_req); + return bw_profiling_command(bwbuf); +} + + +static int profiler_get_bw_info(void __user *argp) +{ + int ret = 0; + struct tz_bw_svc_buf *bwbuf = NULL; + struct profiler_bw_cntrs_req cnt_buf; + + ret = copy_from_user(&cnt_buf, argp, + sizeof(struct profiler_bw_cntrs_req)); + if (ret) + return ret; + /* Allocate memory for request */ + bwbuf = kzalloc(PAGE_ALIGN(sizeof(struct tz_bw_svc_buf)), GFP_KERNEL); + if (bwbuf == NULL) + return -ENOMEM; + switch (cnt_buf.cmd) { + case TZ_BW_SVC_START_ID: + ret = bw_profiling_start(bwbuf); + if (ret) + pr_err("bw_profiling_start Failed with ret: %d\n", ret); + break; + case TZ_BW_SVC_GET_ID: + ret = bw_profiling_get(argp, bwbuf); + if (ret) + pr_err("bw_profiling_get Failed with ret: %d\n", ret); + break; + case TZ_BW_SVC_STOP_ID: + ret = bw_profiling_stop(bwbuf); + if (ret) + pr_err("bw_profiling_stop Failed with ret: %d\n", ret); + break; + default: + pr_err("Invalid IOCTL: 0x%x\n", cnt_buf.cmd); + ret = -EINVAL; + } + /* Free memory for command */ + if (bwbuf != NULL) { + kfree(bwbuf); + bwbuf = NULL; + } + return ret; +} + +static int profiler_open(struct inode *inode, struct file *file) +{ + int ret = 0; + struct profiler_dev_handle *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + file->private_data = data; + data->abort = 0; + data->released = false; + atomic_set(&data->ioctl_count, 0); + return ret; +} + +static int compat_get_profiler_bw_info( + struct compat_profiler_bw_cntrs_req __user *data32, + struct profiler_bw_cntrs_req __user *data) +{ + compat_uint_t val = 0; + int err = 0; + int i = 0; + + for (i = 0; i < (sizeof(struct profiler_bw_cntrs_req)) + /sizeof(uint32_t) - 1; ++i) { + err |= get_user(val, (compat_uint_t *)data32 + i); + err |= put_user(val, (uint32_t *)data + i); + } + + return err; +} + +static int compat_put_profiler_bw_info( + struct compat_profiler_bw_cntrs_req __user *data32, + struct profiler_bw_cntrs_req __user *data) +{ + compat_uint_t val = 0; + int err = 0; + int i = 0; + + for (i = 0; i < (sizeof(struct profiler_bw_cntrs_req)) + /sizeof(uint32_t) - 1; ++i) { + err |= get_user(val, (uint32_t *)data + i); + err |= put_user(val, (compat_uint_t *)data32 + i); + } + + return err; +} + +static unsigned int convert_cmd(unsigned int cmd) +{ + switch (cmd) { + case COMPAT_PROFILER_IOCTL_GET_BW_INFO: + return PROFILER_IOCTL_GET_BW_INFO; + + default: + return cmd; + } +} + + +static long profiler_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct profiler_dev_handle *data = file->private_data; + void __user *argp = (void __user *) arg; + + if (!data) { + pr_err("Invalid/uninitialized device handle\n"); + return -EINVAL; + } + + if (data->abort) { + pr_err("Aborting profiler driver\n"); + return -ENODEV; + } + + switch (cmd) { + case PROFILER_IOCTL_GET_BW_INFO: + atomic_inc(&data->ioctl_count); + ret = profiler_get_bw_info(argp); + if (ret) + pr_err("failed get system bandwidth info: %d\n", ret); + atomic_dec(&data->ioctl_count); + break; + default: + pr_err("Invalid IOCTL: 0x%x\n", cmd); + return -EINVAL; + } + return ret; +} + +static long compat_profiler_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + + switch (cmd) { + case COMPAT_PROFILER_IOCTL_GET_BW_INFO:{ + struct compat_profiler_bw_cntrs_req __user *data32; + struct profiler_bw_cntrs_req __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + err = compat_get_profiler_bw_info(data32, data); + if (err) + return err; + ret = profiler_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + err = compat_put_profiler_bw_info(data32, data); + return ret ? ret : err; + } + default: + return -ENOIOCTLCMD; + } + return 0; +} + + +static int profiler_release(struct inode *inode, struct file *file) +{ + pr_info("profiler release\n"); + return 0; +} + +static const struct file_operations profiler_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = profiler_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_profiler_ioctl, +#endif + .open = profiler_open, + .release = profiler_release +}; + +static int profiler_init(void) +{ + int rc; + struct device *class_dev; + + rc = alloc_chrdev_region(&profiler_device_no, 0, 1, PROFILER_DEV); + if (rc < 0) { + pr_err("alloc_chrdev_region failed %d\n", rc); + return rc; + } + + driver_class = class_create(THIS_MODULE, PROFILER_DEV); + if (IS_ERR(driver_class)) { + rc = -ENOMEM; + pr_err("class_create failed %d\n", rc); + goto exit_unreg_chrdev_region; + } + + class_dev = device_create(driver_class, NULL, profiler_device_no, NULL, + PROFILER_DEV); + if (IS_ERR(class_dev)) { + pr_err("class_device_create failed %d\n", rc); + rc = -ENOMEM; + goto exit_destroy_class; + } + + cdev_init(&profiler.cdev, &profiler_fops); + profiler.cdev.owner = THIS_MODULE; + + rc = cdev_add(&profiler.cdev, MKDEV(MAJOR(profiler_device_no), 0), 1); + if (rc < 0) { + pr_err("%s: cdev_add failed %d\n", __func__, rc); + goto exit_destroy_device; + } + + profiler.pdev = class_dev; + return 0; + +exit_destroy_device: + device_destroy(driver_class, profiler_device_no); +exit_destroy_class: + class_destroy(driver_class); +exit_unreg_chrdev_region: + unregister_chrdev_region(profiler_device_no, 1); + return rc; +} + +static void profiler_exit(void) +{ + pr_info("Exiting from profiler\n"); +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. trustzone Communicator"); + +module_init(profiler_init); +module_exit(profiler_exit); diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index f402e161e55ffd0aaf906f151e7db59da5ed6318..f3c12b118f3ad4bee7d57b53b16165444b4d7bee 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -5108,8 +5108,10 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, } perf_enabled = true; } - if (!strcmp(data->client.app_name, "securemm")) + if (!strcmp(data->client.app_name, "securemm") || + !strcmp(data->client.app_name, "bgapp")) { data->use_legacy_cmd = true; + } dmac_flush_range(req.cmd_req_buf, req.cmd_req_buf + req.cmd_req_len); @@ -9005,6 +9007,7 @@ static int qseecom_probe(struct platform_device *pdev) struct device *class_dev; struct qseecom_command_scm_resp resp; struct qseecom_ce_info_use *pce_info_use = NULL; + struct msm_bus_scale_pdata *qseecom_platform_support = NULL; qseecom.qsee_bw_count = 0; qseecom.qsee_perf_client = 0; @@ -9185,6 +9188,9 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk; } + qseecom_platform_support = (struct msm_bus_scale_pdata *) + msm_bus_cl_get_pdata(pdev); + if (qseecom.qsee_version >= (QSEE_VERSION_02) && (!qseecom.is_apps_region_protected && !qseecom.appsbl_qseecom_support)) { @@ -9252,6 +9258,9 @@ static int qseecom_probe(struct platform_device *pdev) if (qseecom.is_apps_region_protected || qseecom.appsbl_qseecom_support) qseecom.commonlib_loaded = true; + } else { + qseecom_platform_support = (struct msm_bus_scale_pdata *) + pdev->dev.platform_data; } if (qseecom.support_bus_scaling) { @@ -9260,8 +9269,10 @@ static int qseecom_probe(struct platform_device *pdev) qseecom_bw_inactive_req_work); qseecom.bw_scale_down_timer.function = qseecom_scale_bus_bandwidth_timer_callback; + qseecom.timer_running = false; + qseecom.qsee_perf_client = msm_bus_scale_register_client( + qseecom_platform_support); } - qseecom.timer_running = false; qseecom.whitelist_support = qseecom_check_whitelist_feature(); pr_warn("qseecom.whitelist_support = %d\n", @@ -9291,6 +9302,9 @@ static int qseecom_probe(struct platform_device *pdev) atomic_set(&qseecom.unload_app_kthread_state, UNLOAD_APP_KT_SLEEP); + if (!qseecom.qsee_perf_client) + pr_err("Unable to register bus client\n"); + atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY); return 0; diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 6956f7e7d43921ec80f5e450a471429bc21f55fc..ca5f0102daef413cc0edea634ecbe15f77a2090e 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -70,7 +70,7 @@ xpc_get_rsvd_page_pa(int nasid) unsigned long rp_pa = nasid; /* seed with nasid */ size_t len = 0; size_t buf_len = 0; - void *buf = buf; + void *buf = NULL; void *buf_base = NULL; enum xp_retval (*get_partition_rsvd_page_pa) (void *, u64 *, unsigned long *, size_t *) = diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index a224b72bcedeecff024797d6c966317508a265ad..9eed28afe3b887aee9c7855e62f0a92a134a2c25 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -701,8 +701,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) if (mmc_gpio_alloc(host)) { put_device(&host->class_dev); - ida_simple_remove(&mmc_host_ida, host->index); - kfree(host); return NULL; } diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 71319c7b260a492a6e14258fd41ca7ffd5823a89..dab99b99c804501f5c487d4c8b9c47df2e84ca56 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -249,6 +249,12 @@ static const struct mmc_fixup sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_2, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), + SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, + add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), + + SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, + add_quirk, MMC_QUIRK_DISABLE_CD), + SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c index 552bddc5096ce2e2d2638483f3baf7317115d5bf..1cd10356fc14fd1ddbe9d20306b913b684de0add 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -55,7 +55,9 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) } sdhci_get_of_property(pdev); - mmc_of_parse(host->mmc); + res = mmc_of_parse(host->mmc); + if (res) + goto err; /* * Supply the existing CAPS, but clear the UHS modes. This diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index ce3f344d2b66ec70cf15c129c1cc89f592e5edfa..d2b0a62bfce189837b305ba40bb9c926c390bd58 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -177,7 +177,7 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; - if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50) + if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8d5ac691ff9ac8af0a9b7cf31ab0713570819948..90ff537636b1e7283f0b726ce676deede009752a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -4572,11 +4572,13 @@ int sdhci_setup_host(struct sdhci_host *host) if (host->ops->get_min_clock) mmc->f_min = host->ops->get_min_clock(host); else if (host->version >= SDHCI_SPEC_300) { - if (host->clk_mul) { - mmc->f_min = (host->max_clk * host->clk_mul) / 1024; + if (host->clk_mul) max_clk = host->max_clk * host->clk_mul; - } else - mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; + /* + * Divided Clock Mode minimum clock rate is always less than + * Programmable Clock Mode minimum clock rate. + */ + mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; } else mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index e094673f9cacac2d6f50cb311f1edcde6594b989..8cb1feb3dcd1dc8bdd7ce69f74c2d5a0cee7aeaa 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -881,10 +881,12 @@ static int msm_nand_flash_onfi_probe(struct msm_nand_info *info) struct version nandc_version = {0}; ret = msm_nand_version_check(info, &nandc_version); - if (!ret && !(nandc_version.nand_major == 1 && + if (!ret && !((nandc_version.nand_major == 1 && nandc_version.nand_minor >= 5 && nandc_version.qpic_major == 1 && - nandc_version.qpic_minor >= 5)) { + nandc_version.qpic_minor >= 5) || + (nandc_version.nand_major >= 2 && + nandc_version.qpic_major >= 2))) { ret = -EPERM; goto out; } @@ -1993,7 +1995,7 @@ static int msm_nand_is_erased_page_ps(struct mtd_info *mtd, loff_t from, if (last_pos < ecc_bytes_percw_in_bits) num_zero_bits++; - if (num_zero_bits > 4) { + if (num_zero_bits > MAX_ECC_BIT_FLIPS) { *erased_page = false; goto free_mem; } @@ -2005,7 +2007,7 @@ static int msm_nand_is_erased_page_ps(struct mtd_info *mtd, loff_t from, ecc_temp += chip->ecc_parity_bytes; } - if ((n == cwperpage) && (num_zero_bits <= 4)) + if ((n == cwperpage) && (num_zero_bits <= MAX_ECC_BIT_FLIPS)) *erased_page = true; free_mem: kfree(ecc); @@ -2228,6 +2230,33 @@ static int msm_nand_read_pagescope(struct mtd_info *mtd, loff_t from, goto free_dma; /* Check for flash status errors */ pageerr = rawerr = 0; + + /* + * PAGE_ERASED bit will set only if all + * CODEWORD_ERASED bit of all codewords + * of the page is set. + * + * PAGE_ERASED bit is a 'logical and' of all + * CODEWORD_ERASED bit of all codewords i.e. + * even if one codeword is detected as not + * an erased codeword, PAGE_ERASED bit will unset. + */ + for (n = rw_params.start_sector; n < cwperpage; n++) { + if ((dma_buffer->result[n].erased_cw_status & + (1 << PAGE_ERASED)) && + (dma_buffer->result[n].buffer_status & + NUM_ERRORS)) { + err = msm_nand_is_erased_page_ps(mtd, + from, ops, + &rw_params, + &erased_page); + if (err) + goto free_dma; + if (erased_page) + rawerr = -EIO; + break; + } + } for (n = rw_params.start_sector; n < cwperpage; n++) { if (dma_buffer->result[n].flash_status & (FS_OP_ERR | FS_MPU_ERR)) { @@ -2633,7 +2662,7 @@ static int msm_nand_is_erased_page(struct mtd_info *mtd, loff_t from, if (last_pos < ecc_bytes_percw_in_bits) num_zero_bits++; - if (num_zero_bits > 4) { + if (num_zero_bits > MAX_ECC_BIT_FLIPS) { *erased_page = false; goto free_mem; } @@ -2645,7 +2674,7 @@ static int msm_nand_is_erased_page(struct mtd_info *mtd, loff_t from, ecc_temp += chip->ecc_parity_bytes; } - if ((n == cwperpage) && (num_zero_bits <= 4)) + if ((n == cwperpage) && (num_zero_bits <= MAX_ECC_BIT_FLIPS)) *erased_page = true; free_mem: kfree(ecc); @@ -2840,6 +2869,33 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, goto free_dma; /* Check for flash status errors */ pageerr = rawerr = 0; + + /* + * PAGE_ERASED bit will set only if all + * CODEWORD_ERASED bit of all codewords + * of the page is set. + * + * PAGE_ERASED bit is a 'logical and' of all + * CODEWORD_ERASED bit of all codewords i.e. + * even if one codeword is detected as not + * an erased codeword, PAGE_ERASED bit will unset. + */ + for (n = rw_params.start_sector; n < cwperpage; n++) { + if ((dma_buffer->result[n].erased_cw_status & + (1 << PAGE_ERASED)) && + (dma_buffer->result[n].buffer_status & + NUM_ERRORS)) { + err = msm_nand_is_erased_page(mtd, + from, ops, + &rw_params, + &erased_page); + if (err) + goto free_dma; + if (erased_page) + rawerr = -EIO; + break; + } + } for (n = rw_params.start_sector; n < cwperpage; n++) { if (dma_buffer->result[n].flash_status & (FS_OP_ERR | FS_MPU_ERR)) { diff --git a/drivers/mtd/devices/msm_qpic_nand.h b/drivers/mtd/devices/msm_qpic_nand.h index d6c6d4080e48c80b1692ed6edfdd20f2e3d679ea..b48272a552f1c9cd1bdf041bcfb8df5119258014 100644 --- a/drivers/mtd/devices/msm_qpic_nand.h +++ b/drivers/mtd/devices/msm_qpic_nand.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020 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 @@ -165,7 +165,10 @@ #define RESET_ERASED_DET (1 << AUTO_DETECT_RES) #define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES) #define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC) -#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC) +#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC | SET_N_MAX_ZEROS) +#define N_MAX_ZEROS 2 +#define MAX_ECC_BIT_FLIPS 4 +#define SET_N_MAX_ZEROS (MAX_ECC_BIT_FLIPS << N_MAX_ZEROS) #define MSM_NAND_ERASED_CW_DETECT_STATUS(info) MSM_NAND_REG(info, 0x300EC) #define PAGE_ALL_ERASED 7 @@ -174,6 +177,7 @@ #define CODEWORD_ERASED 4 #define ERASED_PAGE ((1 << PAGE_ALL_ERASED) | (1 << PAGE_ERASED)) #define ERASED_CW ((1 << CODEWORD_ALL_ERASED) | (1 << CODEWORD_ERASED)) +#define NUM_ERRORS 0x1f #define MSM_NAND_CTRL(info) MSM_NAND_REG(info, 0x30F00) #define BAM_MODE_EN 0 diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d550148177a014acbfdfa65bbeca1bd403b1f038..0fe3e39f870fd99e3bcb4baddb518be42827f329 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1216,7 +1216,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); - int ret; + ssize_t ret; dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); @@ -1445,7 +1445,7 @@ static int macronix_quad_enable(struct spi_nor *nor) */ static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr) { - int ret; + ssize_t ret; write_enable(nor); diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index acb708fc14636e76959c068ec249682ac64564de..0a7d818a06f3f11f6fc3139ce6fd4aad145dc068 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -392,13 +392,12 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota) struct net_device *dev = napi->dev; struct mscan_regs __iomem *regs = priv->reg_base; struct net_device_stats *stats = &dev->stats; - int npackets = 0; - int ret = 1; + int work_done = 0; struct sk_buff *skb; struct can_frame *frame; u8 canrflg; - while (npackets < quota) { + while (work_done < quota) { canrflg = in_8(®s->canrflg); if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF))) break; @@ -419,18 +418,18 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota) stats->rx_packets++; stats->rx_bytes += frame->can_dlc; - npackets++; + work_done++; netif_receive_skb(skb); } - if (!(in_8(®s->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) { - napi_complete(&priv->napi); - clear_bit(F_RX_PROGRESS, &priv->flags); - if (priv->can.state < CAN_STATE_BUS_OFF) - out_8(®s->canrier, priv->shadow_canrier); - ret = 0; + if (work_done < quota) { + if (likely(napi_complete_done(&priv->napi, work_done))) { + clear_bit(F_RX_PROGRESS, &priv->flags); + if (priv->can.state < CAN_STATE_BUS_OFF) + out_8(®s->canrier, priv->shadow_canrier); + } } - return ret; + return work_done; } static irqreturn_t mscan_isr(int irq, void *dev_id) diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index a42737b4ac79f20639300296b364d7404d18b1a3..35564a9561b7828be777e5b288afb77f88e95ce8 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -343,9 +343,16 @@ static void slcan_transmit(struct work_struct *work) */ static void slcan_write_wakeup(struct tty_struct *tty) { - struct slcan *sl = tty->disc_data; + struct slcan *sl; + + rcu_read_lock(); + sl = rcu_dereference(tty->disc_data); + if (!sl) + goto out; schedule_work(&sl->tx_work); +out: + rcu_read_unlock(); } /* Send a can_frame to a TTY queue. */ @@ -640,10 +647,11 @@ static void slcan_close(struct tty_struct *tty) return; spin_lock_bh(&sl->lock); - tty->disc_data = NULL; + rcu_assign_pointer(tty->disc_data, NULL); sl->tty = NULL; spin_unlock_bh(&sl->lock); + synchronize_rcu(); flush_work(&sl->tx_work); /* Flush network side */ diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index bfbf809496009b5e85fd0042a00bd73b6535eec4..aed8ab6d6c5b03a5115b9851f0b65e342e6b23ee 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -926,7 +926,7 @@ static int gs_usb_probe(struct usb_interface *intf, GS_USB_BREQ_HOST_FORMAT, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 1, - intf->altsetting[0].desc.bInterfaceNumber, + intf->cur_altsetting->desc.bInterfaceNumber, hconf, sizeof(*hconf), 1000); @@ -949,7 +949,7 @@ static int gs_usb_probe(struct usb_interface *intf, GS_USB_BREQ_DEVICE_CONFIG, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 1, - intf->altsetting[0].desc.bInterfaceNumber, + intf->cur_altsetting->desc.bInterfaceNumber, dconf, sizeof(*dconf), 1000); diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 94ad2fdd6ef0d7cba764990821b530b7edff0a18..05440b72726151e0e8d2d961880df8dcceaff28d 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -137,7 +137,7 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) /* Force link status for IMP port */ reg = core_readl(priv, offset); - reg |= (MII_SW_OR | LINK_STS); + reg |= (MII_SW_OR | LINK_STS | GMII_SPEED_UP_2G); core_writel(priv, reg, offset); /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */ diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index d76d7c7ea8197cb7522e4e51cac863bea43e4bc8..544b6a9cc01acad670b70b2a3dd9788b7e4dc3af 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -313,6 +313,11 @@ int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) { u16 ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST; + /* Use the default high priority for management frames sent to + * the CPU. + */ + port |= MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI; + return mv88e6390_g1_monitor_write(chip, ptr, port); } diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 950b914f9251b1d91306c2704c0a452353de8c03..d82e8956cbd58225ecdf154c91cf0a3efb410405 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -189,6 +189,7 @@ #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST 0x2000 #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST 0x2100 #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST 0x3000 +#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI 0x00e0 #define MV88E6390_G1_MONITOR_MGMT_CTL_DATA_MASK 0x00ff /* Offset 0x1C: Global Control 2 */ diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 8e49974ffa0ed8ec8e6c2c96dec65c7e3bad46d6..8ee59b20b47a342db170cfed598eadc91d544f91 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -459,6 +459,18 @@ qca8k_set_pad_ctrl(struct qca8k_priv *priv, int port, int mode) qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); break; + case PHY_INTERFACE_MODE_RGMII_ID: + /* RGMII_ID needs internal delay. This is enabled through + * PORT5_PAD_CTRL for all ports, rather than individual port + * registers + */ + qca8k_write(priv, reg, + QCA8K_PORT_PAD_RGMII_EN | + QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) | + QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY)); + qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, + QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); + break; case PHY_INTERFACE_MODE_SGMII: qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); break; diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h index 613fe5c50236c50cfbc6659b5a7d895b21409ec9..d146e54c8a6c615045ff18b31b413fba08365221 100644 --- a/drivers/net/dsa/qca8k.h +++ b/drivers/net/dsa/qca8k.h @@ -40,6 +40,7 @@ ((0x8 + (x & 0x3)) << 22) #define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) \ ((0x10 + (x & 0x3)) << 20) +#define QCA8K_MAX_DELAY 3 #define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) #define QCA8K_PORT_PAD_SGMII_EN BIT(7) #define QCA8K_REG_MODULE_EN 0x030 diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 1a4ffc5d3da4ebd2a3662a78885a6086f3cdfb40..10e6053f667123f2473fbdee232025515a8be88d 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -2002,7 +2002,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) if (unlikely(ret)) return ret; - if (get_resp.u.flow_hash_func.supported_func & (1 << rss->hash_func)) { + if (!(get_resp.u.flow_hash_func.supported_func & BIT(rss->hash_func))) { pr_err("Func hash %d isn't supported by device, abort\n", rss->hash_func); return -EOPNOTSUPP; @@ -2087,6 +2087,7 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev, return -EINVAL; } + rss->hash_func = func; rc = ena_com_set_hash_function(ena_dev); /* Restore the old function */ diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 967020fb26ee17a6995a7ae11df668e8ab4fe9f0..a2f02c23fe141014556a9cb5d24cd4bd856f8f8e 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -694,8 +694,8 @@ static int ena_set_rxfh(struct net_device *netdev, const u32 *indir, if (indir) { for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) { rc = ena_com_indirect_table_fill_entry(ena_dev, - ENA_IO_RXQ_IDX(indir[i]), - i); + i, + ENA_IO_RXQ_IDX(indir[i])); if (unlikely(rc)) { netif_err(adapter, drv, netdev, "Cannot fill indirect table (index is too large)\n"); diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index d22b138c2b096813b7471a0219ce7430ba3b739c..518ff393a026b7f86be9a27ae98396ffa8e6bab4 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1796,6 +1796,7 @@ static int ena_up(struct ena_adapter *adapter) err_setup_tx: ena_free_io_irq(adapter); err_req_irq: + ena_del_napi(adapter); return rc; } diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/Documentation/networking/atlantic.txt b/drivers/net/ethernet/aquantia/atlantic-fwd/Documentation/networking/atlantic.txt new file mode 100644 index 0000000000000000000000000000000000000000..5956851c04ed25e34dc1d20cab4833d4bdbdf84f --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/Documentation/networking/atlantic.txt @@ -0,0 +1,283 @@ + + + +Supported hardware +------------------ + +AQC-107 / -108 / -109, revisions B0 / B1. FW versions 1.x / 2.x / 3.x +supported + + + +Features / acceleration +----------------------- + + - Message-signalled interrupts + - Hardware VLAN tag offloads + - Hardware checksum offloads: + - IPv4 header checksums + - UDP / TCP checksums with IPv4 and IPv6 + - Hardware LSO for TCP v4/v6 + - Hardware LRO for TCP v4/v6 + - Coalescing TCP segments with TCP options not supported due to a + HW limitation + - Software GRO using the Linux NAPI GRO interface + - Hardware Rx header splitting + - RSS over up to 8 queues using MSI-X + - Linear skb receive mode + - N-tuple Rx filters + - Runtime power management + - Hardware MACSEC offload + + +Building and installation +------------------------- + +1. Unpack the archive into a directory of your choice. + +2. Change to that directory and compile the module: + $ make [KDIR=] + + Explicitly specifying KDIR is only necessary when the headers can't + be found automatically via the + /lib/modules/`uname -r`/{build,source} symlinks + +3. Load the module + # insmod atlnew.ko [] + +4. Unload the module + # rmmod atlnew + + + +Device configuration +-------------------- + + # ip link set up dev + # ip addr add / brd + dev + +Add a VLAN ID: + # ip link add link name . type vlan id + # ip link set up dev . + +Remove a VLAN ID: + # ip link del dev . + + + +Module parameters +----------------- + +Module parameters may be specified at module load time on the insmod +command line or via modprobe.conf files. Some parameters marked as +[RW] below can also be changed at run time via files in +/sys/module/atlnew/parameters directory + + - msi = < 1 | 0 > (default: 1) [RO] + Enable use of MSI interrupts. + + - rx_refill_batch = (default: 16) [RW] + Number of cleaned Rx ring descriptors to trigger Rx refill + + - tx_clean_budget = (default: 256) [RW] + Max number of processed Tx descriptors to clean in one pass of + NAPI poll + + - max_queues = (default: 8) [RO] + Max number of RSS queues. The actual number of queues will the + minimum of this parameter and the number of logical CPUs in + the system. + + - rx_linear = <0 | 1> (default: 0) + Enables linear skb receive mode. Frames larger than + ATL_RX_BUF_SIZE defined in atl_ring.h will be dropped. + + - min_intr_delay (default: 10) [RW] + When an interrupt is about to be asserted on an LRO-enabled + queue, LRO requires some lead time to close and flush + in-progress flows. This parameter sets the LRO interrupt delay + and provides the lower boundary for interrupt coalescing + delays settable via ethtool. When modified, the new value + takes effect on interface down/up cycle or on setting an + interrupt coalescing delay via ethtool. + + - rx_mod_hyst (default: 10) [RW] + - tx_mod_hyst (default: 10) [RW] + Each ring has two interrupt coalescing timers. When an + interrupt-causing event happens, they're initialized with + values called minimum and maximum respectively. The former + timer is restarted each time another such event happens, while + the latter keeps running. When either timer reaches zero, the + interrupt is reported to the host. The minimum value is set + via ethtool. These module parameters set the difference + between the maximum and minimum values for Rx and Tx + paths. When modified, the new max values go into effect upon + interface down/up cycle or upon modifying ethtool interrupt + coalescing settings. + +- keep_link = < 1 | 0 > (default: 0) [RO] + When set to 1, the ethernet link is established at PCI probe + time, and is not dropped on ifdown. This allows the rings + allocated to forwarding engines to handle traffic even when + linux network interface is down. + +- sleep_delay = (default: 10000) [RW] + Delay in ms after link goes down to suspend the device if runtime power + management is turned on. + +- macsec_bridge = < 1 | 0 > (default: 1) [RO] + When set to 0, several SecY can be created, macsec will filter by source mac + address to apply apropriate SecY. + By default, only 1 SecY can be created, macsec will handle all packets. + +- rx/tx_ring_size = <8..8184> (default: 4096) [RO] + Default size for the rings. + +VLAN filters +------------ + +Sixteen VLAN filters are programmable via the ethtool -N interface using +locations 0 through 15. The only flow-type supported is ether and only +VLAN id can be matched. + +For VLAN filters only, it's possible not to specify an explicit +filter location. In this case an appropriate location will be assigned +automatically. + +These filters are also used for HW filter acceleration for Linux VLAN +subdevices. Filters automatically added by Linux VLAN code can be +overridden using ethtool subject to restrictions described below: + +* A special ring number 32 is used in ethtool interface to signify + 'any ring'. An ethtool filter rule with ring set to 32 accepts a + packet leaving the ring to be determined using the standard RSS + mechanism. VLAN code adds rules in this manner. Such a rule can be + modified using ethool to set a specific destination ring. + +* There can't be two filters with the same VID. An attempt to add a + duplicate filter using an explicit location different from the + location of existing filter with the same VID will fail. When the + location is not specified, the existing filter will be modified. + +* An attempt to change the VID of a filter added by VLAN code using an + explicit location will fail. Either use a different explicit + location or no location. + +* An attempt to delete a rule created by VLAN code will return + success, but the rule will remain in place. If a specific ring was + set in the rule, it will be reset to 'any ring'. + +* If a VLAN sub-device is added when there're no unused filters, VLAN + promiscuous mode will be enabled. This will result in all VIDs being + accepted. Filters can still be used to direct specific VIDs to + specific rings. + +* Even when all 16 filters are used, attempting to add a rule with a + new VID via ethtool will succeed as long as at least one existing + filter was set by VLAN code and still has 'any ring' as + destination. This filter will be re-used for the new rule and VLAN + promiscuous mode will be enabled. + +* When a filter becomes available as a result of a deletion of a VLAN + subdevice or a deletion of an ethtool filter rule, and a VLAN + promiscuous mode is enabled, the vacated filter will be re-used for + another enabled VLAN subdevice. This may result in VLAN promiscuous + mode being turned off if that VLAN subdevice was the last one with + no filter allocated. + +Ethertype filters +----------------- + +Fifteen ethertype filters are programmable via the ethtool -N +interface using locations 16 through 30. The only flow-type supported +is ether and only the ethertype field can be matched. + +N-tuple filters +--------------- + +Eight IPv4 n-tuple filters are supported, programmable using ethtool +-N command with filter locations 32 through 39. + +Fields that can be matched are source / destination IP addresses, and, +for TCP / UDP / SCTP protocols, additionally source / destination +ports can be matched. Partial (masked) matches are not supported, a +mask for each field must consist of either all ones or all zeroes. + +Each aligned group of four filters (locations 32 through 35 or 36 +through 39) can alternatively be used as one IPv6 filter, using filter +locations 32 or 36. + + + +Testing forwarding performance +------------------------------ + +Since this is a design for a router, the best way to test would be +between our aquantia port and another high speed port on the same +DUT. However, in the situation where the Aquantia interface is the +only high speed one, we have devised the following testing strategy +to emulate these two ports on same DUT. + +One of the simplest ways is to set up two VLAN interfaces and forward +traffic between them as in the following example: + +Set up two VLANs with examlple ids 42 and 43 on the Aquantia +interface, assign the switch port connected to it to both of those +VLANs. +# ip link set up dev +# ip link add link name .42 type vlan id 42 +# ip link add link name .43 type vlan id 43 +# ip link set up dev .42 +# ip link set up dev .43 +# ip addr add 10.42.42.1/24 brd + dev .42 +# ip addr add 10.42.43.1/24 brd + dev .43 +# sysctl net.ipv4.ip_forward=1 + +This sets up two VLAN interfaces with VLAN ids 42 and 43 and enables +IP routing. Two hosts should be set up to generate and terminate the +traffic: + +On a host on the 42 VLAN with IP 10.42.42.xx run + $ iperf3 -s +On a host on the 43 VLAN run + $ iperf3 -c 10.42.42.xx + +Another possibility is to use a single host running Linux as a link +partner both generating and terminating the traffic. Two VLAN +sub-interfaces should be configured on a high-speed port on that host, +belonging to VLAN 42 / IP network 10.42.42/24 and VLAN 43 / IP network +10.42.43/24 respectively. + +Since, by default, traffic addressed to one of the local IPs is +received locally, a special configuration of Linux policy routing is +required to make such traffic actually go out on the wire to the DUT, +as described below, where stands for the chosen network interface: + +# ip rule add table local prio 100 +# ip rule del table local prio 0 +# ip rule add iif lo table 42 prio 42 +# ip link set up dev + +# ip link add link name .42 type vlan id 42 +# ip link add link name .43 type vlan id 43 +# ip link set up dev .42 +# ip link set up dev .43 +# ip addr add 10.42.42.10/24 brd + dev .42 +# ip addr add 10.42.43.10/24 brd + dev .43 + +# ip route add 10.42.42.10 via 10.42.43.1 table 42 +# ip route add 10.42.43.10 via 10.42.42.1 table 42 + +This routes the locally-originated traffic, that is addressed to the local IP +of one of the VLAN interfaces, out via the other VLAN interface, instead of +being immediately looped back locally. + + +$ iperf3 -s + +$ iperf3 -c 10.42.42.10 + +The following command can be used to restore the default routing +behavior: + +# ip route flush table 42 diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c index b5b0c20336ecaae462a6fd5ca6185da8118b4d36..7aee0e1e63dabceb29d82ad49a9589aa8d4ef1f3 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c @@ -578,7 +578,7 @@ static int atl2_fw_get_phy_temperature(struct atl_hw *hw, int *temp) ret = atl2_shared_buffer_read_safe(hw, phy_health_monitor, &phy_health_monitor); - *temp = (phy_health_monitor.phy_temperature & 0xffff) * 1000; + *temp = (int8_t)(phy_health_monitor.phy_temperature) * 1000; atl_unlock_fw(hw); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h index aca28a972909dff6586befe98d81850cf3379345..7476d093ffddf1ea199dbbcf5859849fdc85d3a6 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h @@ -20,7 +20,7 @@ #include #include -#define ATL_VERSION "1.1.6" +#define ATL_VERSION "1.1.7" struct atl_nic; diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c index 7ebddca7f857a6cd42f1184bc21b0ffc6e695fbf..b04ec5090bd327d4dff7228def256904ff70c112 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c @@ -535,7 +535,7 @@ static int __atl_fw2_get_phy_temperature(struct atl_hw *hw, int *temp) if (ret) return ret; - *temp = (res & 0xffff) * 1000 / 256; + *temp = (int16_t)(res & 0xFFFF) * 1000 / 256; return ret; } diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c index 06a46226cbef672f10b8c8b44361233e982996f5..2761411995d7100d5e7e95319adfbaa4d14e7bd2 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c @@ -473,7 +473,14 @@ void atl_refresh_link(struct atl_nic *nic) netif_carrier_on(nic->ndev); pm_runtime_get_sync(&nic->hw.pdev->dev); #if IS_ENABLED(CONFIG_MACSEC) && defined(NETIF_F_HW_MACSEC) - atl_init_macsec(hw); + { + int ret; + + ret = atl_init_macsec(hw); + + if (ret) + atl_dev_err("atl_init_macsec failed with %d", ret); + } #endif } } else { @@ -549,8 +556,8 @@ int atl_alloc_link_intr(struct atl_nic *nic) int ret; if (nic->flags & ATL_FL_MULTIPLE_VECTORS) { - ret = request_irq(pci_irq_vector(pdev, 0), atl_link_irq, 0, - nic->ndev->name, nic); + ret = request_irq(pci_irq_vector(pdev, 0), atl_link_irq, + IRQF_NO_SUSPEND, nic->ndev->name, nic); if (ret) atl_nic_err("request MSI link vector failed: %d\n", -ret); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c index 763f1f611e85a8ba0df6792cf575947e3f6efd3e..b2b3cfb4bfc6c92217722cbc97ebdf3c602593b6 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c @@ -551,6 +551,15 @@ static int atl_set_txsc(struct atl_hw *hw, int txsc_idx) sc_rec.fresh = 1; if (atl_macsec_bridge) { + struct aq_mss_ingress_prectlf_record rx_prectlf_rec; + + memset(&rx_prectlf_rec, 0, sizeof(rx_prectlf_rec)); + ret = aq_mss_set_ingress_prectlf_record(hw, &rx_prectlf_rec, 0); + if (ret) + return ret; + ret = aq_mss_set_packet_edit_control(hw, 0); + if (ret) + return ret; ret = aq_mss_set_drop_igprc_miss_packets(hw, 1); if (ret) return ret; @@ -719,7 +728,19 @@ static int atl_clear_txsc(struct atl_nic *nic, const int txsc_idx, if (ret) return ret; + /* if last txsc is removed then pass macsec packets to host */ if (atl_macsec_bridge) { + struct aq_mss_ingress_prectlf_record rx_prectlf; + + memset(&rx_prectlf, 0, sizeof(rx_prectlf)); + rx_prectlf.match_type = 4; /* Match eth_type only */ + rx_prectlf.action = 0; + ret = aq_mss_set_ingress_prectlf_record(hw, &rx_prectlf, 0); + if (ret) + return ret; + ret = aq_mss_set_packet_edit_control(hw, 0xb068); + if (ret) + return ret; ret = aq_mss_set_drop_igprc_miss_packets(hw, 0); if (ret) return ret; @@ -911,7 +932,6 @@ static int atl_set_rxsc(struct atl_hw *hw, const u32 rxsc_idx) &hw->macsec_cfg.atl_rxsc[rxsc_idx]; struct aq_mss_ingress_preclass_record pre_class_record; const struct macsec_rx_sc *rx_sc = atl_rxsc->sw_rxsc; - struct aq_mss_ingress_prectlf_record rx_prectlf_rec; const struct macsec_secy *secy = atl_rxsc->sw_secy; const u32 hw_sc_idx = atl_rxsc->hw_sc_idx; struct aq_mss_ingress_sc_record sc_record; @@ -921,12 +941,6 @@ static int atl_set_rxsc(struct atl_hw *hw, const u32 rxsc_idx) atl_dev_dbg("set rx_sc: rxsc_idx=%d, sci %#llx, hw_sc_idx=%d\n", rxsc_idx, rx_sc->sci, hw_sc_idx); - if (atl_macsec_bridge) { - memset(&rx_prectlf_rec, 0, sizeof(rx_prectlf_rec)); - aq_mss_set_ingress_prectlf_record(hw, &rx_prectlf_rec, 0); - aq_mss_set_packet_edit_control(hw, 0); - } - memset(&pre_class_record, 0, sizeof(pre_class_record)); nsci = cpu_to_be64((__force u64)rx_sc->sci); memcpy(pre_class_record.sci, &nsci, sizeof(nsci)); @@ -1060,19 +1074,8 @@ static int atl_clear_rxsc(struct atl_nic *nic, const int rxsc_idx, if (clear_type & ATL_CLEAR_HW) { struct aq_mss_ingress_preclass_record pre_class_record; - struct aq_mss_ingress_prectlf_record rx_prectlf; struct aq_mss_ingress_sc_record sc_record; - /* if last rxsc is removed then pass macsec packets to host */ - if (atl_macsec_bridge && - hweight_long(hw->macsec_cfg.rxsc_idx_busy) == 1) { - memset(&rx_prectlf, 0, sizeof(rx_prectlf)); - rx_prectlf.match_type = 4; /* Match eth_type only */ - rx_prectlf.action = 0; - aq_mss_set_ingress_prectlf_record(hw, &rx_prectlf, 0); - aq_mss_set_packet_edit_control(hw, 0xb068); - } - memset(&pre_class_record, 0, sizeof(pre_class_record)); memset(&sc_record, 0, sizeof(sc_record)); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c index 554ba012db1046c1ac5f7026b49e76ab1711ec68..b68d83d2a6f3968a17147181791bf2cf44a2d727 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c @@ -36,6 +36,11 @@ module_param_named(keep_link, atl_keep_link, uint, 0644); static unsigned int atl_sleep_delay = 10000; module_param_named(sleep_delay, atl_sleep_delay, uint, 0644); +static unsigned int atl_rx_ring_size = ATL_RING_SIZE; +static unsigned int atl_tx_ring_size = ATL_RING_SIZE; +module_param_named(rx_ring_size, atl_rx_ring_size, uint, 0444); +module_param_named(tx_ring_size, atl_tx_ring_size, uint, 0444); + static void atl_start_link(struct atl_nic *nic) { struct atl_hw *hw = &nic->hw; @@ -64,6 +69,7 @@ static int atl_start(struct atl_nic *nic) int ret = 0; atl_start_hw_global(nic); + atl_set_rx_mode(nic->ndev); if (atl_keep_link || netif_running(nic->ndev)) atl_start_link(nic); @@ -527,8 +533,8 @@ static int atl_probe(struct pci_dev *pdev, const struct pci_device_id *id) atl_dev_dbg("got MAC address: %pM\n", hw->mac_addr); nic->requested_nvecs = atl_max_queues; - nic->requested_tx_size = ATL_RING_SIZE; - nic->requested_rx_size = ATL_RING_SIZE; + nic->requested_tx_size = (atl_tx_ring_size & ~7); + nic->requested_rx_size = (atl_rx_ring_size & ~7); nic->rx_intr_delay = atl_rx_mod; nic->tx_intr_delay = atl_tx_mod; @@ -678,6 +684,8 @@ static int atl_suspend_common(struct device *dev, unsigned int wol_mode) atl_stop(nic, true); + atl_intr_disable_non_ring(nic); + atl_clear_rdm_cache(nic); atl_clear_tdm_cache(nic); @@ -863,6 +871,19 @@ static int __init atl_module_init(void) struct atl_hw *hw = NULL; int ret; + if ((atl_tx_ring_size < 8) || (atl_tx_ring_size > ATL_MAX_RING_SIZE)) { + atl_dev_init_err( + "Bad atl_tx_ring_size value %d, must be between 8 and %d inclusive\n", + atl_tx_ring_size, ATL_MAX_RING_SIZE); + return -EINVAL; + } + if ((atl_rx_ring_size < 8) || (atl_rx_ring_size > ATL_MAX_RING_SIZE)) { + atl_dev_init_err( + "Bad atl_rx_ring_size value %d, must be between 8 and %d inclusive\n", + atl_rx_ring_size, ATL_MAX_RING_SIZE); + return -EINVAL; + } + atl_def_thermal.flags = atl_def_thermal_monitor << atl_thermal_monitor_shift | atl_def_thermal_throttle << atl_thermal_throttle_shift | diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c index 2ae71c5d18b30fbe29ecbb6a179d8dce7121f68d..93d99db691785e3b345b1606cca3771e012f2760 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c @@ -444,7 +444,7 @@ static bool atl_checksum_workaround(struct sk_buff *skb, break; case atl_rx_pkt_type_ipv6: ipv6 = (struct ipv6hdr *) &skb->data[ip_header_offset]; - l4_header_offset = ip_header_offset + sizeof(struct ipv6hdr); + l4_header_offset = sizeof(struct ipv6hdr); /* padding inside Ethernet frame */ if (ip_header_offset + sizeof(struct ipv6hdr) + ntohs(ipv6->payload_len) < desc->pkt_len) @@ -1512,7 +1512,8 @@ static int atl_alloc_qvec_intr(struct atl_queue_vec *qvec) return 0; vector = pci_irq_vector(nic->hw.pdev, atl_qvec_intr(qvec)); - ret = request_irq(vector, atl_ring_irq, 0, qvec->name, &qvec->napi); + ret = request_irq(vector, atl_ring_irq, IRQF_NO_SUSPEND, + qvec->name, &qvec->napi); if (ret) { atl_nic_err("request MSI ring vector failed: %d\n", -ret); return ret; diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt b/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt index 382fe9fd1bd17e9542836752237b3a94e70977ce..5fac6ea6eb45f739a6a8e957fe020f5b6424bb31 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt @@ -1,3 +1,10 @@ +Version 1.1.7 +============= + + [ATLDRV-1469] - AQ083: After suspend resume EAPOL frames is not received + [ATLDRV-1497] - Incorrect temperature is displayed in hwmon + [ATLDRV-1519] - AQ086: Configuring default ring size + Version 1.1.6 ============= [ATLDRV-1355] - Sporadically unable to set EEE diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c index 5fecc9a099ef7fd34d3a36b9ee1eb9c01a3f9fcd..bb2894a333f20706dc8e9d0825e5b30a0780d803 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c @@ -310,15 +310,13 @@ irqreturn_t aq_vec_isr_legacy(int irq, void *private) { struct aq_vec_s *self = private; u64 irq_mask = 0U; - irqreturn_t err = 0; + int err; - if (!self) { - err = -EINVAL; - goto err_exit; - } + if (!self) + return IRQ_NONE; err = self->aq_hw_ops->hw_irq_read(self->aq_hw, &irq_mask); if (err < 0) - goto err_exit; + return IRQ_NONE; if (irq_mask) { self->aq_hw_ops->hw_irq_disable(self->aq_hw, @@ -326,11 +324,10 @@ irqreturn_t aq_vec_isr_legacy(int irq, void *private) napi_schedule(&self->napi); } else { self->aq_hw_ops->hw_irq_enable(self->aq_hw, 1U); - err = IRQ_NONE; + return IRQ_NONE; } -err_exit: - return err >= 0 ? IRQ_HANDLED : IRQ_NONE; + return IRQ_HANDLED; } cpumask_t *aq_vec_get_affinity_mask(struct aq_vec_s *self) diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index b0abd187cead95a34da01d2b07f54e5bf30726cb..b83ee74d28391e35accd1f59b9154490a2dd0356 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c @@ -182,8 +182,8 @@ static int hw_atl_a0_hw_rss_set(struct aq_hw_s *self, u32 i = 0U; u32 num_rss_queues = max(1U, self->aq_nic_cfg->num_rss_queues); int err = 0; - u16 bitary[(HW_ATL_A0_RSS_REDIRECTION_MAX * - HW_ATL_A0_RSS_REDIRECTION_BITS / 16U)]; + u16 bitary[1 + (HW_ATL_A0_RSS_REDIRECTION_MAX * + HW_ATL_A0_RSS_REDIRECTION_BITS / 16U)]; memset(bitary, 0, sizeof(bitary)); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 236325f48ec9befa14da52e41b7b0927014b94d2..1c1bb074f664594c143223d92ffc5833622cd4a4 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -183,8 +183,8 @@ static int hw_atl_b0_hw_rss_set(struct aq_hw_s *self, u32 i = 0U; u32 num_rss_queues = max(1U, self->aq_nic_cfg->num_rss_queues); int err = 0; - u16 bitary[(HW_ATL_B0_RSS_REDIRECTION_MAX * - HW_ATL_B0_RSS_REDIRECTION_BITS / 16U)]; + u16 bitary[1 + (HW_ATL_B0_RSS_REDIRECTION_MAX * + HW_ATL_B0_RSS_REDIRECTION_BITS / 16U)]; memset(bitary, 0, sizeof(bitary)); diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index a1125d10c8255f6eb8fbb6046b09473c35ba52b8..8b9a0ce1d29f5f4a4e266db455fc9c1d3dfd7113 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -1521,8 +1521,10 @@ static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset) int ethaddr_bytes = ETH_ALEN; memset(ppattern + offset, 0xff, magicsync); - for (j = 0; j < magicsync; j++) - set_bit(len++, (unsigned long *) pmask); + for (j = 0; j < magicsync; j++) { + pmask[len >> 3] |= BIT(len & 7); + len++; + } for (j = 0; j < B44_MAX_PATTERNS; j++) { if ((B44_PATTERN_SIZE - len) >= ETH_ALEN) @@ -1534,7 +1536,8 @@ static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset) for (k = 0; k< ethaddr_bytes; k++) { ppattern[offset + magicsync + (j * ETH_ALEN) + k] = macaddr[k]; - set_bit(len++, (unsigned long *) pmask); + pmask[len >> 3] |= BIT(len & 7); + len++; } } return len - 1; diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 79018fea7be24109df82d5fdab5b6709dde8bc20..69b2f99b0c19d568c3dd6b08f81b7cda7c78218c 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -2116,7 +2116,7 @@ static int bcm_sysport_probe(struct platform_device *pdev) priv->phy_interface = of_get_phy_mode(dn); /* Default to GMII interface mode */ - if (priv->phy_interface < 0) + if ((int)priv->phy_interface < 0) priv->phy_interface = PHY_INTERFACE_MODE_GMII; /* In the case of a fixed PHY, the DT node associated diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 4e091a11daaf33e3707d044c6a29a1002ebd631f..52bce009d096a2575c9c28bdf348ca354d0349fa 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -1112,7 +1112,7 @@ static inline u8 bnx2x_get_path_func_num(struct bnx2x *bp) for (i = 0; i < E1H_FUNC_MAX / 2; i++) { u32 func_config = MF_CFG_RD(bp, - func_mf_config[BP_PORT(bp) + 2 * i]. + func_mf_config[BP_PATH(bp) + 2 * i]. config); func_num += ((func_config & FUNC_MF_CFG_FUNC_HIDE) ? 0 : 1); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index dbe8feec456c2acb15922116b0f1e441b86554b6..b0ada7eac652a47e54b445f5091b54911ce6d348 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9995,10 +9995,18 @@ static void bnx2x_recovery_failed(struct bnx2x *bp) */ static void bnx2x_parity_recover(struct bnx2x *bp) { - bool global = false; u32 error_recovered, error_unrecovered; - bool is_parity; + bool is_parity, global = false; +#ifdef CONFIG_BNX2X_SRIOV + int vf_idx; + + for (vf_idx = 0; vf_idx < bp->requested_nr_virtfn; vf_idx++) { + struct bnx2x_virtf *vf = BP_VF(bp, vf_idx); + if (vf) + vf->state = VF_LOST; + } +#endif DP(NETIF_MSG_HW, "Handling parity\n"); while (1) { switch (bp->recovery_state) { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index 53466f6cebabc4cd3089a0b45fdaa74e8bd9d905..a887bfa24c888d39ef6aa2d2f6712b95c8155196 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -139,6 +139,7 @@ struct bnx2x_virtf { #define VF_ACQUIRED 1 /* VF acquired, but not initialized */ #define VF_ENABLED 2 /* VF Enabled */ #define VF_RESET 3 /* VF FLR'd, pending cleanup */ +#define VF_LOST 4 /* Recovery while VFs are loaded */ bool flr_clnup_stage; /* true during flr cleanup */ bool malicious; /* true if FW indicated so, until FLR */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index 76a4668c50fe98edb3d6e955351a357a3e3f0608..6d5b81a971e32cba2d7aa1ef60abbefa82caf316 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -2112,6 +2112,18 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf, { int i; + if (vf->state == VF_LOST) { + /* Just ack the FW and return if VFs are lost + * in case of parity error. VFs are supposed to be timedout + * on waiting for PF response. + */ + DP(BNX2X_MSG_IOV, + "VF 0x%x lost, not handling the request\n", vf->abs_vfid); + + storm_memset_vf_mbx_ack(bp, vf->abs_vfid); + return; + } + /* check if tlv type is known */ if (bnx2x_tlv_supported(mbx->first_tlv.tl.type)) { /* Lock the per vf op mutex and note the locker's identity. diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 38ee7692132c50637729e6544597dcadf367105f..7461e7b9eaae5db3d62c67a016c195871852bbd8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7402,11 +7402,23 @@ static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1, struct flow_keys *keys1 = &f1->fkeys; struct flow_keys *keys2 = &f2->fkeys; - if (keys1->addrs.v4addrs.src == keys2->addrs.v4addrs.src && - keys1->addrs.v4addrs.dst == keys2->addrs.v4addrs.dst && - keys1->ports.ports == keys2->ports.ports && - keys1->basic.ip_proto == keys2->basic.ip_proto && - keys1->basic.n_proto == keys2->basic.n_proto && + if (keys1->basic.n_proto != keys2->basic.n_proto || + keys1->basic.ip_proto != keys2->basic.ip_proto) + return false; + + if (keys1->basic.n_proto == htons(ETH_P_IP)) { + if (keys1->addrs.v4addrs.src != keys2->addrs.v4addrs.src || + keys1->addrs.v4addrs.dst != keys2->addrs.v4addrs.dst) + return false; + } else { + if (memcmp(&keys1->addrs.v6addrs.src, &keys2->addrs.v6addrs.src, + sizeof(keys1->addrs.v6addrs.src)) || + memcmp(&keys1->addrs.v6addrs.dst, &keys2->addrs.v6addrs.dst, + sizeof(keys1->addrs.v6addrs.dst))) + return false; + } + + if (keys1->ports.ports == keys2->ports.ports && keys1->control.flags == keys2->control.flags && ether_addr_equal(f1->src_mac_addr, f2->src_mac_addr) && ether_addr_equal(f1->dst_mac_addr, f2->dst_mac_addr)) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index fc8e185718a1d768f80b992ab5935cf63b021935..3c78cd1cdd6fb7ce5caddabf063816fda069aaa6 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1667,21 +1667,19 @@ static int bnxt_flash_package_from_file(struct net_device *dev, mutex_lock(&bp->hwrm_cmd_lock); hwrm_err = _hwrm_send_message(bp, &install, sizeof(install), INSTALL_PACKAGE_TIMEOUT); - if (hwrm_err) - goto flash_pkg_exit; - - if (resp->error_code) { + if (hwrm_err) { u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err; - if (error_code == NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) { + if (resp->error_code && error_code == + NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) { install.flags |= cpu_to_le16( NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); hwrm_err = _hwrm_send_message(bp, &install, sizeof(install), INSTALL_PACKAGE_TIMEOUT); - if (hwrm_err) - goto flash_pkg_exit; } + if (hwrm_err) + goto flash_pkg_exit; } if (resp->result) { @@ -2463,7 +2461,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, bool offline = false; u8 test_results = 0; u8 test_mask = 0; - int rc, i; + int rc = 0, i; if (!bp->num_tests || !BNXT_SINGLE_PF(bp)) return; @@ -2521,9 +2519,9 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, } bnxt_hwrm_phy_loopback(bp, false); bnxt_half_close_nic(bp); - bnxt_open_nic(bp, false, true); + rc = bnxt_open_nic(bp, false, true); } - if (bnxt_test_irq(bp)) { + if (rc || bnxt_test_irq(bp)) { buf[BNXT_IRQ_TEST_IDX] = 1; etest->flags |= ETH_TEST_FL_FAILED; } diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 338683e5ef1e85859621d7c4ddb79b4ad323efc3..b8779afb85505f7d614c598e3a30a29f4a5a6807 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -2449,6 +2449,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) if (!is_offload(adapter)) return -EOPNOTSUPP; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; if (!(adapter->flags & FULL_INIT_DONE)) return -EIO; /* need the memory controllers */ if (copy_from_user(&t, useraddr, sizeof(t))) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 9e5cd18e7358c710d18991740cbdbbe0614683f2..8bd90ad15607369adf675162b9ac11e924231a7e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -66,8 +66,7 @@ static void *seq_tab_start(struct seq_file *seq, loff_t *pos) static void *seq_tab_next(struct seq_file *seq, void *v, loff_t *pos) { v = seq_tab_get_idx(seq->private, *pos + 1); - if (v) - ++*pos; + ++(*pos); return v; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index f7ef8871dd0b02125b8aeedd11781544c0db6de9..67aa3c9974173b299224cbeec130399533ec8fb4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -682,8 +682,7 @@ static void *l2t_seq_start(struct seq_file *seq, loff_t *pos) static void *l2t_seq_next(struct seq_file *seq, void *v, loff_t *pos) { v = l2t_get_idx(seq, *pos); - if (v) - ++*pos; + ++(*pos); return v; } diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c index 75ce773c21a62eb3e26ae30bce000678d3deda5e..b33650a897f184d431183a6e8fea94755ab743d1 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -110,7 +110,7 @@ do { \ /* Interface Mode Register (IF_MODE) */ #define IF_MODE_MASK 0x00000003 /* 30-31 Mask on i/f mode bits */ -#define IF_MODE_XGMII 0x00000000 /* 30-31 XGMII (10G) interface */ +#define IF_MODE_10G 0x00000000 /* 30-31 10G interface */ #define IF_MODE_GMII 0x00000002 /* 30-31 GMII (1G) interface */ #define IF_MODE_RGMII 0x00000004 #define IF_MODE_RGMII_AUTO 0x00008000 @@ -439,7 +439,7 @@ static int init(struct memac_regs __iomem *regs, struct memac_cfg *cfg, tmp = 0; switch (phy_if) { case PHY_INTERFACE_MODE_XGMII: - tmp |= IF_MODE_XGMII; + tmp |= IF_MODE_10G; break; default: tmp |= IF_MODE_GMII; diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index e03b30c60dcfda168291ce7f3a93306b3f3748de..c82c85ef5fb3407d1a0016573b325dd39e068ffa 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -49,6 +49,7 @@ struct tgec_mdio_controller { struct mdio_fsl_priv { struct tgec_mdio_controller __iomem *mdio_base; bool is_little_endian; + bool has_a011043; }; static u32 xgmac_read32(void __iomem *regs, @@ -226,7 +227,8 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) return ret; /* Return all Fs if nothing was there */ - if (xgmac_read32(®s->mdio_stat, endian) & MDIO_STAT_RD_ER) { + if ((xgmac_read32(®s->mdio_stat, endian) & MDIO_STAT_RD_ER) && + !priv->has_a011043) { dev_err(&bus->dev, "Error while reading PHY%d reg at %d.%hhu\n", phy_id, dev_addr, regnum); @@ -274,6 +276,9 @@ static int xgmac_mdio_probe(struct platform_device *pdev) priv->is_little_endian = of_property_read_bool(pdev->dev.of_node, "little-endian"); + priv->has_a011043 = of_property_read_bool(pdev->dev.of_node, + "fsl,erratum-a011043"); + ret = of_mdiobus_register(bus, np); if (ret) { dev_err(&pdev->dev, "cannot register MDIO bus\n"); diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index aab6fb10af94a3842541e8b5d15a14efedf6d1fc..6adf6831d120afb53c525d096a87cef0471db98d 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -1202,7 +1202,7 @@ static int hix5hd2_dev_probe(struct platform_device *pdev) goto err_free_mdio; priv->phy_mode = of_get_phy_mode(node); - if (priv->phy_mode < 0) { + if ((int)priv->phy_mode < 0) { netdev_err(ndev, "not find phy-mode\n"); ret = -EINVAL; goto err_mdiobus; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index b681c07b33fb6aa44db9611640f0915eb1606b1f..0733745f4be6ce832d2360a80b1771f5bf53ab94 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -669,7 +669,6 @@ static int hns_nic_poll_rx_skb(struct hns_nic_ring_data *ring_data, skb = *out_skb = napi_alloc_skb(&ring_data->napi, HNS_RX_HEAD_SIZE); if (unlikely(!skb)) { - netdev_err(ndev, "alloc rx skb fail\n"); ring->stats.sw_err_cnt++; return -ENOMEM; } @@ -1180,7 +1179,6 @@ static int hns_nic_common_poll(struct napi_struct *napi, int budget) container_of(napi, struct hns_nic_ring_data, napi); struct hnae_ring *ring = ring_data->ring; -try_again: clean_complete += ring_data->poll_one( ring_data, budget - clean_complete, ring_data->ex_process); @@ -1190,7 +1188,7 @@ static int hns_nic_common_poll(struct napi_struct *napi, int budget) napi_complete(napi); ring->q->handle->dev->ops->toggle_ring_irq(ring, 0); } else { - goto try_again; + return budget; } } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 9fcfd9395424538870f4b837ad9ade21476867ae..a4c5e72d6012ae17fc0997e92adcd81825206c29 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -480,7 +480,7 @@ struct hclge_vport { u16 alloc_rss_size; u16 qs_offset; - u16 bw_limit; /* VSI BW Limit (0 = disabled) */ + u32 bw_limit; /* VSI BW Limit (0 = disabled) */ u8 dwrr; int vport_id; diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index 30cbdf0fed595460e181aea473f5320dc872f37b..373deb247ac01bdc97501b7df959b41192c08395 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -1475,7 +1475,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, memset(pr, 0, sizeof(struct ehea_port_res)); - pr->tx_bytes = rx_bytes; + pr->tx_bytes = tx_bytes; pr->tx_packets = tx_packets; pr->rx_bytes = rx_bytes; pr->rx_packets = rx_packets; diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index c37cc8bccf47760481481b09dcb61a48de1ed2fc..158c277ec35389cf781cb887aec40edbc2a63267 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -562,7 +562,7 @@ static s32 igb_set_sfp_media_type_82575(struct e1000_hw *hw) dev_spec->module_plugged = true; if (eth_flags->e1000_base_lx || eth_flags->e1000_base_sx) { hw->phy.media_type = e1000_media_type_internal_serdes; - } else if (eth_flags->e100_base_fx) { + } else if (eth_flags->e100_base_fx || eth_flags->e100_base_lx) { dev_spec->sgmii_active = true; hw->phy.media_type = e1000_media_type_internal_serdes; } else if (eth_flags->e1000_base_t) { @@ -689,14 +689,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) break; } - /* do not change link mode for 100BaseFX */ - if (dev_spec->eth_flags.e100_base_fx) - break; - /* change current link mode setting */ ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK; - if (hw->phy.media_type == e1000_media_type_copper) + if (dev_spec->sgmii_active) ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_SGMII; else ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index d06a8db514d4a09753193c31e5ca0b006ae0c640..82028ce355fb15a8b0681a6c166aa4dc24a07de4 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -201,7 +201,7 @@ static int igb_get_link_ksettings(struct net_device *netdev, advertising &= ~ADVERTISED_1000baseKX_Full; } } - if (eth_flags->e100_base_fx) { + if (eth_flags->e100_base_fx || eth_flags->e100_base_lx) { supported |= SUPPORTED_100baseT_Full; advertising |= ADVERTISED_100baseT_Full; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 0edfd199937d5afc7183b3886de043c7c744cb46..ba184287e11f3da76212f3e7038ef4fed5caf1b7 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1871,13 +1871,7 @@ static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring, static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring, struct sk_buff *skb) { - /* if the page was released unmap it, else just sync our portion */ - if (unlikely(IXGBE_CB(skb)->page_released)) { - dma_unmap_page_attrs(rx_ring->dev, IXGBE_CB(skb)->dma, - ixgbe_rx_pg_size(rx_ring), - DMA_FROM_DEVICE, - IXGBE_RX_DMA_ATTR); - } else if (ring_uses_build_skb(rx_ring)) { + if (ring_uses_build_skb(rx_ring)) { unsigned long offset = (unsigned long)(skb->data) & ~PAGE_MASK; dma_sync_single_range_for_cpu(rx_ring->dev, @@ -1894,6 +1888,14 @@ static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring, skb_frag_size(frag), DMA_FROM_DEVICE); } + + /* If the page was released, just unmap it. */ + if (unlikely(IXGBE_CB(skb)->page_released)) { + dma_unmap_page_attrs(rx_ring->dev, IXGBE_CB(skb)->dma, + ixgbe_rx_pg_size(rx_ring), + DMA_FROM_DEVICE, + IXGBE_RX_DMA_ATTR); + } } /** @@ -5129,7 +5131,7 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; struct hlist_node *node2; struct ixgbe_fdir_filter *filter; - u64 action; + u8 queue; spin_lock(&adapter->fdir_perfect_lock); @@ -5138,17 +5140,34 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter) hlist_for_each_entry_safe(filter, node2, &adapter->fdir_filter_list, fdir_node) { - action = filter->action; - if (action != IXGBE_FDIR_DROP_QUEUE && action != 0) - action = - (action >> ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF) - 1; + if (filter->action == IXGBE_FDIR_DROP_QUEUE) { + queue = IXGBE_FDIR_DROP_QUEUE; + } else { + u32 ring = ethtool_get_flow_spec_ring(filter->action); + u8 vf = ethtool_get_flow_spec_ring_vf(filter->action); + + if (!vf && (ring >= adapter->num_rx_queues)) { + e_err(drv, "FDIR restore failed without VF, ring: %u\n", + ring); + continue; + } else if (vf && + ((vf > adapter->num_vfs) || + ring >= adapter->num_rx_queues_per_pool)) { + e_err(drv, "FDIR restore failed with VF, vf: %hhu, ring: %u\n", + vf, ring); + continue; + } + + /* Map the ring onto the absolute queue index */ + if (!vf) + queue = adapter->rx_ring[ring]->reg_idx; + else + queue = ((vf - 1) * + adapter->num_rx_queues_per_pool) + ring; + } ixgbe_fdir_write_perfect_filter_82599(hw, - &filter->filter, - filter->sw_idx, - (action == IXGBE_FDIR_DROP_QUEUE) ? - IXGBE_FDIR_DROP_QUEUE : - adapter->rx_ring[action]->reg_idx); + &filter->filter, filter->sw_idx, queue); } spin_unlock(&adapter->fdir_perfect_lock); diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index e238f6e85ab66724ec63202aafd5c82ab71a6e9c..a7708e14aa5ca402fc24da9ee247b757f946e1a2 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -1858,11 +1858,6 @@ static int ixgbevf_write_uc_addr_list(struct net_device *netdev) struct ixgbe_hw *hw = &adapter->hw; int count = 0; - if ((netdev_uc_count(netdev)) > 10) { - pr_err("Too many unicast filters - No Space\n"); - return -ENOSPC; - } - if (!netdev_uc_empty(netdev)) { struct netdev_hw_addr *ha; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index 5f091c6ea049dfc7061adb1bdf9179b7670508e9..b92d5690287b5789612c5f254804542aee2a4d4d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -44,14 +44,15 @@ static struct mlx5_core_rsc_common *mlx5_get_rsc(struct mlx5_core_dev *dev, { struct mlx5_qp_table *table = &dev->priv.qp_table; struct mlx5_core_rsc_common *common; + unsigned long flags; - spin_lock(&table->lock); + spin_lock_irqsave(&table->lock, flags); common = radix_tree_lookup(&table->tree, rsn); if (common) atomic_inc(&common->refcount); - spin_unlock(&table->lock); + spin_unlock_irqrestore(&table->lock, flags); if (!common) { mlx5_core_warn(dev, "Async event for bogus resource 0x%x\n", diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 8ab7a4f98a07cdb4713351d6feb161275b50de28..e7974ba064324963d141decdb0748d41709f4dc8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -2452,7 +2452,7 @@ static inline void mlxsw_reg_qtct_pack(char *payload, u8 local_port, * Configures the ETS elements. */ #define MLXSW_REG_QEEC_ID 0x400D -#define MLXSW_REG_QEEC_LEN 0x1C +#define MLXSW_REG_QEEC_LEN 0x20 MLXSW_REG_DEFINE(qeec, MLXSW_REG_QEEC_ID, MLXSW_REG_QEEC_LEN); @@ -2494,6 +2494,15 @@ MLXSW_ITEM32(reg, qeec, element_index, 0x04, 0, 8); */ MLXSW_ITEM32(reg, qeec, next_element_index, 0x08, 0, 8); +/* reg_qeec_mise + * Min shaper configuration enable. Enables configuration of the min + * shaper on this ETS element + * 0 - Disable + * 1 - Enable + * Access: RW + */ +MLXSW_ITEM32(reg, qeec, mise, 0x0C, 31, 1); + enum { MLXSW_REG_QEEC_BYTES_MODE, MLXSW_REG_QEEC_PACKETS_MODE, @@ -2510,6 +2519,17 @@ enum { */ MLXSW_ITEM32(reg, qeec, pb, 0x0C, 28, 1); +/* The smallest permitted min shaper rate. */ +#define MLXSW_REG_QEEC_MIS_MIN 200000 /* Kbps */ + +/* reg_qeec_min_shaper_rate + * Min shaper information rate. + * For CPU port, can only be configured for port hierarchy. + * When in bytes mode, value is specified in units of 1000bps. + * Access: RW + */ +MLXSW_ITEM32(reg, qeec, min_shaper_rate, 0x0C, 0, 28); + /* reg_qeec_mase * Max shaper configuration enable. Enables configuration of the max * shaper on this ETS element. diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index 23821540ab078de3aafcb07c781e7f5ebc932299..254e6dbc4c6aa3da226f84f405c234e32c2b127e 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -50,6 +50,8 @@ static int sonic_open(struct net_device *dev) if (sonic_debug > 2) printk("sonic_open: initializing sonic driver.\n"); + spin_lock_init(&lp->lock); + for (i = 0; i < SONIC_NUM_RRS; i++) { struct sk_buff *skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2); if (skb == NULL) { @@ -101,6 +103,24 @@ static int sonic_open(struct net_device *dev) return 0; } +/* Wait for the SONIC to become idle. */ +static void sonic_quiesce(struct net_device *dev, u16 mask) +{ + struct sonic_local * __maybe_unused lp = netdev_priv(dev); + int i; + u16 bits; + + for (i = 0; i < 1000; ++i) { + bits = SONIC_READ(SONIC_CMD) & mask; + if (!bits) + return; + if (irqs_disabled() || in_interrupt()) + udelay(20); + else + usleep_range(100, 200); + } + WARN_ONCE(1, "command deadline expired! 0x%04x\n", bits); +} /* * Close the SONIC device @@ -118,6 +138,9 @@ static int sonic_close(struct net_device *dev) /* * stop the SONIC, disable interrupts */ + SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); + sonic_quiesce(dev, SONIC_CR_ALL); + SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); @@ -157,6 +180,9 @@ static void sonic_tx_timeout(struct net_device *dev) * put the Sonic into software-reset mode and * disable all interrupts before releasing DMA buffers */ + SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); + sonic_quiesce(dev, SONIC_CR_ALL); + SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); @@ -194,8 +220,6 @@ static void sonic_tx_timeout(struct net_device *dev) * wake the tx queue * Concurrently with all of this, the SONIC is potentially writing to * the status flags of the TDs. - * Until some mutual exclusion is added, this code will not work with SMP. However, - * MIPS Jazz machines and m68k Macs were all uni-processor machines. */ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) @@ -203,7 +227,8 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) struct sonic_local *lp = netdev_priv(dev); dma_addr_t laddr; int length; - int entry = lp->next_tx; + int entry; + unsigned long flags; if (sonic_debug > 2) printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev); @@ -221,11 +246,15 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE); if (!laddr) { - printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name); - dev_kfree_skb(skb); - return NETDEV_TX_BUSY; + pr_err_ratelimited("%s: failed to map tx DMA buffer.\n", dev->name); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } + spin_lock_irqsave(&lp->lock, flags); + + entry = lp->next_tx; + sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */ sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */ @@ -235,10 +264,6 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) sonic_tda_put(dev, entry, SONIC_TD_LINK, sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL); - /* - * Must set tx_skb[entry] only after clearing status, and - * before clearing EOL and before stopping queue - */ wmb(); lp->tx_len[entry] = length; lp->tx_laddr[entry] = laddr; @@ -263,6 +288,8 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); + spin_unlock_irqrestore(&lp->lock, flags); + return NETDEV_TX_OK; } @@ -275,9 +302,21 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) struct net_device *dev = dev_id; struct sonic_local *lp = netdev_priv(dev); int status; + unsigned long flags; + + /* The lock has two purposes. Firstly, it synchronizes sonic_interrupt() + * with sonic_send_packet() so that the two functions can share state. + * Secondly, it makes sonic_interrupt() re-entrant, as that is required + * by macsonic which must use two IRQs with different priority levels. + */ + spin_lock_irqsave(&lp->lock, flags); + + status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT; + if (!status) { + spin_unlock_irqrestore(&lp->lock, flags); - if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)) return IRQ_NONE; + } do { if (status & SONIC_INT_PKTRX) { @@ -292,11 +331,12 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) int td_status; int freed_some = 0; - /* At this point, cur_tx is the index of a TD that is one of: - * unallocated/freed (status set & tx_skb[entry] clear) - * allocated and sent (status set & tx_skb[entry] set ) - * allocated and not yet sent (status clear & tx_skb[entry] set ) - * still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear) + /* The state of a Transmit Descriptor may be inferred + * from { tx_skb[entry], td_status } as follows. + * { clear, clear } => the TD has never been used + * { set, clear } => the TD was handed to SONIC + * { set, set } => the TD was handed back + * { clear, set } => the TD is available for re-use */ if (sonic_debug > 2) @@ -398,10 +438,30 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) /* load CAM done */ if (status & SONIC_INT_LCD) SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */ - } while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)); + + status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT; + } while (status); + + spin_unlock_irqrestore(&lp->lock, flags); + return IRQ_HANDLED; } +/* Return the array index corresponding to a given Receive Buffer pointer. */ +static int index_from_addr(struct sonic_local *lp, dma_addr_t addr, + unsigned int last) +{ + unsigned int i = last; + + do { + i = (i + 1) & SONIC_RRS_MASK; + if (addr == lp->rx_laddr[i]) + return i; + } while (i != last); + + return -ENOENT; +} + /* * We have a good packet(s), pass it/them up the network stack. */ @@ -421,6 +481,16 @@ static void sonic_rx(struct net_device *dev) status = sonic_rda_get(dev, entry, SONIC_RD_STATUS); if (status & SONIC_RCR_PRX) { + u32 addr = (sonic_rda_get(dev, entry, + SONIC_RD_PKTPTR_H) << 16) | + sonic_rda_get(dev, entry, SONIC_RD_PKTPTR_L); + int i = index_from_addr(lp, addr, entry); + + if (i < 0) { + WARN_ONCE(1, "failed to find buffer!\n"); + break; + } + /* Malloc up new buffer. */ new_skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2); if (new_skb == NULL) { @@ -442,7 +512,7 @@ static void sonic_rx(struct net_device *dev) /* now we have a new skb to replace it, pass the used one up the stack */ dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE); - used_skb = lp->rx_skb[entry]; + used_skb = lp->rx_skb[i]; pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN); skb_trim(used_skb, pkt_len); used_skb->protocol = eth_type_trans(used_skb, dev); @@ -451,13 +521,13 @@ static void sonic_rx(struct net_device *dev) lp->stats.rx_bytes += pkt_len; /* and insert the new skb */ - lp->rx_laddr[entry] = new_laddr; - lp->rx_skb[entry] = new_skb; + lp->rx_laddr[i] = new_laddr; + lp->rx_skb[i] = new_skb; bufadr_l = (unsigned long)new_laddr & 0xffff; bufadr_h = (unsigned long)new_laddr >> 16; - sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, bufadr_l); - sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h); + sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l); + sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h); } else { /* This should only happen, if we enable accepting broken packets. */ lp->stats.rx_errors++; @@ -592,6 +662,7 @@ static int sonic_init(struct net_device *dev) */ SONIC_WRITE(SONIC_CMD, 0); SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); + sonic_quiesce(dev, SONIC_CR_ALL); /* * initialize the receive resource area diff --git a/drivers/net/ethernet/natsemi/sonic.h b/drivers/net/ethernet/natsemi/sonic.h index 421b1a283fedae971e0a487f75adfd7881ba4796..7dc011655e70a8dc2cc69541c8f4398fb13a828f 100644 --- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -110,6 +110,9 @@ #define SONIC_CR_TXP 0x0002 #define SONIC_CR_HTX 0x0001 +#define SONIC_CR_ALL (SONIC_CR_LCAM | SONIC_CR_RRRA | \ + SONIC_CR_RXEN | SONIC_CR_TXP) + /* * SONIC data configuration bits */ @@ -274,8 +277,9 @@ #define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ #define SONIC_NUM_TDS 16 /* number of transmit descriptors */ -#define SONIC_RDS_MASK (SONIC_NUM_RDS-1) -#define SONIC_TDS_MASK (SONIC_NUM_TDS-1) +#define SONIC_RRS_MASK (SONIC_NUM_RRS - 1) +#define SONIC_RDS_MASK (SONIC_NUM_RDS - 1) +#define SONIC_TDS_MASK (SONIC_NUM_TDS - 1) #define SONIC_RBSIZE 1520 /* size of one resource buffer */ @@ -321,6 +325,7 @@ struct sonic_local { unsigned int next_tx; /* next free TD */ struct device *device; /* generic device */ struct net_device_stats stats; + spinlock_t lock; }; #define TX_TIMEOUT (3 * HZ) @@ -342,30 +347,30 @@ static void sonic_tx_timeout(struct net_device *dev); as far as we can tell. */ /* OpenBSD calls this "SWO". I'd like to think that sonic_buf_put() is a much better name. */ -static inline void sonic_buf_put(void* base, int bitmode, +static inline void sonic_buf_put(u16 *base, int bitmode, int offset, __u16 val) { if (bitmode) #ifdef __BIG_ENDIAN - ((__u16 *) base + (offset*2))[1] = val; + __raw_writew(val, base + (offset * 2) + 1); #else - ((__u16 *) base + (offset*2))[0] = val; + __raw_writew(val, base + (offset * 2) + 0); #endif else - ((__u16 *) base)[offset] = val; + __raw_writew(val, base + (offset * 1) + 0); } -static inline __u16 sonic_buf_get(void* base, int bitmode, +static inline __u16 sonic_buf_get(u16 *base, int bitmode, int offset) { if (bitmode) #ifdef __BIG_ENDIAN - return ((volatile __u16 *) base + (offset*2))[1]; + return __raw_readw(base + (offset * 2) + 1); #else - return ((volatile __u16 *) base + (offset*2))[0]; + return __raw_readw(base + (offset * 2) + 0); #endif else - return ((volatile __u16 *) base)[offset]; + return __raw_readw(base + (offset * 1) + 0); } /* Inlines that you should actually use for reading/writing DMA buffers */ diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c index 49591d9c2e1b9f4bde7217e750396d99f032f302..c9b4ac9d3330a0c746095373b2df8afe4aeec4d6 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac.c @@ -1053,7 +1053,6 @@ static int pasemi_mac_phy_init(struct net_device *dev) dn = pci_device_to_OF_node(mac->pdev); phy_dn = of_parse_phandle(dn, "phy-handle", 0); - of_node_put(phy_dn); mac->link = 0; mac->speed = 0; @@ -1062,6 +1061,7 @@ static int pasemi_mac_phy_init(struct net_device *dev) phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0, PHY_INTERFACE_MODE_SGMII); + of_node_put(phy_dn); if (!phydev) { printk(KERN_ERR "%s: Could not attach to phy\n", dev->name); return -ENODEV; diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c index bb09f5a9846f6db3c9eb63fac22b7ba2db58d341..38d0f62bf037a377b6682d36857eb9d6a1af2d57 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -509,7 +509,8 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) /* Make sure ep is closed before returning and freeing memory. */ if (ep) { - while (ep->state != QED_IWARP_EP_CLOSED && wait_count++ < 200) + while (READ_ONCE(ep->state) != QED_IWARP_EP_CLOSED && + wait_count++ < 200) msleep(100); if (ep->state != QED_IWARP_EP_CLOSED) @@ -991,8 +992,6 @@ qed_iwarp_mpa_complete(struct qed_hwfn *p_hwfn, params.ep_context = ep; - ep->state = QED_IWARP_EP_CLOSED; - switch (fw_return_code) { case RDMA_RETURN_OK: ep->qp->max_rd_atomic_req = ep->cm_info.ord; @@ -1052,6 +1051,10 @@ qed_iwarp_mpa_complete(struct qed_hwfn *p_hwfn, break; } + if (fw_return_code != RDMA_RETURN_OK) + /* paired with READ_ONCE in destroy_qp */ + smp_store_release(&ep->state, QED_IWARP_EP_CLOSED); + ep->event_cb(ep->cb_context, ¶ms); /* on passive side, if there is no associated QP (REJECT) we need to @@ -2069,7 +2072,9 @@ void qed_iwarp_qp_in_error(struct qed_hwfn *p_hwfn, params.status = (fw_return_code == IWARP_QP_IN_ERROR_GOOD_CLOSE) ? 0 : -ECONNRESET; - ep->state = QED_IWARP_EP_CLOSED; + /* paired with READ_ONCE in destroy_qp */ + smp_store_release(&ep->state, QED_IWARP_EP_CLOSED); + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); list_del(&ep->list_entry); spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); @@ -2157,7 +2162,8 @@ qed_iwarp_tcp_connect_unsuccessful(struct qed_hwfn *p_hwfn, params.event = QED_IWARP_EVENT_ACTIVE_COMPLETE; params.ep_context = ep; params.cm_info = &ep->cm_info; - ep->state = QED_IWARP_EP_CLOSED; + /* paired with READ_ONCE in destroy_qp */ + smp_store_release(&ep->state, QED_IWARP_EP_CLOSED); switch (fw_return_code) { case IWARP_CONN_ERROR_TCP_CONNECT_INVALID_PACKET: diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 62cde3854a5cd42dc99bd40e9276e5d115bdd427..5d7adedac68d2805e5ded1b2392eb86b94a3bf24 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -1629,10 +1629,9 @@ static void __qed_get_vport_pstats_addrlen(struct qed_hwfn *p_hwfn, } } -static void __qed_get_vport_pstats(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_eth_stats *p_stats, - u16 statistics_bin) +static noinline_for_stack void +__qed_get_vport_pstats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_eth_stats *p_stats, u16 statistics_bin) { struct eth_pstorm_per_queue_stat pstats; u32 pstats_addr = 0, pstats_len = 0; @@ -1659,10 +1658,9 @@ static void __qed_get_vport_pstats(struct qed_hwfn *p_hwfn, HILO_64_REGPAIR(pstats.error_drop_pkts); } -static void __qed_get_vport_tstats(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_eth_stats *p_stats, - u16 statistics_bin) +static noinline_for_stack void +__qed_get_vport_tstats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_eth_stats *p_stats, u16 statistics_bin) { struct tstorm_per_port_stat tstats; u32 tstats_addr, tstats_len; @@ -1705,10 +1703,9 @@ static void __qed_get_vport_ustats_addrlen(struct qed_hwfn *p_hwfn, } } -static void __qed_get_vport_ustats(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_eth_stats *p_stats, - u16 statistics_bin) +static noinline_for_stack +void __qed_get_vport_ustats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_eth_stats *p_stats, u16 statistics_bin) { struct eth_ustorm_per_queue_stat ustats; u32 ustats_addr = 0, ustats_len = 0; @@ -1747,10 +1744,9 @@ static void __qed_get_vport_mstats_addrlen(struct qed_hwfn *p_hwfn, } } -static void __qed_get_vport_mstats(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_eth_stats *p_stats, - u16 statistics_bin) +static noinline_for_stack void +__qed_get_vport_mstats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_eth_stats *p_stats, u16 statistics_bin) { struct eth_mstorm_per_queue_stat mstats; u32 mstats_addr = 0, mstats_len = 0; @@ -1776,9 +1772,9 @@ static void __qed_get_vport_mstats(struct qed_hwfn *p_hwfn, HILO_64_REGPAIR(mstats.tpa_coalesced_bytes); } -static void __qed_get_vport_port_stats(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_eth_stats *p_stats) +static noinline_for_stack void +__qed_get_vport_port_stats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_eth_stats *p_stats) { struct qed_eth_stats_common *p_common = &p_stats->common; struct port_stats port_stats; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index a496390b8632fa3f9dfa9f5ca18bf64d0b9e7f31..07f9067affc65ea4d73543c18016174217c1971a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2043,6 +2043,7 @@ static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev, break; } entry += p_hdr->size; + cond_resched(); } p_dev->ahw->reset.seq_index = index; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index afa10a163da1fc1a43ea5dde6f8c6da297aa0f48..f34ae8c75bc5e11f4e2a4ee02b20e87983c656f7 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -703,6 +703,7 @@ static u32 qlcnic_read_memory_test_agent(struct qlcnic_adapter *adapter, addr += 16; reg_read -= 16; ret += 16; + cond_resched(); } out: mutex_unlock(&adapter->ahw->mem_lock); @@ -1383,6 +1384,7 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) buf_offset += entry->hdr.cap_size; entry_offset += entry->hdr.offset; buffer = fw_dump->data + buf_offset; + cond_resched(); } fw_dump->clr = 1; diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 275fc6f154a71e52db57993d4e5e5c2d598abab9..1c87178fc48585c5c162d051dbd554339efa6b8a 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -475,7 +475,6 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event) u16 signature = 0; u16 spi_config; u16 wrbuf_space = 0; - static u16 reset_count; if (event == QCASPI_EVENT_CPUON) { /* Read signature twice, if not valid @@ -528,13 +527,13 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event) qca->sync = QCASPI_SYNC_RESET; qca->stats.trig_reset++; - reset_count = 0; + qca->reset_count = 0; break; case QCASPI_SYNC_RESET: - reset_count++; + qca->reset_count++; netdev_dbg(qca->net_dev, "sync: waiting for CPU on, count %u.\n", - reset_count); - if (reset_count >= QCASPI_RESET_TIMEOUT) { + qca->reset_count); + if (qca->reset_count >= QCASPI_RESET_TIMEOUT) { /* reset did not seem to take place, try again */ qca->sync = QCASPI_SYNC_UNKNOWN; qca->stats.reset_timeout++; diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index fc0e98726b3613ddd3774169fa13aa6099a5c6e5..719c41227f221b89c4c62f0e98be0d6e5a6faca3 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -92,6 +92,7 @@ struct qcaspi { unsigned int intr_req; unsigned int intr_svc; + u16 reset_count; #ifdef CONFIG_DEBUG_FS struct dentry *device_root; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index 6244f3da37c52b9ec851113b1a09a1029849093a..2a21dbdba973938f3fc10deee7780c45eac4bcc8 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -126,7 +126,7 @@ static void rmnet_vnd_uninit(struct net_device *dev) gro_cells_destroy(&priv->gro_cells); free_percpu(priv->pcpu_stats); - qos = priv->qos_info; + qos = rcu_dereference(priv->qos_info); RCU_INIT_POINTER(priv->qos_info, NULL); qmi_rmnet_qos_exit_pre(qos); } @@ -370,7 +370,8 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, rmnet_dev->rtnl_link_ops = &rmnet_link_ops; priv->mux_id = id; - priv->qos_info = qmi_rmnet_qos_init(real_dev, id); + rcu_assign_pointer(priv->qos_info, + qmi_rmnet_qos_init(real_dev, rmnet_dev, id)); netdev_dbg(rmnet_dev, "rmnet dev created\n"); } diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 9b1906a65e11396f0a36d6ab455f3242e7c27548..25f3b2ad26e9ce5a683bfcd0ead6d28aca189032 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -3046,12 +3046,16 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev) struct device_node *np = dev->of_node; struct sh_eth_plat_data *pdata; const char *mac_addr; + int ret; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return NULL; - pdata->phy_interface = of_get_phy_mode(np); + ret = of_get_phy_mode(np); + if (ret < 0) + return NULL; + pdata->phy_interface = ret; mac_addr = of_get_mac_address(np); if (mac_addr) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 7a1678edafa57e86c8943c87b70c1f2bc05ebe86..82f838544dc24216db97f264b0c5cb35bc7d93d2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -343,9 +343,8 @@ struct dma_features { unsigned int pps_out_num; }; -/* GMAC TX FIFO is 8K, Rx FIFO is 16K */ -#define BUF_SIZE_16KiB 16384 -/* RX Buffer size must be < 8191 and multiple of 4/8/16 bytes */ +/* RX Buffer size must be multiple of 4/8/16 bytes */ +#define BUF_SIZE_16KiB 16368 #define BUF_SIZE_8KiB 8188 #define BUF_SIZE_4KiB 4096 #define BUF_SIZE_2KiB 2048 @@ -448,9 +447,9 @@ struct stmmac_dma_ops { void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode, int rxfifosz); void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel, - int fifosz); + int fifosz, u8 qmode); void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel, - int fifosz); + int fifosz, u8 qmode); /* To track extra statistic (if supported) */ void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x, void __iomem *ioaddr); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index 866444b6c82faa773b622c861bb000e544a05d7a..11a4a81b0397cd3ce02550af97f85cd0256744f4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -203,7 +203,7 @@ static int ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac) struct device *dev = &gmac->pdev->dev; gmac->phy_mode = of_get_phy_mode(dev->of_node); - if (gmac->phy_mode < 0) { + if ((int)gmac->phy_mode < 0) { dev_err(dev, "missing phy mode property\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c index 8be4b32544ef86cd85304f6903a285f2ff1efc0e..d71d3c1c85eed7cfdb2c4e79104f7ef305b99995 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c @@ -285,7 +285,7 @@ static int meson8b_dwmac_probe(struct platform_device *pdev) dwmac->pdev = pdev; dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node); - if (dwmac->phy_mode < 0) { + if ((int)dwmac->phy_mode < 0) { dev_err(&pdev->dev, "missing phy-mode property\n"); ret = -EINVAL; goto err_remove_config_dt; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index f1626e102e50e69d43b21ab08a9e48ac8fd6ccce..b54efdad26d5fb274893c5d2f93c12db66ade2c3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -30,9 +30,23 @@ #include "stmmac_ptp.h" #include "dwmac-qcom-ipa-offload.h" -static unsigned long tlmm_central_base_addr; +static void __iomem *tlmm_central_base_addr; bool phy_intr_en; +static struct ethqos_emac_por emac_por[] = { + { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x0 }, + { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x0 }, + { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x0 }, + { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x0 }, + { .offset = SDCC_USR_CTL, .value = 0x0 }, + { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x0}, +}; + +static struct ethqos_emac_driver_data emac_por_data = { + .por = emac_por, + .num_por = ARRAY_SIZE(emac_por), +}; + struct qcom_ethqos *pethqos; struct stmmac_emb_smmu_cb_ctx stmmac_emb_smmu_ctx = {0}; @@ -48,6 +62,21 @@ static struct qmp_pkt pkt; static char qmp_buf[MAX_QMP_MSG_SIZE + 1] = {0}; static struct ip_params pparams = {"", "", "", ""}; +static void qcom_ethqos_read_iomacro_por_values(struct qcom_ethqos *ethqos) +{ + int i; + + ethqos->por = emac_por_data.por; + ethqos->num_por = emac_por_data.num_por; + + /* Read to POR values and enable clk */ + for (i = 0; i < ethqos->num_por; i++) + ethqos->por[i].value = + readl_relaxed( + ethqos->rgmii_base + + ethqos->por[i].offset); +} + static inline unsigned int dwmac_qcom_get_eth_type(unsigned char *buf) { return @@ -112,18 +141,21 @@ u16 dwmac_qcom_select_queue( return txqueue_select; } -void dwmac_qcom_program_avb_algorithm( +int dwmac_qcom_program_avb_algorithm( struct stmmac_priv *priv, struct ifr_data_struct *req) { struct dwmac_qcom_avb_algorithm l_avb_struct, *u_avb_struct = (struct dwmac_qcom_avb_algorithm *)req->ptr; struct dwmac_qcom_avb_algorithm_params *avb_params; + int ret = 0; ETHQOSDBG("\n"); if (copy_from_user(&l_avb_struct, (void __user *)u_avb_struct, - sizeof(struct dwmac_qcom_avb_algorithm))) + sizeof(struct dwmac_qcom_avb_algorithm))) { ETHQOSERR("Failed to fetch AVB Struct\n"); + return -EFAULT; + } if (priv->speed == SPEED_1000) avb_params = &l_avb_struct.speed1000params; @@ -158,6 +190,7 @@ void dwmac_qcom_program_avb_algorithm( l_avb_struct.qinx); ETHQOSDBG("\n"); + return ret; } unsigned int dwmac_qcom_get_plat_tx_coal_frames( @@ -223,7 +256,7 @@ int ethqos_handle_prv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ret = ppsout_config(pdata, ð_pps_cfg); break; case ETHQOS_AVB_ALGORITHM: - dwmac_qcom_program_avb_algorithm(pdata, &req); + ret = dwmac_qcom_program_avb_algorithm(pdata, &req); break; default: break; @@ -1045,7 +1078,7 @@ static void ethqos_pps_irq_config(struct qcom_ethqos *ethqos) } static const struct of_device_id qcom_ethqos_match[] = { - { .compatible = "qcom,sdxprairie-ethqos", .data = &emac_v2_3_2_por}, + { .compatible = "qcom,sdxprairie-ethqos",}, { .compatible = "qcom,emac-smmu-embedded", }, { .compatible = "qcom,stmmac-ethqos", }, {} @@ -1311,6 +1344,7 @@ static int stmmac_emb_smmu_cb_probe(struct platform_device *pdev) int atomic_ctx = 1; int fast = 1; int bypass = 1; + struct iommu_domain_geometry geometry = {0}; ETHQOSDBG("EMAC EMB SMMU CB probe: smmu pdev=%p\n", pdev); @@ -1325,6 +1359,10 @@ static int stmmac_emb_smmu_cb_probe(struct platform_device *pdev) stmmac_emb_smmu_ctx.va_end = stmmac_emb_smmu_ctx.va_start + stmmac_emb_smmu_ctx.va_size; + geometry.aperture_start = stmmac_emb_smmu_ctx.va_start; + geometry.aperture_end = + stmmac_emb_smmu_ctx.va_start + stmmac_emb_smmu_ctx.va_size; + stmmac_emb_smmu_ctx.smmu_pdev = pdev; if (dma_set_mask(dev, DMA_BIT_MASK(32)) || @@ -1369,6 +1407,19 @@ static int stmmac_emb_smmu_cb_probe(struct platform_device *pdev) goto err_smmu_probe; } ETHQOSDBG("SMMU fast map set\n"); + if (of_property_read_bool(dev->of_node, + "qcom,smmu-geometry")) { + if (iommu_domain_set_attr + (stmmac_emb_smmu_ctx.mapping->domain, + DOMAIN_ATTR_GEOMETRY, + &geometry)) { + ETHQOSERR("Couldn't set DOMAIN_ATTR_GEOMETRY"); + result = -EIO; + goto err_smmu_probe; + } + ETHQOSDBG("SMMU DOMAIN_ATTR_GEOMETRY set\n"); + } + } result = arm_iommu_attach_device(&stmmac_emb_smmu_ctx.smmu_pdev->dev, @@ -1417,9 +1468,9 @@ static int ethqos_update_rgmii_tx_drv_strength(struct qcom_ethqos *ethqos) ETHQOSDBG("tlmm_central_base = 0x%x, size = 0x%x\n", tlmm_central_base, tlmm_central_size); - tlmm_central_base_addr = (unsigned long)ioremap( + tlmm_central_base_addr = ioremap( tlmm_central_base, tlmm_central_size); - if ((void __iomem *)!tlmm_central_base_addr) { + if (!tlmm_central_base_addr) { ETHQOSERR("cannot map dwc_tlmm_central reg memory, aborting\n"); ret = -EIO; goto err_out; @@ -1459,7 +1510,7 @@ static int ethqos_update_rgmii_tx_drv_strength(struct qcom_ethqos *ethqos) err_out: if (tlmm_central_base_addr) - iounmap((void __iomem *)tlmm_central_base_addr); + iounmap(tlmm_central_base_addr); return ret; } @@ -1763,6 +1814,13 @@ static int qcom_ethqos_probe(struct platform_device *pdev) return PTR_ERR(plat_dat); } + if (plat_dat->tx_sched_algorithm == MTL_TX_ALGORITHM_WFQ || + plat_dat->tx_sched_algorithm == MTL_TX_ALGORITHM_DWRR) { + ETHQOSERR("WFO and DWRR TX Algorithm is not supported\n"); + ETHQOSDBG("Set TX Algorithm to default WRR\n"); + plat_dat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR; + } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rgmii"); ethqos->rgmii_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ethqos->rgmii_base)) { @@ -1771,8 +1829,6 @@ static int qcom_ethqos_probe(struct platform_device *pdev) goto err_mem; } - ethqos->por = of_device_get_match_data(&pdev->dev); - ethqos->rgmii_clk = devm_clk_get(&pdev->dev, "rgmii"); if (!ethqos->rgmii_clk) { ret = -ENOMEM; @@ -1880,6 +1936,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev) pethqos = ethqos; ethqos_create_debugfs(ethqos); + qcom_ethqos_read_iomacro_por_values(ethqos); + ndev = dev_get_drvdata(ðqos->pdev->dev); priv = netdev_priv(ndev); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h index 73849621f46ead4b58297c1048dff1b0c4414559..0df87f533ab85a2bd71910297d1b3e0d69b88f86 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h @@ -380,22 +380,9 @@ struct ethqos_emac_por { unsigned int value; }; -static const struct ethqos_emac_por emac_v2_3_0_por[] = { - { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, - { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, - { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x00000000 }, - { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, - { .offset = SDCC_USR_CTL, .value = 0x00010800 }, - { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, -}; - -static const struct ethqos_emac_por emac_v2_3_2_por[] = { - { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, - { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, - { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x80040800 }, - { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, - { .offset = SDCC_USR_CTL, .value = 0x00010800 }, - { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, +struct ethqos_emac_driver_data { + struct ethqos_emac_por *por; + unsigned int num_por; }; struct qcom_ethqos { @@ -415,7 +402,7 @@ struct qcom_ethqos { /* Work struct for handling phy interrupt */ struct work_struct emac_phy_work; - const struct ethqos_emac_por *por; + struct ethqos_emac_por *por; unsigned int num_por; unsigned int emac_ver; @@ -584,7 +571,7 @@ struct dwmac_qcom_avb_algorithm { enum dwmac_qcom_queue_operating_mode op_mode; }; -void dwmac_qcom_program_avb_algorithm( +int dwmac_qcom_program_avb_algorithm( struct stmmac_priv *priv, struct ifr_data_struct *req); unsigned int dwmac_qcom_get_plat_tx_coal_frames( struct sk_buff *skb); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c index adfe4b81525b1df3f114ca9cffaf5de0daa526f2..76aafe7008516f28f3af31b9c5cc700a9da62cb2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c index 90f7899197845f7aa023331a5b0edd3f301e63dd..fc6a346a4b7f982b75f0263c5a9038880c7a59f0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c @@ -95,7 +95,7 @@ static int ethqos_alloc_ipa_tx_queue_struct(struct qcom_ethqos *ethqos) goto err_out_tx_q_alloc_failed; } - eth_ipa_ctx.tx_queue->desc_cnt = IPA_TX_DESC_CNT; + eth_ipa_ctx.tx_queue->desc_cnt = eth_ipa_ctx.ipa_dma_tx_desc_cnt; /* Allocate tx_desc_ptrs */ eth_ipa_ctx.tx_queue->tx_desc_ptrs = @@ -224,7 +224,7 @@ static int ethqos_alloc_ipa_rx_queue_struct(struct qcom_ethqos *ethqos) goto err_out_rx_q_alloc_failed; } - eth_ipa_ctx.rx_queue->desc_cnt = IPA_RX_DESC_CNT; + eth_ipa_ctx.rx_queue->desc_cnt = eth_ipa_ctx.ipa_dma_rx_desc_cnt; /* Allocate rx_desc_ptrs */ eth_ipa_ctx.rx_queue->rx_desc_ptrs = @@ -1664,8 +1664,8 @@ static int ethqos_ipa_create_debugfs(struct qcom_ethqos *ethqos) debugfs_create_file("dma_stats", 0600, ethqos->debugfs_dir, ethqos, &fops_ntn_dma_stats); - if (!eth_ipa->debugfs_suspend_ipa_offload || - IS_ERR(eth_ipa->debugfs_suspend_ipa_offload)) { + if (!eth_ipa->debugfs_dma_stats || + IS_ERR(eth_ipa->debugfs_dma_stats)) { ETHQOSERR("Cannot create debugfs_dma_stats %d\n", (int)eth_ipa->debugfs_dma_stats); goto fail; @@ -2193,11 +2193,29 @@ static int ethqos_ipa_uc_ready(struct qcom_ethqos *pdata) void ethqos_ipa_offload_event_handler(void *data, int ev) { + int ret; ETHQOSDBG("Enter: event=%d\n", ev); if (ev == EV_PROBE_INIT) { eth_ipa_ctx.ethqos = data; mutex_init(ð_ipa_ctx.ipa_lock); + ret = + of_property_read_u32(eth_ipa_ctx.ethqos->pdev->dev.of_node, + "ipa-dma-rx-desc-cnt", + ð_ipa_ctx.ipa_dma_rx_desc_cnt); + if (ret) { + ETHQOSDBG(":resource ipa-dma-rx-desc-cnt not in dt\n"); + eth_ipa_ctx.ipa_dma_rx_desc_cnt = IPA_RX_DESC_CNT; + } + + ret = + of_property_read_u32(eth_ipa_ctx.ethqos->pdev->dev.of_node, + "ipa-dma-tx-desc-cnt", + ð_ipa_ctx.ipa_dma_tx_desc_cnt); + if (ret) { + ETHQOSDBG(":resource ipa-dma-tx-desc-cnt not in dt\n"); + eth_ipa_ctx.ipa_dma_tx_desc_cnt = IPA_TX_DESC_CNT; + } return; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.h index adae4a481aa5c7cd996e0b1d35423422e5ba03f7..ee32f4e2dbfe27228c73289db55ad72816ffd696 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.h @@ -76,8 +76,8 @@ static char * const IPA_OFFLOAD_EVENT_string[] = { #define ETHQOS_ETH_FRAME_LEN_IPA ((1 << 11)) /*IPA can support 2KB max length*/ -#define IPA_TX_DESC_CNT 128 /*Increase TX desc count to 128 for IPA offload*/ -#define IPA_RX_DESC_CNT 128 /*Increase RX desc count to 128 for IPA offload*/ +#define IPA_TX_DESC_CNT 128 /*Default TX desc count to 128 for IPA offload*/ +#define IPA_RX_DESC_CNT 128 /*Default RX desc count to 128 for IPA offload*/ #define BASE_ADDRESS (ethqos->ioaddr) @@ -644,6 +644,9 @@ struct ethqos_prv_ipa_data { phys_addr_t uc_db_tx_addr; u32 ipa_client_hndl; + u32 ipa_dma_tx_desc_cnt; + u32 ipa_dma_rx_desc_cnt; + /* IPA state variables */ /* State of EMAC HW initialization */ bool emac_dev_ready; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index a62128a444a602f3f1fda7a7079bed5deadd4515..149fd0d5e069f61091013bd400d72008926bffa9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -724,6 +724,9 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) /* default */ break; case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII; break; case PHY_INTERFACE_MODE_RMII: diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index 62ccbd47c1db2b60319051718a51fe159d2e7a54..fc1fa0f9f338713da5c6fcfdd19062ced459a91f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -53,7 +53,7 @@ static int sun7i_gmac_init(struct platform_device *pdev, void *priv) * rate, which then uses the auto-reparenting feature of the * clock driver, and enabling/disabling the clock. */ - if (gmac->interface == PHY_INTERFACE_MODE_RGMII) { + if (phy_interface_mode_is_rgmii(gmac->interface)) { clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE); clk_prepare_enable(gmac->tx_clk); gmac->clk_enabled = 1; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index ed79bdbfc4f6f67c306c3bdca954645edf71c16e..aa56a6258ba9207934475af858b154b0caf7b7e1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -229,6 +229,8 @@ enum power_event { #define MTL_CHAN_RX_DEBUG(x) (MTL_CHANX_BASE_ADDR(x) + 0x38) #define MTL_OP_MODE_RSF BIT(5) +#define MTL_OP_MODE_TXQEN_MASK GENMASK(3, 2) +#define MTL_OP_MODE_TXQEN_AV BIT(2) #define MTL_OP_MODE_TXQEN BIT(3) #define MTL_OP_MODE_TSF BIT(1) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index c3414bd93d4ac6d0f8eb4dca6e7e161fc588736e..3bbe38980cb5dc9782ec807c61fe097e324640c3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -194,6 +194,8 @@ static void dwmac4_prog_mtl_tx_algorithms(struct mac_device_info *hw, default: break; } + + writel_relaxed(value, ioaddr + MTL_OPERATION_MODE); } static void dwmac4_set_mtl_tx_queue_weight(struct mac_device_info *hw, @@ -441,7 +443,7 @@ static void dwmac4_set_filter(struct mac_device_info *hw, } /* Handle multiple unicast addresses */ - if (netdev_uc_count(dev) > GMAC_MAX_PERFECT_ADDRESSES) { + if (netdev_uc_count(dev) > hw->unicast_filter_entries) { /* Switch to promiscuous mode if more than 128 addrs * are required */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 2bec6118a062064bdb38fbb667b1acbca10388a1..9cdc06a3a113e333bfb2e3074d5a55edbd92550d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -191,7 +191,7 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 number_chan) } static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode, - u32 channel, int fifosz) + u32 channel, int fifosz, u8 qmode) { unsigned int rqs = fifosz / 256 - 1; u32 mtl_rx_op, mtl_rx_int; @@ -218,8 +218,10 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode, mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK; mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT; - /* enable flow control only if each channel gets 4 KiB or more FIFO */ - if (fifosz >= 4096) { + /* Enable flow control only if each channel gets 4 KiB or more FIFO and + * only if channel is not an AVB channel. + */ + if (fifosz >= 4096 && qmode != MTL_QUEUE_AVB) { unsigned int rfd, rfa; mtl_rx_op |= MTL_OP_MODE_EHFC; @@ -271,7 +273,7 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode, } static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode, - u32 channel, int fifosz) + u32 channel, int fifosz, u8 qmode) { u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel)); unsigned int tqs = fifosz / 256 - 1; @@ -311,7 +313,11 @@ static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode, * reflect the available fifo size per queue (total fifo size / number * of enabled queues). */ - mtl_tx_op |= MTL_OP_MODE_TXQEN; + mtl_tx_op &= ~MTL_OP_MODE_TXQEN_MASK; + if (qmode != MTL_QUEUE_AVB) + mtl_tx_op |= MTL_OP_MODE_TXQEN; + else + mtl_tx_op |= MTL_OP_MODE_TXQEN_AV; mtl_tx_op &= ~MTL_OP_MODE_TQS_MASK; mtl_tx_op |= tqs << MTL_OP_MODE_TQS_SHIFT; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index f6ba02ef92e2d451dd8ccda50631056336bfc794..828c0d62c43af4743ebf541f55b3eadc25626ac3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -51,8 +51,7 @@ #include #include "dwmac1000.h" - -#define STMMAC_ALIGN(x) __ALIGN_KERNEL(x, SMP_CACHE_BYTES) +#define STMMAC_ALIGN(x) ALIGN(ALIGN(x, SMP_CACHE_BYTES), 16) #define TSO_MAX_BUFF_SIZE (SZ_16K - 1) /* Module parameters */ @@ -1126,7 +1125,9 @@ static int stmmac_set_bfsize(int mtu, int bufsize) { int ret = bufsize; - if (mtu >= BUF_SIZE_4KiB) + if (mtu >= BUF_SIZE_8KiB) + ret = BUF_SIZE_16KiB; + else if (mtu >= BUF_SIZE_4KiB) ret = BUF_SIZE_8KiB; else if (mtu >= BUF_SIZE_2KiB) ret = BUF_SIZE_4KiB; @@ -1866,6 +1867,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) u32 rxmode = 0; u32 chan = 0; u32 mtl_rx_int; + u8 qmode = 0; if (rxfifosz == 0) rxfifosz = priv->dma_cap.rx_fifo_size; @@ -1898,8 +1900,10 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) /* configure all channels */ if (priv->synopsys_id >= DWMAC_CORE_4_00) { for (chan = 0; chan < rx_channels_count; chan++) { + qmode = priv->plat->rx_queues_cfg[chan].mode_to_use; + priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan, - rxfifosz); + rxfifosz, qmode); if (priv->rx_queue[chan].skip_sw) { mtl_rx_int = readl_relaxed(priv->ioaddr + (0x00000d00 + 0x2c)); @@ -1909,9 +1913,12 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) } } - for (chan = 0; chan < tx_channels_count; chan++) + for (chan = 0; chan < tx_channels_count; chan++) { + qmode = priv->plat->tx_queues_cfg[chan].mode_to_use; + priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan, - txfifosz); + txfifosz, qmode); + } } else { priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode, rxfifosz); @@ -2094,6 +2101,8 @@ static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan) static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode, u32 rxmode, u32 chan) { + u8 rxqmode = priv->plat->rx_queues_cfg[chan].mode_to_use; + u8 txqmode = priv->plat->tx_queues_cfg[chan].mode_to_use; u32 rx_channels_count = priv->plat->rx_queues_to_use; u32 tx_channels_count = priv->plat->tx_queues_to_use; int rxfifosz = priv->plat->rx_fifo_size; @@ -2110,9 +2119,9 @@ static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode, if (priv->synopsys_id >= DWMAC_CORE_4_00) { priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan, - rxfifosz); + rxfifosz, rxqmode); priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan, - txfifosz); + txfifosz, txqmode); } else { priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode, rxfifosz); @@ -3799,12 +3808,24 @@ static void stmmac_set_rx_mode(struct net_device *dev) static int stmmac_change_mtu(struct net_device *dev, int new_mtu) { struct stmmac_priv *priv = netdev_priv(dev); + int txfifosz = priv->plat->tx_fifo_size; + + if (txfifosz == 0) + txfifosz = priv->dma_cap.tx_fifo_size; + + txfifosz /= priv->plat->tx_queues_to_use; if (netif_running(dev)) { netdev_err(priv->dev, "must be stopped to change its MTU\n"); return -EBUSY; } + new_mtu = STMMAC_ALIGN(new_mtu); + + /* If condition true, FIFO is too small or MTU too large */ + if ((txfifosz < new_mtu) || (new_mtu > BUF_SIZE_16KiB)) + return -EINVAL; + dev->mtu = new_mtu; netdev_update_features(dev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index e471a903c6543f8f29c817cc0f7c8b5c474e3cec..1c1d6a9428229b407cb1c96e739f1e1a39105cc2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -154,7 +154,7 @@ static int stmmac_enable(struct ptp_clock_info *ptp, /* structure describing a PTP hardware clock */ static const struct ptp_clock_info stmmac_ptp_clock_ops = { .owner = THIS_MODULE, - .name = "stmmac_ptp_clock", + .name = "stmmac ptp", .max_adj = 62500000, .n_alarm = 0, .n_ext_ts = 0, diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 9ccd08a051f6a4699fbd9057cf57c6bcf6d40ab7..1152d74433f6e5c395345d1894cc82cbe52abd05 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1574,7 +1574,7 @@ static int axienet_probe(struct platform_device *pdev) } } else { lp->phy_mode = of_get_phy_mode(pdev->dev.of_node); - if (lp->phy_mode < 0) { + if ((int)lp->phy_mode < 0) { ret = -EINVAL; goto free_netdev; } diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 35905e9ee9ecf940a1500148c624c306672929ed..3840f21dd635aa805195625b0e6d146e2700634a 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -807,19 +807,21 @@ static struct sock *gtp_encap_enable_socket(int fd, int type, return NULL; } - if (sock->sk->sk_protocol != IPPROTO_UDP) { + sk = sock->sk; + if (sk->sk_protocol != IPPROTO_UDP || + sk->sk_type != SOCK_DGRAM || + (sk->sk_family != AF_INET && sk->sk_family != AF_INET6)) { pr_debug("socket fd=%d not UDP\n", fd); sk = ERR_PTR(-EINVAL); goto out_sock; } - lock_sock(sock->sk); - if (sock->sk->sk_user_data) { + lock_sock(sk); + if (sk->sk_user_data) { sk = ERR_PTR(-EBUSY); - goto out_sock; + goto out_rel_sock; } - sk = sock->sk; sock_hold(sk); tuncfg.sk_user_data = gtp; @@ -829,8 +831,9 @@ static struct sock *gtp_encap_enable_socket(int fd, int type, setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg); -out_sock: +out_rel_sock: release_sock(sock->sk); +out_sock: sockfd_put(sock); return sk; } diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 0f07b5978fa1afd99348de486caaf985ce6ae1dc..fc794e69e6a1028ea4638ff923404500e938e933 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -179,7 +179,6 @@ struct rndis_device { u8 hw_mac_adr[ETH_ALEN]; u8 rss_key[NETVSC_HASH_KEYLEN]; - u16 rx_table[ITAB_NUM]; }; @@ -741,6 +740,8 @@ struct net_device_context { u32 tx_table[VRSS_SEND_TAB_SIZE]; + u16 rx_table[ITAB_NUM]; + /* Ethtool settings */ bool udp4_l4_hash; bool udp6_l4_hash; diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 5a44b9795266902d419dc70972d388a52b46d967..14451e14d99dc9427fb6a8de1e31a84bbe246104 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -282,9 +282,9 @@ static inline u32 netvsc_get_hash( else if (flow.basic.n_proto == htons(ETH_P_IPV6)) hash = jhash2((u32 *)&flow.addrs.v6addrs, 8, hashrnd); else - hash = 0; + return 0; - skb_set_hash(skb, hash, PKT_HASH_TYPE_L3); + __skb_set_sw_hash(skb, hash, false); } return hash; @@ -802,8 +802,7 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, skb->protocol == htons(ETH_P_IP)) netvsc_comp_ipcsum(skb); - /* Do L4 checksum offload if enabled and present. - */ + /* Do L4 checksum offload if enabled and present. */ if (csum_info && (net->features & NETIF_F_RXCSUM)) { if (csum_info->receive.tcp_checksum_succeeded || csum_info->receive.udp_checksum_succeeded) @@ -1528,7 +1527,7 @@ static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, rndis_dev = ndev->extension; if (indir) { for (i = 0; i < ITAB_NUM; i++) - indir[i] = rndis_dev->rx_table[i]; + indir[i] = ndc->rx_table[i]; } if (key) @@ -1558,7 +1557,7 @@ static int netvsc_set_rxfh(struct net_device *dev, const u32 *indir, return -EINVAL; for (i = 0; i < ITAB_NUM; i++) - rndis_dev->rx_table[i] = indir[i]; + ndc->rx_table[i] = indir[i]; } if (!key) { @@ -1840,6 +1839,12 @@ static rx_handler_result_t netvsc_vf_handle_frame(struct sk_buff **pskb) struct netvsc_vf_pcpu_stats *pcpu_stats = this_cpu_ptr(ndev_ctx->vf_stats); + skb = skb_share_check(skb, GFP_ATOMIC); + if (unlikely(!skb)) + return RX_HANDLER_CONSUMED; + + *pskb = skb; + skb->dev = ndev; u64_stats_update_begin(&pcpu_stats->syncp); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index fc1d5e14d83e9fb25feaf6eca2dd8adf38c9ebc3..aa0bbffe490059ef7d243007a7fdfa8032f6cbdd 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -715,6 +715,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev, const u8 *rss_key, u16 flag) { struct net_device *ndev = rdev->ndev; + struct net_device_context *ndc = netdev_priv(ndev); struct rndis_request *request; struct rndis_set_request *set; struct rndis_set_complete *set_complete; @@ -754,7 +755,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev, /* Set indirection table entries */ itab = (u32 *)(rssp + 1); for (i = 0; i < ITAB_NUM; i++) - itab[i] = rdev->rx_table[i]; + itab[i] = ndc->rx_table[i]; /* Set hask key values */ keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset); @@ -1204,6 +1205,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, struct netvsc_device_info *device_info) { struct net_device *net = hv_get_drvdata(dev); + struct net_device_context *ndc = netdev_priv(net); struct netvsc_device *net_device; struct rndis_device *rndis_device; struct ndis_recv_scale_cap rsscap; @@ -1286,9 +1288,11 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, /* We will use the given number of channels if available. */ net_device->num_chn = min(net_device->max_chn, device_info->num_chn); - for (i = 0; i < ITAB_NUM; i++) - rndis_device->rx_table[i] = ethtool_rxfh_indir_default( + if (!netif_is_rxfh_configured(net)) { + for (i = 0; i < ITAB_NUM; i++) + ndc->rx_table[i] = ethtool_rxfh_indir_default( i, net_device->num_chn); + } atomic_set(&net_device->open_chn, 1); vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open); @@ -1327,8 +1331,6 @@ void rndis_filter_device_remove(struct hv_device *dev, /* Halt and release the rndis device */ rndis_filter_halt_device(rndis_dev); - net_dev->extension = NULL; - netvsc_device_remove(dev); } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 8d5f88a538fcf73bced509ac150a6090ef738e3e..ab539136d5bff8770b38f2547d92f0e4a9226480 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -515,10 +515,11 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) const struct macvlan_dev *dest; if (vlan->mode == MACVLAN_MODE_BRIDGE) { - const struct ethhdr *eth = (void *)skb->data; + const struct ethhdr *eth = skb_eth_hdr(skb); /* send to other bridge ports directly */ if (is_multicast_ether_addr(eth->h_dest)) { + skb_reset_mac_header(skb); macvlan_broadcast(skb, port, dev, MACVLAN_MODE_BRIDGE); goto xmit_world; } diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index eb51672106811e35ee0a7b3f0578560e16bc3670..3ab2eb677a599d9bb6aba0750f808ea73d639bca 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -67,11 +67,11 @@ static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num) do { s = read_seqcount_begin(&fp->seqcount); /* Issue callback if user registered it. */ - if (fp->link_update) { + if (fp->link_update) fp->link_update(fp->phydev->attached_dev, &fp->status); - fixed_phy_update(fp); - } + /* Check the GPIO for change in status */ + fixed_phy_update(fp); state = fp->status; } while (read_seqcount_retry(&fp->seqcount, s)); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 5acd63eac5d96bd30f5c7679d1b9075509409047..0a85141d8e7691088641a26358a815db1ec7f5f3 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -76,7 +76,7 @@ static LIST_HEAD(phy_fixup_list); static DEFINE_MUTEX(phy_fixup_lock); #ifdef CONFIG_PM -static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) +static bool mdio_bus_phy_may_suspend(struct phy_device *phydev, bool suspend) { struct device_driver *drv = phydev->mdio.dev.driver; struct phy_driver *phydrv = to_phy_driver(drv); @@ -88,10 +88,11 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) /* PHY not attached? May suspend if the PHY has not already been * suspended as part of a prior call to phy_disconnect() -> * phy_detach() -> phy_suspend() because the parent netdev might be the - * MDIO bus driver and clock gated at this point. + * MDIO bus driver and clock gated at this point. Also may resume if + * PHY is not attached. */ if (!netdev) - return !phydev->suspended; + return suspend ? !phydev->suspended : phydev->suspended; /* Don't suspend PHY if the attached netdev parent may wakeup. * The parent may point to a PCI device, as in tg3 driver. @@ -121,7 +122,7 @@ static int mdio_bus_phy_suspend(struct device *dev) if (phydev->attached_dev && phydev->adjust_link) phy_stop_machine(phydev); - if (!mdio_bus_phy_may_suspend(phydev)) + if (!mdio_bus_phy_may_suspend(phydev, true)) return 0; return phy_suspend(phydev); @@ -132,7 +133,7 @@ static int mdio_bus_phy_resume(struct device *dev) struct phy_device *phydev = to_phy_device(dev); int ret; - if (!mdio_bus_phy_may_suspend(phydev)) + if (!mdio_bus_phy_may_suspend(phydev, false)) goto no_resume; ret = phy_resume(phydev); diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index d6dc00b4ba5520fdb1175cca94b197dcc7d3feb4..b07f367abd9157ee2416af634d8853cb6af9f7d7 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -452,9 +452,16 @@ static void slip_transmit(struct work_struct *work) */ static void slip_write_wakeup(struct tty_struct *tty) { - struct slip *sl = tty->disc_data; + struct slip *sl; + + rcu_read_lock(); + sl = rcu_dereference(tty->disc_data); + if (!sl) + goto out; schedule_work(&sl->tx_work); +out: + rcu_read_unlock(); } static void sl_tx_timeout(struct net_device *dev) @@ -886,10 +893,11 @@ static void slip_close(struct tty_struct *tty) return; spin_lock_bh(&sl->lock); - tty->disc_data = NULL; + rcu_assign_pointer(tty->disc_data, NULL); sl->tty = NULL; spin_unlock_bh(&sl->lock); + synchronize_rcu(); flush_work(&sl->tx_work); /* VSV = very important to remove timers */ diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 3f10330206af851a3aa727173fecdc2de1481705..9c6246c3d3d1c24454f5d91415d97203f824431d 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -497,7 +498,7 @@ static int lan78xx_read_stats(struct lan78xx_net *dev, } } else { netdev_warn(dev->net, - "Failed to read stat ret = 0x%x", ret); + "Failed to read stat ret = %d", ret); } kfree(stats); @@ -2602,11 +2603,6 @@ static int lan78xx_stop(struct net_device *net) return 0; } -static int lan78xx_linearize(struct sk_buff *skb) -{ - return skb_linearize(skb); -} - static struct sk_buff *lan78xx_tx_prep(struct lan78xx_net *dev, struct sk_buff *skb, gfp_t flags) { @@ -2617,8 +2613,10 @@ static struct sk_buff *lan78xx_tx_prep(struct lan78xx_net *dev, return NULL; } - if (lan78xx_linearize(skb) < 0) + if (skb_linearize(skb)) { + dev_kfree_skb_any(skb); return NULL; + } tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN_MASK_) | TX_CMD_A_FCS_; @@ -3526,6 +3524,19 @@ static void lan78xx_tx_timeout(struct net_device *net) tasklet_schedule(&dev->bh); } +static netdev_features_t lan78xx_features_check(struct sk_buff *skb, + struct net_device *netdev, + netdev_features_t features) +{ + if (skb->len + TX_OVERHEAD > MAX_SINGLE_PACKET_SIZE) + features &= ~NETIF_F_GSO_MASK; + + features = vlan_features_check(skb, features); + features = vxlan_features_check(skb, features); + + return features; +} + static const struct net_device_ops lan78xx_netdev_ops = { .ndo_open = lan78xx_open, .ndo_stop = lan78xx_stop, @@ -3539,6 +3550,7 @@ static const struct net_device_ops lan78xx_netdev_ops = { .ndo_set_features = lan78xx_set_features, .ndo_vlan_rx_add_vid = lan78xx_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = lan78xx_vlan_rx_kill_vid, + .ndo_features_check = lan78xx_features_check, }; static void lan78xx_stat_monitor(unsigned long param) @@ -3612,6 +3624,7 @@ static int lan78xx_probe(struct usb_interface *intf, /* MTU range: 68 - 9000 */ netdev->max_mtu = MAX_SINGLE_PACKET_SIZE; + netif_set_gso_max_size(netdev, MAX_SINGLE_PACKET_SIZE - MAX_HEADER); dev->ep_blkin = (intf->cur_altsetting)->endpoint + 0; dev->ep_blkout = (intf->cur_altsetting)->endpoint + 1; diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 4a984b76a60ec6a420694b1e5fe64df3aed48088..db70d4c5778a621293701873977491137b350140 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -999,6 +999,7 @@ static const struct usb_device_id products[] = { {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ + {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ /* 3. Combined interface devices matching on interface number */ {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 6a86a03c5e95af76c322a960e05d43a3c902d4f0..a7f9c1886bd4c42d946aa4b755606af5729e9598 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -5158,6 +5158,9 @@ static int rtl8152_probe(struct usb_interface *intf, return -ENODEV; } + if (intf->cur_altsetting->desc.bNumEndpoints < 3) + return -ENODEV; + usb_reset_device(udev); netdev = alloc_etherdev(sizeof(struct r8152)); if (!netdev) { @@ -5241,6 +5244,11 @@ static int rtl8152_probe(struct usb_interface *intf, intf->needs_remote_wakeup = 1; + if (!rtl_can_wakeup(tp)) + __rtl_set_wol(tp, 0); + else + tp->saved_wolopts = __rtl_get_wol(tp); + tp->rtl_ops.init(tp); queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); set_ethernet_addr(tp); @@ -5254,10 +5262,6 @@ static int rtl8152_probe(struct usb_interface *intf, goto out1; } - if (!rtl_can_wakeup(tp)) - __rtl_set_wol(tp, 0); - - tp->saved_wolopts = __rtl_get_wol(tp); if (tp->saved_wolopts) device_set_wakeup_enable(&udev->dev, true); else diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 153a81ece9fe48fdf61b165ea54a09ed9be69b0c..4d97a7b5fe3cabc074a28b20dd9a32afd686ded7 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2216,7 +2216,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, skb_dst_update_pmtu(skb, mtu); } - tos = ip_tunnel_ecn_encap(tos, old_iph, skb); + tos = ip_tunnel_ecn_encap(RT_TOS(tos), old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), vni, md, flags, udp_sum); @@ -2257,7 +2257,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, skb_dst_update_pmtu(skb, mtu); } - tos = ip_tunnel_ecn_encap(tos, old_iph, skb); + tos = ip_tunnel_ecn_encap(RT_TOS(tos), old_iph, skb); ttl = ttl ? : ip6_dst_hoplimit(ndst); skb_scrub_packet(skb, xnet); err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), @@ -3494,7 +3494,6 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], struct vxlan_rdst *dst = &vxlan->default_dst; struct vxlan_rdst old_dst; struct vxlan_config conf; - struct vxlan_fdb *f = NULL; int err; err = vxlan_nl2conf(tb, data, @@ -3520,19 +3519,19 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], old_dst.remote_ifindex, 0); if (!vxlan_addr_any(&dst->remote_ip)) { - err = vxlan_fdb_create(vxlan, all_zeros_mac, + err = vxlan_fdb_update(vxlan, all_zeros_mac, &dst->remote_ip, NUD_REACHABLE | NUD_PERMANENT, + NLM_F_APPEND | NLM_F_CREATE, vxlan->cfg.dst_port, dst->remote_vni, dst->remote_vni, dst->remote_ifindex, - NTF_SELF, &f); + NTF_SELF); if (err) { spin_unlock_bh(&vxlan->hash_lock); return err; } - vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH); } spin_unlock_bh(&vxlan->hash_lock); } diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 289dff262948df9cce1d7a723e3c83b6a3e3d71e..571a1ff8f81f2606ab24036af373546251d7b65e 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -76,7 +76,7 @@ static struct ucc_tdm_info utdm_primary_info = { }, }; -static struct ucc_tdm_info utdm_info[MAX_HDLC_NUM]; +static struct ucc_tdm_info utdm_info[UCC_MAX_NUM]; static int uhdlc_init(struct ucc_hdlc_private *priv) { diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 236c625380368affa00c5c65bbed1c3563ffa0b6..1eb329fc724137db204b93df902e2ce3c3e5f145 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -711,7 +711,7 @@ static netdev_tx_t sdla_transmit(struct sk_buff *skb, spin_lock_irqsave(&sdla_lock, flags); SDLA_WINDOW(dev, addr); - pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK)); + pbuf = (void *)(dev->mem_start + (addr & SDLA_ADDR_MASK)); __sdla_write(dev, pbuf->buf_addr, skb->data, skb->len); SDLA_WINDOW(dev, addr); pbuf->opp_flag = 1; diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c index b0dba35a8ad2ae94e4cf89d78767156616fee59c..dc6fe93ce71f65e9e60491fbf4cc45ecde6174a2 100644 --- a/drivers/net/wimax/i2400m/op-rfkill.c +++ b/drivers/net/wimax/i2400m/op-rfkill.c @@ -147,6 +147,7 @@ int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev, error_alloc: d_fnend(4, dev, "(wimax_dev %p state %d) = %d\n", wimax_dev, state, result); + kfree(cmd); return result; } diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index c0173883578d88e259f2181049d85a4f8774b408..eeeb6156905a02a9bd83577e885ac92e02a08066 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -392,16 +392,11 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar, struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data; bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT; enum ath10k_htc_ep_id eid; - u16 payload_len; u8 *trailer; int ret; - payload_len = le16_to_cpu(htc_hdr->len); - skb->len = payload_len + sizeof(struct ath10k_htc_hdr); - if (trailer_present) { - trailer = skb->data + sizeof(*htc_hdr) + - payload_len - htc_hdr->trailer_len; + trailer = skb->data + skb->len - htc_hdr->trailer_len; eid = pipe_id_to_eid(htc_hdr->eid); @@ -635,13 +630,31 @@ static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar, { struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); struct sk_buff *skb = pkt->skb; + struct ath10k_htc_hdr *htc_hdr; int ret; ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr, skb->data, pkt->alloc_len); + if (ret) + goto out; + + /* Update actual length. The original length may be incorrect, + * as the FW will bundle multiple packets as long as their sizes + * fit within the same aligned length (pkt->alloc_len). + */ + htc_hdr = (struct ath10k_htc_hdr *)skb->data; + pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr); + if (pkt->act_len > pkt->alloc_len) { + ath10k_warn(ar, "rx packet too large (%zu > %zu)\n", + pkt->act_len, pkt->alloc_len); + ret = -EMSGSIZE; + goto out; + } + + skb_put(skb, pkt->act_len); + +out: pkt->status = ret; - if (!ret) - skb_put(skb, pkt->act_len); return ret; } diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index 03a7f60cc1631b6e453ed8de993b60b4437f758a..c59205ef8f30182a0b83c2e3727545c596e55f42 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -454,6 +454,7 @@ static int ath10k_usb_hif_tx_sg(struct ath10k *ar, u8 pipe_id, ath10k_dbg(ar, ATH10K_DBG_USB_BULK, "usb bulk transmit failed: %d\n", ret); usb_unanchor_urb(urb); + usb_free_urb(urb); ret = -EINVAL; goto err_free_urb_to_pipe; } diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c index 6e236a4854311cc972b97ccda8e782392bf9a2e3..71b4888b30e717fd590288f530e64837aec44afd 100644 --- a/drivers/net/wireless/ath/ath9k/dynack.c +++ b/drivers/net/wireless/ath/ath9k/dynack.c @@ -300,9 +300,9 @@ void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an) an->ackto = ackto; - spin_lock(&da->qlock); + spin_lock_bh(&da->qlock); list_add_tail(&an->list, &da->nodes); - spin_unlock(&da->qlock); + spin_unlock_bh(&da->qlock); } EXPORT_SYMBOL(ath_dynack_node_init); @@ -316,9 +316,9 @@ void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an) { struct ath_dynack *da = &ah->dynack; - spin_lock(&da->qlock); + spin_lock_bh(&da->qlock); list_del(&an->list); - spin_unlock(&da->qlock); + spin_unlock_bh(&da->qlock); } EXPORT_SYMBOL(ath_dynack_node_deinit); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index c5f4dd808745a639556d8b0f10bc0af50ddbdaff..6f669166c2632882280263e29da13a463908a0e4 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1214,7 +1214,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context) static int send_eject_command(struct usb_interface *interface) { struct usb_device *udev = interface_to_usbdev(interface); - struct usb_host_interface *iface_desc = &interface->altsetting[0]; + struct usb_host_interface *iface_desc = interface->cur_altsetting; struct usb_endpoint_descriptor *endpoint; unsigned char *cmd; u8 bulk_out_ep; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index be855aa32154d5687bd70ece0fe5678851b49cb0..2eb5fe7367c6f5ccbeb08eb6b444bf30629469e4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1333,7 +1333,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) goto fail; } - desc = &intf->altsetting[0].desc; + desc = &intf->cur_altsetting->desc; if ((desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || (desc->bInterfaceSubClass != 2) || (desc->bInterfaceProtocol != 0xff)) { @@ -1346,7 +1346,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) num_of_eps = desc->bNumEndpoints; for (ep = 0; ep < num_of_eps; ep++) { - endpoint = &intf->altsetting[0].endpoint[ep].desc; + endpoint = &intf->cur_altsetting->endpoint[ep].desc; endpoint_num = usb_endpoint_num(endpoint); if (!usb_endpoint_xfer_bulk(endpoint)) continue; diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index fc49255bab009f2e4bf77257b94e169574393cdf..f3f20abbe2696a057d724ffecea87937676be57e 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -7788,16 +7788,8 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { case AIROGVLIST: ridcode = RID_APLIST; break; case AIROGDRVNAM: ridcode = RID_DRVNAME; break; case AIROGEHTENC: ridcode = RID_ETHERENCAP; break; - case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; - /* Only super-user can read WEP keys */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - break; - case AIROGWEPKNV: ridcode = RID_WEP_PERM; - /* Only super-user can read WEP keys */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - break; + case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; break; + case AIROGWEPKNV: ridcode = RID_WEP_PERM; break; case AIROGSTAT: ridcode = RID_STATUS; break; case AIROGSTATSD32: ridcode = RID_STATSDELTA; break; case AIROGSTATSC32: ridcode = RID_STATS; break; @@ -7811,7 +7803,13 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { return -EINVAL; } - if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) + if (ridcode == RID_WEP_TEMP || ridcode == RID_WEP_PERM) { + /* Only super-user can read WEP keys */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + } + + if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL) return -ENOMEM; PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1); diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 315cb9e310aed46ade5d36aefdb6c79dc8fd65e5..70f6376afd14ca6fdd9b47f5ae1afd4f8e24564d 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -851,26 +851,22 @@ static int cnss_qca6174_ramdump(struct cnss_pci_data *pci_priv) static int cnss_pci_force_wake_get(struct cnss_pci_data *pci_priv) { struct device *dev = &pci_priv->pci_dev->dev; - u32 timeout = 0; int ret; - ret = cnss_pci_force_wake_request(dev); + ret = cnss_pci_force_wake_request_sync(dev, + FORCE_WAKE_DELAY_TIMEOUT_US); if (ret) { - cnss_pr_err("Failed to request force wake\n"); + if (ret != -EAGAIN) + cnss_pr_err("Failed to request force wake\n"); return ret; } - while (!cnss_pci_is_device_awake(dev) && - timeout <= FORCE_WAKE_DELAY_TIMEOUT_US) { - usleep_range(FORCE_WAKE_DELAY_MIN_US, FORCE_WAKE_DELAY_MAX_US); - timeout += FORCE_WAKE_DELAY_MAX_US; - } - - if (cnss_pci_is_device_awake(dev) != true) { - cnss_pr_err("Timed out to request force wake\n"); - cnss_pci_force_wake_release(dev); - return -ETIMEDOUT; - } + /* If device's M1 state-change event races here, it can be ignored, + * as the device is expected to immediately move from M2 to M0 + * without entering low power state. + */ + if (cnss_pci_is_device_awake(dev) != true) + cnss_pr_warn("MHI not in M0, while reg still accessible\n"); return 0; } @@ -1972,6 +1968,31 @@ int cnss_pm_request_resume(struct cnss_pci_data *pci_priv) return pm_request_resume(&pci_dev->dev); } +int cnss_pci_force_wake_request_sync(struct device *dev, int timeout_us) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + struct cnss_plat_data *plat_priv; + struct mhi_controller *mhi_ctrl; + + if (pci_priv->device_id != QCA6390_DEVICE_ID) + return 0; + + mhi_ctrl = pci_priv->mhi_ctrl; + if (!mhi_ctrl) + return -EINVAL; + + plat_priv = pci_priv->plat_priv; + if (!plat_priv) + return -ENODEV; + + if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) + return -EAGAIN; + + return mhi_device_get_sync_atomic(mhi_ctrl->mhi_dev, timeout_us); +} +EXPORT_SYMBOL(cnss_pci_force_wake_request_sync); + int cnss_pci_force_wake_request(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 4650b9e5da2bc8d8c89318486e248ca37b4f838c..ba9e7bfeca2c8921ce76ad3904a96a75d6a26e77 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -532,6 +532,7 @@ static struct scatterlist *alloc_sgtable(int size) if (new_page) __free_page(new_page); } + kfree(table); return NULL; } alloc_size = min_t(int, size, PAGE_SIZE); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 78228f870f8f5bcc0df429f8ededbde8b0342b36..754dcc1c1f4007a6fe899d03898744c6784f032a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -107,12 +107,12 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) int i; struct iwl_rss_config_cmd cmd = { .flags = cpu_to_le32(IWL_RSS_ENABLE), - .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP | - IWL_RSS_HASH_TYPE_IPV4_UDP | - IWL_RSS_HASH_TYPE_IPV4_PAYLOAD | - IWL_RSS_HASH_TYPE_IPV6_TCP | - IWL_RSS_HASH_TYPE_IPV6_UDP | - IWL_RSS_HASH_TYPE_IPV6_PAYLOAD, + .hash_mask = BIT(IWL_RSS_HASH_TYPE_IPV4_TCP) | + BIT(IWL_RSS_HASH_TYPE_IPV4_UDP) | + BIT(IWL_RSS_HASH_TYPE_IPV4_PAYLOAD) | + BIT(IWL_RSS_HASH_TYPE_IPV6_TCP) | + BIT(IWL_RSS_HASH_TYPE_IPV6_UDP) | + BIT(IWL_RSS_HASH_TYPE_IPV6_PAYLOAD), }; if (mvm->trans->num_rx_queues == 1) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 7fb8bbaf21420f24fa987d1d10b3fd4dd97d1d6e..1a12e829e98b06b152013d1a844c8a91f3874d73 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -871,12 +871,12 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; rx_status->flag |= RX_FLAG_AMPDU_DETAILS; - rx_status->ampdu_reference = mvm->ampdu_ref; /* toggle is switched whenever new aggregation starts */ if (toggle_bit != mvm->ampdu_toggle) { mvm->ampdu_ref++; mvm->ampdu_toggle = toggle_bit; } + rx_status->ampdu_reference = mvm->ampdu_ref; } rcu_read_lock(); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 0cfdbaa2af3a774df050953e01cbc31f90b51f3d..684c0f65a0528a6bcb46b17276a8b0a64892ff46 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2417,7 +2417,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data; u16 normalized_ssn; - int txq_id; + u16 txq_id; int ret; if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) @@ -2452,17 +2452,24 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, */ txq_id = mvmsta->tid_data[tid].txq_id; if (txq_id == IWL_MVM_INVALID_QUEUE) { - txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, - IWL_MVM_DQA_MIN_DATA_QUEUE, - IWL_MVM_DQA_MAX_DATA_QUEUE); - if (txq_id < 0) { - ret = txq_id; + ret = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, + IWL_MVM_DQA_MIN_DATA_QUEUE, + IWL_MVM_DQA_MAX_DATA_QUEUE); + if (ret < 0) { IWL_ERR(mvm, "Failed to allocate agg queue\n"); goto release_locks; } + txq_id = ret; + /* TXQ hasn't yet been enabled, so mark it only as reserved */ mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_RESERVED; + } else if (WARN_ON(txq_id >= IWL_MAX_HW_QUEUES)) { + ret = -ENXIO; + IWL_ERR(mvm, "tid_id %d out of range (0, %d)!\n", + tid, IWL_MAX_HW_QUEUES - 1); + goto out; + } else if (unlikely(mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_SHARED)) { ret = -ENXIO; diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c index 56f6e3b71f485daa3996628742ece1462ef1353b..95015d74b1c0e2311912514bd7a0c3d5ea7f3528 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c @@ -1613,9 +1613,9 @@ static int ezusb_probe(struct usb_interface *interface, /* set up the endpoint information */ /* check out the endpoints */ - iface_desc = &interface->altsetting[0].desc; + iface_desc = &interface->cur_altsetting->desc; for (i = 0; i < iface_desc->bNumEndpoints; ++i) { - ep = &interface->altsetting[0].endpoint[i].desc; + ep = &interface->cur_altsetting->endpoint[i].desc; if (usb_endpoint_is_bulk_in(ep)) { /* we found a bulk in endpoint */ diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 9f3a7b512673596d10457e05ef69eb705c8c5f22..4ffc188d2ffd315f33637fdc69a410545e01af7d 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -273,6 +273,10 @@ add_ie_rates(u8 *tlv, const u8 *ie, int *nrates) int hw, ap, ap_max = ie[1]; u8 hw_rate; + if (ap_max > MAX_RATES) { + lbs_deb_assoc("invalid rates\n"); + return tlv; + } /* Advance past IE header */ ie += 2; @@ -1720,6 +1724,9 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, struct cmd_ds_802_11_ad_hoc_join cmd; u8 preamble = RADIO_PREAMBLE_SHORT; int ret = 0; + int hw, i; + u8 rates_max; + u8 *rates; /* TODO: set preamble based on scan result */ ret = lbs_set_radio(priv, preamble, 1); @@ -1778,9 +1785,12 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, if (!rates_eid) { lbs_add_rates(cmd.bss.rates); } else { - int hw, i; - u8 rates_max = rates_eid[1]; - u8 *rates = cmd.bss.rates; + rates_max = rates_eid[1]; + if (rates_max > MAX_RATES) { + lbs_deb_join("invalid rates"); + goto out; + } + rates = cmd.bss.rates; for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) { u8 hw_rate = lbs_rates[hw].bitrate / 5; for (i = 0; i < rates_max; i++) { diff --git a/drivers/net/wireless/marvell/libertas_tf/cmd.c b/drivers/net/wireless/marvell/libertas_tf/cmd.c index 909ac3685010f116d160063a5e95ebcb2f34f358..2b193f1257a5ac6271af561573dba23449d26863 100644 --- a/drivers/net/wireless/marvell/libertas_tf/cmd.c +++ b/drivers/net/wireless/marvell/libertas_tf/cmd.c @@ -69,7 +69,7 @@ static void lbtf_geo_init(struct lbtf_private *priv) break; } - for (ch = priv->range.start; ch < priv->range.end; ch++) + for (ch = range->start; ch < range->end; ch++) priv->channels[CHAN_TO_IDX(ch)].flags = 0; } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 9d0d790a131974e3ca1b352fa297920bda5a59f0..8ee9609ef974978e05a4411dc180f53c773f2d55 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1022,8 +1022,10 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) } skb_put(skb, MWIFIEX_UPLD_SIZE); if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, - PCI_DMA_FROMDEVICE)) + PCI_DMA_FROMDEVICE)) { + kfree_skb(skb); return -1; + } card->cmdrsp_buf = skb; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index a8043d76152a401ca14ca7d20f77f9ae69cd64f3..f88a953b3cd577d4c5322f1c19e50456556c717a 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -271,6 +271,14 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv, "11D: skip setting domain info in FW\n"); return 0; } + + if (country_ie_len > + (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) { + mwifiex_dbg(priv->adapter, ERROR, + "11D: country_ie_len overflow!, deauth AP\n"); + return -EINVAL; + } + memcpy(priv->adapter->country_code, &country_ie[2], 2); domain_info->country_code[0] = country_ie[2]; @@ -314,8 +322,9 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, priv->scan_block = false; if (bss) { - if (adapter->region_code == 0x00) - mwifiex_process_country_ie(priv, bss); + if (adapter->region_code == 0x00 && + mwifiex_process_country_ie(priv, bss)) + return -EINVAL; /* Allocate and fill new bss descriptor */ bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index e76af2866a19350ff1326a3fe966b1c9737d8beb..b5340af9fa5ecfd0a2719c0a7b14de9f7ff68f84 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -956,59 +956,117 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, switch (*pos) { case WLAN_EID_SUPP_RATES: + if (pos[1] > 32) + return; sta_ptr->tdls_cap.rates_len = pos[1]; for (i = 0; i < pos[1]; i++) sta_ptr->tdls_cap.rates[i] = pos[i + 2]; break; case WLAN_EID_EXT_SUPP_RATES: + if (pos[1] > 32) + return; basic = sta_ptr->tdls_cap.rates_len; + if (pos[1] > 32 - basic) + return; for (i = 0; i < pos[1]; i++) sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2]; sta_ptr->tdls_cap.rates_len += pos[1]; break; case WLAN_EID_HT_CAPABILITY: - memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos, + if (pos > end - sizeof(struct ieee80211_ht_cap) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_ht_cap)) + return; + /* copy the ie's value into ht_capb*/ + memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos + 2, sizeof(struct ieee80211_ht_cap)); sta_ptr->is_11n_enabled = 1; break; case WLAN_EID_HT_OPERATION: - memcpy(&sta_ptr->tdls_cap.ht_oper, pos, + if (pos > end - + sizeof(struct ieee80211_ht_operation) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_ht_operation)) + return; + /* copy the ie's value into ht_oper*/ + memcpy(&sta_ptr->tdls_cap.ht_oper, pos + 2, sizeof(struct ieee80211_ht_operation)); break; case WLAN_EID_BSS_COEX_2040: + if (pos > end - 3) + return; + if (pos[1] != 1) + return; sta_ptr->tdls_cap.coex_2040 = pos[2]; break; case WLAN_EID_EXT_CAPABILITY: + if (pos > end - sizeof(struct ieee_types_header)) + return; + if (pos[1] < sizeof(struct ieee_types_header)) + return; + if (pos[1] > 8) + return; memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos, sizeof(struct ieee_types_header) + min_t(u8, pos[1], 8)); break; case WLAN_EID_RSN: + if (pos > end - sizeof(struct ieee_types_header)) + return; + if (pos[1] < sizeof(struct ieee_types_header)) + return; + if (pos[1] > IEEE_MAX_IE_SIZE - + sizeof(struct ieee_types_header)) + return; memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos, sizeof(struct ieee_types_header) + min_t(u8, pos[1], IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header))); break; case WLAN_EID_QOS_CAPA: + if (pos > end - 3) + return; + if (pos[1] != 1) + return; sta_ptr->tdls_cap.qos_info = pos[2]; break; case WLAN_EID_VHT_OPERATION: - if (priv->adapter->is_hw_11ac_capable) - memcpy(&sta_ptr->tdls_cap.vhtoper, pos, + if (priv->adapter->is_hw_11ac_capable) { + if (pos > end - + sizeof(struct ieee80211_vht_operation) - 2) + return; + if (pos[1] != + sizeof(struct ieee80211_vht_operation)) + return; + /* copy the ie's value into vhtoper*/ + memcpy(&sta_ptr->tdls_cap.vhtoper, pos + 2, sizeof(struct ieee80211_vht_operation)); + } break; case WLAN_EID_VHT_CAPABILITY: if (priv->adapter->is_hw_11ac_capable) { - memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos, + if (pos > end - + sizeof(struct ieee80211_vht_cap) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_vht_cap)) + return; + /* copy the ie's value into vhtcap*/ + memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos + 2, sizeof(struct ieee80211_vht_cap)); sta_ptr->is_11ac_enabled = 1; } break; case WLAN_EID_AID: - if (priv->adapter->is_hw_11ac_capable) + if (priv->adapter->is_hw_11ac_capable) { + if (pos > end - 4) + return; + if (pos[1] != 2) + return; sta_ptr->tdls_cap.aid = get_unaligned_le16((pos + 2)); + } + break; default: break; } diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c index ca09a5d4305efff5972028e38e429774aeb93976..71a47459bf8a88ca24ae6c621c69ca22626a33a8 100644 --- a/drivers/net/wireless/mediatek/mt7601u/phy.c +++ b/drivers/net/wireless/mediatek/mt7601u/phy.c @@ -221,7 +221,7 @@ int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev) do { val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION); - if (val && ~val) + if (val && val != 0xff) break; } while (--i); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index b58bf8e2cad2fba8d07bed32aca5cd8a644355f6..63f37fa72e4babad190cab1ffcc893aa13c7d4a8 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5453,6 +5453,7 @@ static int rtl8xxxu_submit_int_urb(struct ieee80211_hw *hw) ret = usb_submit_urb(urb, GFP_KERNEL); if (ret) { usb_unanchor_urb(urb); + usb_free_urb(urb); goto error; } @@ -5920,7 +5921,7 @@ static int rtl8xxxu_parse_usb(struct rtl8xxxu_priv *priv, u8 dir, xtype, num; int ret = 0; - host_interface = &interface->altsetting[0]; + host_interface = interface->cur_altsetting; interface_desc = &host_interface->desc; endpoints = interface_desc->bNumEndpoints; diff --git a/drivers/net/wireless/realtek/rtlwifi/regd.c b/drivers/net/wireless/realtek/rtlwifi/regd.c index 1bf3eb25c1da85a805451e885e51665b85478781..72ca370331fb46ab927467a3fcde6cf495d9b8f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/regd.c +++ b/drivers/net/wireless/realtek/rtlwifi/regd.c @@ -427,7 +427,7 @@ int rtl_regd_init(struct ieee80211_hw *hw, struct wiphy *wiphy = hw->wiphy; struct country_code_to_enum_rd *country = NULL; - if (wiphy == NULL || &rtlpriv->regd == NULL) + if (!wiphy) return -EINVAL; /* init country_code from efuse channel plan */ diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 120b0ff545c176410998d13149b0616c9d928a5a..d205947c4c55f3843409b606b3bd08fe18da22c2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -541,6 +541,7 @@ static int bl_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, char *str) bl_start_cmd_timer(adapter, timeout); status = bl_write_cmd(adapter, cmd, exp_resp, ®out_val); if (status < 0) { + bl_stop_cmd_timer(adapter); rsi_dbg(ERR_ZONE, "%s: Command %s (%0x) writing failed..\n", __func__, str, cmd); @@ -656,10 +657,9 @@ static int ping_pong_write(struct rsi_hw *adapter, u8 cmd, u8 *addr, u32 size) } status = bl_cmd(adapter, cmd_req, cmd_resp, str); - if (status) { - bl_stop_cmd_timer(adapter); + if (status) return status; - } + return 0; } @@ -749,10 +749,9 @@ static int auto_fw_upgrade(struct rsi_hw *adapter, u8 *flash_content, status = bl_cmd(adapter, EOF_REACHED, FW_LOADING_SUCCESSFUL, "EOF_REACHED"); - if (status) { - bl_stop_cmd_timer(adapter); + if (status) return status; - } + rsi_dbg(INFO_ZONE, "FW loading is done and FW is running..\n"); return 0; } @@ -773,6 +772,7 @@ static int rsi_load_firmware(struct rsi_hw *adapter) status = hif_ops->master_reg_read(adapter, SWBL_REGOUT, ®out_val, 2); if (status < 0) { + bl_stop_cmd_timer(adapter); rsi_dbg(ERR_ZONE, "%s: REGOUT read failed\n", __func__); return status; diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index fa12c05d9e237c1d615990456b50cbe987187cf4..233b2239311d8484cc3dd354dbd7940307e4ab1e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -218,6 +218,7 @@ void rsi_mac80211_detach(struct rsi_hw *adapter) ieee80211_stop_queues(hw); ieee80211_unregister_hw(hw); ieee80211_free_hw(hw); + adapter->hw = NULL; } for (band = 0; band < NUM_NL80211_BANDS; band++) { diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index f90c10b3c921195d23756bc3a607b2379b6cb02b..786a330bc470748ae65fccb10af6c8aa74075ef7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -105,7 +105,7 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface, __le16 buffer_size; int ii, bep_found = 0; - iface_desc = &(interface->altsetting[0]); + iface_desc = interface->cur_altsetting; for (ii = 0; ii < iface_desc->desc.bNumEndpoints; ++ii) { endpoint = &(iface_desc->endpoint[ii].desc); diff --git a/drivers/net/wireless/st/cw1200/fwio.c b/drivers/net/wireless/st/cw1200/fwio.c index 30e7646d04affac71a3f3a1ad65702883fef5bef..16be7fa82a233bee067fcf8cbec42bd39156106c 100644 --- a/drivers/net/wireless/st/cw1200/fwio.c +++ b/drivers/net/wireless/st/cw1200/fwio.c @@ -323,12 +323,12 @@ int cw1200_load_firmware(struct cw1200_common *priv) goto out; } - priv->hw_type = cw1200_get_hw_type(val32, &major_revision); - if (priv->hw_type < 0) { + ret = cw1200_get_hw_type(val32, &major_revision); + if (ret < 0) { pr_err("Can't deduce hardware type.\n"); - ret = -ENOTSUPP; goto out; } + priv->hw_type = ret; /* Set DPLL Reg value, and read back to confirm writes work */ ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c index c30bf118c67d81beced03f28279b11a838e02ad2..1e396eb26ccfb6230753cf7a42c87623e50c32f0 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c @@ -1272,7 +1272,7 @@ static void print_id(struct usb_device *udev) static int eject_installer(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); - struct usb_host_interface *iface_desc = &intf->altsetting[0]; + struct usb_host_interface *iface_desc = intf->cur_altsetting; struct usb_endpoint_descriptor *endpoint; unsigned char *cmd; u8 bulk_out_ep; diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c index fcb57d64d97e60d37dbc30364a4fc5d222f4d1a4..a2c9b3f3bc2322a7504cdcdb96ba8bf144fcc4ec 100644 --- a/drivers/nfc/pn533/usb.c +++ b/drivers/nfc/pn533/usb.c @@ -403,7 +403,7 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy) cmd, sizeof(cmd), false); rc = usb_bulk_msg(phy->udev, phy->out_urb->pipe, buffer, sizeof(cmd), - &transferred, 0); + &transferred, 5000); kfree(buffer); if (rc || (transferred != sizeof(cmd))) { nfc_err(&phy->udev->dev, diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c index d44d7ef38fe88fef82b7ff5420e117cd73d43edd..b68e2cad74cc76d440c133a8aca2918f49c52362 100644 --- a/drivers/ntb/hw/idt/ntb_hw_idt.c +++ b/drivers/ntb/hw/idt/ntb_hw_idt.c @@ -1105,9 +1105,9 @@ static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port, } /* Allocate memory for memory window descriptors */ - ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, - sizeof(*ret_mws), GFP_KERNEL); - if (IS_ERR_OR_NULL(ret_mws)) + ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, sizeof(*ret_mws), + GFP_KERNEL); + if (!ret_mws) return ERR_PTR(-ENOMEM); /* Copy the info of detected memory windows */ @@ -2393,7 +2393,7 @@ static struct idt_ntb_dev *idt_create_dev(struct pci_dev *pdev, /* Allocate memory for the IDT PCIe-device descriptor */ ndev = devm_kzalloc(&pdev->dev, sizeof(*ndev), GFP_KERNEL); - if (IS_ERR_OR_NULL(ndev)) { + if (!ndev) { dev_err(&pdev->dev, "Memory allocation failed for descriptor"); return ERR_PTR(-ENOMEM); } diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 5bdd499b5f4f1b6a489924db86051e9c89175401..250471fa0fe68c524b21f6fb0893ff589f9c9061 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig @@ -102,4 +102,14 @@ config NVDIMM_DAX Select Y if unsure +config OF_PMEM + tristate "Device-tree support for persistent memory regions" + depends on OF + default LIBNVDIMM + help + Allows regions of persistent memory to be described in the + device-tree. + + Select Y if unsure. + endif diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile index 447e0e14f3b65b86d945f4c2d6186f595da3dbc0..5b4f3d50b83c0ed4cd087d5b34b56157f2790f62 100644 --- a/drivers/nvdimm/Makefile +++ b/drivers/nvdimm/Makefile @@ -4,6 +4,8 @@ obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o obj-$(CONFIG_ND_BTT) += nd_btt.o obj-$(CONFIG_ND_BLK) += nd_blk.o obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o +obj-$(CONFIG_OF_PMEM) += of_pmem.o +obj-$(CONFIG_VIRTIO_PMEM) += virtio_pmem.o nd_virtio.o nd_pmem-y := pmem.o diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 2f1b54fab399f6e9efe2fb695196926c5f423a87..4587c97735600aa25ca1b05253dab7d576be9cde 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -358,6 +358,7 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent, nvdimm_bus->dev.release = nvdimm_bus_release; nvdimm_bus->dev.groups = nd_desc->attr_groups; nvdimm_bus->dev.bus = &nvdimm_bus_type; + nvdimm_bus->dev.of_node = nd_desc->of_node; dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id); rc = device_register(&nvdimm_bus->dev); if (rc) { diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index b2fc29b8279b1e96682cbb9f29a81a84107bba74..32f2aaf62f270f2715e9d2175508acf86456f7f7 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -263,7 +263,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev); unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512); sector_t sector = offset >> 9; - int rc = 0; + int rc = 0, ret = 0; if (unlikely(!size)) return 0; @@ -299,7 +299,9 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, } memcpy_flushcache(nsio->addr + offset, buf, size); - nvdimm_flush(to_nd_region(ndns->dev.parent)); + ret = nvdimm_flush(to_nd_region(ndns->dev.parent), NULL); + if (ret) + rc = ret; return rc; } diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index e3f060f0b83ea27646515ba09b788593b9ea8b3a..b79a8d0f9b486ff9f98d686f589ba2a618b1bf07 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -170,6 +170,7 @@ struct nd_region { struct badblocks bb; struct nd_interleave_set *nd_set; struct nd_percpu_lane __percpu *lane; + int (*flush)(struct nd_region *nd_region, struct bio *bio); struct nd_mapping mapping[0]; }; diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c new file mode 100644 index 0000000000000000000000000000000000000000..8645275c08c21cd2ad93888dd129fa1f2f8ae754 --- /dev/null +++ b/drivers/nvdimm/nd_virtio.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * virtio_pmem.c: Virtio pmem Driver + * + * Discovers persistent memory range information + * from host and provides a virtio based flushing + * interface. + */ +#include "virtio_pmem.h" +#include "nd.h" + + /* The interrupt handler */ +void virtio_pmem_host_ack(struct virtqueue *vq) +{ + struct virtio_pmem *vpmem = vq->vdev->priv; + struct virtio_pmem_request *req_data, *req_buf; + unsigned long flags; + unsigned int len; + + spin_lock_irqsave(&vpmem->pmem_lock, flags); + while ((req_data = virtqueue_get_buf(vq, &len)) != NULL) { + req_data->done = true; + wake_up(&req_data->host_acked); + + if (!list_empty(&vpmem->req_list)) { + req_buf = list_first_entry(&vpmem->req_list, + struct virtio_pmem_request, list); + req_buf->wq_buf_avail = true; + wake_up(&req_buf->wq_buf); + list_del(&req_buf->list); + } + } + spin_unlock_irqrestore(&vpmem->pmem_lock, flags); +} +EXPORT_SYMBOL_GPL(virtio_pmem_host_ack); + + /* The request submission function */ +static int virtio_pmem_flush(struct nd_region *nd_region) +{ + struct virtio_device *vdev = nd_region->provider_data; + struct virtio_pmem *vpmem = vdev->priv; + struct virtio_pmem_request *req_data; + struct scatterlist *sgs[2], sg, ret; + unsigned long flags; + int err, err1; + + might_sleep(); + req_data = kmalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) + return -ENOMEM; + + req_data->done = false; + init_waitqueue_head(&req_data->host_acked); + init_waitqueue_head(&req_data->wq_buf); + INIT_LIST_HEAD(&req_data->list); + req_data->req.type = cpu_to_virtio32(vdev, VIRTIO_PMEM_REQ_TYPE_FLUSH); + sg_init_one(&sg, &req_data->req, sizeof(req_data->req)); + sgs[0] = &sg; + sg_init_one(&ret, &req_data->resp.ret, sizeof(req_data->resp)); + sgs[1] = &ret; + + spin_lock_irqsave(&vpmem->pmem_lock, flags); + /* + * If virtqueue_add_sgs returns -ENOSPC then req_vq virtual + * queue does not have free descriptor. We add the request + * to req_list and wait for host_ack to wake us up when free + * slots are available. + */ + while ((err = virtqueue_add_sgs(vpmem->req_vq, sgs, 1, 1, req_data, + GFP_ATOMIC)) == -ENOSPC) { + + dev_info(&vdev->dev, "failed to send command to virtio pmem device, no free slots in the virtqueue\n"); + req_data->wq_buf_avail = false; + list_add_tail(&req_data->list, &vpmem->req_list); + spin_unlock_irqrestore(&vpmem->pmem_lock, flags); + + /* A host response results in "host_ack" getting called */ + wait_event(req_data->wq_buf, req_data->wq_buf_avail); + spin_lock_irqsave(&vpmem->pmem_lock, flags); + } + err1 = virtqueue_kick(vpmem->req_vq); + spin_unlock_irqrestore(&vpmem->pmem_lock, flags); + /* + * virtqueue_add_sgs failed with error different than -ENOSPC, we can't + * do anything about that. + */ + if (err || !err1) { + dev_info(&vdev->dev, "failed to send command to virtio pmem device\n"); + err = -EIO; + } else { + /* A host repsonse results in "host_ack" getting called */ + wait_event(req_data->host_acked, req_data->done); + err = virtio32_to_cpu(vdev, req_data->resp.ret); + } + + kfree(req_data); + return err; +}; + +/* The asynchronous flush callback function */ +int async_pmem_flush(struct nd_region *nd_region, struct bio *bio) +{ + /* + * Create child bio for asynchronous flush and chain with + * parent bio. Otherwise directly call nd_region flush. + */ + if (bio && bio->bi_iter.bi_sector != -1) { + struct bio *child = bio_alloc(GFP_ATOMIC, 0); + + if (!child) + return -ENOMEM; + bio_copy_dev(child, bio); + child->bi_opf = REQ_PREFLUSH; + child->bi_iter.bi_sector = -1; + bio_chain(child, bio); + submit_bio(child); + return 0; + } + if (virtio_pmem_flush(nd_region)) + return -EIO; + + return 0; +}; +EXPORT_SYMBOL_GPL(async_pmem_flush); +MODULE_LICENSE("GPL"); diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c new file mode 100644 index 0000000000000000000000000000000000000000..6e5cbfd8cb13fb179a613d7afa0035a1587b1b57 --- /dev/null +++ b/drivers/nvdimm/of_pmem.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#define pr_fmt(fmt) "of_pmem: " fmt + +#include +#include +#include +#include +#include +#include + +static const struct attribute_group *region_attr_groups[] = { + &nd_region_attribute_group, + &nd_device_attribute_group, + NULL, +}; + +static const struct attribute_group *bus_attr_groups[] = { + &nvdimm_bus_attribute_group, + NULL, +}; + +struct of_pmem_private { + struct nvdimm_bus_descriptor bus_desc; + struct nvdimm_bus *bus; +}; + +static int of_pmem_region_probe(struct platform_device *pdev) +{ + struct of_pmem_private *priv; + struct device_node *np; + struct nvdimm_bus *bus; + bool is_volatile; + int i; + + np = dev_of_node(&pdev->dev); + if (!np) + return -ENXIO; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->bus_desc.attr_groups = bus_attr_groups; + priv->bus_desc.provider_name = kstrdup(pdev->name, GFP_KERNEL); + priv->bus_desc.module = THIS_MODULE; + priv->bus_desc.of_node = np; + + priv->bus = bus = nvdimm_bus_register(&pdev->dev, &priv->bus_desc); + if (!bus) { + kfree(priv); + return -ENODEV; + } + platform_set_drvdata(pdev, priv); + + is_volatile = !!of_find_property(np, "volatile", NULL); + dev_dbg(&pdev->dev, "Registering %s regions from %pOF\n", + is_volatile ? "volatile" : "non-volatile", np); + + for (i = 0; i < pdev->num_resources; i++) { + struct nd_region_desc ndr_desc; + struct nd_region *region; + + /* + * NB: libnvdimm copies the data from ndr_desc into it's own + * structures so passing a stack pointer is fine. + */ + memset(&ndr_desc, 0, sizeof(ndr_desc)); + ndr_desc.attr_groups = region_attr_groups; + ndr_desc.numa_node = dev_to_node(&pdev->dev); + ndr_desc.res = &pdev->resource[i]; + ndr_desc.of_node = np; + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); + + if (is_volatile) + region = nvdimm_volatile_region_create(bus, &ndr_desc); + else + region = nvdimm_pmem_region_create(bus, &ndr_desc); + + if (!region) + dev_warn(&pdev->dev, "Unable to register region %pR from %pOF\n", + ndr_desc.res, np); + else + dev_dbg(&pdev->dev, "Registered region %pR from %pOF\n", + ndr_desc.res, np); + } + + return 0; +} + +static int of_pmem_region_remove(struct platform_device *pdev) +{ + struct of_pmem_private *priv = platform_get_drvdata(pdev); + + nvdimm_bus_unregister(priv->bus); + kfree(priv); + + return 0; +} + +static const struct of_device_id of_pmem_region_match[] = { + { .compatible = "pmem-region" }, + { }, +}; + +static struct platform_driver of_pmem_region_driver = { + .probe = of_pmem_region_probe, + .remove = of_pmem_region_remove, + .driver = { + .name = "of_pmem", + .of_match_table = of_pmem_region_match, + }, +}; + +module_platform_driver(of_pmem_region_driver); +MODULE_DEVICE_TABLE(of, of_pmem_region_match); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("IBM Corporation"); diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index b45a3c71f08f5371becb7034d3222f66835760bf..5d5200091845d7a99a8ca5ed03981c04efb4f34c 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -170,6 +170,7 @@ static blk_status_t pmem_do_bvec(struct pmem_device *pmem, struct page *page, static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio) { + int ret = 0; blk_status_t rc = 0; bool do_acct; unsigned long start; @@ -179,7 +180,7 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio) struct nd_region *nd_region = to_region(pmem); if (bio->bi_opf & REQ_FLUSH) - nvdimm_flush(nd_region); + ret = nvdimm_flush(nd_region, bio); do_acct = nd_iostat_start(bio, &start); bio_for_each_segment(bvec, bio, iter) { @@ -195,7 +196,10 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio) nd_iostat_end(bio, start); if (bio->bi_opf & REQ_FUA) - nvdimm_flush(nd_region); + ret = nvdimm_flush(nd_region, bio); + + if (ret) + bio->bi_status = errno_to_blk_status(ret); bio_endio(bio); return BLK_QC_T_NONE; @@ -417,7 +421,6 @@ static int pmem_attach_disk(struct device *dev, } dax_write_cache(dax_dev, wbc); pmem->dax_dev = dax_dev; - gendev = disk_to_dev(disk); gendev->groups = pmem_attribute_groups; @@ -475,14 +478,14 @@ static int nd_pmem_remove(struct device *dev) sysfs_put(pmem->bb_state); pmem->bb_state = NULL; } - nvdimm_flush(to_nd_region(dev->parent)); + nvdimm_flush(to_nd_region(dev->parent), NULL); return 0; } static void nd_pmem_shutdown(struct device *dev) { - nvdimm_flush(to_nd_region(dev->parent)); + nvdimm_flush(to_nd_region(dev->parent), NULL); } static void nd_pmem_notify(struct device *dev, enum nvdimm_event event) diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 708043d20d0dfde0b2c9f301271dcf0bc8fbdac0..c0e6a6d235de56da678b7a4bfa035449d574cdf5 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -282,7 +282,9 @@ static ssize_t deep_flush_store(struct device *dev, struct device_attribute *att return rc; if (!flush) return -EINVAL; - nvdimm_flush(nd_region); + rc = nvdimm_flush(nd_region, NULL); + if (rc) + return rc; return len; } @@ -999,8 +1001,14 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, dev->parent = &nvdimm_bus->dev; dev->type = dev_type; dev->groups = ndr_desc->attr_groups; + dev->of_node = ndr_desc->of_node; nd_region->ndr_size = resource_size(ndr_desc->res); nd_region->ndr_start = ndr_desc->res->start; + if (ndr_desc->flush) + nd_region->flush = ndr_desc->flush; + else + nd_region->flush = NULL; + nd_device_register(dev); return nd_region; @@ -1041,11 +1049,24 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus, } EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create); +int nvdimm_flush(struct nd_region *nd_region, struct bio *bio) +{ + int rc = 0; + + if (!nd_region->flush) + rc = generic_nvdimm_flush(nd_region); + else { + if (nd_region->flush(nd_region, bio)) + rc = -EIO; + } + + return rc; +} /** * nvdimm_flush - flush any posted write queues between the cpu and pmem media * @nd_region: blk or interleaved pmem region */ -void nvdimm_flush(struct nd_region *nd_region) +int generic_nvdimm_flush(struct nd_region *nd_region) { struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev); int i, idx; @@ -1069,6 +1090,8 @@ void nvdimm_flush(struct nd_region *nd_region) if (ndrd_get_flush_wpq(ndrd, i, 0)) writeq(1, ndrd_get_flush_wpq(ndrd, i, idx)); wmb(); + + return 0; } EXPORT_SYMBOL_GPL(nvdimm_flush); diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c new file mode 100644 index 0000000000000000000000000000000000000000..5e3d07b47e0cad7881d9b1ac14447770e8b695c3 --- /dev/null +++ b/drivers/nvdimm/virtio_pmem.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * virtio_pmem.c: Virtio pmem Driver + * + * Discovers persistent memory range information + * from host and registers the virtual pmem device + * with libnvdimm core. + */ +#include "virtio_pmem.h" +#include "nd.h" + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + + /* Initialize virt queue */ +static int init_vq(struct virtio_pmem *vpmem) +{ + /* single vq */ + vpmem->req_vq = virtio_find_single_vq(vpmem->vdev, + virtio_pmem_host_ack, "flush_queue"); + if (IS_ERR(vpmem->req_vq)) + return PTR_ERR(vpmem->req_vq); + + spin_lock_init(&vpmem->pmem_lock); + INIT_LIST_HEAD(&vpmem->req_list); + + return 0; +}; + +static int virtio_pmem_probe(struct virtio_device *vdev) +{ + struct nd_region_desc ndr_desc = {}; + int nid = dev_to_node(&vdev->dev); + struct nd_region *nd_region; + struct virtio_pmem *vpmem; + struct resource res; + int err = 0; + + if (!vdev->config->get) { + dev_err(&vdev->dev, "%s failure: config access disabled\n", + __func__); + return -EINVAL; + } + + vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL); + if (!vpmem) { + err = -ENOMEM; + goto out_err; + } + + vpmem->vdev = vdev; + vdev->priv = vpmem; + err = init_vq(vpmem); + if (err) { + dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n"); + goto out_err; + } + + virtio_cread(vpmem->vdev, struct virtio_pmem_config, + start, &vpmem->start); + virtio_cread(vpmem->vdev, struct virtio_pmem_config, + size, &vpmem->size); + + res.start = vpmem->start; + res.end = vpmem->start + vpmem->size - 1; + vpmem->nd_desc.provider_name = "virtio-pmem"; + vpmem->nd_desc.module = THIS_MODULE; + + vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev, + &vpmem->nd_desc); + if (!vpmem->nvdimm_bus) { + dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n"); + err = -ENXIO; + goto out_vq; + } + + dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus); + + ndr_desc.res = &res; + ndr_desc.numa_node = nid; + ndr_desc.flush = async_pmem_flush; + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); + set_bit(ND_REGION_ASYNC, &ndr_desc.flags); + nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc); + if (!nd_region) { + dev_err(&vdev->dev, "failed to create nvdimm region\n"); + err = -ENXIO; + goto out_nd; + } + nd_region->provider_data = dev_to_virtio(nd_region->dev.parent->parent); + return 0; +out_nd: + nvdimm_bus_unregister(vpmem->nvdimm_bus); +out_vq: + vdev->config->del_vqs(vdev); +out_err: + return err; +} + +static void virtio_pmem_remove(struct virtio_device *vdev) +{ + struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev); + + nvdimm_bus_unregister(nvdimm_bus); + vdev->config->del_vqs(vdev); + vdev->config->reset(vdev); +} + +static struct virtio_driver virtio_pmem_driver = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtio_pmem_probe, + .remove = virtio_pmem_remove, +}; + +module_virtio_driver(virtio_pmem_driver); +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio pmem driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h new file mode 100644 index 0000000000000000000000000000000000000000..0dddefe594c46ad7e0c0557f73ffcdc20bbe9c1c --- /dev/null +++ b/drivers/nvdimm/virtio_pmem.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * virtio_pmem.h: virtio pmem Driver + * + * Discovers persistent memory range information + * from host and provides a virtio based flushing + * interface. + **/ + +#ifndef _LINUX_VIRTIO_PMEM_H +#define _LINUX_VIRTIO_PMEM_H + +#include +#include +#include +#include + +struct virtio_pmem_request { + struct virtio_pmem_req req; + struct virtio_pmem_resp resp; + + /* Wait queue to process deferred work after ack from host */ + wait_queue_head_t host_acked; + bool done; + + /* Wait queue to process deferred work after virt queue buffer avail */ + wait_queue_head_t wq_buf; + bool wq_buf_avail; + struct list_head list; +}; + +struct virtio_pmem { + struct virtio_device *vdev; + + /* Virtio pmem request queue */ + struct virtqueue *req_vq; + + /* nvdimm bus registers virtio pmem device */ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_bus_descriptor nd_desc; + + /* List to store deferred work if virtqueue is full */ + struct list_head req_list; + + /* Synchronize virtqueue data */ + spinlock_t pmem_lock; + + /* Memory region information */ + __u64 start; + __u64 size; +}; + +void virtio_pmem_host_ack(struct virtqueue *vq); +int async_pmem_flush(struct nd_region *nd_region, struct bio *bio); +#endif diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 6c5a12d53f75ff0fc1e4ef60058fd88949b9e360..b144c86f5a787eea44c6f5c04ba1fdb71c5613dc 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2276,7 +2276,7 @@ static int nvme_pci_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val) static int nvme_pci_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val) { - *val = readq(to_nvme_dev(ctrl)->bar + off); + *val = lo_hi_readq(to_nvme_dev(ctrl)->bar + off); return 0; } diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c index 193ca8fd350a428356cfd7120b5394d36161bdad..0c8c3b9bb6a7a26d18ff85cac9512941cbb356ff 100644 --- a/drivers/nvmem/imx-ocotp.c +++ b/drivers/nvmem/imx-ocotp.c @@ -199,7 +199,8 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val, strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1; strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1; - timing = strobe_prog & 0x00000FFF; + timing = readl(priv->base + IMX_OCOTP_ADDR_TIMING) & 0x0FC00000; + timing |= strobe_prog & 0x00000FFF; timing |= (relax << 12) & 0x0000F000; timing |= (strobe_read << 16) & 0x003F0000; diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 8c1819230ed2377d6726d33265c1a9b44b7cbf1e..fe26697d3bd724d048df132d95ab74797fc0f100 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -358,7 +358,7 @@ struct phy_device *of_phy_get_and_connect(struct net_device *dev, struct phy_device *phy; iface = of_get_phy_mode(np); - if (iface < 0) + if ((int)iface < 0) return NULL; phy_np = of_parse_phandle(np, "phy-handle", 0); diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index f9308c2f22e6754d0b50fc627c11a96cf44af8f4..c2541a772abc84399b9267a23d6e557135ae9025 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -177,7 +177,7 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test) goto err_map_addr; } - memcpy(buf, src_addr, reg->size); + memcpy_fromio(buf, src_addr, reg->size); crc32 = crc32_le(~0, buf, reg->size); if (crc32 != reg->checksum) @@ -231,7 +231,7 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test) get_random_bytes(buf, reg->size); reg->checksum = crc32_le(~0, buf, reg->size); - memcpy(dst_addr, buf, reg->size); + memcpy_toio(dst_addr, buf, reg->size); /* * wait 1ms inorder for the write to complete. Without this delay L3 diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index c0ecc9f35667f7f330b1e1a994b8dbcfa0153e46..8f8dac0155d638c261bb2ad3cd647ec682d531fd 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -573,14 +573,6 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie, return (pcie->base + offset); } - /* - * PAXC is connected to an internally emulated EP within the SoC. It - * allows only one device. - */ - if (pcie->ep_is_internal) - if (slot > 0) - return NULL; - return iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where); } diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c index bab8ac63c4f3e0e3682d9c30d7b8b8370a6a86da..3008bba360f354216e4aba113005ca8a43abd80c 100644 --- a/drivers/pci/pcie/ptm.c +++ b/drivers/pci/pcie/ptm.c @@ -29,7 +29,7 @@ static void pci_ptm_info(struct pci_dev *dev) snprintf(clock_desc, sizeof(clock_desc), ">254ns"); break; default: - snprintf(clock_desc, sizeof(clock_desc), "%udns", + snprintf(clock_desc, sizeof(clock_desc), "%uns", dev->ptm_granularity); break; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 90df085e9f9258c1ed62251a9885539c7e16740f..e7ed051ec125ee37768ee4771a43609eaac92500 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4019,6 +4019,40 @@ static void quirk_mic_x200_dma_alias(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2260, quirk_mic_x200_dma_alias); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias); +/* + * Intel Visual Compute Accelerator (VCA) is a family of PCIe add-in devices + * exposing computational units via Non Transparent Bridges (NTB, PEX 87xx). + * + * Similarly to MIC x200, we need to add DMA aliases to allow buffer access + * when IOMMU is enabled. These aliases allow computational unit access to + * host memory. These aliases mark the whole VCA device as one IOMMU + * group. + * + * All possible slot numbers (0x20) are used, since we are unable to tell + * what slot is used on other side. This quirk is intended for both host + * and computational unit sides. The VCA devices have up to five functions + * (four for DMA channels and one additional). + */ +static void quirk_pex_vca_alias(struct pci_dev *pdev) +{ + const unsigned int num_pci_slots = 0x20; + unsigned int slot; + + for (slot = 0; slot < num_pci_slots; slot++) { + pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x1)); + pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x2)); + pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x3)); + pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x4)); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2954, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2955, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2956, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2958, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2959, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x295A, quirk_pex_vca_alias); + /* * The IOMMU and interrupt controller on Broadcom Vulcan/Cavium ThunderX2 are * associated not at the root bus, but at a bridge below. This quirk avoids diff --git a/drivers/pci/switch/Kconfig b/drivers/pci/switch/Kconfig index 4c49648e0646f047446f6b1429ad82f45f1fd061..0dcf34d7f8f4bd82dc6e8b128369a1187d1e4e65 100644 --- a/drivers/pci/switch/Kconfig +++ b/drivers/pci/switch/Kconfig @@ -10,4 +10,12 @@ config PCI_SW_SWITCHTEC devices. See for more information. +config PCI_SW_QCOM_SWITCH + depends on ARCH_QCOM + tristate "Qualcomm Technologies, Inc. PCIe Switch Management Driver" + help + Enables support for switches connected to Qualcomm Technologies, Inc. + PCIe Rootport. Switches that require erratas can bind with this driver + and run errata for the corresponding port. + endmenu diff --git a/drivers/pci/switch/Makefile b/drivers/pci/switch/Makefile index 37d8cfb03f3f87156c7ae29790d4d1aa3b18ca28..da9126f137784ec9d81c25de81cc83ab3136fd6b 100644 --- a/drivers/pci/switch/Makefile +++ b/drivers/pci/switch/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_PCI_SW_SWITCHTEC) += switchtec.o +obj-$(CONFIG_PCI_SW_QCOM_SWITCH) += switch-qcom.o diff --git a/drivers/pci/switch/switch-qcom.c b/drivers/pci/switch/switch-qcom.c new file mode 100644 index 0000000000000000000000000000000000000000..ebe40fd6cfb180e8e20a87cfe02addf9cfdc707d --- /dev/null +++ b/drivers/pci/switch/switch-qcom.c @@ -0,0 +1,222 @@ +/* Copyright (c) 2020, 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. + */ + +/* + * MSM PCIe switch controller + */ + +#include +#include +#include +#include +#include +#include + +#define DIODE_VENDOR_ID 0x12d8 +#define DIODE_DEVICE_ID 0xb304 + +/* + * @DIODE_ERRATA_0: Apply errata specific to the upstream port (USP). + * @DIODE_ERRATA_1: Apply errata configuration to downstream port1 (DSP1). + * @DIODE_ERRATA_2: Common errata applied to (DSP2) port in the switch. + */ +enum { + DIODE_ERRATA_0, + DIODE_ERRATA_1, + DIODE_ERRATA_2, + SWITCH_MAX, +}; + +struct pci_qcom_switch_errata { + int (*config_errata)(struct device *dev, void *data); +}; + +static int config_common_port_diode(struct device *dev, void *data) +{ + struct pci_dev *pcidev = to_pci_dev(dev); + int ret = 0; + u32 addr, val; + + if (!pcidev) { + pr_err("%s: port not found\n", __func__); + return -ENODEV; + } + + addr = 0x3c; + ret = pci_read_config_dword(pcidev, addr, &val); + if (ret) { + pr_err("read fail: port %s read cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + val |= 1 << 17; + ret = pci_write_config_dword(pcidev, addr, val); + if (ret) { + pr_err("write fail: port %s read cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + return 0; +} + +static int config_upstream_port_diode(struct device *dev, void *data) +{ + struct pci_dev *pcidev = to_pci_dev(dev); + u32 addr, val; + int ret; + + if (!pcidev) { + pr_err("%s: port not found\n", __func__); + return -ENODEV; + } + + /* write cfg offset 74h.bit[7] = 1 */ + addr = 0x74; + ret = pci_read_config_dword(pcidev, addr, &val); + if (ret) { + pr_err("read fail: port %s read cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + val |= 1 << 7; + ret = pci_write_config_dword(pcidev, addr, val); + if (ret) { + pr_err("write fail: port %s write cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + ret = config_common_port_diode(dev, NULL); + if (ret) { + pr_err("%s: Applying common configuration failed\n", __func__); + return ret; + } + + return 0; +} + +static int config_downstream_port_1_diode(struct device *dev, void *data) +{ + struct pci_dev *pcidev = to_pci_dev(dev); + int ret; + u32 addr, val; + + if (!pcidev) { + pr_err("%s: port not found\n", __func__); + return -ENODEV; + } + + /* write cfg offset 6ch.bit[25] = 1 */ + addr = 0x6c; + ret = pci_read_config_dword(pcidev, addr, &val); + if (ret) { + pr_err("read fail: port %s read cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + val |= 1 << 25; + ret = pci_write_config_dword(pcidev, addr, val); + if (ret) { + pr_err("write fail: port %s write cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + /* write cfg offset 33ch.bit[2] = 1 */ + addr = 0x33c; + ret = pci_read_config_dword(pcidev, addr, &val); + if (ret) { + pr_err("read fail: port %s read cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + val |= 1 << 2; + ret = pci_write_config_dword(pcidev, addr, val); + if (ret) { + pr_err("write fail: port %s write cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + ret = config_common_port_diode(dev, NULL); + if (ret) { + pr_err("%s: Applying common configuration failed\n", __func__); + return ret; + } + + return 0; +} + +struct pci_qcom_switch_errata errata[] = { + [DIODE_ERRATA_0] = {config_upstream_port_diode}, + [DIODE_ERRATA_1] = {config_downstream_port_1_diode}, + [DIODE_ERRATA_2] = {config_common_port_diode}, +}; + +static struct pci_device_id switch_qcom_pci_tbl[] = { + { + PCI_DEVICE(DIODE_VENDOR_ID, DIODE_DEVICE_ID), + }, + {0}, +}; +MODULE_DEVICE_TABLE(pci, switch_qcom_pci_tbl); + +static int switch_qcom_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret = 0, errata_num = 0; + + ret = of_property_read_u32((&pdev->dev)->of_node, "errata", + &errata_num); + if (ret) { + pr_info("No erratas needed\n"); + return 0; + } + + pr_info("Errata being requested: %d\n", errata_num); + + if (errata_num >= SWITCH_MAX) { + pr_err("Invalid errata num:%d\n", errata_num); + return -EINVAL; + } + + ret = errata[errata_num].config_errata(&pdev->dev, NULL); + if (ret) { + pr_err("Error applying errata\n"); + return ret; + } + + return 0; +} + +static struct pci_driver switch_qcom_pci_driver = { + .name = "pcie-qcom-switch", + .id_table = switch_qcom_pci_tbl, + .probe = switch_qcom_pci_probe, +}; + +static int __init switch_qcom_pci_init(void) +{ + return pci_register_driver(&switch_qcom_pci_driver); +} +module_init(switch_qcom_pci_init); + +static void __exit switch_qcom_pci_exit(void) +{ + return pci_unregister_driver(&switch_qcom_pci_driver); +} +module_exit(switch_qcom_pci_exit); diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index e3aefdafae89132dd67ad40905f327222d653dc5..73dba2739849b08218996a7b759412cf9c3da693 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -23,7 +23,7 @@ #include #include #include - +#include #include MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver"); @@ -399,10 +399,6 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stuser->data, stuser->data_len); iowrite32(stuser->cmd, &stdev->mmio_mrpc->cmd); - stuser->status = ioread32(&stdev->mmio_mrpc->status); - if (stuser->status != SWITCHTEC_MRPC_STATUS_INPROGRESS) - mrpc_complete_cmd(stdev); - schedule_delayed_work(&stdev->mrpc_timeout, msecs_to_jiffies(500)); } @@ -898,7 +894,7 @@ static int ioctl_event_summary(struct switchtec_dev *stdev, u32 reg; s.global = ioread32(&stdev->mmio_sw_event->global_summary); - s.part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap); + s.part_bitmap = readq(&stdev->mmio_sw_event->part_event_bitmap); s.local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary); for (i = 0; i < stdev->partition_count; i++) { diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 6601ad0dfb3ad23c77865138b3db7bd0c4f55ae8..593c77dbde2eb37ec072955ba1a877e877954bc6 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -115,7 +115,7 @@ struct cpcap_usb_ints_state { enum cpcap_gpio_mode { CPCAP_DM_DP, CPCAP_MDM_RX_TX, - CPCAP_UNKNOWN, + CPCAP_UNKNOWN_DISABLED, /* Seems to disable USB lines */ CPCAP_OTG_DM_DP, }; @@ -207,6 +207,19 @@ static int cpcap_phy_get_ints_state(struct cpcap_phy_ddata *ddata, static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata); static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata); +static void cpcap_usb_try_musb_mailbox(struct cpcap_phy_ddata *ddata, + enum musb_vbus_id_status status) +{ + int error; + + error = musb_mailbox(status); + if (!error) + return; + + dev_dbg(ddata->dev, "%s: musb_mailbox failed: %i\n", + __func__, error); +} + static void cpcap_usb_detect(struct work_struct *work) { struct cpcap_phy_ddata *ddata; @@ -226,9 +239,7 @@ static void cpcap_usb_detect(struct work_struct *work) if (error) goto out_err; - error = musb_mailbox(MUSB_ID_GROUND); - if (error) - goto out_err; + cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND); error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, CPCAP_BIT_VBUSSTBY_EN, @@ -255,9 +266,7 @@ static void cpcap_usb_detect(struct work_struct *work) error = cpcap_usb_set_usb_mode(ddata); if (error) goto out_err; - error = musb_mailbox(MUSB_ID_GROUND); - if (error) - goto out_err; + cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND); return; } @@ -267,22 +276,18 @@ static void cpcap_usb_detect(struct work_struct *work) error = cpcap_usb_set_usb_mode(ddata); if (error) goto out_err; - error = musb_mailbox(MUSB_VBUS_VALID); - if (error) - goto out_err; + cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_VALID); return; } + cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF); + /* Default to debug UART mode */ error = cpcap_usb_set_uart_mode(ddata); if (error) goto out_err; - error = musb_mailbox(MUSB_VBUS_OFF); - if (error) - goto out_err; - dev_dbg(ddata->dev, "set UART mode\n"); return; @@ -374,7 +379,8 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata) { int error; - error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP); + /* Disable lines to prevent glitches from waking up mdm6600 */ + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED); if (error) goto out_err; @@ -401,6 +407,11 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata) if (error) goto out_err; + /* Enable UART mode */ + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP); + if (error) + goto out_err; + return 0; out_err: @@ -413,7 +424,8 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata) { int error; - error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP); + /* Disable lines to prevent glitches from waking up mdm6600 */ + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED); if (error) return error; @@ -453,6 +465,11 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata) if (error) goto out_err; + /* Enable USB mode */ + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP); + if (error) + goto out_err; + return 0; out_err: @@ -647,9 +664,7 @@ static int cpcap_usb_phy_remove(struct platform_device *pdev) if (error) dev_err(ddata->dev, "could not set UART mode\n"); - error = musb_mailbox(MUSB_VBUS_OFF); - if (error) - dev_err(ddata->dev, "could not set mailbox\n"); + cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF); usb_remove_phy(&ddata->phy); cancel_delayed_work_sync(&ddata->detect_work); diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c index 85a8c97d9dfed2bfa0a9674596ea2a2bfbd15c93..5fe419e468ecc239ebd140bfceadc78fe6d65f6c 100644 --- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c +++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c @@ -54,8 +54,12 @@ /* drive strength control for ASIU GPIO */ #define IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58 -/* drive strength control for CCM/CRMU (AON) GPIO */ -#define IPROC_GPIO_DRV0_CTRL_OFFSET 0x00 +/* pinconf for CCM GPIO */ +#define IPROC_GPIO_PULL_DN_OFFSET 0x10 +#define IPROC_GPIO_PULL_UP_OFFSET 0x14 + +/* pinconf for CRMU(aon) GPIO and CCM GPIO*/ +#define IPROC_GPIO_DRV_CTRL_OFFSET 0x00 #define GPIO_BANK_SIZE 0x200 #define NGPIOS_PER_BANK 32 @@ -76,6 +80,12 @@ enum iproc_pinconf_param { IPROC_PINCON_MAX, }; +enum iproc_pinconf_ctrl_type { + IOCTRL_TYPE_AON = 1, + IOCTRL_TYPE_CDRU, + IOCTRL_TYPE_INVALID, +}; + /* * Iproc GPIO core * @@ -100,6 +110,7 @@ struct iproc_gpio { void __iomem *base; void __iomem *io_ctrl; + enum iproc_pinconf_ctrl_type io_ctrl_type; raw_spinlock_t lock; @@ -461,20 +472,44 @@ static const struct pinctrl_ops iproc_pctrl_ops = { static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio, bool disable, bool pull_up) { + void __iomem *base; unsigned long flags; + unsigned int shift; + u32 val_1, val_2; raw_spin_lock_irqsave(&chip->lock, flags); - - if (disable) { - iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, false); + if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) { + base = chip->io_ctrl; + shift = IPROC_GPIO_SHIFT(gpio); + + val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET); + val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET); + if (disable) { + /* no pull-up or pull-down */ + val_1 &= ~BIT(shift); + val_2 &= ~BIT(shift); + } else if (pull_up) { + val_1 |= BIT(shift); + val_2 &= ~BIT(shift); + } else { + val_1 &= ~BIT(shift); + val_2 |= BIT(shift); + } + writel(val_1, base + IPROC_GPIO_PULL_UP_OFFSET); + writel(val_2, base + IPROC_GPIO_PULL_DN_OFFSET); } else { - iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio, - pull_up); - iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, true); + if (disable) { + iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, + false); + } else { + iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio, + pull_up); + iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, + true); + } } raw_spin_unlock_irqrestore(&chip->lock, flags); - dev_dbg(chip->dev, "gpio:%u set pullup:%d\n", gpio, pull_up); return 0; @@ -483,14 +518,35 @@ static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio, static void iproc_gpio_get_pull(struct iproc_gpio *chip, unsigned gpio, bool *disable, bool *pull_up) { + void __iomem *base; unsigned long flags; + unsigned int shift; + u32 val_1, val_2; raw_spin_lock_irqsave(&chip->lock, flags); - *disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio); - *pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio); + if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) { + base = chip->io_ctrl; + shift = IPROC_GPIO_SHIFT(gpio); + + val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET) & BIT(shift); + val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET) & BIT(shift); + + *pull_up = val_1 ? true : false; + *disable = (val_1 | val_2) ? false : true; + + } else { + *disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio); + *pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio); + } raw_spin_unlock_irqrestore(&chip->lock, flags); } +#define DRV_STRENGTH_OFFSET(gpio, bit, type) ((type) == IOCTRL_TYPE_AON ? \ + ((2 - (bit)) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \ + ((type) == IOCTRL_TYPE_CDRU) ? \ + ((bit) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \ + ((bit) * 4 + IPROC_GPIO_REG(gpio, IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET))) + static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio, unsigned strength) { @@ -505,11 +561,8 @@ static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio, if (chip->io_ctrl) { base = chip->io_ctrl; - offset = IPROC_GPIO_DRV0_CTRL_OFFSET; } else { base = chip->base; - offset = IPROC_GPIO_REG(gpio, - IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET); } shift = IPROC_GPIO_SHIFT(gpio); @@ -520,11 +573,11 @@ static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio, raw_spin_lock_irqsave(&chip->lock, flags); strength = (strength / 2) - 1; for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) { + offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type); val = readl(base + offset); val &= ~BIT(shift); val |= ((strength >> i) & 0x1) << shift; writel(val, base + offset); - offset += 4; } raw_spin_unlock_irqrestore(&chip->lock, flags); @@ -541,11 +594,8 @@ static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio, if (chip->io_ctrl) { base = chip->io_ctrl; - offset = IPROC_GPIO_DRV0_CTRL_OFFSET; } else { base = chip->base; - offset = IPROC_GPIO_REG(gpio, - IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET); } shift = IPROC_GPIO_SHIFT(gpio); @@ -553,10 +603,10 @@ static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio, raw_spin_lock_irqsave(&chip->lock, flags); *strength = 0; for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) { + offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type); val = readl(base + offset) & BIT(shift); val >>= shift; *strength += (val << i); - offset += 4; } /* convert to mA */ @@ -734,6 +784,7 @@ static int iproc_gpio_probe(struct platform_device *pdev) u32 ngpios, pinconf_disable_mask = 0; int irq, ret; bool no_pinconf = false; + enum iproc_pinconf_ctrl_type io_ctrl_type = IOCTRL_TYPE_INVALID; /* NSP does not support drive strength config */ if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio")) @@ -764,8 +815,15 @@ static int iproc_gpio_probe(struct platform_device *pdev) dev_err(dev, "unable to map I/O memory\n"); return PTR_ERR(chip->io_ctrl); } + if (of_device_is_compatible(dev->of_node, + "brcm,cygnus-ccm-gpio")) + io_ctrl_type = IOCTRL_TYPE_CDRU; + else + io_ctrl_type = IOCTRL_TYPE_AON; } + chip->io_ctrl_type = io_ctrl_type; + if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) { dev_err(&pdev->dev, "missing ngpios DT property\n"); return -ENODEV; diff --git a/drivers/pinctrl/intel/pinctrl-lewisburg.c b/drivers/pinctrl/intel/pinctrl-lewisburg.c index 14d56ea6cfdcec76f7760876eea147fb865243a1..c2164db14e9cf9a6571eb3893a2b44cb2a23881a 100644 --- a/drivers/pinctrl/intel/pinctrl-lewisburg.c +++ b/drivers/pinctrl/intel/pinctrl-lewisburg.c @@ -34,6 +34,7 @@ .npins = ((e) - (s) + 1), \ } +/* Lewisburg */ static const struct pinctrl_pin_desc lbg_pins[] = { /* GPP_A */ PINCTRL_PIN(0, "RCINB"), @@ -73,7 +74,7 @@ static const struct pinctrl_pin_desc lbg_pins[] = { PINCTRL_PIN(33, "SRCCLKREQB_4"), PINCTRL_PIN(34, "SRCCLKREQB_5"), PINCTRL_PIN(35, "GPP_B_11"), - PINCTRL_PIN(36, "GLB_RST_WARN_N"), + PINCTRL_PIN(36, "SLP_S0B"), PINCTRL_PIN(37, "PLTRSTB"), PINCTRL_PIN(38, "SPKR"), PINCTRL_PIN(39, "GPP_B_15"), @@ -186,96 +187,96 @@ static const struct pinctrl_pin_desc lbg_pins[] = { PINCTRL_PIN(141, "GBE_PCI_DIS"), PINCTRL_PIN(142, "GBE_LAN_DIS"), PINCTRL_PIN(143, "GPP_I_10"), - PINCTRL_PIN(144, "GPIO_RCOMP_3P3"), /* GPP_J */ - PINCTRL_PIN(145, "GBE_LED_0_0"), - PINCTRL_PIN(146, "GBE_LED_0_1"), - PINCTRL_PIN(147, "GBE_LED_1_0"), - PINCTRL_PIN(148, "GBE_LED_1_1"), - PINCTRL_PIN(149, "GBE_LED_2_0"), - PINCTRL_PIN(150, "GBE_LED_2_1"), - PINCTRL_PIN(151, "GBE_LED_3_0"), - PINCTRL_PIN(152, "GBE_LED_3_1"), - PINCTRL_PIN(153, "GBE_SCL_0"), - PINCTRL_PIN(154, "GBE_SDA_0"), - PINCTRL_PIN(155, "GBE_SCL_1"), - PINCTRL_PIN(156, "GBE_SDA_1"), - PINCTRL_PIN(157, "GBE_SCL_2"), - PINCTRL_PIN(158, "GBE_SDA_2"), - PINCTRL_PIN(159, "GBE_SCL_3"), - PINCTRL_PIN(160, "GBE_SDA_3"), - PINCTRL_PIN(161, "GBE_SDP_0_0"), - PINCTRL_PIN(162, "GBE_SDP_0_1"), - PINCTRL_PIN(163, "GBE_SDP_1_0"), - PINCTRL_PIN(164, "GBE_SDP_1_1"), - PINCTRL_PIN(165, "GBE_SDP_2_0"), - PINCTRL_PIN(166, "GBE_SDP_2_1"), - PINCTRL_PIN(167, "GBE_SDP_3_0"), - PINCTRL_PIN(168, "GBE_SDP_3_1"), + PINCTRL_PIN(144, "GBE_LED_0_0"), + PINCTRL_PIN(145, "GBE_LED_0_1"), + PINCTRL_PIN(146, "GBE_LED_1_0"), + PINCTRL_PIN(147, "GBE_LED_1_1"), + PINCTRL_PIN(148, "GBE_LED_2_0"), + PINCTRL_PIN(149, "GBE_LED_2_1"), + PINCTRL_PIN(150, "GBE_LED_3_0"), + PINCTRL_PIN(151, "GBE_LED_3_1"), + PINCTRL_PIN(152, "GBE_SCL_0"), + PINCTRL_PIN(153, "GBE_SDA_0"), + PINCTRL_PIN(154, "GBE_SCL_1"), + PINCTRL_PIN(155, "GBE_SDA_1"), + PINCTRL_PIN(156, "GBE_SCL_2"), + PINCTRL_PIN(157, "GBE_SDA_2"), + PINCTRL_PIN(158, "GBE_SCL_3"), + PINCTRL_PIN(159, "GBE_SDA_3"), + PINCTRL_PIN(160, "GBE_SDP_0_0"), + PINCTRL_PIN(161, "GBE_SDP_0_1"), + PINCTRL_PIN(162, "GBE_SDP_1_0"), + PINCTRL_PIN(163, "GBE_SDP_1_1"), + PINCTRL_PIN(164, "GBE_SDP_2_0"), + PINCTRL_PIN(165, "GBE_SDP_2_1"), + PINCTRL_PIN(166, "GBE_SDP_3_0"), + PINCTRL_PIN(167, "GBE_SDP_3_1"), /* GPP_K */ - PINCTRL_PIN(169, "GBE_RMIICLK"), - PINCTRL_PIN(170, "GBE_RMII_TXD_0"), - PINCTRL_PIN(171, "GBE_RMII_TXD_1"), + PINCTRL_PIN(168, "GBE_RMIICLK"), + PINCTRL_PIN(169, "GBE_RMII_RXD_0"), + PINCTRL_PIN(170, "GBE_RMII_RXD_1"), + PINCTRL_PIN(171, "GBE_RMII_CRS_DV"), PINCTRL_PIN(172, "GBE_RMII_TX_EN"), - PINCTRL_PIN(173, "GBE_RMII_CRS_DV"), - PINCTRL_PIN(174, "GBE_RMII_RXD_0"), - PINCTRL_PIN(175, "GBE_RMII_RXD_1"), - PINCTRL_PIN(176, "GBE_RMII_RX_ER"), - PINCTRL_PIN(177, "GBE_RMII_ARBIN"), - PINCTRL_PIN(178, "GBE_RMII_ARB_OUT"), - PINCTRL_PIN(179, "PE_RST_N"), - PINCTRL_PIN(180, "GPIO_RCOMP_1P8_3P3"), + PINCTRL_PIN(173, "GBE_RMII_TXD_0"), + PINCTRL_PIN(174, "GBE_RMII_TXD_1"), + PINCTRL_PIN(175, "GBE_RMII_RX_ER"), + PINCTRL_PIN(176, "GBE_RMII_ARBIN"), + PINCTRL_PIN(177, "GBE_RMII_ARB_OUT"), + PINCTRL_PIN(178, "PE_RST_N"), /* GPP_G */ - PINCTRL_PIN(181, "FAN_TACH_0"), - PINCTRL_PIN(182, "FAN_TACH_1"), - PINCTRL_PIN(183, "FAN_TACH_2"), - PINCTRL_PIN(184, "FAN_TACH_3"), - PINCTRL_PIN(185, "FAN_TACH_4"), - PINCTRL_PIN(186, "FAN_TACH_5"), - PINCTRL_PIN(187, "FAN_TACH_6"), - PINCTRL_PIN(188, "FAN_TACH_7"), - PINCTRL_PIN(189, "FAN_PWM_0"), - PINCTRL_PIN(190, "FAN_PWM_1"), - PINCTRL_PIN(191, "FAN_PWM_2"), - PINCTRL_PIN(192, "FAN_PWM_3"), - PINCTRL_PIN(193, "GSXDOUT"), - PINCTRL_PIN(194, "GSXSLOAD"), - PINCTRL_PIN(195, "GSXDIN"), - PINCTRL_PIN(196, "GSXSRESETB"), - PINCTRL_PIN(197, "GSXCLK"), - PINCTRL_PIN(198, "ADR_COMPLETE"), - PINCTRL_PIN(199, "NMIB"), - PINCTRL_PIN(200, "SMIB"), - PINCTRL_PIN(201, "SSATA_DEVSLP_0"), - PINCTRL_PIN(202, "SSATA_DEVSLP_1"), - PINCTRL_PIN(203, "SSATA_DEVSLP_2"), - PINCTRL_PIN(204, "SSATAXPCIE0_SSATAGP0"), + PINCTRL_PIN(179, "FAN_TACH_0"), + PINCTRL_PIN(180, "FAN_TACH_1"), + PINCTRL_PIN(181, "FAN_TACH_2"), + PINCTRL_PIN(182, "FAN_TACH_3"), + PINCTRL_PIN(183, "FAN_TACH_4"), + PINCTRL_PIN(184, "FAN_TACH_5"), + PINCTRL_PIN(185, "FAN_TACH_6"), + PINCTRL_PIN(186, "FAN_TACH_7"), + PINCTRL_PIN(187, "FAN_PWM_0"), + PINCTRL_PIN(188, "FAN_PWM_1"), + PINCTRL_PIN(189, "FAN_PWM_2"), + PINCTRL_PIN(190, "FAN_PWM_3"), + PINCTRL_PIN(191, "GSXDOUT"), + PINCTRL_PIN(192, "GSXSLOAD"), + PINCTRL_PIN(193, "GSXDIN"), + PINCTRL_PIN(194, "GSXSRESETB"), + PINCTRL_PIN(195, "GSXCLK"), + PINCTRL_PIN(196, "ADR_COMPLETE"), + PINCTRL_PIN(197, "NMIB"), + PINCTRL_PIN(198, "SMIB"), + PINCTRL_PIN(199, "SSATA_DEVSLP_0"), + PINCTRL_PIN(200, "SSATA_DEVSLP_1"), + PINCTRL_PIN(201, "SSATA_DEVSLP_2"), + PINCTRL_PIN(202, "SSATAXPCIE0_SSATAGP0"), /* GPP_H */ - PINCTRL_PIN(205, "SRCCLKREQB_6"), - PINCTRL_PIN(206, "SRCCLKREQB_7"), - PINCTRL_PIN(207, "SRCCLKREQB_8"), - PINCTRL_PIN(208, "SRCCLKREQB_9"), - PINCTRL_PIN(209, "SRCCLKREQB_10"), - PINCTRL_PIN(210, "SRCCLKREQB_11"), - PINCTRL_PIN(211, "SRCCLKREQB_12"), - PINCTRL_PIN(212, "SRCCLKREQB_13"), - PINCTRL_PIN(213, "SRCCLKREQB_14"), - PINCTRL_PIN(214, "SRCCLKREQB_15"), - PINCTRL_PIN(215, "SML2CLK"), - PINCTRL_PIN(216, "SML2DATA"), - PINCTRL_PIN(217, "SML2ALERTB"), - PINCTRL_PIN(218, "SML3CLK"), - PINCTRL_PIN(219, "SML3DATA"), - PINCTRL_PIN(220, "SML3ALERTB"), - PINCTRL_PIN(221, "SML4CLK"), - PINCTRL_PIN(222, "SML4DATA"), - PINCTRL_PIN(223, "SML4ALERTB"), - PINCTRL_PIN(224, "SSATAXPCIE1_SSATAGP1"), - PINCTRL_PIN(225, "SSATAXPCIE2_SSATAGP2"), - PINCTRL_PIN(226, "SSATAXPCIE3_SSATAGP3"), - PINCTRL_PIN(227, "SSATAXPCIE4_SSATAGP4"), - PINCTRL_PIN(228, "SSATAXPCIE5_SSATAGP5"), + PINCTRL_PIN(203, "SRCCLKREQB_6"), + PINCTRL_PIN(204, "SRCCLKREQB_7"), + PINCTRL_PIN(205, "SRCCLKREQB_8"), + PINCTRL_PIN(206, "SRCCLKREQB_9"), + PINCTRL_PIN(207, "SRCCLKREQB_10"), + PINCTRL_PIN(208, "SRCCLKREQB_11"), + PINCTRL_PIN(209, "SRCCLKREQB_12"), + PINCTRL_PIN(210, "SRCCLKREQB_13"), + PINCTRL_PIN(211, "SRCCLKREQB_14"), + PINCTRL_PIN(212, "SRCCLKREQB_15"), + PINCTRL_PIN(213, "SML2CLK"), + PINCTRL_PIN(214, "SML2DATA"), + PINCTRL_PIN(215, "SML2ALERTB"), + PINCTRL_PIN(216, "SML3CLK"), + PINCTRL_PIN(217, "SML3DATA"), + PINCTRL_PIN(218, "SML3ALERTB"), + PINCTRL_PIN(219, "SML4CLK"), + PINCTRL_PIN(220, "SML4DATA"), + PINCTRL_PIN(221, "SML4ALERTB"), + PINCTRL_PIN(222, "SSATAXPCIE1_SSATAGP1"), + PINCTRL_PIN(223, "SSATAXPCIE2_SSATAGP2"), + PINCTRL_PIN(224, "SSATAXPCIE3_SSATAGP3"), + PINCTRL_PIN(225, "SSATAXPCIE4_SSATAGP4"), + PINCTRL_PIN(226, "SSATAXPCIE5_SSATAGP5"), /* GPP_L */ + PINCTRL_PIN(227, "GPP_L_0"), + PINCTRL_PIN(228, "EC_CSME_INTR_OUT"), PINCTRL_PIN(229, "VISA2CH0_D0"), PINCTRL_PIN(230, "VISA2CH0_D1"), PINCTRL_PIN(231, "VISA2CH0_D2"), diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 2eec26f7fbd5385cd6c97525088536231c125c60..b6a6aa007f1969bb37e78121bbd5c1fa07cb0a9d 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -750,6 +750,7 @@ static void msm_gpio_irq_enable(struct irq_data *d) static void msm_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + uint32_t irqtype = irqd_get_trigger_type(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); const struct msm_pingroup *g; unsigned long flags; @@ -761,6 +762,12 @@ static void msm_gpio_irq_unmask(struct irq_data *d) raw_spin_lock_irqsave(&pctrl->lock, flags); + if (irqtype & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) { + val = readl_relaxed(pctrl->regs + g->intr_status_reg); + val &= ~BIT(g->intr_status_bit); + writel_relaxed(val, pctrl->regs + g->intr_status_reg); + } + val = readl(base + g->intr_cfg_reg); val |= BIT(g->intr_enable_bit); writel(val, base + g->intr_cfg_reg); diff --git a/drivers/pinctrl/sh-pfc/pfc-emev2.c b/drivers/pinctrl/sh-pfc/pfc-emev2.c index 1cbbe04d7df657e8fa11bfddc93433739a9a73ec..eafd8edbcbe95b7ec9ac64ab723dc9443af8016d 100644 --- a/drivers/pinctrl/sh-pfc/pfc-emev2.c +++ b/drivers/pinctrl/sh-pfc/pfc-emev2.c @@ -1263,6 +1263,14 @@ static const char * const dtv_groups[] = { "dtv_b", }; +static const char * const err_rst_reqb_groups[] = { + "err_rst_reqb", +}; + +static const char * const ext_clki_groups[] = { + "ext_clki", +}; + static const char * const iic0_groups[] = { "iic0", }; @@ -1285,6 +1293,10 @@ static const char * const lcd_groups[] = { "yuv3", }; +static const char * const lowpwr_groups[] = { + "lowpwr", +}; + static const char * const ntsc_groups[] = { "ntsc_clk", "ntsc_data", @@ -1298,6 +1310,10 @@ static const char * const pwm1_groups[] = { "pwm1", }; +static const char * const ref_clko_groups[] = { + "ref_clko", +}; + static const char * const sd_groups[] = { "sd_cki", }; @@ -1391,13 +1407,17 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(cam), SH_PFC_FUNCTION(cf), SH_PFC_FUNCTION(dtv), + SH_PFC_FUNCTION(err_rst_reqb), + SH_PFC_FUNCTION(ext_clki), SH_PFC_FUNCTION(iic0), SH_PFC_FUNCTION(iic1), SH_PFC_FUNCTION(jtag), SH_PFC_FUNCTION(lcd), + SH_PFC_FUNCTION(lowpwr), SH_PFC_FUNCTION(ntsc), SH_PFC_FUNCTION(pwm0), SH_PFC_FUNCTION(pwm1), + SH_PFC_FUNCTION(ref_clko), SH_PFC_FUNCTION(sd), SH_PFC_FUNCTION(sdi0), SH_PFC_FUNCTION(sdi1), diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c index 35f436bcb849185a559f4ad4095b6914d5163f4c..e9739dbcb356e90b9e19538886f6acf732eb1e06 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c @@ -1982,7 +1982,7 @@ static const unsigned int gether_gmii_pins[] = { */ 185, 186, 187, 188, 189, 190, 191, 192, 174, 161, 204, 171, 170, 169, 168, 167, 166, 173, 172, 176, 184, 183, 203, - 205, 163, 206, 207, + 205, 163, 206, 207, 158, }; static const unsigned int gether_gmii_mux[] = { ET_ERXD0_MARK, ET_ERXD1_MARK, ET_ERXD2_MARK, ET_ERXD3_MARK, @@ -2154,6 +2154,7 @@ static const unsigned int lcd0_data24_1_mux[] = { LCD0_D0_MARK, LCD0_D1_MARK, LCD0_D2_MARK, LCD0_D3_MARK, LCD0_D4_MARK, LCD0_D5_MARK, LCD0_D6_MARK, LCD0_D7_MARK, LCD0_D8_MARK, LCD0_D9_MARK, LCD0_D10_MARK, LCD0_D11_MARK, + LCD0_D12_MARK, LCD0_D13_MARK, LCD0_D14_MARK, LCD0_D15_MARK, LCD0_D16_MARK, LCD0_D17_MARK, LCD0_D18_PORT163_MARK, LCD0_D19_PORT162_MARK, LCD0_D20_PORT161_MARK, LCD0_D21_PORT158_MARK, LCD0_D22_PORT160_MARK, LCD0_D23_PORT159_MARK, diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index c01ef02d326b7bc23983885e84348236b219cdc2..e4774b220040527e085eb8afae7a7cb4b4333849 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -3220,8 +3220,7 @@ static const unsigned int qspi_data4_b_pins[] = { RCAR_GP_PIN(6, 4), }; static const unsigned int qspi_data4_b_mux[] = { - SPCLK_B_MARK, MOSI_IO0_B_MARK, MISO_IO1_B_MARK, - IO2_B_MARK, IO3_B_MARK, SSL_B_MARK, + MOSI_IO0_B_MARK, MISO_IO1_B_MARK, IO2_B_MARK, IO3_B_MARK, }; /* - SCIF0 ------------------------------------------------------------------ */ static const unsigned int scif0_data_pins[] = { @@ -4349,17 +4348,14 @@ static const unsigned int vin1_b_data18_pins[] = { }; static const unsigned int vin1_b_data18_mux[] = { /* B */ - VI1_DATA0_B_MARK, VI1_DATA1_B_MARK, VI1_DATA2_B_MARK, VI1_DATA3_B_MARK, VI1_DATA4_B_MARK, VI1_DATA5_B_MARK, VI1_DATA6_B_MARK, VI1_DATA7_B_MARK, /* G */ - VI1_G0_B_MARK, VI1_G1_B_MARK, VI1_G2_B_MARK, VI1_G3_B_MARK, VI1_G4_B_MARK, VI1_G5_B_MARK, VI1_G6_B_MARK, VI1_G7_B_MARK, /* R */ - VI1_R0_B_MARK, VI1_R1_B_MARK, VI1_R2_B_MARK, VI1_R3_B_MARK, VI1_R4_B_MARK, VI1_R5_B_MARK, VI1_R6_B_MARK, VI1_R7_B_MARK, @@ -5213,7 +5209,7 @@ static const char * const scifb2_groups[] = { "scifb2_data_b", "scifb2_clk_b", "scifb2_ctrl_b", - "scifb0_data_c", + "scifb2_data_c", "scifb2_clk_c", "scifb2_data_d", }; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c index cc3597f66605a3e2d1960534b755f3e70062353c..46c41ca6ea38b6f958e0fcc42551a890b412c478 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c @@ -1916,6 +1916,7 @@ static const char * const vin1_groups[] = { "vin1_data8", "vin1_data24_b", "vin1_data20_b", + "vin1_data18_b", "vin1_data16_b", "vin1_sync", "vin1_field", diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c index a0ed220071f5faf496c12967d45ab9faa15a10e6..93bdd3e8fb6700f7053d5015b637268a7b7d2b45 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c @@ -4742,7 +4742,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_AVB_MDC, FN_SSI_SDATA6_B, 0, 0, } }, { PINMUX_CFG_REG_VAR("IPSR9", 0xE6060044, 32, - 1, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3) { + 1, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3) { /* IP9_31 [1] */ 0, 0, /* IP9_30_28 [3] */ diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c index 4f5ee1d7317d36a635aac3b1344b76559851e1fa..36421df1b32600424f80ca931eedb0c90aeaeb19 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c @@ -391,10 +391,10 @@ FM(IP12_31_28) IP12_31_28 \ #define MOD_SEL0_27 FM(SEL_MSIOF3_0) FM(SEL_MSIOF3_1) #define MOD_SEL0_26 FM(SEL_HSCIF3_0) FM(SEL_HSCIF3_1) #define MOD_SEL0_25 FM(SEL_SCIF4_0) FM(SEL_SCIF4_1) -#define MOD_SEL0_24_23 FM(SEL_PWM0_0) FM(SEL_PWM0_1) FM(SEL_PWM0_2) FM(SEL_PWM0_3) -#define MOD_SEL0_22_21 FM(SEL_PWM1_0) FM(SEL_PWM1_1) FM(SEL_PWM1_2) FM(SEL_PWM1_3) -#define MOD_SEL0_20_19 FM(SEL_PWM2_0) FM(SEL_PWM2_1) FM(SEL_PWM2_2) FM(SEL_PWM2_3) -#define MOD_SEL0_18_17 FM(SEL_PWM3_0) FM(SEL_PWM3_1) FM(SEL_PWM3_2) FM(SEL_PWM3_3) +#define MOD_SEL0_24_23 FM(SEL_PWM0_0) FM(SEL_PWM0_1) FM(SEL_PWM0_2) F_(0, 0) +#define MOD_SEL0_22_21 FM(SEL_PWM1_0) FM(SEL_PWM1_1) FM(SEL_PWM1_2) F_(0, 0) +#define MOD_SEL0_20_19 FM(SEL_PWM2_0) FM(SEL_PWM2_1) FM(SEL_PWM2_2) F_(0, 0) +#define MOD_SEL0_18_17 FM(SEL_PWM3_0) FM(SEL_PWM3_1) FM(SEL_PWM3_2) F_(0, 0) #define MOD_SEL0_15 FM(SEL_IRQ_0_0) FM(SEL_IRQ_0_1) #define MOD_SEL0_14 FM(SEL_IRQ_1_0) FM(SEL_IRQ_1_1) #define MOD_SEL0_13 FM(SEL_IRQ_2_0) FM(SEL_IRQ_2_1) diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7269.c b/drivers/pinctrl/sh-pfc/pfc-sh7269.c index a50d22bef1f444517523c6bce95dc091a7d42b9a..cfdb4fc177c3e2133cf8b59afce5b7fbcc91a28b 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7269.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7269.c @@ -2119,7 +2119,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { }, { PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PC8_IN, PC8_OUT, PC7_IN, PC7_OUT, PC6_IN, PC6_OUT, diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c index d25e6f674d0aba84cdb3ca7ba9b555eba0729f13..6dca760f9f280dd5997cfb266a535aeeac814e03 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c @@ -3086,6 +3086,7 @@ static const unsigned int tpu4_to2_mux[] = { }; static const unsigned int tpu4_to3_pins[] = { /* TO */ + PIN_NUMBER(6, 26), }; static const unsigned int tpu4_to3_mux[] = { TPU4TO3_MARK, @@ -3366,7 +3367,8 @@ static const char * const fsic_groups[] = { "fsic_sclk_out", "fsic_data_in", "fsic_data_out", - "fsic_spdif", + "fsic_spdif_0", + "fsic_spdif_1", }; static const char * const fsid_groups[] = { diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c index 3eccc9b3ca84aabe8ce6081355a0a3f7f7dee752..c691e5e9d9dea56d2a16dcc416cd53c0d6d4ec4a 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c @@ -2231,13 +2231,13 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_LCD_CL1_B, 0, 0, /* IP10_5_3 [3] */ FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B, - FN_LCD_DON_B, 0, 0, 0, + FN_LCD_DON_B, 0, 0, /* IP10_2_0 [3] */ FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B, FN_LCD_DATA15_B, 0, 0, 0 } }, { PINMUX_CFG_REG_VAR("IPSR11", 0xFFFC0048, 32, - 3, 1, 2, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) { + 3, 1, 2, 3, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) { /* IP11_31_29 [3] */ 0, 0, 0, 0, 0, 0, 0, 0, /* IP11_28 [1] */ diff --git a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c index 5c1b6325d80d183040952cfc146f72005670c0d7..8ac1f1ce44422f3c9dc986b17b8082e023d0d2af 100644 --- a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c +++ b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c @@ -496,7 +496,7 @@ static int ti_iodelay_dt_node_to_map(struct pinctrl_dev *pctldev, return -EINVAL; rows = pinctrl_count_index_with_args(np, name); - if (rows == -EINVAL) + if (rows < 0) return rows; *map = devm_kzalloc(iod->dev, sizeof(**map), GFP_KERNEL); diff --git a/drivers/platform/mips/cpu_hwmon.c b/drivers/platform/mips/cpu_hwmon.c index 322de58eebaf57a0d15690a5c0805209093f4c5b..02484ae9a1165e8f1c4fd681cd27cb8a693eb579 100644 --- a/drivers/platform/mips/cpu_hwmon.c +++ b/drivers/platform/mips/cpu_hwmon.c @@ -158,7 +158,7 @@ static int __init loongson_hwmon_init(void) cpu_hwmon_dev = hwmon_device_register(NULL); if (IS_ERR(cpu_hwmon_dev)) { - ret = -ENOMEM; + ret = PTR_ERR(cpu_hwmon_dev); pr_err("hwmon_device_register fail!\n"); goto fail_hwmon_device_register; } diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index 5b7d70823b2f7552fdb7faf68cf00071f0a70471..25893daa688603fb31d88b2d7db77b4d5bd7608d 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -298,6 +298,13 @@ config IPA3_REGDUMP This option is to be used when the saving of IPA/GSI register state is desired upon system crash. +config QCOM_ETHERNET_UTIL + bool "ethernet utilities" + depends on PCI + help + This module will provide API's for clients to attach smmu & + other functionalities + choice prompt "Platform whose registers are to be dumped/collected" depends on IPA3_REGDUMP diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile index 2bc4e11a77e547de2c2a5dc82cac947a1b7136d3..05cf004e10b7f09cd58931e5a01e5054dbab0d64 100644 --- a/drivers/platform/msm/Makefile +++ b/drivers/platform/msm/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/ obj-$(CONFIG_MSM_11AD) += msm_11ad/ obj-$(CONFIG_SEEMP_CORE) += seemp_core/ obj-$(CONFIG_VETH_IPA) += veth_ipa/ +obj-$(CONFIG_QCOM_ETHERNET_UTIL) += ethernet/ diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index a6044f85c39d5a599cd18a7b4032e851fd42b0e6..e77734e1b476193c8c493249a52e736a83b841a7 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -372,6 +372,7 @@ struct ep_pcie_dev_t { u32 dbi_base_reg; u32 slv_space_reg; u32 phy_status_reg; + u32 phy_status_bit_mask_bit; u32 phy_init_len; u32 mhi_soc_reset_offset; struct ep_pcie_phy_info_t *phy_init; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index e087bd4c93bfff2c55d83b7dc77e2f9b75b48e29..d3c79d7a291235bb0547da2c40353b2bf132da89 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "ep_pcie_com.h" #include @@ -1712,6 +1713,15 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) ep_pcie_core_init(dev, true); dev->link_status = EP_PCIE_LINK_UP; dev->l23_ready = false; + + /* enable pipe clock for early link init case*/ + ret = ep_pcie_pipe_clk_init(dev); + if (ret) { + EP_PCIE_ERR(dev, + "PCIe V%d: failed to enable pipe clock\n", + dev->rev); + goto pipe_clk_fail; + } goto checkbme; } else { ltssm_en = readl_relaxed(dev->parf @@ -1884,6 +1894,9 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) EP_PCIE_INFO(dev, "PCIe V%d: link initialized for LE PCIe endpoint\n", dev->rev); + pr_crit("PCIe - link initialized for LE PCIe endpoint\n"); + place_marker( + "PCIe - link initialized for LE PCIe endpoint\n"); } checkbme: @@ -3074,6 +3087,21 @@ static int ep_pcie_probe(struct platform_device *pdev) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: phy-status-reg:0x%x\n", ep_pcie_dev.rev, ep_pcie_dev.phy_status_reg); + ep_pcie_dev.phy_status_bit_mask_bit = BIT(6); + + ret = of_property_read_u32((&pdev->dev)->of_node, + "qcom,phy-status-reg2", + &ep_pcie_dev.phy_status_reg); + if (ret) { + EP_PCIE_DBG(&ep_pcie_dev, + "PCIe V%d: phy-status-reg2 does not exist\n", + ep_pcie_dev.rev); + } else { + EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: phy-status-reg2:0x%x\n", + ep_pcie_dev.rev, ep_pcie_dev.phy_status_reg); + ep_pcie_dev.phy_status_bit_mask_bit = BIT(7); + } + ep_pcie_dev.phy_rev = 1; ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,pcie-phy-ver", diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c index 89562ef33cea08a6b83975d2334afec6e872cf53..0b95947ba3d9088cc63be0fcf889fa3a55fd345e 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2019-2020, 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 @@ -158,7 +158,7 @@ bool ep_pcie_phy_is_ready(struct ep_pcie_dev_t *dev) else offset = PCIE_PHY_PCS_STATUS; - if (readl_relaxed(dev->phy + offset) & BIT(6)) + if (readl_relaxed(dev->phy + offset) & dev->phy_status_bit_mask_bit) return false; else return true; diff --git a/drivers/platform/msm/ethernet/Makefile b/drivers/platform/msm/ethernet/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bda2e6f994c3251d23abd06930d2370b21ef48b3 --- /dev/null +++ b/drivers/platform/msm/ethernet/Makefile @@ -0,0 +1 @@ +obj-y += qcom_eth_smmu.o diff --git a/drivers/platform/msm/ethernet/qcom_eth_smmu.c b/drivers/platform/msm/ethernet/qcom_eth_smmu.c new file mode 100644 index 0000000000000000000000000000000000000000..e42332609cd7c5ad361f1834b6b653bdbd447b78 --- /dev/null +++ b/drivers/platform/msm/ethernet/qcom_eth_smmu.c @@ -0,0 +1,243 @@ +/* Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include +#include +#include + +#include + +static int (*vendor_probe_real)(struct pci_dev *, const struct pci_device_id *); +static void (*vendor_remove_real)(struct pci_dev *); + +static int qcom_parse_smmu_attr(struct device *dev, + struct iommu_domain *domain, + const char *key, + enum iommu_attr attr) +{ + int rc = 0; + unsigned int data = 1; + + if (of_find_property(dev->of_node, key, NULL)) { + rc = iommu_domain_set_attr(domain, attr, &data); + if (!rc) + dev_dbg(dev, "enabled SMMU attribute %u\n", attr); + else + dev_err(dev, "failed to set SMMU attribute %u\n", attr); + } + + return rc; +} + +static int qcom_parse_smmu_attrs(struct device *dev, + struct iommu_domain *domain) +{ + int rc = 0; + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-s1-bypass", DOMAIN_ATTR_S1_BYPASS); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-fastmap", DOMAIN_ATTR_FAST); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-atomic", DOMAIN_ATTR_ATOMIC); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-pt-coherent", + DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-pt-coherent-force", + DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT); + + return rc; +} + +static int __qcom_attach_smmu(struct device *dev) +{ + int rc; + const char *key; + u64 val64; + + dma_addr_t iova_base = 0; + u64 iova_size = 0; + + struct dma_iommu_mapping *mapping = NULL; + + key = "qcom,smmu-iova-base"; + rc = of_property_read_u64(dev->of_node, key, &val64); + if (rc) { + dev_err(dev, "error parsing DT prop %s: %d\n", key, rc); + return rc; + } + + iova_base = (dma_addr_t)val64; + + key = "qcom,smmu-iova-size"; + rc = of_property_read_u64(dev->of_node, key, &val64); + if (rc) { + dev_err(dev, "error parsing DT prop %s: %d\n", key, rc); + return rc; + } + + iova_size = val64; + + dev_dbg(dev, "creating SMMU mapping with base=0x%llx, size=0x%llx\n", + iova_base, iova_size); + + mapping = arm_iommu_create_mapping(dev->bus, iova_base, iova_size); + if (IS_ERR(mapping)) { + dev_err(dev, "failed to create SMMU mapping\n"); + return PTR_ERR(mapping); + } + + rc = qcom_parse_smmu_attrs(dev, mapping->domain); + if (rc) { + dev_err(dev, "error parsing SMMU DT attributes\n"); + goto err_release_mapping; + } + + rc = arm_iommu_attach_device(dev, mapping); + if (rc) { + dev_err(dev, "failed to attach device to smmu\n"); + goto err_release_mapping; + } + + return 0; + +err_release_mapping: + arm_iommu_release_mapping(mapping); + return rc; +} + +static int qcom_attach_smmu(struct device *dev) +{ + bool dt_present = !!of_find_property(dev->of_node, "qcom,smmu", NULL); + bool smmu_attached = !!iommu_get_domain_for_dev(dev); + + if (smmu_attached) { + /* On platforms where IOMMU is attached automatically, we do + * not expect qcom,smmu property to be present in devicetree. + */ + if (dt_present) { + dev_err(dev, "SMMU DT node is not expected\n"); + return -EEXIST; + } + + return 0; + } + + if (!dt_present) { + dev_err(dev, "SMMU DT is required for the device\n"); + return -EFAULT; + } + + return __qcom_attach_smmu(dev); +} + +static void qcom_detach_smmu(struct device *dev) +{ + bool dt_present = !!of_find_property(dev->of_node, "qcom,smmu", NULL); + bool smmu_attached = !!iommu_get_domain_for_dev(dev); + + /* Perform a manual deattach only if we were tasked with doing the + * attach originally. + */ + if (dt_present && smmu_attached) { + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + if (!mapping) { + dev_err(dev, "Failed to retrieve IOMMU mapping\n"); + return; + } + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); + } +} + +static int vendor_qcom_probe( + struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int rc; + + rc = qcom_attach_smmu(&pdev->dev); + if (rc) + return rc; + + rc = vendor_probe_real(pdev, id); + if (rc) { + qcom_detach_smmu(&pdev->dev); + return rc; + } + + return 0; +} + +static void vendor_qcom_remove(struct pci_dev *pdev) +{ + vendor_remove_real(pdev); + qcom_detach_smmu(&pdev->dev); +} + +static int __vendor_qcom_register(struct pci_driver *pdrv) +{ + if (vendor_probe_real || vendor_remove_real) { + pr_warn("%s: Driver already registered\n", __func__); + return -EEXIST; + } + + vendor_probe_real = pdrv->probe; + pdrv->probe = vendor_qcom_probe; + + vendor_remove_real = pdrv->remove; + pdrv->remove = vendor_qcom_remove; + + return 0; +} + +static void __vendor_qcom_unregister(struct pci_driver *pdrv) +{ + if (vendor_probe_real) { + pdrv->probe = vendor_probe_real; + vendor_probe_real = NULL; + } + + if (vendor_remove_real) { + pdrv->remove = vendor_remove_real; + vendor_remove_real = NULL; + } +} + +int qcom_smmu_register(struct pci_driver *pdrv) +{ + int rc; + + rc = __vendor_qcom_register(pdrv); + if (rc) + return rc; + + + return 0; +} +EXPORT_SYMBOL(qcom_smmu_register); + +void qcom_smmu_unregister(struct pci_driver *pdrv) +{ + __vendor_qcom_unregister(pdrv); +} +EXPORT_SYMBOL(qcom_smmu_unregister); + diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index cba9f546fb3889c57abbad3f9f3c0c877a9807a3..0626b7f3234f7ace3f626037c2dfa2633863859c 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -2173,6 +2173,7 @@ static void gsi_program_chan_ctx(struct gsi_chan_props *props, unsigned int ee, break; case GSI_CHAN_PROT_AQC: case GSI_CHAN_PROT_11AD: + case GSI_CHAN_PROT_QDSS: prot_msb = 1; break; default: diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 0977a048f93d9d12c26c132498ecf97993c29857..755910c02582099e2e3504ecd3a461d87bac9d90 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -222,7 +222,7 @@ const char *ipa_clients_strings[IPA_CLIENT_MAX] = { __stringify(IPA_CLIENT_Q6_CV2X_CONS), __stringify(IPA_CLIENT_MHI_LOW_LAT_PROD), __stringify(IPA_CLIENT_MHI_LOW_LAT_CONS), - __stringify(RESERVERD_PROD_110), + __stringify(IPA_CLIENT_QDSS_PROD), __stringify(IPA_CLIENT_MHI_QDSS_CONS), }; @@ -3809,6 +3809,33 @@ bool ipa_pm_is_used(void) return ret; } +/** + * ipa_conn_qdss_pipes() - connect qdss pipes + */ +int ipa_qdss_conn_pipes(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out) +{ + int ret; + + IPA_API_DISPATCH_RETURN(ipa_conn_qdss_pipes, in, out); + + return ret; +} +EXPORT_SYMBOL(ipa_qdss_conn_pipes); + +/** + * ipa_disconn_qdss_pipes() - disconnect qdss pipes + */ +int ipa_qdss_disconn_pipes(void) +{ + int ret; + + IPA_API_DISPATCH_RETURN(ipa_disconn_qdss_pipes); + + return ret; +} +EXPORT_SYMBOL(ipa_qdss_disconn_pipes); + static const struct dev_pm_ops ipa_pm_ops = { .suspend_noirq = ipa_ap_suspend, .resume_noirq = ipa_ap_resume, diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h index 8b7799ca053c650b2d7d580d52ff5b8a11d313bb..b1f8a00d12ace432653c5e0a0a7304754740ff12 100644 --- a/drivers/platform/msm/ipa/ipa_api.h +++ b/drivers/platform/msm/ipa/ipa_api.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "ipa_common_i.h" #ifndef _IPA_API_H_ @@ -498,6 +499,11 @@ struct ipa_api_controller { int (*ipa_del_socksv5_conn)(uint32_t handle); + int (*ipa_conn_qdss_pipes)(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out); + + int (*ipa_disconn_qdss_pipes)(void); + }; #ifdef CONFIG_IPA diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c index 042ed5b0eb2cabfb38d386f6bae9d04f9b6e4af0..7090b63f4cc35bc19b3036180c62c4e6c33119e1 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c @@ -592,6 +592,10 @@ int ipa_uc_offload_conn_pipes(struct ipa_uc_offload_conn_in_params *inp, return -EPERM; } + /*Store the connection info, required during disconnect pipe */ + memcpy(&offload_ctx->conn, &inp->u.ntn, + sizeof(struct ipa_ntn_conn_in_params)); + switch (offload_ctx->proto) { case IPA_UC_NTN: ret = ipa_uc_ntn_conn_pipes(&inp->u.ntn, &outp->u.ntn, diff --git a/drivers/platform/msm/ipa/ipa_v3/Makefile b/drivers/platform/msm/ipa/ipa_v3/Makefile index a7b53937ac1e00d3ce1083596144bf25470afbcc..64096537f865885436eee3ef768e9b5ee1bbcd07 100644 --- a/drivers/platform/msm/ipa/ipa_v3/Makefile +++ b/drivers/platform/msm/ipa/ipa_v3/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_IPA3) += ipat.o ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \ ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o \ ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o \ - ipa_hw_stats.o ipa_pm.o ipa_wdi3_i.o ipa_odl.o ipa_wigig_i.o + ipa_hw_stats.o ipa_pm.o ipa_wdi3_i.o ipa_odl.o ipa_wigig_i.o ipa_qdss.o ipat-$(CONFIG_IPA_EMULATION) += ipa_dt_replacement.o diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index e2f6cb039253e7f52311cce846737f1141f3e29d..a1191427c30cf02c79c81ef85bd95ed2955a6e0c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -145,6 +145,7 @@ static struct { bool present[IPA_SMMU_CB_MAX]; bool arm_smmu; bool fast_map; + bool fast_map_arr[IPA_SMMU_CB_MAX]; bool s1_bypass_arr[IPA_SMMU_CB_MAX]; bool use_64_bit_dma_mask; u32 ipa_base; @@ -1014,7 +1015,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (!ipa3_is_ready()) { IPAERR("IPA not ready, waiting for init completion\n"); - wait_for_completion(&ipa3_ctx->init_completion_obj); + if (ipa3_ctx->manual_fw_load) { + if (!wait_for_completion_timeout( + &ipa3_ctx->init_completion_obj, + msecs_to_jiffies(1000))) { + IPAERR("IPA not ready, return\n"); + return -ETIME; + } + } else { + wait_for_completion(&ipa3_ctx->init_completion_obj); + } } IPA_ACTIVE_CLIENTS_INC_SIMPLE(); @@ -6891,6 +6901,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->uc_act_tbl_total = 0; ipa3_ctx->uc_act_tbl_next_index = 0; ipa3_ctx->ipa_config_is_auto = resource_p->ipa_config_is_auto; + ipa3_ctx->manual_fw_load = resource_p->manual_fw_load; if (ipa3_ctx->secure_debug_check_action == USE_SCM) { if (ipa_is_mem_dump_allowed()) @@ -7556,6 +7567,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->ipa_fltrt_not_hashable = false; ipa_drv_res->ipa_endp_delay_wa = false; ipa_drv_res->ipa_config_is_auto = false; + ipa_drv_res->manual_fw_load = false; /* Get IPA HW Version */ result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-ver", @@ -7965,6 +7977,13 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, IPADBG(": secure-debug-check-action = %d\n", ipa_drv_res->secure_debug_check_action); + ipa_drv_res->manual_fw_load = + of_property_read_bool(pdev->dev.of_node, + "qcom,manual-fw-load"); + IPADBG(": manual-fw-load (%s)\n", + ipa_drv_res->manual_fw_load + ? "True" : "False"); + return 0; } @@ -7998,6 +8017,9 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev) "dma-coherent"); cb->valid = true; + if (of_property_read_bool(dev->of_node, + "qcom,smmu-fast-map")) + smmu_info.fast_map_arr[IPA_SMMU_CB_WLAN] = true; if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass") || ipa3_ctx->ipa_config_is_mhi) { smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = true; @@ -8025,7 +8047,8 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev) } IPADBG(" WLAN SMMU ATTR ATOMIC\n"); - if (smmu_info.fast_map) { + if (smmu_info.fast_map_arr[IPA_SMMU_CB_WLAN] || + smmu_info.fast_map) { if (iommu_domain_set_attr(cb->iommu, DOMAIN_ATTR_FAST, &fast)) { @@ -8038,7 +8061,8 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev) } pr_info("IPA smmu_info.s1_bypass_arr[WLAN]=%d smmu_info.fast_map=%d\n", - smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN], smmu_info.fast_map); + smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN], + smmu_info.fast_map_arr[IPA_SMMU_CB_WLAN]); ret = iommu_attach_device(cb->iommu, dev); if (ret) { @@ -8106,6 +8130,10 @@ static int ipa_smmu_uc_cb_probe(struct device *dev) IPAERR("Fail to read UC start/size iova addresses\n"); return ret; } + + if (of_property_read_bool(dev->of_node, + "qcom,smmu-fast-map")) + smmu_info.fast_map_arr[IPA_SMMU_CB_UC] = true; cb->va_start = iova_ap_mapping[0]; cb->va_size = iova_ap_mapping[1]; cb->va_end = cb->va_start + cb->va_size; @@ -8170,7 +8198,8 @@ static int ipa_smmu_uc_cb_probe(struct device *dev) } IPADBG("SMMU atomic set\n"); - if (smmu_info.fast_map) { + if (smmu_info.fast_map_arr[IPA_SMMU_CB_UC] || + smmu_info.fast_map) { if (iommu_domain_set_attr(cb->mapping->domain, DOMAIN_ATTR_FAST, &fast)) { @@ -8184,7 +8213,8 @@ static int ipa_smmu_uc_cb_probe(struct device *dev) } pr_info("IPA smmu_info.s1_bypass_arr[UC]=%d smmu_info.fast_map=%d\n", - smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC], smmu_info.fast_map); + smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC], + smmu_info.fast_map_arr[IPA_SMMU_CB_UC]); IPADBG("UC CB PROBE sub pdev=%pK attaching IOMMU device\n", dev); ret = arm_iommu_attach_device(cb->dev, cb->mapping); @@ -8233,6 +8263,8 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) u32 size_p; phys_addr_t iova; phys_addr_t pa; + u32 geometry_mapping[2]; + struct iommu_domain_geometry geometry = {0}; IPADBG("AP CB probe: sub pdev=%pK\n", dev); @@ -8247,6 +8279,9 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) IPAERR("Fail to read AP start/size iova addresses\n"); return result; } + if (of_property_read_bool(dev->of_node, + "qcom,smmu-fast-map")) + smmu_info.fast_map_arr[IPA_SMMU_CB_AP] = true; cb->va_start = iova_ap_mapping[0]; cb->va_size = iova_ap_mapping[1]; cb->va_end = cb->va_start + cb->va_size; @@ -8307,7 +8342,8 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) } IPADBG("AP/USB SMMU atomic set\n"); - if (smmu_info.fast_map) { + if (smmu_info.fast_map_arr[IPA_SMMU_CB_AP] || + smmu_info.fast_map) { if (iommu_domain_set_attr(cb->mapping->domain, DOMAIN_ATTR_FAST, &fast)) { @@ -8317,11 +8353,26 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) return -EIO; } IPADBG("SMMU fast map set\n"); + result = of_property_read_u32_array(dev->of_node, + "qcom,geometry-mapping", + geometry_mapping, 2); + if (!result) { + IPAERR("AP Geometry start = %x size= %x\n", + geometry_mapping[0], geometry_mapping[1]); + geometry.aperture_start = geometry_mapping[0]; + geometry.aperture_end = geometry_mapping[1]; + if (iommu_domain_set_attr(cb->mapping->domain, + DOMAIN_ATTR_GEOMETRY, &geometry)) { + IPAERR("Failed to set AP GEOMETRY\n"); + return -EIO; + } + } } } pr_info("IPA smmu_info.s1_bypass_arr[AP]=%d smmu_info.fast_map=%d\n", - smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP], smmu_info.fast_map); + smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP], + smmu_info.fast_map_arr[IPA_SMMU_CB_AP]); result = arm_iommu_attach_device(cb->dev, cb->mapping); if (result) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 6dd01a7a843a70eaacdea5c41c131e9cfa63127b..16e5db011bb8643d39ee76de186cd59018f6ab9c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1840,6 +1840,7 @@ struct ipa3_app_clock_vote { * @app_vote: holds userspace application clock vote count * IPA context - holds all relevant info about IPA driver and its state * @coal_cmd_pyld: holds the coslescing close frame command payload + * @manual_fw_load: bool,if fw load is done manually */ struct ipa3_context { struct ipa3_char_device_context cdev; @@ -2019,6 +2020,7 @@ struct ipa3_context { struct mutex act_tbl_lock; int uc_act_tbl_total; int uc_act_tbl_next_index; + bool manual_fw_load; }; struct ipa3_plat_drv_res { @@ -2068,6 +2070,7 @@ struct ipa3_plat_drv_res { u32 secure_debug_check_action; bool ipa_mhi_proxy; bool ipa_wan_skb_page; + bool manual_fw_load; }; /** @@ -2391,6 +2394,9 @@ int ipa3_cfg_ep_route(u32 clnt_hdl, const struct ipa_ep_cfg_route *ipa_ep_cfg); int ipa3_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ipa_ep_cfg); +int ipa3_force_cfg_ep_holb(u32 clnt_hdl, + struct ipa_ep_cfg_holb *ipa_ep_cfg); + void ipa3_cal_ep_holb_scale_base_val(u32 tmr_val, struct ipa_ep_cfg_holb *ep_holb); @@ -2820,6 +2826,10 @@ void ipa3_debugfs_post_init(void); void ipa3_debugfs_remove(void); void ipa3_dump_buff_internal(void *base, dma_addr_t phy_base, u32 size); + +int ipa3_conn_qdss_pipes(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out); +int ipa3_disconn_qdss_pipes(void); #ifdef IPA_DEBUG #define IPA_DUMP_BUFF(base, phy_base, size) \ ipa3_dump_buff_internal(base, phy_base, size) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 8a2914bf968cc9c51500e0c93d0f333d426ae513..62cbce233e88606fb6135abd7e7266155e15e5fb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -20,7 +20,6 @@ #include #include "../ipa_common_i.h" #include "ipa_i.h" -#include "ipa_qmi_service.h" #define IPA_MHI_DRV_NAME "ipa_mhi" @@ -106,33 +105,6 @@ bool ipa3_mhi_stop_gsi_channel(enum ipa_client_type client) return false; } -static int ipa3_mhi_send_endp_ind_to_modem(void) -{ - struct ipa_endp_desc_indication_msg_v01 req; - struct ipa_ep_id_type_v01 *ep_info; - int ipa_mhi_prod_ep_idx = - ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_PROD); - int ipa_mhi_cons_ep_idx = - ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_CONS); - - memset(&req, 0, sizeof(struct ipa_endp_desc_indication_msg_v01)); - req.ep_info_len = 2; - req.ep_info_valid = true; - req.num_eps_valid = true; - req.num_eps = 2; - ep_info = &req.ep_info[0]; - ep_info->ep_id = ipa_mhi_cons_ep_idx; - ep_info->ic_type = DATA_IC_TYPE_MHI_V01; - ep_info->ep_type = DATA_EP_DESC_TYPE_EMB_FLOW_CTL_PROD_V01; - ep_info->ep_status = DATA_EP_STATUS_CONNECTED_V01; - ep_info = &req.ep_info[1]; - ep_info->ep_id = ipa_mhi_prod_ep_idx; - ep_info->ic_type = DATA_IC_TYPE_MHI_V01; - ep_info->ep_type = DATA_EP_DESC_TYPE_EMB_FLOW_CTL_CONS_V01; - ep_info->ep_status = DATA_EP_STATUS_CONNECTED_V01; - return ipa3_qmi_send_endp_desc_indication(&req); -} - static int ipa3_mhi_reset_gsi_channel(enum ipa_client_type client) { int res; @@ -553,10 +525,6 @@ int ipa3_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in, int ipa_ep_idx; int res; enum ipa_client_type client; - int ipa_mhi_prod_ep_idx = - ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_PROD); - int ipa_mhi_cons_ep_idx = - ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_CONS); IPA_MHI_FUNC_ENTRY(); @@ -602,14 +570,6 @@ int ipa3_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in, ipa3_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg; IPA_MHI_DBG("client %d (ep: %d) connected\n", client, ipa_ep_idx); - if ((client == IPA_CLIENT_MHI_LOW_LAT_PROD || - client == IPA_CLIENT_MHI_LOW_LAT_CONS) && - ipa_mhi_prod_ep_idx != -1 && - ipa3_ctx->ep[ipa_mhi_prod_ep_idx].valid && - ipa_mhi_cons_ep_idx != -1 && - ipa3_ctx->ep[ipa_mhi_cons_ep_idx].valid) - ipa3_mhi_send_endp_ind_to_modem(); - IPA_MHI_FUNC_EXIT(); return 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qdss.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qdss.c new file mode 100644 index 0000000000000000000000000000000000000000..dd95fcd398a07bdc9ec8028433f58987404a9e60 --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qdss.c @@ -0,0 +1,267 @@ +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include "ipa_i.h" + +#define IPA_HOLB_TMR_VALUE 0 +#define OFFLOAD_DRV_NAME "ipa_qdss" +#define IPA_QDSS_DBG(fmt, args...) \ + do { \ + pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPA_QDSS_ERR(fmt, args...) \ + do { \ + pr_err(OFFLOAD_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +static void ipa3_qdss_gsi_chan_err_cb(struct gsi_chan_err_notify *notify) +{ + switch (notify->evt_id) { + case GSI_CHAN_INVALID_TRE_ERR: + IPAERR("Got GSI_CHAN_INVALID_TRE_ERR\n"); + break; + case GSI_CHAN_NON_ALLOCATED_EVT_ACCESS_ERR: + IPAERR("Got GSI_CHAN_NON_ALLOCATED_EVT_ACCESS_ERR\n"); + break; + case GSI_CHAN_OUT_OF_BUFFERS_ERR: + IPAERR("Got GSI_CHAN_OUT_OF_BUFFERS_ERR\n"); + break; + case GSI_CHAN_OUT_OF_RESOURCES_ERR: + IPAERR("Got GSI_CHAN_OUT_OF_RESOURCES_ERR\n"); + break; + case GSI_CHAN_UNSUPPORTED_INTER_EE_OP_ERR: + IPAERR("Got GSI_CHAN_UNSUPPORTED_INTER_EE_OP_ERR\n"); + break; + case GSI_CHAN_HWO_1_ERR: + IPAERR("Got GSI_CHAN_HWO_1_ERR\n"); + break; + default: + IPAERR("Unexpected err evt: %d\n", notify->evt_id); + } + ipa_assert(); +} + +int ipa3_conn_qdss_pipes(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out) +{ + struct gsi_chan_props gsi_channel_props; + struct ipa3_ep_context *ep_rx; + const struct ipa_gsi_ep_config *gsi_ep_info; + union __packed gsi_channel_scratch ch_scratch; + u32 gsi_db_addr_low, gsi_db_addr_high; + struct ipa_ep_cfg ep_cfg = { { 0 } }; + int ipa_ep_idx_rx, ipa_ep_idx_tx; + int result = 0; + struct ipa_ep_cfg_holb holb_cfg; + + if (!(in && out)) { + IPA_QDSS_ERR("Empty parameters. in=%pK out=%pK\n", in, out); + return -IPA_QDSS_PIPE_CONN_FAILURE; + } + + ipa_ep_idx_tx = ipa3_get_ep_mapping(IPA_CLIENT_MHI_QDSS_CONS); + if ((ipa_ep_idx_tx) < 0 || (!ipa3_ctx->ipa_config_is_mhi)) { + IPA_QDSS_ERR("getting EP map failed\n"); + return -IPA_QDSS_PIPE_CONN_FAILURE; + } + + ipa_ep_idx_rx = ipa3_get_ep_mapping(IPA_CLIENT_QDSS_PROD); + if ((ipa_ep_idx_rx == -1) || + (ipa_ep_idx_rx >= IPA3_MAX_NUM_PIPES)) { + IPA_QDSS_ERR("out of range ipa_ep_idx_rx = %d\n", + ipa_ep_idx_rx); + return -IPA_QDSS_PIPE_CONN_FAILURE; + } + + ep_rx = &ipa3_ctx->ep[ipa_ep_idx_rx]; + + if (ep_rx->valid) { + IPA_QDSS_ERR("EP already allocated.\n"); + return IPA_QDSS_SUCCESS; + } + + memset(ep_rx, 0, offsetof(struct ipa3_ep_context, sys)); + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + + ep_rx->valid = 1; + ep_rx->client = IPA_CLIENT_QDSS_PROD; + if (ipa3_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) { + IPAERR("fail to setup rx pipe cfg\n"); + goto fail; + } + + /* setup channel ring */ + memset(&gsi_channel_props, 0, sizeof(gsi_channel_props)); + gsi_channel_props.prot = GSI_CHAN_PROT_QDSS; + gsi_channel_props.dir = GSI_CHAN_DIR_TO_GSI; + + gsi_ep_info = ipa3_get_gsi_ep_info(ep_rx->client); + if (!gsi_ep_info) { + IPA_QDSS_ERR("Failed getting GSI EP info for client=%d\n", + ep_rx->client); + goto fail; + } + + gsi_channel_props.ch_id = gsi_ep_info->ipa_gsi_chan_num; + gsi_channel_props.re_size = GSI_CHAN_RE_SIZE_8B; + gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + gsi_channel_props.err_cb = ipa3_qdss_gsi_chan_err_cb; + gsi_channel_props.ring_len = in->desc_fifo_size; + gsi_channel_props.ring_base_addr = + in->desc_fifo_base_addr; + result = gsi_alloc_channel(&gsi_channel_props, ipa3_ctx->gsi_dev_hdl, + &ep_rx->gsi_chan_hdl); + if (result != GSI_STATUS_SUCCESS) { + IPA_QDSS_ERR("Failed allocating gsi_chan_hdl=%d\n", + &ep_rx->gsi_chan_hdl); + goto fail; + } + + ep_rx->gsi_mem_info.chan_ring_len = gsi_channel_props.ring_len; + ep_rx->gsi_mem_info.chan_ring_base_addr = + gsi_channel_props.ring_base_addr; + + /* write channel scratch, do we need this? */ + memset(&ch_scratch, 0, sizeof(ch_scratch)); + ch_scratch.qdss.bam_p_evt_dest_addr = in->bam_p_evt_dest_addr; + ch_scratch.qdss.data_fifo_base_addr = in->data_fifo_base_addr; + ch_scratch.qdss.data_fifo_size = in->data_fifo_size; + ch_scratch.qdss.bam_p_evt_threshold = in->bam_p_evt_threshold; + ch_scratch.qdss.override_eot = in->override_eot; + result = gsi_write_channel_scratch( + ep_rx->gsi_chan_hdl, ch_scratch); + if (result != GSI_STATUS_SUCCESS) { + IPA_QDSS_ERR("failed to write channel scratch\n"); + goto fail_write_scratch; + } + + /* query channel db address */ + if (gsi_query_channel_db_addr(ep_rx->gsi_chan_hdl, + &gsi_db_addr_low, &gsi_db_addr_high)) { + IPA_QDSS_ERR("failed to query gsi rx db addr\n"); + goto fail_write_scratch; + } + out->ipa_rx_db_pa = (phys_addr_t)(gsi_db_addr_low); + IPA_QDSS_DBG("QDSS out->ipa_rx_db_pa %llu\n", out->ipa_rx_db_pa); + + /* Configuring HOLB on MHI endpoint */ + memset(&holb_cfg, 0, sizeof(holb_cfg)); + holb_cfg.en = IPA_HOLB_TMR_EN; + holb_cfg.tmr_val = IPA_HOLB_TMR_VALUE; + result = ipa3_force_cfg_ep_holb(ipa_ep_idx_tx, &holb_cfg); + if (result) + IPA_QDSS_ERR("Configuring HOLB failed client_type =%d\n", + IPA_CLIENT_MHI_QDSS_CONS); + + /* Set DMA */ + IPA_QDSS_DBG("DMA from %d to %d", IPA_CLIENT_QDSS_PROD, + IPA_CLIENT_MHI_QDSS_CONS); + ep_cfg.mode.mode = IPA_DMA; + ep_cfg.mode.dst = IPA_CLIENT_MHI_QDSS_CONS; + ep_cfg.seq.set_dynamic = true; + if (ipa3_cfg_ep(ipa3_get_ep_mapping(IPA_CLIENT_QDSS_PROD), + &ep_cfg)) { + IPA_QDSS_ERR("Setting DMA mode failed\n"); + goto fail_write_scratch; + } + + /* Start QDSS_rx gsi channel */ + result = ipa3_start_gsi_channel(ipa_ep_idx_rx); + if (result) { + IPA_QDSS_ERR("Failed starting QDSS gsi channel\n"); + goto fail_write_scratch; + } + + IPA_QDSS_DBG("QDSS connect pipe success"); + + return IPA_QDSS_SUCCESS; + +fail_write_scratch: + gsi_dealloc_channel(ep_rx->gsi_chan_hdl); + memset(ep_rx, 0, sizeof(struct ipa3_ep_context)); +fail: + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return -IPA_QDSS_PIPE_CONN_FAILURE; +} + +int ipa3_disconn_qdss_pipes(void) +{ + int result = 0; + int ipa_ep_idx_rx; + struct ipa3_ep_context *ep_rx; + struct ipa_ep_cfg ep_cfg = { { 0 } }; + + ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_QDSS_PROD); + if (ipa_ep_idx_rx == -1) { + IPA_QDSS_ERR("fail to get ep mapping\n"); + return -IPA_QDSS_PIPE_DISCONN_FAILURE; + } + + if (ipa_ep_idx_rx >= IPA3_MAX_NUM_PIPES) { + IPA_QDSS_ERR("ep out of range.\n"); + return -IPA_QDSS_PIPE_DISCONN_FAILURE; + } + + /* Stop QDSS_rx gsi channel / release channel */ + result = ipa3_stop_gsi_channel(ipa_ep_idx_rx); + if (result) { + IPA_QDSS_ERR("Failed stopping QDSS gsi channel\n"); + goto fail; + } + + /* Resetting gsi channel */ + result = ipa3_reset_gsi_channel(ipa_ep_idx_rx); + if (result) { + IPA_QDSS_ERR("Failed resetting QDSS gsi channel\n"); + goto fail; + } + + /* Reset DMA */ + IPA_QDSS_ERR("Resetting DMA %d to %d", + IPA_CLIENT_QDSS_PROD, IPA_CLIENT_MHI_QDSS_CONS); + ep_cfg.mode.mode = IPA_BASIC; + ep_cfg.mode.dst = IPA_CLIENT_MHI_QDSS_CONS; + ep_cfg.seq.set_dynamic = true; + if (ipa3_cfg_ep(ipa3_get_ep_mapping(IPA_CLIENT_QDSS_PROD), + &ep_cfg)) { + IPAERR("Resetting DMA mode failed\n"); + } + + /* Deallocating and Clearing ep config */ + ep_rx = &ipa3_ctx->ep[ipa_ep_idx_rx]; + gsi_dealloc_channel(ep_rx->gsi_chan_hdl); + memset(ep_rx, 0, sizeof(struct ipa3_ep_context)); + + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + IPA_QDSS_DBG("QDSS disconnect pipe success"); + + return IPA_QDSS_SUCCESS; +fail: + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return -IPA_QDSS_PIPE_DISCONN_FAILURE; +} diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index c91ba21e7cb721ff7b98ff2e4c254a39bf1b3c95..266734f4ba9ff64cd2c3e6e5d6637e6062028d5c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -790,6 +790,44 @@ int ipa3_qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) resp.resp.error, "ipa_install_filter"); } +static int ipa3_qmi_filter_request_ex_calc_length( + struct ipa_install_fltr_rule_req_ex_msg_v01 *req) +{ + int len = 0; + + /* caller should validate and send the req */ + /* instead of sending max length,the approximate length is calculated */ + len += ((sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01)) - + (QMI_IPA_MAX_FILTERS_EX_V01 * + sizeof(struct ipa_filter_spec_ex_type_v01) - + QMI_IPA_MAX_FILTERS_EX_V01 * sizeof(uint32_t)) - + (QMI_IPA_MAX_FILTERS_V01 * + sizeof(struct ipa_filter_spec_ex2_type_v01))); + + if (req->filter_spec_ex_list_valid && + req->filter_spec_ex_list_len > 0) { + len += sizeof(struct ipa_filter_spec_ex_type_v01)* + req->filter_spec_ex_list_len; + } + if (req->xlat_filter_indices_list_valid && + req->xlat_filter_indices_list_len > 0) { + len += sizeof(uint32_t)*req->xlat_filter_indices_list_len; + } + + if (req->filter_spec_ex2_list_valid && + req->filter_spec_ex2_list_len > 0) { + len += sizeof(struct ipa_filter_spec_ex2_type_v01)* + req->filter_spec_ex2_list_len; + } + + if (req->ul_firewall_indices_list_valid && + req->ul_firewall_indices_list_len > 0) { + len += sizeof(uint32_t)*req->ul_firewall_indices_list_len; + } + + return len; +} + /* sending filter-install-request to modem*/ int ipa3_qmi_filter_request_ex_send( struct ipa_install_fltr_rule_req_ex_msg_v01 *req) @@ -855,8 +893,9 @@ int ipa3_qmi_filter_request_ex_send( } mutex_unlock(&ipa3_qmi_lock); - req_desc.max_msg_len = - QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_MAX_MSG_LEN_V01; + req_desc.max_msg_len = ipa3_qmi_filter_request_ex_calc_length(req); + IPAWANDBG("QMI send request length = %d\n", req_desc.max_msg_len); + req_desc.msg_id = QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_V01; req_desc.ei_array = ipa3_install_fltr_rule_req_ex_msg_data_v01_ei; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c index c35c54e78e8611892cd474415ed743d2f04d7435..e3be643c3d0c057d7332ed1a91ea34c3e8603086 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, 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 @@ -263,7 +263,7 @@ static int ipa3_uc_send_ntn_setup_pipe_cmd( } static int ipa3_smmu_map_uc_ntn_pipes(struct ipa_ntn_setup_info *params, - bool map) + bool map, bool map_unmap_once) { struct iommu_domain *smmu_domain; int result; @@ -279,14 +279,16 @@ static int ipa3_smmu_map_uc_ntn_pipes(struct ipa_ntn_setup_info *params, return -EINVAL; } - result = ipa3_smmu_map_peer_reg(rounddown(params->ntn_reg_base_ptr_pa, - PAGE_SIZE), map, IPA_SMMU_CB_UC); - if (result) { - IPAERR("failed to %s uC regs %d\n", - map ? "map" : "unmap", result); - goto fail; + if (map_unmap_once) { + result = ipa3_smmu_map_peer_reg(rounddown( + params->ntn_reg_base_ptr_pa, PAGE_SIZE), + map, IPA_SMMU_CB_UC); + if (result) { + IPAERR("failed to %s uC regs %d\n", + map ? "map" : "unmap", result); + goto fail; + } } - if (params->smmu_enabled) { IPADBG("smmu is enabled on EMAC\n"); result = ipa3_smmu_map_peer_buff((u64)params->ring_base_iova, @@ -349,14 +351,13 @@ static int ipa3_smmu_map_uc_ntn_pipes(struct ipa_ntn_setup_info *params, IPAERR("Fail to map 0x%llx\n", iova); } else { result = iommu_unmap(smmu_domain, iova_p, size_p); - if (result != params->data_buff_size) + if (result != size_p) { IPAERR("Fail to unmap 0x%llx\n", iova); - } - if (result) { - if (params->smmu_enabled) - goto fail_map_data_buff_smmu_enabled; - else - goto fail_map_data_buff_smmu_disabled; + if (params->smmu_enabled) + goto fail_map_data_buff_smmu_enabled; + else + goto fail_map_data_buff_smmu_disabled; + } } } return 0; @@ -396,6 +397,7 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, int ipa_ep_idx_ul; int ipa_ep_idx_dl; int result = 0; + bool unmapped = false; if (in == NULL) { IPAERR("invalid input\n"); @@ -449,7 +451,7 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, goto fail; } - result = ipa3_smmu_map_uc_ntn_pipes(&in->ul, true); + result = ipa3_smmu_map_uc_ntn_pipes(&in->ul, true, true); if (result) { IPAERR("failed to map SMMU for UL %d\n", result); goto fail; @@ -488,7 +490,7 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, goto fail_disable_dp_ul; } - result = ipa3_smmu_map_uc_ntn_pipes(&in->dl, true); + result = ipa3_smmu_map_uc_ntn_pipes(&in->dl, true, false); if (result) { IPAERR("failed to map SMMU for DL %d\n", result); goto fail_disable_dp_ul; @@ -519,11 +521,12 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, fail_disable_dp_dl: ipa3_disable_data_path(ipa_ep_idx_dl); fail_smmu_unmap_dl: - ipa3_smmu_map_uc_ntn_pipes(&in->dl, false); + ipa3_smmu_map_uc_ntn_pipes(&in->dl, false, true); + unmapped = true; fail_disable_dp_ul: ipa3_disable_data_path(ipa_ep_idx_ul); fail_smmu_unmap_ul: - ipa3_smmu_map_uc_ntn_pipes(&in->ul, false); + ipa3_smmu_map_uc_ntn_pipes(&in->ul, false, !unmapped); fail: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return result; @@ -603,7 +606,7 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, } /* unmap the DL pipe */ - result = ipa3_smmu_map_uc_ntn_pipes(¶ms->dl, false); + result = ipa3_smmu_map_uc_ntn_pipes(¶ms->dl, false, true); if (result) { IPAERR("failed to unmap SMMU for DL %d\n", result); goto fail; @@ -624,7 +627,7 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, } /* unmap the UL pipe */ - result = ipa3_smmu_map_uc_ntn_pipes(¶ms->ul, false); + result = ipa3_smmu_map_uc_ntn_pipes(¶ms->ul, false, false); if (result) { IPAERR("failed to unmap SMMU for UL %d\n", result); goto fail; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index cf42c36d8c25cd55d7b418ccdfa51cf0c9574b25..668311add95f0c8df7e330adafaa74ce025c9840 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -409,7 +409,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config [IPA_4_5_MHI] = { /* PCIE DDR DMA QDSS unused N/A */ [IPA_v4_0_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { - {3, 8}, {4, 11}, {1, 1}, {1, 1}, {0, 0}, {0, 0} }, + {3, 8}, {4, 11}, {1, 6}, {1, 1}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { {9, 9}, {12, 12}, {2, 2}, {2, 2}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRC_DESCRIPTOR_BUFF] = { @@ -435,7 +435,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config [IPA_4_5_AUTO_MHI] = { /* PCIE DDR DMA/CV2X QDSS unused N/A */ [IPA_v4_0_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { - {3, 8}, {4, 11}, {1, 1}, {1, 1}, {0, 0}, {0, 0} }, + {3, 8}, {4, 11}, {1, 6}, {1, 1}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { {9, 9}, {12, 12}, {2, 2}, {2, 2}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRC_DESCRIPTOR_BUFF] = { @@ -2608,6 +2608,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_PCIE, { 3, 5, 8, 16, IPA_EE_AP, GSI_SMART_PRE_FETCH, 3 } }, + [IPA_4_5_MHI][IPA_CLIENT_QDSS_PROD] = { + true, IPA_v4_5_MHI_GROUP_QDSS, + false, + IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY, + QMB_MASTER_SELECT_DDR, + { 11, 14, 10, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, /* Only for test purpose */ [IPA_4_5_MHI][IPA_CLIENT_TEST_PROD] = { true, QMB_MASTER_SELECT_DDR, @@ -2701,11 +2707,11 @@ static const struct ipa_ep_configuration ipa3_ep_mapping QMB_MASTER_SELECT_PCIE, { 30, 6, 9, 9, IPA_EE_AP, GSI_SMART_PRE_FETCH, 4 } }, [IPA_4_5_MHI][IPA_CLIENT_MHI_QDSS_CONS] = { - true, IPA_v4_5_MHI_GROUP_PCIE, + true, IPA_v4_5_MHI_GROUP_QDSS, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_PCIE, - { 24, 3, 8, 14, IPA_EE_AP, GSI_SMART_PRE_FETCH, 3 } }, + { 24, 3, 8, 14, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_5_MHI][IPA_CLIENT_DUMMY_CONS] = { true, QMB_MASTER_SELECT_DDR, @@ -5495,6 +5501,78 @@ int ipa3_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ep_holb) return 0; } +/** + * ipa3_force_cfg_ep_holb() - IPA end-point holb configuration + * for QDSS_MHI_CONS pipe + * + * If an IPA producer pipe is full, IPA HW by default will block + * indefinitely till space opens up. During this time no packets + * including those from unrelated pipes will be processed. Enabling + * HOLB means IPA HW will be allowed to drop packets as/when needed + * and indefinite blocking is avoided. + * + * @clnt_hdl: [in] opaque client handle assigned by IPA to client + * @ipa_ep_cfg: [in] IPA end-point configuration params + * + * Returns: 0 on success, negative on failure + */ +int ipa3_force_cfg_ep_holb(u32 clnt_hdl, + struct ipa_ep_cfg_holb *ep_holb) +{ + if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || + ep_holb == NULL) { + IPAERR("bad parm.\n"); + return -EINVAL; + } + + IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl)); + + if (ep_holb->en == IPA_HOLB_TMR_DIS) { + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n, + clnt_hdl, ep_holb); + goto success; + } + + /* Follow HPG sequence to DIS_HOLB, Configure Timer, and HOLB_EN */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) { + ep_holb->en = IPA_HOLB_TMR_DIS; + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n, + clnt_hdl, ep_holb); + } + + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) { + int res; + + res = ipa3_process_timer_cfg(ep_holb->tmr_val * 1000, + &ep_holb->pulse_generator, + &ep_holb->scaled_time); + if (res) { + IPAERR("failed to process HOLB timer tmr=%u\n", + ep_holb->tmr_val); + ipa_assert(); + return res; + } + } + + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, + clnt_hdl, ep_holb); + + /* Enable HOLB */ + ep_holb->en = IPA_HOLB_TMR_EN; + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n, + clnt_hdl, ep_holb); + /* IPA4.5 issue requires HOLB_EN to be written twice */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n, + clnt_hdl, ep_holb); + +success: + IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); + IPADBG("cfg holb %u ep=%d tmr=%d\n", ep_holb->en, clnt_hdl, + ep_holb->tmr_val); + return 0; +} + /** * ipa3_cfg_ep_holb_by_client() - IPA end-point holb configuration * @@ -7293,6 +7371,8 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type, ipa3_get_prot_id; api_ctrl->ipa_add_socksv5_conn = ipa3_add_socksv5_conn; api_ctrl->ipa_del_socksv5_conn = ipa3_del_socksv5_conn; + api_ctrl->ipa_conn_qdss_pipes = ipa3_conn_qdss_pipes; + api_ctrl->ipa_disconn_qdss_pipes = ipa3_disconn_qdss_pipes; return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c index 072d99456b9ac807cd2387648e93b6ed9ef2bfe2..e82a849317bd28d57af39046db3063eb6798afb7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c @@ -446,7 +446,7 @@ int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in, int result = 0; u32 gsi_db_addr_low, gsi_db_addr_high; void __iomem *db_addr; - u32 evt_ring_db_addr_low, evt_ring_db_addr_high; + u32 evt_ring_db_addr_low, evt_ring_db_addr_high, db_val = 0; /* wdi3 only support over gsi */ if (ipa3_get_wdi_version() != IPA_WDI_3) { @@ -612,11 +612,18 @@ int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in, * initialization of the event, with a value that is * outside of the ring range. Eg: ring base = 0x1000, * ring size = 0x100 => AP can write value > 0x1100 - * into the doorbell address. Eg: 0x 1110 + * into the doorbell address. Eg: 0x 1110. + * Use event ring base addr + event ring size + 1 element size. */ - iowrite32(in->u_rx.rx.event_ring_size / 4 + 10, db_addr); + db_val = (u32)ep_rx->gsi_mem_info.evt_ring_base_addr; + db_val += ((in->is_smmu_enabled) ? in->u_rx.rx_smmu.event_ring_size : + in->u_rx.rx.event_ring_size); + db_val += GSI_EVT_RING_RE_SIZE_8B; + iowrite32(db_val, db_addr); gsi_query_evt_ring_db_addr(ep_tx->gsi_evt_ring_hdl, &evt_ring_db_addr_low, &evt_ring_db_addr_high); + IPADBG("RX base_addr 0x%x evt wp val: 0x%x\n", + ep_rx->gsi_mem_info.evt_ring_base_addr, db_val); /* only 32 bit lsb is used */ db_addr = ioremap((phys_addr_t)(evt_ring_db_addr_low), 4); @@ -626,9 +633,16 @@ int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in, * outside of the ring range. Eg: ring base = 0x1000, * ring size = 0x100 => AP can write value > 0x1100 * into the doorbell address. Eg: 0x 1110 + * Use event ring base addr + event ring size + 1 element size. */ - iowrite32(in->u_tx.tx.event_ring_size / 4 + 10, db_addr); - + db_val = (u32)ep_tx->gsi_mem_info.evt_ring_base_addr; + db_val += ((in->is_smmu_enabled) ? in->u_tx.tx_smmu.event_ring_size : + in->u_tx.tx.event_ring_size); + db_val += GSI_EVT_RING_RE_SIZE_16B; + iowrite32(db_val, db_addr); + IPADBG("db_addr %u TX base_addr 0x%x evt wp val: 0x%x\n", + evt_ring_db_addr_low, + ep_tx->gsi_mem_info.evt_ring_base_addr, db_val); fail: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return result; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c index c2f8e1a2d62609efc9131c19e68f07f683db9fc0..e16003813a9ce3970fd5deb45caa3175e1f4eb0a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c @@ -49,6 +49,8 @@ static const char *ipahal_pkt_status_exception_to_str __stringify(IPAHAL_PKT_STATUS_EXCEPTION_SW_FILT), __stringify(IPAHAL_PKT_STATUS_EXCEPTION_NAT), __stringify(IPAHAL_PKT_STATUS_EXCEPTION_IPV6CT), + __stringify(IPAHAL_PKT_STATUS_EXCEPTION_UCP), + __stringify(IPAHAL_PKT_STATUS_EXCEPTION_CSUM), }; static u16 ipahal_imm_cmd_get_opcode(enum ipahal_imm_cmd_name cmd); @@ -978,6 +980,9 @@ static void ipa_pkt_status_parse( else exception_type = IPAHAL_PKT_STATUS_EXCEPTION_NAT; break; + case 128: + exception_type = IPAHAL_PKT_STATUS_EXCEPTION_UCP; + break; case 229: exception_type = IPAHAL_PKT_STATUS_EXCEPTION_CSUM; break; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h index 164d75d1edb44d9a5d10c18cddf3b3e9d874ea90..3576aea239ec80c7fdcb18d4da89366e91ed642a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, 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 @@ -444,6 +444,7 @@ enum ipahal_pkt_status_exception { */ IPAHAL_PKT_STATUS_EXCEPTION_NAT, IPAHAL_PKT_STATUS_EXCEPTION_IPV6CT, + IPAHAL_PKT_STATUS_EXCEPTION_UCP, IPAHAL_PKT_STATUS_EXCEPTION_CSUM, IPAHAL_PKT_STATUS_EXCEPTION_MAX, }; diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 5bc34f896cd98449051425d2fb87a8cfb7b7be10..8c2f12e6dc2c1224e1da5f30cc0f29e1f4f239f2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -1486,8 +1486,35 @@ static void apps_ipa_packet_receive_notify(void *priv, } } -/* Send RSC endpoint info to modem using QMI indication message */ +/* Send MHI endpoint info to modem using QMI indication message */ +static int ipa_send_mhi_endp_ind_to_modem(void) +{ + struct ipa_endp_desc_indication_msg_v01 req; + struct ipa_ep_id_type_v01 *ep_info; + int ipa_mhi_prod_ep_idx = + ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_PROD); + int ipa_mhi_cons_ep_idx = + ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_CONS); + + memset(&req, 0, sizeof(struct ipa_endp_desc_indication_msg_v01)); + req.ep_info_len = 2; + req.ep_info_valid = true; + req.num_eps_valid = true; + req.num_eps = 2; + ep_info = &req.ep_info[0]; + ep_info->ep_id = ipa_mhi_cons_ep_idx; + ep_info->ic_type = DATA_IC_TYPE_MHI_V01; + ep_info->ep_type = DATA_EP_DESC_TYPE_EMB_FLOW_CTL_PROD_V01; + ep_info->ep_status = DATA_EP_STATUS_CONNECTED_V01; + ep_info = &req.ep_info[1]; + ep_info->ep_id = ipa_mhi_prod_ep_idx; + ep_info->ic_type = DATA_IC_TYPE_MHI_V01; + ep_info->ep_type = DATA_EP_DESC_TYPE_EMB_FLOW_CTL_CONS_V01; + ep_info->ep_status = DATA_EP_STATUS_CONNECTED_V01; + return ipa3_qmi_send_endp_desc_indication(&req); +} +/* Send RSC endpoint info to modem using QMI indication message */ static int ipa_send_rsc_pipe_ind_to_modem(void) { struct ipa_endp_desc_indication_msg_v01 req; @@ -4137,6 +4164,9 @@ void ipa3_q6_handshake_complete(bool ssr_bootup) } if (ipa3_ctx->ipa_mhi_proxy) imp_handle_modem_ready(); + + if (ipa3_ctx->ipa_config_is_mhi) + ipa_send_mhi_endp_ind_to_modem(); } static inline bool rmnet_ipa3_check_any_client_inited diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c index 8c53d5df1e6f36fd6f720ab508de9e5783c94da2..688197e2610983a1305cf47c695647e09e31f012 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2020, 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 @@ -103,7 +103,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG("device %s got WAN_IOC_ADD_FLT_RULE :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct ipa_install_fltr_rule_req_msg_v01); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -128,7 +128,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG("device %s got WAN_IOC_ADD_FLT_RULE_EX :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -153,7 +153,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG("device %s got WAN_IOC_ADD_OFFLOAD_CONNECTION :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct ipa_add_offload_connection_req_msg_v01); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -180,7 +180,7 @@ static long ipa3_wan_ioctl(struct file *filp, DRIVER_NAME); pyld_sz = rmv_offload_req__msg_size; - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -207,7 +207,7 @@ static long ipa3_wan_ioctl(struct file *filp, DRIVER_NAME); pyld_sz = sizeof(struct ipa_configure_ul_firewall_rules_req_msg_v01); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -233,7 +233,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG("device %s got WAN_IOC_ADD_FLT_RULE_INDEX :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct ipa_fltr_installed_notif_req_msg_v01); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -258,7 +258,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG("device %s got WAN_IOC_VOTE_FOR_BW_MBPS :>>>\n", DRIVER_NAME); pyld_sz = sizeof(uint32_t); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -281,7 +281,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_POLL_TETHERING_STATS: IPAWANDBG_LOW("got WAN_IOCTL_POLL_TETHERING_STATS :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_poll_tethering_stats); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -305,7 +305,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_SET_DATA_QUOTA: IPAWANDBG_LOW("got WAN_IOCTL_SET_DATA_QUOTA :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_set_data_quota); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -333,7 +333,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_SET_TETHER_CLIENT_PIPE: IPAWANDBG_LOW("got WAN_IOC_SET_TETHER_CLIENT_PIPE :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_set_tether_client_pipe); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -353,7 +353,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_QUERY_TETHER_STATS: IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_query_tether_stats); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -379,7 +379,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_QUERY_TETHER_STATS_ALL: IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS_ALL :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_query_tether_stats_all); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -406,7 +406,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG_LOW("device %s got WAN_IOC_RESET_TETHER_STATS :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct wan_ioctl_reset_tether_stats); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -428,7 +428,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG_LOW("device %s got WAN_IOC_NOTIFY_WAN_STATE :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct wan_ioctl_notify_wan_state); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -454,7 +454,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_ENABLE_PER_CLIENT_STATS: IPAWANDBG_LOW("got WAN_IOC_ENABLE_PER_CLIENT_STATS :>>>\n"); pyld_sz = sizeof(bool); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -473,7 +473,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_QUERY_PER_CLIENT_STATS: IPAWANDBG_LOW("got WAN_IOC_QUERY_PER_CLIENT_STATS :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_query_per_client_stats); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -502,7 +502,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_SET_LAN_CLIENT_INFO: IPAWANDBG_LOW("got WAN_IOC_SET_LAN_CLIENT_INFO :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_lan_client_info); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -522,7 +522,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_CLEAR_LAN_CLIENT_INFO: IPAWANDBG_LOW("got WAN_IOC_CLEAR_LAN_CLIENT_INFO :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_lan_client_info); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -543,7 +543,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_SEND_LAN_CLIENT_MSG: IPAWANDBG_LOW("got WAN_IOC_SEND_LAN_CLIENT_MSG :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_send_lan_client_msg); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -564,7 +564,8 @@ static long ipa3_wan_ioctl(struct file *filp, default: retval = -ENOTTY; } - kfree(param); + if (param) + vfree(param); return retval; } diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index b03135b2c1950a7ac0ac5df5d2b9de82ba08e0f5..fc98fec90068915043b12bfaca1b2fa8a88c67a9 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "mhi.h" #include "mhi_hwio.h" @@ -444,10 +445,11 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, struct event_req *flush_ereq; /* - * Channel got closed with transfers pending + * Channel got stopped or closed with transfers pending * Do not send completion events to host */ - if (ch->state == MHI_DEV_CH_CLOSED) { + if (ch->state == MHI_DEV_CH_CLOSED || + ch->state == MHI_DEV_CH_STOPPED) { mhi_log(MHI_MSG_DBG, "Ch %d closed with %d writes pending\n", ch->ch_id, ch->pend_wr_count + 1); return -ENODEV; @@ -1269,6 +1271,9 @@ static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event, pr_err("Error configuring interrupts, rc = %d\n", rc); return; } + + mhi_log(MHI_MSG_CRITICAL, "Device in M0 State\n"); + place_marker("MHI - Device in M0 State\n"); break; case IPA_MHI_EVENT_DATA_AVAILABLE: rc = mhi_dev_notify_sm_event(MHI_DEV_EVENT_HW_ACC_WAKEUP); @@ -1294,6 +1299,11 @@ static int mhi_hwc_chcmd(struct mhi_dev *mhi, uint chid, switch (type) { case MHI_DEV_RING_EL_RESET: case MHI_DEV_RING_EL_STOP: + if ((chid-HW_CHANNEL_BASE) > NUM_HW_CHANNELS) { + pr_err("Invalid Channel ID = 0x%X\n", chid); + return -EINVAL; + } + rc = ipa_mhi_disconnect_pipe( mhi->ipa_clnt_hndl[chid-HW_CHANNEL_BASE]); if (rc) @@ -1304,6 +1314,16 @@ static int mhi_hwc_chcmd(struct mhi_dev *mhi, uint chid, connect_params.channel_id = chid; connect_params.sys.skip_ep_cfg = true; + if (chid > HW_CHANNEL_END) { + pr_err("Channel DB for %d not enabled\n", chid); + return -EINVAL; + } + + if ((chid-HW_CHANNEL_BASE) > NUM_HW_CHANNELS) { + pr_err("Invalid Channel = 0x%X\n", chid); + return -EINVAL; + } + rc = ipa_mhi_connect_pipe(&connect_params, &mhi->ipa_clnt_hndl[chid-HW_CHANNEL_BASE]); if (rc) @@ -2124,12 +2144,14 @@ static void mhi_dev_transfer_completion_cb(void *mreq) req->len, DMA_FROM_DEVICE); /* - * Channel got closed with transfers pending + * Channel got stopped or closed with transfers pending * Do not trigger callback or send cmpl to host */ - if (ch->state == MHI_DEV_CH_CLOSED) { - mhi_log(MHI_MSG_DBG, "Ch %d closed with %d writes pending\n", - ch->ch_id, ch->pend_wr_count + 1); + if (ch->state == MHI_DEV_CH_CLOSED || + ch->state == MHI_DEV_CH_STOPPED) { + mhi_log(MHI_MSG_DBG, + "Ch %d not in started state, %d writes pending\n", + ch->ch_id, ch->pend_wr_count + 1); return; } @@ -2364,6 +2386,10 @@ static int mhi_dev_cache_host_cfg(struct mhi_dev *mhi) return rc; } + mhi_log(MHI_MSG_VERBOSE, + "Number of Event rings : %d, HW Event rings : %d\n", + mhi->cfg.event_rings, mhi->cfg.hw_event_rings); + mhi->cmd_ctx_shadow.size = sizeof(struct mhi_dev_cmd_ctx); mhi->ev_ctx_shadow.size = sizeof(struct mhi_dev_ev_ctx) * mhi->cfg.event_rings; @@ -2976,6 +3002,7 @@ int mhi_dev_write_channel(struct mhi_req *wreq) size_t bytes_written = 0; uint32_t tre_len = 0, suspend_wait_timeout = 0; bool async_wr_sched = false; + enum mhi_ctrl_info info; if (WARN_ON(!wreq || !wreq->client || !wreq->buf)) { pr_err("%s: invalid parameters\n", __func__); @@ -3024,6 +3051,14 @@ int mhi_dev_write_channel(struct mhi_req *wreq) mutex_lock(&ch->ch_lock); + rc = mhi_ctrl_state_info(ch->ch_id, &info); + if (rc || (info != MHI_STATE_CONNECTED)) { + mhi_log(MHI_MSG_ERROR, "Channel %d not started by host\n", + ch->ch_id); + mutex_unlock(&ch->ch_lock); + return -ENODEV; + } + ch->pend_wr_count++; if (ch->state == MHI_DEV_CH_STOPPED) { mhi_log(MHI_MSG_ERROR, diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index 5dd8559dcaa47144be54493179561db4db1aa3fa..ecd9708fc768f4a76c5dc169b3aac30cea59881f 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -271,6 +271,7 @@ struct mhi_config { #define NUM_CHANNELS 128 #define HW_CHANNEL_BASE 100 +#define NUM_HW_CHANNELS 15 #define HW_CHANNEL_END 110 #define MHI_ENV_VALUE 2 #define MHI_MASK_ROWS_CH_EV_DB 4 @@ -549,7 +550,7 @@ struct mhi_dev { size_t ch_ring_start; /* IPA Handles */ - u32 ipa_clnt_hndl[4]; + u32 ipa_clnt_hndl[NUM_HW_CHANNELS]; struct workqueue_struct *ring_init_wq; struct work_struct ring_init_cb_work; struct work_struct re_init; diff --git a/drivers/platform/msm/mhi_dev/mhi_mmio.c b/drivers/platform/msm/mhi_dev/mhi_mmio.c index 3ee2c2bc150e8989a714f4be1d34820804cbe5d3..7770ea6943302f85d3e224b4f9ad4cfba8425a34 100644 --- a/drivers/platform/msm/mhi_dev/mhi_mmio.c +++ b/drivers/platform/msm/mhi_dev/mhi_mmio.c @@ -709,13 +709,21 @@ EXPORT_SYMBOL(mhi_dev_mmio_init); int mhi_dev_update_ner(struct mhi_dev *dev) { + int rc = 0, mhi_cfg = 0; + if (WARN_ON(!dev)) return -EINVAL; - mhi_dev_mmio_masked_read(dev, MHICFG, MHICFG_NER_MASK, - MHICFG_NER_SHIFT, &dev->cfg.event_rings); + rc = mhi_dev_mmio_read(dev, MHICFG, &mhi_cfg); + if (rc) + return rc; + + pr_debug("MHICFG: 0x%x", mhi_cfg); - pr_debug("NER in HW :%d\n", dev->cfg.event_rings); + dev->cfg.event_rings = + (mhi_cfg & MHICFG_NER_MASK) >> MHICFG_NER_SHIFT; + dev->cfg.hw_event_rings = + (mhi_cfg & MHICFG_NHWER_MASK) >> MHICFG_NHWER_SHIFT; return 0; } diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index 7c08ad1eae8c9e5f25d84513e0f2534b5e0204ad..62d4fe0bf7de2d61a961c2f71b10b23856b26c6a 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -1142,6 +1142,7 @@ int mhi_dev_sm_exit(struct mhi_dev *mhi_dev) flush_workqueue(mhi_sm_ctx->mhi_sm_wq); destroy_workqueue(mhi_sm_ctx->mhi_sm_wq); /* Initiate MHI IPA reset */ + ipa_dma_disable(); ipa_mhi_destroy(); ipa_dma_destroy(); mutex_destroy(&mhi_sm_ctx->mhi_state_lock); diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c index a88a292b261fb59bce40f3f010e31c5cfdc3847f..d2b8a8d75099da3d77967416735dd17074814559 100644 --- a/drivers/platform/msm/qcom-geni-se.c +++ b/drivers/platform/msm/qcom-geni-se.c @@ -50,6 +50,12 @@ static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000, #define TZ_PIL_AUTH_GSI_QUP_PROC 0x13 #define SSR_SCM_CMD 0x2 +enum ssc_core_clocks { + SSC_CORE_CLK, + SSC_CORE2X_CLK, + SSC_NUM_CLKS +}; + struct bus_vectors { int src; int dst; @@ -133,6 +139,7 @@ struct geni_se_device { int update; bool vote_for_bw; struct ssc_qup_ssr ssr; + struct clk_bulk_data *ssc_clks; }; #define HW_VER_MAJOR_MASK GENMASK(31, 28) @@ -375,10 +382,17 @@ static void geni_se_ssc_qup_down(struct geni_se_device *dev) struct se_geni_rsc *rsc = NULL; dev->ssr.is_ssr_down = true; + if (list_empty(&dev->ssr.active_list_head)) { + GENI_SE_ERR(dev->log_ctx, false, NULL, + "%s: No Active usecase\n", __func__); + return; + } + list_for_each_entry(rsc, &dev->ssr.active_list_head, rsc_ssr.active_list) { rsc->rsc_ssr.force_suspend(rsc->ctrl_dev); } + clk_bulk_disable_unprepare(SSC_NUM_CLKS, dev->ssc_clks); } static void geni_se_ssc_qup_up(struct geni_se_device *dev) @@ -391,16 +405,39 @@ static void geni_se_ssc_qup_up(struct geni_se_device *dev) desc.args[1] = TZ_SCM_CALL_FROM_HLOS; desc.arginfo = SCM_ARGS(2, SCM_VAL); + if (list_empty(&dev->ssr.active_list_head)) { + GENI_SE_ERR(dev->log_ctx, false, NULL, + "%s: No Active usecase\n", __func__); + return; + } + /* Enable core/2x clk before TZ SCM call */ + ret = clk_bulk_prepare_enable(SSC_NUM_CLKS, dev->ssc_clks); + if (ret) { + GENI_SE_ERR(dev->log_ctx, false, NULL, + "%s: corex/2x clk enable failed ret:%d\n", + __func__, ret); + return; + } + + list_for_each_entry(rsc, &dev->ssr.active_list_head, + rsc_ssr.active_list) + se_geni_clks_on(rsc); + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SSR_SCM_CMD), &desc); if (ret) { - dev_err(dev->dev, "Unable to load firmware after SSR\n"); + GENI_SE_ERR(dev->log_ctx, false, NULL, + "%s: Unable to load firmware after SSR ret:%d\n", + __func__, ret); return; } list_for_each_entry(rsc, &dev->ssr.active_list_head, - rsc_ssr.active_list) { + rsc_ssr.active_list) + se_geni_clks_off(rsc); + + list_for_each_entry(rsc, &dev->ssr.active_list_head, + rsc_ssr.active_list) rsc->rsc_ssr.force_resume(rsc->ctrl_dev); - } dev->ssr.is_ssr_down = false; } @@ -1974,6 +2011,25 @@ static int geni_se_probe(struct platform_device *pdev) ret = of_property_read_string(geni_se_dev->dev->of_node, "qcom,subsys-name", &geni_se_dev->ssr.subsys_name); if (!ret) { + + geni_se_dev->ssc_clks = devm_kcalloc(dev, SSC_NUM_CLKS, + sizeof(*geni_se_dev->ssc_clks), GFP_KERNEL); + if (!geni_se_dev->ssc_clks) { + ret = -ENOMEM; + dev_err(dev, "%s: Unable to allocate memmory ret:%d\n", + __func__, ret); + return ret; + } + + geni_se_dev->ssc_clks[SSC_CORE_CLK].id = "corex"; + geni_se_dev->ssc_clks[SSC_CORE2X_CLK].id = "core2x"; + ret = devm_clk_bulk_get(dev, SSC_NUM_CLKS, + geni_se_dev->ssc_clks); + if (ret) { + dev_err(dev, "%s: Err getting core/2x clk:%d\n", ret); + return ret; + } + INIT_LIST_HEAD(&geni_se_dev->ssr.active_list_head); ret = geni_se_ssc_qup_ssr_reg(geni_se_dev); if (ret) { diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c index c9c52f76b9fb5e5ac0b860c40506a98f7d1e7d02..c2b2137185b826fd14312f299065443055b99616 100644 --- a/drivers/platform/msm/sps/bam.c +++ b/drivers/platform/msm/sps/bam.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, 2020, 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 @@ -1388,8 +1388,13 @@ int bam_pipe_init(void *base, u32 pipe, struct bam_pipe_parameters *param, bam_write_reg_field(base, P_FIFO_SIZES, pipe, P_DATA_FIFO_SIZE, param->data_size); - bam_write_reg(base, P_EVNT_DEST_ADDR, pipe, peer_dest_addr); - + if (!(param->dummy_peer)) { + bam_write_reg(base, P_EVNT_DEST_ADDR, pipe, + peer_dest_addr); + } else { + bam_write_reg(base, P_EVNT_DEST_ADDR, pipe, + param->peer_phys_addr); + } SPS_DBG2(dev, "sps:bam=0x%pK(va).pipe=%d.peer_bam=0x%x.peer_pipe=%d.\n", dev->base, pipe, diff --git a/drivers/platform/msm/sps/bam.h b/drivers/platform/msm/sps/bam.h index c0e4cde35cbaa82a39bb35c74fe5934459051bfb..60fdbff379012833cd695aca7ff2c18d9b11d27b 100644 --- a/drivers/platform/msm/sps/bam.h +++ b/drivers/platform/msm/sps/bam.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, 2020, 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 @@ -83,6 +83,7 @@ struct bam_pipe_parameters { u32 peer_pipe; phys_addr_t data_base; /* Physical address of data FIFO */ u32 data_size; /* Size (bytes) of data FIFO */ + bool dummy_peer; }; /** diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c index 92359c2021026114f0a93349b916aab91177f39a..68f4e3e91c90499c2a21f9d6dd530d25fd6eaf6b 100644 --- a/drivers/platform/msm/sps/sps_bam.c +++ b/drivers/platform/msm/sps/sps_bam.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, 2019-2020, 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 @@ -875,13 +875,15 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, } /* Determine operational mode */ - if (other_pipe->bam != NULL) { + if ((bam_pipe->connect.options & SPS_O_DUMMY_PEER) || + other_pipe->bam != NULL) { unsigned long iova; - struct sps_bam *peer_bam = (struct sps_bam *)(other_pipe->bam); + struct sps_bam *peer_bam; /* BAM-to-BAM mode */ bam_pipe->state |= BAM_STATE_BAM2BAM; hw_params.mode = BAM_PIPE_MODE_BAM2BAM; - + if (!(bam_pipe->connect.options & SPS_O_DUMMY_PEER)) + peer_bam = (struct sps_bam *)(other_pipe->bam); if (dev->props.options & SPS_BAM_SMMU_EN) { if (bam_pipe->mode == SPS_MODE_SRC) iova = bam_pipe->connect.dest_iova; @@ -892,11 +894,21 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, BAM_ID(dev), pipe_index, (void *)iova); hw_params.peer_phys_addr = (u32)iova; } else { - hw_params.peer_phys_addr = peer_bam->props.phys_addr; + if (!(bam_pipe->connect.options & SPS_O_DUMMY_PEER)) + hw_params.peer_phys_addr = + peer_bam->props.phys_addr; + } + if (!(bam_pipe->connect.options & SPS_O_DUMMY_PEER)) { + hw_params.peer_phys_addr = + bam_pipe->connect.destination; + hw_params.peer_pipe = + bam_pipe->connect.dest_pipe_index; + } else { + hw_params.peer_phys_addr = + bam_pipe->connect.destination; + hw_params.peer_pipe = other_pipe->pipe_index; + hw_params.dummy_peer = true; } - - hw_params.peer_pipe = other_pipe->pipe_index; - /* Verify FIFO buffers are allocated for BAM-to-BAM pipes */ if (map->desc.phys_base == SPS_ADDR_INVALID || map->data.phys_base == SPS_ADDR_INVALID || diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c index 593fbc1def4bd53334f506f40ec3e31745794b02..3ee057a5b7b9d914b7f1347f3f3995baed096896 100644 --- a/drivers/platform/msm/sps/sps_rm.c +++ b/drivers/platform/msm/sps/sps_rm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 2017-2020, 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 @@ -402,16 +402,20 @@ static struct sps_connection *sps_rm_create(struct sps_pipe *pipe) (void *)(&map->src.dev)); goto exit_err; } - map->src.pipe_index = SPS_BAM_PIPE_INVALID; + map->src.pipe_index = SPS_BAM_PIPE_INVALID; } - map->dest.bam = sps_h2bam(map->dest.dev); - if (map->dest.bam == NULL) { - if (map->dest.dev != SPS_DEV_HANDLE_MEM) { - SPS_ERR(sps, "sps:Invalid BAM handle: %pK", - (void *)(&map->dest.dev)); - goto exit_err; - } + + if (!(pipe->connect.options & SPS_O_DUMMY_PEER)) { + map->dest.bam = sps_h2bam(map->dest.dev); + if (map->dest.bam == NULL) { + if (map->dest.dev != SPS_DEV_HANDLE_MEM) { + SPS_ERR(sps, + "sps:Invalid BAM handle: %pK", + (void *)(&map->dest.dev)); + goto exit_err; + } map->dest.pipe_index = SPS_BAM_PIPE_INVALID; + } } /* Check the BAM device for the pipe */ @@ -504,7 +508,8 @@ static struct sps_connection *sps_rm_create(struct sps_pipe *pipe) if (map->data.size == SPSRM_CLEAR) map->data.size = data_size; } else { - map->data.size = 0; + if (!(pipe->connect.options & SPS_O_DUMMY_PEER)) + map->data.size = 0; } if (map->desc.size > SPSRM_MAX_DESC_FIFO_SIZE) { SPS_ERR(sps, "sps:Invalid desc FIFO size: 0x%x", diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index e335b18da20fc8ccc3264f20b5cdb883d4149580..2c82188f8486c7ce5b1483e79ffd2e3cdf3006a0 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -505,23 +505,22 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, input.length = (acpi_size) sizeof(*in_args); input.pointer = in_args; - if (out_data != NULL) { + if (out_data) { output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, command, &input, &output); - } else + if (ACPI_SUCCESS(status)) { + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + *out_data = (u32)obj->integer.value; + } + kfree(output.pointer); + } else { status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, command, &input, NULL); - - if (ACPI_SUCCESS(status) && out_data != NULL) { - obj = (union acpi_object *)output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - *out_data = (u32) obj->integer.value; } - kfree(output.pointer); return status; - } /* @@ -571,7 +570,7 @@ static ssize_t show_hdmi_source(struct device *dev, return scnprintf(buf, PAGE_SIZE, "input [gpu] unknown\n"); } - pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data); + pr_err("alienware-wmi: unknown HDMI source status: %u\n", status); return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n"); } diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 1c1999600717c8b37ca5ecd9b2a85dd9a6872579..af26ca49996d46607fe6695036ed03fd5e1b4dc5 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -457,13 +457,7 @@ static void kbd_led_update(struct work_struct *work) asus = container_of(work, struct asus_wmi, kbd_led_work); - /* - * bits 0-2: level - * bit 7: light on/off - */ - if (asus->kbd_led_wk > 0) - ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); - + ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL); } diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 7f8fa42a10840b9b94e0eccc8c162e3ca1f5d613..a56e997816b236bc49054ffad21c7fbcb0c79cfe 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -748,6 +748,9 @@ static int wmi_dev_match(struct device *dev, struct device_driver *driver) struct wmi_block *wblock = dev_to_wblock(dev); const struct wmi_device_id *id = wmi_driver->id_table; + if (id == NULL) + return 0; + while (id->guid_string) { uuid_le driver_guid; diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 660fda70f07f9f38735d772eaaf8580ebd600025..b54c20d8c04e89397e6e244bac240cabd26d3d61 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -366,6 +366,7 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_TYPEC_MODE, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION, + POWER_SUPPLY_PROP_TYPEC_SRC_RP, POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, @@ -456,6 +457,9 @@ static int smb2_usb_get_prop(struct power_supply *psy, else rc = smblib_get_prop_typec_cc_orientation(chg, val); break; + case POWER_SUPPLY_PROP_TYPEC_SRC_RP: + rc = smblib_get_prop_typec_select_rp(chg, val); + break; case POWER_SUPPLY_PROP_PD_ALLOWED: rc = smblib_get_prop_pd_allowed(chg, val); break; @@ -548,6 +552,9 @@ static int smb2_usb_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE: rc = smblib_set_prop_typec_power_role(chg, val); break; + case POWER_SUPPLY_PROP_TYPEC_SRC_RP: + rc = smblib_set_prop_typec_select_rp(chg, val); + break; case POWER_SUPPLY_PROP_PD_ACTIVE: rc = smblib_set_prop_pd_active(chg, val); break; diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index bdd75c003cc79f70284954ae251d7f93aaddaeb9..3903c213c0d39a4b19c96e29a952488b670745bf 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -549,6 +549,9 @@ static int smb5_parse_dt(struct smb5 *chip) chg->suspend_input_on_debug_batt = of_property_read_bool(node, "qcom,suspend-input-on-debug-batt"); + chg->fake_chg_status_on_debug_batt = of_property_read_bool(node, + "qcom,fake-chg-status-on-debug-batt"); + rc = of_property_read_u32(node, "qcom,otg-deglitch-time-ms", &chg->otg_delay_ms); if (rc < 0) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index a704ef254e484885a2ca25b4712d5f8f3c275862..ffec1bf46b0d68af68bbcb388d87345fec14151f 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -1148,6 +1148,44 @@ static int __smblib_set_prop_typec_power_role(struct smb_charger *chg, return rc; } +static inline bool typec_in_src_mode(struct smb_charger *chg) +{ + return (chg->typec_mode > POWER_SUPPLY_TYPEC_NONE && + chg->typec_mode < POWER_SUPPLY_TYPEC_SOURCE_DEFAULT); +} + +int smblib_get_prop_typec_select_rp(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc, rp; + u8 stat; + + if (!typec_in_src_mode(chg)) + return -ENODATA; + + rc = smblib_read(chg, TYPE_C_CFG_2_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_CURRSRC_CFG_REG rc=%d\n", + rc); + return rc; + } + + switch (stat & EN_80UA_180UA_CUR_SOURCE_BIT) { + case TYPEC_SRC_RP_STD: + rp = POWER_SUPPLY_TYPEC_SRC_RP_STD; + break; + case TYPEC_SRC_RP_1P5A: + rp = POWER_SUPPLY_TYPEC_SRC_RP_1P5A; + break; + default: + return -EINVAL; + } + + val->intval = rp; + + return 0; +} + int smblib_toggle_stat(struct smb_charger *chg, int reset) { int rc = 0; @@ -2861,6 +2899,42 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, return 0; } +int smblib_set_prop_typec_select_rp(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int rc = 0; + + if (!typec_in_src_mode(chg)) { + smblib_err(chg, "Couldn't set curr src: not in SRC mode\n"); + return -EINVAL; + } + + if (val->intval < 0 || val->intval >= TYPEC_SRC_RP_MAX_ELEMENTS) + return -EINVAL; + + switch (val->intval) { + case TYPEC_SRC_RP_STD: + rc = smblib_masked_write(chg, TYPE_C_CFG_2_REG, + EN_80UA_180UA_CUR_SOURCE_BIT, + TYPEC_SRC_RP_STD); + break; + case TYPEC_SRC_RP_1P5A: + case TYPEC_SRC_RP_3A: + case TYPEC_SRC_RP_3A_DUPLICATE: + rc = smblib_masked_write(chg, TYPE_C_CFG_2_REG, + EN_80UA_180UA_CUR_SOURCE_BIT, + TYPEC_SRC_RP_1P5A); + break; + default: + return -EINVAL; + } + + if (rc < 0) + smblib_err(chg, "Couldn't write to TYPE_C_CURRSRC_CFG rc=%d\n", + rc); + return rc; +} + int smblib_set_prop_pd_voltage_min(struct smb_charger *chg, const union power_supply_propval *val) { diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index de20612202c66763eda5a5470b7bf376fb082c4b..984a935edfdf0e47a03c2650d476fe75547c70db 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -488,6 +488,8 @@ int smblib_get_prop_usb_current_now(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_typec_select_rp(struct smb_charger *chg, + union power_supply_propval *val); int smblib_get_prop_typec_power_role(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_pd_allowed(struct smb_charger *chg, @@ -520,6 +522,8 @@ int smblib_set_prop_boost_current(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_typec_power_role(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_set_prop_typec_select_rp(struct smb_charger *chg, + const union power_supply_propval *val); int smblib_set_prop_pd_active(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg, diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h index f0af55d1cc6933eeba940c5c77b08d71465e9595..a0858a735d0cebdf1a3cc8002fec78c57d76c03e 100644 --- a/drivers/power/supply/qcom/smb-reg.h +++ b/drivers/power/supply/qcom/smb-reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020 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 @@ -576,6 +576,13 @@ enum { #define USB_FACTORY_MODE_ENABLE_BIT BIT(2) #define TYPE_C_UFP_MODE_BIT BIT(1) #define EN_80UA_180UA_CUR_SOURCE_BIT BIT(0) +enum { + TYPEC_SRC_RP_STD, + TYPEC_SRC_RP_1P5A, + TYPEC_SRC_RP_3A, + TYPEC_SRC_RP_3A_DUPLICATE, + TYPEC_SRC_RP_MAX_ELEMENTS +}; #define TYPE_C_CFG_3_REG (USBIN_BASE + 0x5A) #define TVBUS_DEBOUNCE_BIT BIT(7) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index cd1ae35a17c62f089e76f5afd51029a7f964b621..ea3f74aa578bf9c90622096c1bf9bcdaaa8acf22 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1954,6 +1954,18 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, u8 stat; int rc, suspend = 0; + if (chg->fake_chg_status_on_debug_batt) { + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_DEBUG_BATTERY, &pval); + if (rc < 0) { + pr_err_ratelimited("Couldn't get debug battery prop rc=%d\n", + rc); + } else if (pval.intval == 1) { + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + return 0; + } + } + if (chg->dbc_usbov) { rc = smblib_get_prop_usb_present(chg, &pval); if (rc < 0) { diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index a9dbc9af5e557e7d5268cbef7f82d0efa188291d..de04a7ab4a0671dd1651d047c6a3bd8c5d637fe9 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -514,6 +514,7 @@ struct smb_charger { int connector_type; bool otg_en; bool suspend_input_on_debug_batt; + bool fake_chg_status_on_debug_batt; int default_icl_ua; int otg_cl_ua; bool uusb_apsd_rerun_done; diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index b818f65480c152bda2209fb4a76be083da719ccc..e232233beb8f26f2b3634c684d3096f035d08527 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -179,6 +179,7 @@ static void ptp_clock_release(struct device *dev) { struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev); + ptp_cleanup_pin_groups(ptp); mutex_destroy(&ptp->tsevq_mux); mutex_destroy(&ptp->pincfg_mux); ida_simple_remove(&ptp_clocks_map, ptp->index); @@ -315,9 +316,8 @@ int ptp_clock_unregister(struct ptp_clock *ptp) if (ptp->pps_source) pps_unregister_source(ptp->pps_source); - ptp_cleanup_pin_groups(ptp); - posix_clock_unregister(&ptp->clock); + return 0; } EXPORT_SYMBOL(ptp_clock_unregister); diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 1e69c1c9ec09635c9dffbb6b4d9cfd157f0c9108..7a4a6406cf69adc945d8290df016954ca1c4a323 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -216,6 +216,12 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe); int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) { + int i; + + for (i = 0; i < lpwm->info->npwm; i++) { + if (pwm_is_enabled(&lpwm->chip.pwms[i])) + pm_runtime_put(lpwm->chip.dev); + } return pwmchip_remove(&lpwm->chip); } EXPORT_SYMBOL_GPL(pwm_lpss_remove); diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 9b79cbc7a7152a0ae01d814d96d8c7b0c034c684..3d2c36963a4fc8e2fffdf64a623057815c6d6b5d 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -188,7 +188,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, do_div(fin_ps, fin_freq); /* Calc pre_div with the period */ - for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) { + for (pre_div = 0; pre_div <= MISC_CLK_DIV_MASK; pre_div++) { cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000, fin_ps * (pre_div + 1)); dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n", @@ -197,7 +197,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, break; } - if (pre_div == MISC_CLK_DIV_MASK) { + if (pre_div > MISC_CLK_DIV_MASK) { dev_err(meson->chip.dev, "unable to get period pre_div\n"); return -EINVAL; } @@ -325,11 +325,6 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (state->period != channel->state.period || state->duty_cycle != channel->state.duty_cycle || state->polarity != channel->state.polarity) { - if (channel->state.enabled) { - meson_pwm_disable(meson, pwm->hwpwm); - channel->state.enabled = false; - } - if (state->polarity != channel->state.polarity) { if (state->polarity == PWM_POLARITY_NORMAL) meson->inverter_mask |= BIT(pwm->hwpwm); diff --git a/drivers/rapidio/rio_cm.c b/drivers/rapidio/rio_cm.c index ef989a15aefc41b47aebfced74795d88a7cb88ce..b29fc258eeba4becb609d6e2063af1ebf5022e91 100644 --- a/drivers/rapidio/rio_cm.c +++ b/drivers/rapidio/rio_cm.c @@ -1215,7 +1215,9 @@ static int riocm_ch_listen(u16 ch_id) riocm_debug(CHOP, "(ch_%d)", ch_id); ch = riocm_get_channel(ch_id); - if (!ch || !riocm_cmp_exch(ch, RIO_CM_CHAN_BOUND, RIO_CM_LISTEN)) + if (!ch) + return -EINVAL; + if (!riocm_cmp_exch(ch, RIO_CM_CHAN_BOUND, RIO_CM_LISTEN)) ret = -EINVAL; riocm_put_channel(ch); return ret; diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c index cfdbe294fb6af9cc5a33ca8484d982ece53e6ed6..32d4e6ec2e19867129ddcc19c9d250a521c890ab 100644 --- a/drivers/regulator/lp87565-regulator.c +++ b/drivers/regulator/lp87565-regulator.c @@ -188,7 +188,7 @@ static int lp87565_regulator_probe(struct platform_device *pdev) struct lp87565 *lp87565 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; struct regulator_dev *rdev; - int i, min_idx = LP87565_BUCK_1, max_idx = LP87565_BUCK_3; + int i, min_idx = LP87565_BUCK_0, max_idx = LP87565_BUCK_3; platform_set_drvdata(pdev, lp87565); diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c index a9446056435f9b71772d4cecb33017c42abeebcf..1f2d8180506bc248676ce61429b1b93442f8d718 100644 --- a/drivers/regulator/pv88060-regulator.c +++ b/drivers/regulator/pv88060-regulator.c @@ -135,7 +135,7 @@ static int pv88060_set_current_limit(struct regulator_dev *rdev, int min, int i; /* search for closest to maximum */ - for (i = info->n_current_limits; i >= 0; i--) { + for (i = info->n_current_limits - 1; i >= 0; i--) { if (min <= info->current_limits[i] && max >= info->current_limits[i]) { return regmap_update_bits(rdev->regmap, diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c index 9a08cb2de501e95175fe4f56168ec0bfe123b08a..6770e4de2097804d4c9701ca6598247c1d7ee196 100644 --- a/drivers/regulator/pv88080-regulator.c +++ b/drivers/regulator/pv88080-regulator.c @@ -279,7 +279,7 @@ static int pv88080_set_current_limit(struct regulator_dev *rdev, int min, int i; /* search for closest to maximum */ - for (i = info->n_current_limits; i >= 0; i--) { + for (i = info->n_current_limits - 1; i >= 0; i--) { if (min <= info->current_limits[i] && max >= info->current_limits[i]) { return regmap_update_bits(rdev->regmap, diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c index 7a0c15957bd0b710ec25b65454fe0474ca5f87d7..2302b0df7630f08a090679183bc87a3549645772 100644 --- a/drivers/regulator/pv88090-regulator.c +++ b/drivers/regulator/pv88090-regulator.c @@ -157,7 +157,7 @@ static int pv88090_set_current_limit(struct regulator_dev *rdev, int min, int i; /* search for closest to maximum */ - for (i = info->n_current_limits; i >= 0; i--) { + for (i = info->n_current_limits - 1; i >= 0; i--) { if (min <= info->current_limits[i] && max >= info->current_limits[i]) { return regmap_update_bits(rdev->regmap, diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index f32fbd9f4c2d3b8019dd5c590816fb66f8403b26..396ed5415eea7a02b7c42cc032e462015e10227e 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, 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 @@ -2092,7 +2092,12 @@ static void qpnp_lcdb_pmic_config(struct qpnp_lcdb *lcdb) lcdb->wa_flags |= NCP_SCP_DISABLE_WA; break; case PMI632_SUBTYPE: - case PM6150L_SUBTYPE: + lcdb->wa_flags |= FORCE_PD_ENABLE_WA; + break; + case PM8150L_SUBTYPE: + if (lcdb->pmic_rev_id->rev4 >= PM8150L_V3P0_REV4) + lcdb->voltage_step_ramp = false; + lcdb->wa_flags |= FORCE_PD_ENABLE_WA; break; default: diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c index 790a4a73ea2c8f94c3fb80c8567827d0e8b0860b..40b74648bd31137782adb6d5015794d173354b90 100644 --- a/drivers/regulator/rn5t618-regulator.c +++ b/drivers/regulator/rn5t618-regulator.c @@ -154,6 +154,7 @@ static struct platform_driver rn5t618_regulator_driver = { module_platform_driver(rn5t618_regulator_driver); +MODULE_ALIAS("platform:rn5t618-regulator"); MODULE_AUTHOR("Beniamino Galvani "); MODULE_DESCRIPTION("RN5T618 regulator driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps65086-regulator.c b/drivers/regulator/tps65086-regulator.c index 45e96e15469005f376478d49dbc09045aae4bc3c..5a5e9b5bf4bea7c6935cca2423dce30475c4177c 100644 --- a/drivers/regulator/tps65086-regulator.c +++ b/drivers/regulator/tps65086-regulator.c @@ -90,8 +90,8 @@ static const struct regulator_linear_range tps65086_buck345_25mv_ranges[] = { static const struct regulator_linear_range tps65086_ldoa1_ranges[] = { REGULATOR_LINEAR_RANGE(1350000, 0x0, 0x0, 0), REGULATOR_LINEAR_RANGE(1500000, 0x1, 0x7, 100000), - REGULATOR_LINEAR_RANGE(2300000, 0x8, 0xA, 100000), - REGULATOR_LINEAR_RANGE(2700000, 0xB, 0xD, 150000), + REGULATOR_LINEAR_RANGE(2300000, 0x8, 0xB, 100000), + REGULATOR_LINEAR_RANGE(2850000, 0xC, 0xD, 150000), REGULATOR_LINEAR_RANGE(3300000, 0xE, 0xE, 0), }; diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 5a5bc4bb08d26ee78926aacaa906010cc1f426c2..df591435d12a376f051e79e670ade55ab6ef1b7a 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -327,8 +327,8 @@ static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev) } /* Current limit options */ -static u16 wm831x_dcdc_ilim[] = { - 125, 250, 375, 500, 625, 750, 875, 1000 +static const unsigned int wm831x_dcdc_ilim[] = { + 125000, 250000, 375000, 500000, 625000, 750000, 875000, 1000000 }; static int wm831x_buckv_set_current_limit(struct regulator_dev *rdev, diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index 36d3443af640bacde788c81ee3cda9d2b92c6123..02d3560b1d1f8c2f8915bec739b648268ec842cb 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -59,6 +59,15 @@ config RPMSG_QCOM_GLINK_SPI data to the appropriate SPI bus wire format and allows for GLINK communication with remote subsystems that are external to the SoC. +config RPMSG_QCOM_GLINK_BGCOM + tristate "Qualcomm Technologies, Inc. BGCOM Glink driver" + help + Say y here to enable support for the GLINK BGCOM driver, + which provides support for using the GLINK communication protocol + over BGCOM. This transport performs marshaling of GLINK commands and + data to the appropriate BGCOM format and allows for GLINK + communication with remote subsystems that are external to the SoC. + config RPMSG_QCOM_SMD tristate "Qualcomm Shared Memory Driver (SMD)" depends on QCOM_SMEM diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index 131052abeaf5f3c51728a845f19a0b9497cc6aff..53583a28cb0528c912fec1c6995ca2c3a6c5698d 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SPSS) += qcom_glink_spss.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SPI) += qcom_glink_spi.o +obj-$(CONFIG_RPMSG_QCOM_GLINK_BGCOM) += qcom_glink_bgcom.o obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o diff --git a/drivers/rpmsg/qcom_glink_bgcom.c b/drivers/rpmsg/qcom_glink_bgcom.c new file mode 100644 index 0000000000000000000000000000000000000000..31f9f0cdb47cf08a07779f3d07ab449953167cd1 --- /dev/null +++ b/drivers/rpmsg/qcom_glink_bgcom.c @@ -0,0 +1,2266 @@ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../soc/qcom/bgcom.h" + +#include + +#include "rpmsg_internal.h" +#include "qcom_glink_native.h" + +#define GLINK_LOG_PAGE_CNT 2 +#define GLINK_INFO(ctxt, x, ...) \ +do { \ + if (ctxt->ilc) \ + ipc_log_string(ctxt->ilc, "[%s]: "x, __func__, ##__VA_ARGS__); \ +} while (0) + +#define CH_INFO(ch, x, ...) \ +do { \ + if (ch->glink && ch->glink->ilc) \ + ipc_log_string(ch->glink->ilc, "%s[%d:%d] %s: "x, ch->name, \ + ch->lcid, ch->rcid, __func__, ##__VA_ARGS__); \ +} while (0) + + +#define GLINK_ERR(ctxt, x, ...) \ +do { \ + pr_err_ratelimited("[%s]: "x, __func__, ##__VA_ARGS__); \ + if (ctxt->ilc) \ + ipc_log_string(ctxt->ilc, "[%s]: "x, __func__, ##__VA_ARGS__); \ +} while (0) + +#define BGCOM_ALIGNMENT 16 +#define TX_BLOCKED_CMD_RESERVE 16 +#define DEFAULT_FIFO_SIZE 1024 +#define SHORT_SIZE 16 +#define XPRT_ALIGNMENT 4 + +#define ACTIVE_TX BIT(0) +#define ACTIVE_RX BIT(1) + +#define ID_MASK 0xFFFFFF + +#define GLINK_NAME_SIZE 32 +#define GLINK_VERSION_1 1 + +#define BGCOM_GLINK_CID_MIN 1 +#define BGCOM_GLINK_CID_MAX 65536 + +#define TX_WAIT_US 500 +#define BGCOM_RESET 0x00000000 +#define BGCOM_APPLICATION_RUNNING 0x00000001 +#define BGCOM_TO_SLAVE_FIFO_READY 0x00000002 +#define BGCOM_TO_MASTER_FIFO_READY 0x00000004 +#define BGCOM_AHB_READY 0x00000008 +#define WORD_SIZE 4 +#define TX_BLOCKED_CMD_RESERVE 16 +#define FIFO_FULL_RESERVE (TX_BLOCKED_CMD_RESERVE/WORD_SIZE) +#define BGCOM_LINKUP (BGCOM_APPLICATION_RUNNING \ + | BGCOM_TO_SLAVE_FIFO_READY \ + | BGCOM_TO_MASTER_FIFO_READY \ + | BGCOM_AHB_READY) + +struct glink_bgcom_msg { + __le16 cmd; + __le16 param1; + __le32 param2; + __le32 param3; + __le32 param4; + u8 data[]; +} __packed; + +/** + * struct glink_bgcom_defer_cmd - deferred incoming control message + * @node: list node + * @msg: message header + * data: payload of the message + * + * Copy of a received control message, to be added to @rx_queue and processed + * by @rx_work of @glink_bgcom. + */ +struct glink_bgcom_defer_cmd { + struct list_head node; + + struct glink_bgcom_msg msg; + u8 data[]; +}; + +/** + * struct glink_bgcom_rx_intent - RX intent + * RX intent + * + * @data: pointer to the data (may be NULL for zero-copy) + * @id: remote or local intent ID + * @size: size of the original intent (do not modify) + * @addr: addr to read/write the data from + * @reuse: To mark if the intent can be reused after first use + * @in_use: To mark if intent is already in use for the channel + * @offset: next write offset (initially 0) + */ +struct glink_bgcom_rx_intent { + void *data; + u32 id; + size_t size; + u32 addr; + bool reuse; + bool in_use; + u32 offset; + + struct list_head node; +}; + +struct bgcom_fifo_size { + uint32_t to_master:16; + uint32_t to_slave:16; +}; + +struct bgcom_fifo_fill { + uint32_t rx_avail:16; + uint32_t tx_avail:16; +}; + +/** + * struct glink_bgcom - driver context, relates to one remote subsystem + * @dev: reference to the associated struct device + * @name: name of this edge + * @rx_pipe: pipe object for receive FIFO + * @rx_worker: worker struct for handling received control messages + * @rx_task: task that runs the rx_worker + * @rx_lock: protects the @rx_queue + * @rx_queue: queue of received control messages to be processed in @rx_work + * @tx_lock: synchronizes operations on the tx fifo + * @idr_lock: synchronizes @lcids and @rcids modifications + * @lcids: idr of all channels with a known local channel id + * @rcids: idr of all channels with a known remote channel id + * @spi_ops: spi ops for sending data to the remote + * @cmpnt: component to be registered with the wdsp component manager + * @in_reset indicates that remote processor is in reset + * @ilc: ipc logging context reference + * @sent_read_notify: flag to check cmd sent or not + */ +struct glink_bgcom { + struct device *dev; + + const char *name; + + struct kthread_worker rx_worker; + struct task_struct *rx_task; + + spinlock_t rx_lock; + struct list_head rx_queue; + struct work_struct rx_defer_work; + + struct mutex tx_lock; + + struct mutex idr_lock; + struct idr lcids; + struct idr rcids; + u32 features; + + atomic_t activity_cnt; + atomic_t in_reset; + + void *ilc; + bool sent_read_notify; + + struct bgcom_fifo_fill fifo_fill; + struct bgcom_fifo_size fifo_size; + struct mutex tx_avail_lock; + struct kthread_worker kworker; + + uint32_t bgcom_status; + struct bgcom_open_config_type bgcom_config; + void *bgcom_handle; + bool water_mark_reached; +}; + +enum { + GLINK_STATE_CLOSED, + GLINK_STATE_OPENING, + GLINK_STATE_OPEN, + GLINK_STATE_CLOSING, +}; + +/** + * struct glink_bgcom_channel - internal representation of a channel + * @rpdev: rpdev reference, only used for primary endpoints + * @ept: rpmsg endpoint this channel is associated with + * @glink: glink_bgcom context handle + * @refcount: refcount for the channel object + * @recv_lock: guard for @ept.cb + * @name: unique channel name/identifier + * @lcid: channel id, in local space + * @rcid: channel id, in remote space + * @intent_lock: lock for protection of @liids, @riids + * @liids: idr of all local intents + * @riids: idr of all remote intents + * @open_ack: completed once remote has acked the open-request + * @open_req: completed once open-request has been received + * @intent_req_lock: Synchronises multiple intent requests + * @intent_req_result: Result of intent request + * @intent_req_comp: Completion for intent_req signalling + */ +struct glink_bgcom_channel { + struct rpmsg_endpoint ept; + + struct rpmsg_device *rpdev; + struct glink_bgcom *glink; + + struct kref refcount; + + spinlock_t recv_lock; + + char *name; + unsigned int lcid; + unsigned int rcid; + + struct mutex intent_lock; + struct idr liids; + struct idr riids; + + unsigned int lsigs; + unsigned int rsigs; + + struct completion open_ack; + struct completion open_req; + + struct mutex intent_req_lock; + bool intent_req_result; + struct completion intent_req_comp; +}; + +struct rx_pkt { + void *rx_buf; + uint32_t rx_len; + struct glink_bgcom *glink; + struct kthread_work kwork; +}; + +#define to_glink_channel(_ept) container_of(_ept, \ + struct glink_bgcom_channel, ept) + +static const struct rpmsg_endpoint_ops glink_endpoint_ops; + +#define BGCOM_CMD_VERSION 0 +#define BGCOM_CMD_VERSION_ACK 1 +#define BGCOM_CMD_OPEN 2 +#define BGCOM_CMD_CLOSE 3 +#define BGCOM_CMD_OPEN_ACK 4 +#define BGCOM_CMD_CLOSE_ACK 5 +#define BGCOM_CMD_INTENT 6 +#define BGCOM_CMD_RX_DONE 7 +#define BGCOM_CMD_RX_DONE_W_REUSE 8 +#define BGCOM_CMD_RX_INTENT_REQ 9 +#define BGCOM_CMD_RX_INTENT_REQ_ACK 10 +#define BGCOM_CMD_TX_DATA 11 +#define BGCOM_CMD_TX_DATA_CONT 12 +#define BGCOM_CMD_READ_NOTIF 13 +#define BGCOM_CMD_SIGNALS 14 +#define BGCOM_CMD_TX_SHORT_DATA 17 + +static struct glink_bgcom_channel * +glink_bgcom_alloc_channel(struct glink_bgcom *glink, const char *name) +{ + struct glink_bgcom_channel *channel; + + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) + return ERR_PTR(-ENOMEM); + + /* Setup glink internal glink_spi_channel data */ + spin_lock_init(&channel->recv_lock); + mutex_init(&channel->intent_lock); + mutex_init(&channel->intent_req_lock); + + channel->glink = glink; + channel->name = kstrdup(name, GFP_KERNEL); + + init_completion(&channel->open_req); + init_completion(&channel->open_ack); + init_completion(&channel->intent_req_comp); + + idr_init(&channel->liids); + idr_init(&channel->riids); + kref_init(&channel->refcount); + + return channel; +} + +static void glink_bgcom_channel_release(struct kref *ref) +{ + struct glink_bgcom_channel *channel; + struct glink_bgcom_rx_intent *tmp; + int iid; + + channel = container_of(ref, struct glink_bgcom_channel, refcount); + CH_INFO(channel, "\n"); + + channel->intent_req_result = 0; + complete(&channel->intent_req_comp); + + mutex_lock(&channel->intent_lock); + idr_for_each_entry(&channel->liids, tmp, iid) { + kfree(tmp->data); + kfree(tmp); + } + idr_destroy(&channel->liids); + + idr_for_each_entry(&channel->riids, tmp, iid) + kfree(tmp); + idr_destroy(&channel->riids); + mutex_unlock(&channel->intent_lock); + + kfree(channel->name); + kfree(channel); +} + +static struct glink_bgcom_rx_intent * +glink_bgcom_alloc_intent(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + size_t size, + bool reuseable) +{ + struct glink_bgcom_rx_intent *intent; + int ret; + + intent = kzalloc(sizeof(*intent), GFP_KERNEL); + if (!intent) + return NULL; + + intent->data = kzalloc(size, GFP_KERNEL); + if (!intent->data) + goto free_intent; + + mutex_lock(&channel->intent_lock); + ret = idr_alloc_cyclic(&channel->liids, intent, 1, -1, GFP_ATOMIC); + if (ret < 0) { + mutex_unlock(&channel->intent_lock); + goto free_data; + } + mutex_unlock(&channel->intent_lock); + + intent->id = ret; + intent->size = size; + intent->reuse = reuseable; + + return intent; + +free_data: + kfree(intent->data); +free_intent: + kfree(intent); + return NULL; +} + +/** + * tx_wakeup_worker() - worker function to wakeup tx blocked thread + * @work: kwork associated with the edge to process commands on. + */ +static void tx_wakeup_worker(struct glink_bgcom *glink) +{ + struct bgcom_fifo_fill fifo_fill; + + mutex_lock(&glink->tx_avail_lock); + bgcom_reg_read(glink->bgcom_handle, BGCOM_REG_FIFO_FILL, 1, + &fifo_fill); + glink->fifo_fill.tx_avail = fifo_fill.tx_avail; + if (glink->fifo_fill.tx_avail > glink->fifo_size.to_slave/2) + glink->water_mark_reached = false; + mutex_unlock(&glink->tx_avail_lock); + + if (atomic_read(&glink->in_reset)) + return; +} + +static void glink_bgcom_update_tx_avail(struct glink_bgcom *glink, + uint32_t size) +{ + mutex_lock(&glink->tx_avail_lock); + glink->fifo_fill.tx_avail -= size; + if (glink->fifo_fill.tx_avail < glink->fifo_size.to_slave/2) + glink->water_mark_reached = true; + mutex_unlock(&glink->tx_avail_lock); +} + +size_t glink_bgcom_tx_avail(struct glink_bgcom *glink) +{ + u32 tx_avail; + + mutex_lock(&glink->tx_avail_lock); + tx_avail = glink->fifo_fill.tx_avail; + if (tx_avail < FIFO_FULL_RESERVE) + tx_avail = 0; + else + tx_avail -= FIFO_FULL_RESERVE; + + mutex_unlock(&glink->tx_avail_lock); + return tx_avail; +} + +static int glink_bgcom_tx_write_one(struct glink_bgcom *glink, void *src, + uint32_t size) +{ + u32 tx_avail = glink_bgcom_tx_avail(glink); + int ret; + uint32_t size_in_words = size/WORD_SIZE; + + if (size_in_words > tx_avail) { + GLINK_ERR(glink, "%s: No Space in Fifo\n", __func__); + return -ENOSPC; + } + + ret = bgcom_fifo_write(glink->bgcom_handle, size_in_words, src); + if (ret < 0) { + GLINK_ERR(glink, "%s: Error %d writing data\n", + __func__, ret); + return ret; + } + + glink_bgcom_update_tx_avail(glink, size_in_words); + return ret; +} + +static void glink_bgcom_tx_write(struct glink_bgcom *glink, + void *data, size_t dlen) +{ + int ret; + + if (dlen) { + ret = glink_bgcom_tx_write_one(glink, data, dlen); + if (ret < 0) + GLINK_ERR(glink, "Error %d writing tx data\n", ret); + } +} + +static void glink_bgcom_send_read_notify(struct glink_bgcom *glink) +{ + struct glink_bgcom_msg msg = { 0 }; + int ret; + + msg.cmd = cpu_to_le16(BGCOM_CMD_READ_NOTIF); + msg.param1 = 0; + msg.param2 = 0; + + GLINK_INFO(glink, "Cmd size in words = %d\n", sizeof(msg)/WORD_SIZE); + + ret = bgcom_fifo_write(glink->bgcom_handle, sizeof(msg)/WORD_SIZE, + &msg); + if (ret < 0) { + GLINK_ERR(glink, "%s: Error %d writing data\n", + __func__, ret); + return; + } + + glink_bgcom_update_tx_avail(glink, sizeof(msg)/WORD_SIZE); +} + +static int glink_bgcom_tx(struct glink_bgcom *glink, void *data, + size_t dlen, bool wait) +{ + int ret = 0; + + mutex_lock(&glink->tx_lock); + + while (glink_bgcom_tx_avail(glink) < dlen/WORD_SIZE) { + if (!wait) { + ret = -EAGAIN; + goto out; + } + + if (atomic_read(&glink->in_reset)) { + ret = -ENXIO; + goto out; + } + + if (!glink->sent_read_notify) { + glink->sent_read_notify = true; + glink_bgcom_send_read_notify(glink); + } + /* Wait without holding the tx_lock */ + mutex_unlock(&glink->tx_lock); + + usleep_range(TX_WAIT_US, TX_WAIT_US + 50); + + mutex_lock(&glink->tx_lock); + + if (glink_bgcom_tx_avail(glink) >= dlen/WORD_SIZE) + glink->sent_read_notify = false; + } + + glink_bgcom_tx_write(glink, data, dlen); + +out: + mutex_unlock(&glink->tx_lock); + + return ret; +} + +/** + * glink_bgcom_send_intent_req_ack() - convert an rx intent request ack cmd to + wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @granted: The request response to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int glink_bgcom_send_intent_req_ack(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + bool granted) +{ + struct glink_bgcom_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(BGCOM_CMD_RX_INTENT_REQ_ACK); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(granted); + + CH_INFO(channel, "\n"); + glink_bgcom_tx(glink, &msg, sizeof(msg), true); + + return 0; +} + +static int glink_bgcom_send_data(struct glink_bgcom_channel *channel, + void *data, int chunk_size, int left_size, + struct glink_bgcom_rx_intent *intent, bool wait) +{ + struct glink_bgcom *glink = channel->glink; + struct { + struct glink_bgcom_msg msg; + __le32 chunk_size; + __le32 left_size; + } __packed req; + + CH_INFO(channel, "chunk:%d, left:%d\n", chunk_size, left_size); + + memset(&req, 0, sizeof(req)); + if (intent->offset) + req.msg.cmd = cpu_to_le16(BGCOM_CMD_TX_DATA_CONT); + else + req.msg.cmd = cpu_to_le16(BGCOM_CMD_TX_DATA); + + req.msg.param1 = cpu_to_le16(channel->lcid); + req.msg.param2 = cpu_to_le32(intent->id); + req.chunk_size = cpu_to_le32(chunk_size); + req.left_size = cpu_to_le32(left_size); + + mutex_lock(&glink->tx_lock); + while (glink_bgcom_tx_avail(glink) < sizeof(req)/WORD_SIZE) { + if (!wait) { + mutex_unlock(&glink->tx_lock); + return -EAGAIN; + } + + if (atomic_read(&glink->in_reset)) { + mutex_unlock(&glink->tx_lock); + return -EINVAL; + } + + if (!glink->sent_read_notify) { + glink->sent_read_notify = true; + glink_bgcom_send_read_notify(glink); + } + + /* Wait without holding the tx_lock */ + mutex_unlock(&glink->tx_lock); + + usleep_range(TX_WAIT_US, TX_WAIT_US + 50); + + mutex_lock(&glink->tx_lock); + + if (glink_bgcom_tx_avail(glink) >= sizeof(req)/WORD_SIZE) + glink->sent_read_notify = false; + } + + bgcom_ahb_write(glink->bgcom_handle, + (uint32_t)(size_t)(intent->addr + intent->offset), + ALIGN(chunk_size, WORD_SIZE)/WORD_SIZE, data); + + intent->offset += chunk_size; + glink_bgcom_tx_write(glink, &req, sizeof(req)); + + mutex_unlock(&glink->tx_lock); + return 0; +} + +static void glink_bgcom_handle_intent_req_ack(struct glink_bgcom *glink, + unsigned int cid, bool granted) +{ + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, cid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_err(glink->dev, "unable to find channel\n"); + return; + } + + channel->intent_req_result = granted; + complete(&channel->intent_req_comp); + CH_INFO(channel, "\n"); +} + +/** + * glink_bgcom_advertise_intent - convert an rx intent cmd to wire format and + * transmit + * @glink: The transport to transmit on. + * @channel: The local channel + * @size: The intent to pass on to remote. + * + * Return: 0 on success or standard Linux error code. + */ +static int glink_bgcom_advertise_intent(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + struct glink_bgcom_rx_intent *intent) +{ + struct command { + struct glink_bgcom_msg msg; + __le32 size; + __le32 liid; + __le64 addr; + } __packed; + struct command cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.msg.cmd = cpu_to_le16(BGCOM_CMD_INTENT); + cmd.msg.param1 = cpu_to_le16(channel->lcid); + cmd.msg.param2 = cpu_to_le32(1); + cmd.size = cpu_to_le32(intent->size); + cmd.liid = cpu_to_le32(intent->id); + + glink_bgcom_tx(glink, &cmd, sizeof(cmd), true); + + CH_INFO(channel, "count:%d size:%lu liid:%d\n", 1, + intent->size, intent->id); + + return 0; +} + +/** + * glink_bgcom_handle_intent_req() - Receive a request for rx_intent + * from remote side + * if_ptr: Pointer to the transport interface + * rcid: Remote channel ID + * size: size of the intent + * + * The function searches for the local channel to which the request for + * rx_intent has arrived and allocates and notifies the remote back + */ +static void glink_bgcom_handle_intent_req(struct glink_bgcom *glink, + u32 cid, size_t size) +{ + struct glink_bgcom_rx_intent *intent; + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, cid); + mutex_unlock(&glink->idr_lock); + + if (!channel) { + pr_err("%s channel not found for cid %d\n", __func__, cid); + return; + } + + intent = glink_bgcom_alloc_intent(glink, channel, size, false); + if (intent) + glink_bgcom_advertise_intent(glink, channel, intent); + + glink_bgcom_send_intent_req_ack(glink, channel, !!intent); +} + +static int glink_bgcom_send_short(struct glink_bgcom_channel *channel, + void *data, int len, + struct glink_bgcom_rx_intent *intent, + bool wait) +{ + struct glink_bgcom *glink = channel->glink; + struct { + struct glink_bgcom_msg msg; + u8 data[SHORT_SIZE]; + } __packed req; + + CH_INFO(channel, "intent offset:%d len:%d\n", intent->offset, len); + + req.msg.cmd = cpu_to_le16(BGCOM_CMD_TX_SHORT_DATA); + req.msg.param1 = cpu_to_le16(channel->lcid); + req.msg.param2 = cpu_to_le32(intent->id); + req.msg.param3 = cpu_to_le32(len); + req.msg.param4 = cpu_to_be32(0); + memcpy(req.data, data, len); + + mutex_lock(&glink->tx_lock); + while (glink_bgcom_tx_avail(glink) < sizeof(req)/WORD_SIZE) { + + if (!wait) { + mutex_unlock(&glink->tx_lock); + return -EAGAIN; + } + + if (atomic_read(&glink->in_reset)) { + mutex_unlock(&glink->tx_lock); + return -EINVAL; + } + + if (!glink->sent_read_notify) { + glink->sent_read_notify = true; + glink_bgcom_send_read_notify(glink); + } + + /* Wait without holding the tx_lock */ + mutex_unlock(&glink->tx_lock); + + usleep_range(TX_WAIT_US, TX_WAIT_US + 50); + + mutex_lock(&glink->tx_lock); + + if (glink_bgcom_tx_avail(glink) >= sizeof(req)/WORD_SIZE) + glink->sent_read_notify = false; + } + glink_bgcom_tx_write(glink, &req, sizeof(req)); + + mutex_unlock(&glink->tx_lock); + return 0; +} + +static int glink_bgcom_request_intent(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + size_t size) +{ + struct glink_bgcom_msg req = { 0 }; + int ret; + + kref_get(&channel->refcount); + mutex_lock(&channel->intent_req_lock); + + reinit_completion(&channel->intent_req_comp); + + req.cmd = cpu_to_le16(BGCOM_CMD_RX_INTENT_REQ); + req.param1 = cpu_to_le16(channel->lcid); + req.param2 = cpu_to_le32(size); + + CH_INFO(channel, "size:%lu\n", size); + + ret = glink_bgcom_tx(glink, &req, sizeof(req), true); + if (ret) + goto unlock; + + ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ); + if (!ret) { + dev_err(glink->dev, "intent request timed out\n"); + ret = -ETIMEDOUT; + } else { + ret = channel->intent_req_result ? 0 : -ECANCELED; + } + +unlock: + mutex_unlock(&channel->intent_req_lock); + kref_put(&channel->refcount, glink_bgcom_channel_release); + return ret; +} + +static int __glink_bgcom_send(struct glink_bgcom_channel *channel, + void *data, int len, bool wait) +{ + struct glink_bgcom *glink = channel->glink; + struct glink_bgcom_rx_intent *intent = NULL; + struct glink_bgcom_rx_intent *tmp; + int size = len; + int iid = 0; + int ret = 0; + + CH_INFO(channel, "size:%d, wait:%d\n", len, wait); + + atomic_inc(&glink->activity_cnt); + bgcom_resume(glink->bgcom_handle); + while (!intent) { + mutex_lock(&channel->intent_lock); + idr_for_each_entry(&channel->riids, tmp, iid) { + if (tmp->size >= len && !tmp->in_use) { + if (!intent) + intent = tmp; + else if (intent->size > tmp->size) + intent = tmp; + if (intent->size == len) + break; + } + } + if (intent) + intent->in_use = true; + mutex_unlock(&channel->intent_lock); + + /* We found an available intent */ + if (intent) + break; + + if (!wait) { + ret = -EBUSY; + goto tx_exit; + } + + ret = glink_bgcom_request_intent(glink, channel, len); + if (ret < 0) + goto tx_exit; + } + + if (len <= SHORT_SIZE) + size = 0; + else if (size & (XPRT_ALIGNMENT - 1)) + size = ALIGN(len - SHORT_SIZE, XPRT_ALIGNMENT); + + if (size) { + ret = glink_bgcom_send_data(channel, data, size, len - size, + intent, wait); + if (ret) + goto tx_exit; + } + + data = (char *)data + size; + size = len - size; + if (size) + ret = glink_bgcom_send_short(channel, data, size, intent, wait); + +tx_exit: + /* Mark intent available if we failed */ + if (ret && intent) + intent->in_use = false; + + atomic_dec(&glink->activity_cnt); + + return ret; +} + +/** + * glink_spi_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int glink_bgcom_send_signals(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + u32 sigs) +{ + struct glink_bgcom_msg msg; + + msg.cmd = cpu_to_le16(BGCOM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + GLINK_INFO(glink, "sigs:%d\n", sigs); + return glink_bgcom_tx(glink, &msg, sizeof(msg), true); +} + +static int glink_bgcom_handle_signals(struct glink_bgcom *glink, + unsigned int rcid, unsigned int signals) +{ + struct glink_bgcom_channel *channel; + u32 old; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, rcid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + channel->rsigs = signals; + + if (channel->ept.sig_cb) + channel->ept.sig_cb(channel->ept.rpdev, old, channel->rsigs); + + CH_INFO(channel, "old:%d new:%d\n", old, channel->rsigs); + + return 0; +} + +static int glink_bgcom_send_version(struct glink_bgcom *glink) +{ + struct glink_bgcom_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(BGCOM_CMD_VERSION); + msg.param1 = cpu_to_le16(GLINK_VERSION_1); + msg.param2 = cpu_to_le32(glink->features); + + GLINK_INFO(glink, "vers:%d features:%d\n", msg.param1, msg.param2); + return glink_bgcom_tx(glink, &msg, sizeof(msg), true); +} + +static void glink_bgcom_send_version_ack(struct glink_bgcom *glink) +{ + struct glink_bgcom_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(BGCOM_CMD_VERSION_ACK); + msg.param1 = cpu_to_le16(GLINK_VERSION_1); + msg.param2 = cpu_to_le32(glink->features); + + GLINK_INFO(glink, "vers:%d features:%d\n", msg.param1, msg.param2); + glink_bgcom_tx(glink, &msg, sizeof(msg), true); +} + +static void glink_bgcom_send_close_req(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel) +{ + struct glink_bgcom_msg req = { 0 }; + + req.cmd = cpu_to_le16(BGCOM_CMD_CLOSE); + req.param1 = cpu_to_le16(channel->lcid); + + CH_INFO(channel, "\n"); + glink_bgcom_tx(glink, &req, sizeof(req), true); +} + +/** + * glink_bgcom_send_open_req() - send a BGCOM_CMD_OPEN request to the remote + * @glink: Ptr to the glink edge + * @channel: Ptr to the channel that the open req is sent + * + * Allocates a local channel id and sends a BGCOM_CMD_OPEN message to the + * remote. Will return with refcount held, regardless of outcome. + * + * Returns 0 on success, negative errno otherwise. + */ +static int glink_bgcom_send_open_req(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel) +{ + + struct cmd_msg { + __le16 cmd; + __le16 lcid; + __le16 length; + __le16 req_xprt; + __le64 reserved; + }; + struct { + struct cmd_msg msg; + u8 name[GLINK_NAME_SIZE]; + } __packed req; + int name_len = strlen(channel->name) + 1; + int req_len = ALIGN(sizeof(req.msg) + name_len, BGCOM_ALIGNMENT); + int ret; + + kref_get(&channel->refcount); + + mutex_lock(&glink->idr_lock); + ret = idr_alloc_cyclic(&glink->lcids, channel, + BGCOM_GLINK_CID_MIN, BGCOM_GLINK_CID_MAX, + GFP_ATOMIC); + mutex_unlock(&glink->idr_lock); + if (ret < 0) + return ret; + + channel->lcid = ret; + CH_INFO(channel, "\n"); + + memset(&req, 0, sizeof(req)); + req.msg.cmd = cpu_to_le16(BGCOM_CMD_OPEN); + req.msg.lcid = cpu_to_le16(channel->lcid); + req.msg.length = cpu_to_le16(name_len); + strlcpy(req.name, channel->name, GLINK_NAME_SIZE); + + ret = glink_bgcom_tx(glink, &req, req_len, true); + if (ret) + goto remove_idr; + + return 0; + +remove_idr: + CH_INFO(channel, "remove_idr\n"); + + mutex_lock(&glink->idr_lock); + idr_remove(&glink->lcids, channel->lcid); + channel->lcid = 0; + mutex_unlock(&glink->idr_lock); + + return ret; +} + +static void glink_bgcom_send_open_ack(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel) +{ + struct glink_bgcom_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(BGCOM_CMD_OPEN_ACK); + msg.param1 = cpu_to_le16(channel->rcid); + + CH_INFO(channel, "\n"); + glink_bgcom_tx(glink, &msg, sizeof(msg), true); +} + +static int glink_bgcom_rx_open_ack(struct glink_bgcom *glink, + unsigned int lcid) +{ + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->lcids, lcid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + GLINK_ERR(glink, "Invalid open ack packet %d\n", lcid); + return -EINVAL; + } + + CH_INFO(channel, "\n"); + complete_all(&channel->open_ack); + + return 0; +} + +/* Remote initiated rpmsg_create_ept */ +static int glink_bgcom_create_remote(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel) +{ + int ret; + + CH_INFO(channel, "\n"); + + glink_bgcom_send_open_ack(glink, channel); + + ret = glink_bgcom_send_open_req(glink, channel); + if (ret) + goto close_link; + + ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ); + if (!ret) { + ret = -ETIMEDOUT; + goto close_link; + } + + return 0; + +close_link: + CH_INFO(channel, "close_link %d\n", ret); + + /* + * Send a close request to "undo" our open-ack. The close-ack will + * release glink_bgcom_send_open_req() reference and the last reference + * will be release after rx_close or transport unregister by calling + * glink_bgcom_remove(). + */ + glink_bgcom_send_close_req(glink, channel); + + return ret; +} + +/* Locally initiated rpmsg_create_ept */ +static struct glink_bgcom_channel +*glink_bgcom_create_local(struct glink_bgcom *glink, const char *name) +{ + struct glink_bgcom_channel *channel; + int ret; + + channel = glink_bgcom_alloc_channel(glink, name); + if (IS_ERR(channel)) + return ERR_CAST(channel); + + CH_INFO(channel, "\n"); + ret = glink_bgcom_send_open_req(glink, channel); + if (ret) + goto release_channel; + + ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ); + if (!ret) + goto err_timeout; + + ret = wait_for_completion_timeout(&channel->open_req, 5 * HZ); + if (!ret) + goto err_timeout; + + glink_bgcom_send_open_ack(glink, channel); + + return channel; + +err_timeout: + CH_INFO(channel, "err_timeout\n"); + + /* glink_bgcom_send_open_req() did register the channel in lcids*/ + mutex_lock(&glink->idr_lock); + idr_remove(&glink->lcids, channel->lcid); + mutex_unlock(&glink->idr_lock); + +release_channel: + CH_INFO(channel, "release_channel\n"); + /* Release glink_bgcom_send_open_req() reference */ + kref_put(&channel->refcount, glink_bgcom_channel_release); + /* Release glink_bgcom_alloc_channel() reference */ + kref_put(&channel->refcount, glink_bgcom_channel_release); + + return ERR_PTR(-ETIMEDOUT); +} + +static struct rpmsg_endpoint * +glink_bgcom_create_ept(struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, + void *priv, struct rpmsg_channel_info chinfo) +{ + struct glink_bgcom_channel *parent = to_glink_channel(rpdev->ept); + struct glink_bgcom_channel *channel; + struct glink_bgcom *glink = parent->glink; + struct rpmsg_endpoint *ept; + const char *name = chinfo.name; + int cid; + int ret; + + mutex_lock(&glink->idr_lock); + idr_for_each_entry(&glink->rcids, channel, cid) { + if (!strcmp(channel->name, name)) + break; + } + mutex_unlock(&glink->idr_lock); + + if (!channel) { + channel = glink_bgcom_create_local(glink, name); + if (IS_ERR(channel)) + return NULL; + } else { + ret = glink_bgcom_create_remote(glink, channel); + if (ret) + return NULL; + } + + ept = &channel->ept; + ept->rpdev = rpdev; + ept->cb = cb; + ept->priv = priv; + ept->ops = &glink_endpoint_ops; + + return ept; +} + +static int glink_bgcom_announce_create(struct rpmsg_device *rpdev) +{ + struct glink_bgcom_channel *channel = to_glink_channel(rpdev->ept); + struct device_node *np = rpdev->dev.of_node; + struct glink_bgcom *glink = channel->glink; + struct glink_bgcom_rx_intent *intent; + const struct property *prop = NULL; + __be32 defaults[] = { cpu_to_be32(SZ_1K), cpu_to_be32(5) }; + int num_intents; + int num_groups = 1; + __be32 *val = defaults; + int size; + + if (!completion_done(&channel->open_ack)) + return 0; + + prop = of_find_property(np, "qcom,intents", NULL); + if (prop) { + val = prop->value; + num_groups = prop->length / sizeof(u32) / 2; + } + + /* Channel is now open, advertise base set of intents */ + while (num_groups--) { + size = be32_to_cpup(val++); + num_intents = be32_to_cpup(val++); + while (num_intents--) { + intent = glink_bgcom_alloc_intent(glink, channel, size, + true); + if (!intent) + break; + + glink_bgcom_advertise_intent(glink, channel, intent); + } + } + return 0; +} + +static void glink_bgcom_destroy_ept(struct rpmsg_endpoint *ept) +{ + struct glink_bgcom_channel *channel = to_glink_channel(ept); + struct glink_bgcom *glink = channel->glink; + unsigned long flags; + + spin_lock_irqsave(&channel->recv_lock, flags); + channel->ept.cb = NULL; + spin_unlock_irqrestore(&channel->recv_lock, flags); + + /* Decouple the potential rpdev from the channel */ + channel->rpdev = NULL; + + glink_bgcom_send_close_req(glink, channel); +} + +static void glink_bgcom_send_close_ack(struct glink_bgcom *glink, + unsigned int rcid) +{ + struct glink_bgcom_msg req = { 0 }; + + req.cmd = cpu_to_le16(BGCOM_CMD_CLOSE_ACK); + req.param1 = cpu_to_le16(rcid); + + GLINK_INFO(glink, "rcid:%d\n", rcid); + glink_bgcom_tx(glink, &req, sizeof(req), true); +} + +static void glink_bgcom_rx_close(struct glink_bgcom *glink, unsigned int rcid) +{ + struct rpmsg_channel_info chinfo; + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, rcid); + mutex_unlock(&glink->idr_lock); + if (WARN(!channel, "close request on unknown channel\n")) + return; + CH_INFO(channel, "\n"); + + if (channel->rpdev) { + strlcpy(chinfo.name, channel->name, sizeof(chinfo.name)); + chinfo.src = RPMSG_ADDR_ANY; + chinfo.dst = RPMSG_ADDR_ANY; + + rpmsg_unregister_device(glink->dev, &chinfo); + } + + glink_bgcom_send_close_ack(glink, channel->rcid); + + mutex_lock(&glink->idr_lock); + idr_remove(&glink->rcids, channel->rcid); + channel->rcid = 0; + mutex_unlock(&glink->idr_lock); + + kref_put(&channel->refcount, glink_bgcom_channel_release); +} + +static void glink_bgcom_rx_close_ack(struct glink_bgcom *glink, + unsigned int lcid) +{ + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->lcids, lcid); + if (WARN(!channel, "close ack on unknown channel\n")) { + mutex_unlock(&glink->idr_lock); + return; + } + CH_INFO(channel, "\n"); + + idr_remove(&glink->lcids, channel->lcid); + channel->lcid = 0; + mutex_unlock(&glink->idr_lock); + + kref_put(&channel->refcount, glink_bgcom_channel_release); +} + +static int glink_bgcom_send(struct rpmsg_endpoint *ept, void *data, int len) +{ + struct glink_bgcom_channel *channel = to_glink_channel(ept); + + return __glink_bgcom_send(channel, data, len, true); +} + +static int glink_bgcom_trysend(struct rpmsg_endpoint *ept, void *data, + int len) +{ + struct glink_bgcom_channel *channel = to_glink_channel(ept); + + return __glink_bgcom_send(channel, data, len, false); +} + +/** + * glink_bgcom_receive_version_ack() - receive negotiation ack from remote + * system + * + * @glink: pointer to transport interface + * @r_version: remote version response + * @r_features: remote features response + * + * This function is called in response to a local-initiated version/feature + * negotiation sequence and is the counter-offer from the remote side based + * upon the initial version and feature set requested. + */ +static void glink_bgcom_receive_version_ack(struct glink_bgcom *glink, + u32 version, + u32 features) +{ + GLINK_INFO(glink, "vers:%d features:%d\n", version, features); + + switch (version) { + case 0: + /* Version negotiation failed */ + break; + case GLINK_VERSION_1: + if (features == glink->features) + break; + + glink->features &= features; + /* FALLTHROUGH */ + default: + glink_bgcom_send_version(glink); + break; + } +} + +/** + * glink_bgcom_receive_version() - receive version/features from remote system + * + * @glink: pointer to transport interface + * @r_version: remote version + * @r_features: remote features + * + * This function is called in response to a remote-initiated version/feature + * negotiation sequence. + */ +static void glink_bgcom_receive_version(struct glink_bgcom *glink, + u32 version, + u32 features) +{ + GLINK_INFO(glink, "vers:%d features:%d\n", version, features); + + switch (version) { + case 0: + break; + case GLINK_VERSION_1: + glink->features &= features; + /* FALLTHROUGH */ + default: + glink_bgcom_send_version_ack(glink); + break; + } +} + +static const struct rpmsg_device_ops glink_device_ops = { + .create_ept = glink_bgcom_create_ept, + .announce_create = glink_bgcom_announce_create, +}; + +/* + * Finds the device_node for the glink child interested in this channel. + */ +static struct device_node *glink_bgcom_match_channel(struct device_node *node, + const char *channel) +{ + struct device_node *child; + const char *name; + const char *key; + int ret; + + for_each_available_child_of_node(node, child) { + key = "qcom,glink-channels"; + ret = of_property_read_string(child, key, &name); + if (ret) + continue; + + if (strcmp(name, channel) == 0) + return child; + } + + return NULL; +} + +static void glink_bgcom_rpdev_release(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + struct glink_bgcom_channel *channel = to_glink_channel(rpdev->ept); + + channel->rpdev = NULL; + kfree(rpdev); + +} +static int glink_bgcom_rx_open(struct glink_bgcom *glink, unsigned int rcid, + char *name) +{ + struct glink_bgcom_channel *channel; + struct rpmsg_device *rpdev; + bool create_device = false; + struct device_node *node; + int lcid; + int ret; + + mutex_lock(&glink->idr_lock); + idr_for_each_entry(&glink->lcids, channel, lcid) { + if (!strcmp(channel->name, name)) + break; + } + mutex_unlock(&glink->idr_lock); + + if (!channel) { + channel = glink_bgcom_alloc_channel(glink, name); + if (IS_ERR(channel)) + return PTR_ERR(channel); + + /* The opening dance was initiated by the remote */ + create_device = true; + } + + mutex_lock(&glink->idr_lock); + ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_ATOMIC); + if (ret < 0) { + dev_err(glink->dev, "Unable to insert channel into rcid list\n"); + mutex_unlock(&glink->idr_lock); + goto free_channel; + } + channel->rcid = ret; + mutex_unlock(&glink->idr_lock); + + complete_all(&channel->open_req); + + if (create_device) { + rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); + if (!rpdev) { + ret = -ENOMEM; + goto rcid_remove; + } + + rpdev->ept = &channel->ept; + strlcpy(rpdev->id.name, name, RPMSG_NAME_SIZE); + rpdev->src = RPMSG_ADDR_ANY; + rpdev->dst = RPMSG_ADDR_ANY; + rpdev->ops = &glink_device_ops; + + node = glink_bgcom_match_channel(glink->dev->of_node, name); + rpdev->dev.of_node = node; + rpdev->dev.parent = glink->dev; + rpdev->dev.release = glink_bgcom_rpdev_release; + + ret = rpmsg_register_device(rpdev); + if (ret) + goto free_rpdev; + + channel->rpdev = rpdev; + } + CH_INFO(channel, "\n"); + + return 0; + +free_rpdev: + CH_INFO(channel, "free_rpdev\n"); + kfree(rpdev); +rcid_remove: + CH_INFO(channel, "rcid_remove\n"); + mutex_lock(&glink->idr_lock); + idr_remove(&glink->rcids, channel->rcid); + channel->rcid = 0; + mutex_unlock(&glink->idr_lock); +free_channel: + CH_INFO(channel, "free_channel\n"); + /* Release the reference, iff we took it */ + if (create_device) + kref_put(&channel->refcount, glink_bgcom_channel_release); + + return ret; +} + +static void glink_bgcom_defer_work(struct work_struct *work) +{ + struct glink_bgcom *glink = container_of(work, struct glink_bgcom, + rx_defer_work); + + struct glink_bgcom_defer_cmd *dcmd; + struct glink_bgcom_msg *msg; + unsigned long flags; + unsigned int param1; + unsigned int param2; + unsigned int param3; + unsigned int param4; + unsigned int cmd; + + atomic_inc(&glink->activity_cnt); + bgcom_resume(glink->bgcom_handle); + for (;;) { + spin_lock_irqsave(&glink->rx_lock, flags); + if (list_empty(&glink->rx_queue)) { + spin_unlock_irqrestore(&glink->rx_lock, flags); + break; + } + dcmd = list_first_entry(&glink->rx_queue, + struct glink_bgcom_defer_cmd, node); + list_del(&dcmd->node); + spin_unlock_irqrestore(&glink->rx_lock, flags); + + msg = &dcmd->msg; + cmd = le16_to_cpu(msg->cmd); + param1 = le16_to_cpu(msg->param1); + param2 = le32_to_cpu(msg->param2); + param3 = le32_to_cpu(msg->param3); + param4 = le32_to_cpu(msg->param4); + + switch (cmd) { + case BGCOM_CMD_OPEN: + glink_bgcom_rx_open(glink, param1, msg->data); + break; + case BGCOM_CMD_CLOSE: + glink_bgcom_rx_close(glink, param1); + break; + case BGCOM_CMD_CLOSE_ACK: + glink_bgcom_rx_close_ack(glink, param1); + break; + default: + WARN(1, "Unknown defer object %d\n", cmd); + break; + } + + kfree(dcmd); + } + atomic_dec(&glink->activity_cnt); +} + +static int glink_bgcom_rx_defer(struct glink_bgcom *glink, + void *rx_data, u32 rx_avail, size_t extra) +{ + struct glink_bgcom_defer_cmd *dcmd; + + extra = ALIGN(extra, BGCOM_ALIGNMENT); + + if (rx_avail < sizeof(struct glink_bgcom_msg) + extra) { + dev_dbg(glink->dev, "Insufficient data in rx fifo"); + return -ENXIO; + } + + dcmd = kzalloc(sizeof(*dcmd) + extra, GFP_KERNEL); + if (!dcmd) + return -ENOMEM; + + INIT_LIST_HEAD(&dcmd->node); + + memcpy(&dcmd->msg, rx_data, sizeof(dcmd->msg) + extra); + + spin_lock(&glink->rx_lock); + list_add_tail(&dcmd->node, &glink->rx_queue); + spin_unlock(&glink->rx_lock); + + schedule_work(&glink->rx_defer_work); + + return 0; +} + +/** + * glink_bgcom_send_rx_done() - send a rx done to remote side + * glink: The transport to transmit on + * channel: The glink channel + * intent: the intent to send rx done for + * + * This function assumes the intent lock is held + */ +static void glink_bgcom_send_rx_done(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + struct glink_bgcom_rx_intent *intent) +{ + struct { + u16 id; + u16 lcid; + u32 liid; + u64 reserved; + } __packed cmd; + unsigned int cid = channel->lcid; + unsigned int iid = intent->id; + bool reuse = intent->reuse; + + cmd.id = reuse ? BGCOM_CMD_RX_DONE_W_REUSE : BGCOM_CMD_RX_DONE; + cmd.lcid = cid; + cmd.liid = iid; + glink_bgcom_tx(glink, &cmd, sizeof(cmd), true); + CH_INFO(channel, "reuse:%d liid:%d", reuse, iid); +} + +/** + * glink_bgcom_free_intent() - Reset and free intent if not reusuable + * channel: The glink channel + * intent: the intent to send rx done for + * + * This function assumes the intent lock is held + */ +static void glink_bgcom_free_intent(struct glink_bgcom_channel *channel, + struct glink_bgcom_rx_intent *intent) +{ + CH_INFO(channel, "reuse:%d liid:%d", intent->reuse, intent->id); + intent->offset = 0; + if (!intent->reuse) { + idr_remove(&channel->liids, intent->id); + kfree(intent->data); + kfree(intent); + } +} + +static int glink_bgcom_rx_data(struct glink_bgcom *glink, + unsigned int rcid, unsigned int liid, + void *rx_data, size_t avail) +{ + struct glink_bgcom_rx_intent *intent; + struct glink_bgcom_channel *channel; + struct data_desc { + __le32 chunk_size; + __le32 left_size; + __le64 addr; + }; + struct data_desc *hdr; + unsigned int chunk_size; + unsigned int left_size; + u32 addr; + size_t msglen; + unsigned long flags; + int rc; + + msglen = sizeof(*hdr); + if (avail < msglen) { + dev_dbg(glink->dev, "Not enough data in fifo\n"); + return avail; + } + hdr = (struct data_desc *)rx_data; + + chunk_size = le32_to_cpu(hdr->chunk_size); + left_size = le32_to_cpu(hdr->left_size); + addr = (u32)le64_to_cpu(hdr->addr); + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, rcid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_dbg(glink->dev, "Data on non-existing channel\n"); + return msglen; + } + CH_INFO(channel, "chunk_size:%d left_size:%d\n", chunk_size, left_size); + + mutex_lock(&channel->intent_lock); + intent = idr_find(&channel->liids, liid); + + if (!intent) { + dev_err(glink->dev, + "no intent found for channel %s intent %d", + channel->name, liid); + mutex_unlock(&channel->intent_lock); + + return msglen; + } + + if (intent->size - intent->offset < chunk_size) { + dev_err(glink->dev, "Insufficient space in intent\n"); + mutex_unlock(&channel->intent_lock); + + /* The packet header lied, drop payload */ + return msglen; + } + + rc = bgcom_ahb_read(glink->bgcom_handle, (uint32_t)(size_t)addr, + ALIGN(chunk_size, WORD_SIZE)/WORD_SIZE, + intent->data + intent->offset); + if (rc < 0) { + GLINK_ERR(glink, "%s: Error %d receiving data\n", + __func__, rc); + } + + intent->offset += chunk_size; + + /* Handle message when no fragments remain to be received */ + if (!left_size) { + glink_bgcom_send_rx_done(glink, channel, intent); + + spin_lock_irqsave(&channel->recv_lock, flags); + if (channel->ept.cb) { + channel->ept.cb(channel->ept.rpdev, + intent->data, + intent->offset, + channel->ept.priv, + RPMSG_ADDR_ANY); + } + spin_unlock_irqrestore(&channel->recv_lock, flags); + + glink_bgcom_free_intent(channel, intent); + } + mutex_unlock(&channel->intent_lock); + + return msglen; +} + +static int glink_bgcom_rx_short_data(struct glink_bgcom *glink, + unsigned int rcid, unsigned int liid, + unsigned int chunk_size, + unsigned int left_size, + void *src, size_t avail) +{ + struct glink_bgcom_rx_intent *intent; + struct glink_bgcom_channel *channel; + size_t msglen = SHORT_SIZE; + unsigned long flags; + + if (avail < msglen) { + dev_dbg(glink->dev, "Not enough data in fifo\n"); + return avail; + } + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, rcid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_dbg(glink->dev, "Data on non-existing channel\n"); + return msglen; + } + CH_INFO(channel, "chunk_size:%d left_size:%d\n", chunk_size, left_size); + + mutex_lock(&channel->intent_lock); + intent = idr_find(&channel->liids, liid); + + if (!intent) { + dev_err(glink->dev, + "no intent found for channel %s intent %d", + channel->name, liid); + mutex_unlock(&channel->intent_lock); + return msglen; + } + + if (intent->size - intent->offset < chunk_size) { + dev_err(glink->dev, "Insufficient space in intent\n"); + mutex_unlock(&channel->intent_lock); + + /* The packet header lied, drop payload */ + return msglen; + } + + /* Read message from addr sent by WDSP */ + memcpy(intent->data + intent->offset, src, chunk_size); + intent->offset += chunk_size; + + /* Handle message when no fragments remain to be received */ + if (!left_size) { + glink_bgcom_send_rx_done(glink, channel, intent); + + spin_lock_irqsave(&channel->recv_lock, flags); + if (channel->ept.cb) { + channel->ept.cb(channel->ept.rpdev, + intent->data, + intent->offset, + channel->ept.priv, + RPMSG_ADDR_ANY); + } + spin_unlock_irqrestore(&channel->recv_lock, flags); + + glink_bgcom_free_intent(channel, intent); + } + mutex_unlock(&channel->intent_lock); + + return msglen; +} + +static int glink_bgcom_handle_intent(struct glink_bgcom *glink, + unsigned int cid, + unsigned int count, + void *rx_data, + size_t avail) +{ + struct glink_bgcom_rx_intent *intent; + struct glink_bgcom_channel *channel; + struct intent_pair { + __le32 size; + __le32 iid; + __le64 addr; + }; + struct intent_pair *intents; + const size_t msglen = sizeof(struct intent_pair) * count; + int ret; + int i; + + if (avail < msglen) { + dev_err(glink->dev, "Not enough data in buf\n"); + return avail; + } + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, cid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_err(glink->dev, "intents for non-existing channel\n"); + return msglen; + } + + intents = (struct intent_pair *)rx_data; + for (i = 0; i < count; ++i) { + intent = kzalloc(sizeof(*intent), GFP_ATOMIC); + if (!intent) + break; + + intent->id = le32_to_cpu(intents[i].iid); + intent->size = le32_to_cpu(intents[i].size); + intent->addr = (u32)le64_to_cpu(intents[i].addr); + + CH_INFO(channel, "riid:%d size:%lu\n", intent->id, + intent->size); + + mutex_lock(&channel->intent_lock); + ret = idr_alloc(&channel->riids, intent, + intent->id, intent->id + 1, GFP_ATOMIC); + mutex_unlock(&channel->intent_lock); + + if (ret < 0) + dev_err(glink->dev, "failed to store remote intent\n"); + } + + return msglen; +} + +static void glink_bgcom_handle_rx_done(struct glink_bgcom *glink, + u32 cid, uint32_t iid, + bool reuse) +{ + struct glink_bgcom_rx_intent *intent; + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, cid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_err(glink->dev, "invalid channel id received\n"); + return; + } + + mutex_lock(&channel->intent_lock); + intent = idr_find(&channel->riids, iid); + + if (!intent) { + mutex_unlock(&channel->intent_lock); + dev_err(glink->dev, "invalid intent id received\n"); + return; + } + + intent->offset = 0; + intent->in_use = false; + CH_INFO(channel, "reuse:%d iid:%d\n", reuse, intent->id); + + if (!reuse) { + idr_remove(&channel->riids, intent->id); + kfree(intent); + } + mutex_unlock(&channel->intent_lock); +} + +static void glink_bgcom_process_cmd(struct glink_bgcom *glink, void *rx_data, + u32 rx_size) +{ + struct glink_bgcom_msg *msg; + unsigned int param1; + unsigned int param2; + unsigned int param3; + unsigned int param4; + unsigned int cmd; + int offset = 0; + int ret; + u16 name_len; + char *name; + + while (offset < rx_size) { + msg = (struct glink_bgcom_msg *)(rx_data + offset); + offset += sizeof(*msg); + + cmd = le16_to_cpu(msg->cmd); + param1 = le16_to_cpu(msg->param1); + param2 = le32_to_cpu(msg->param2); + param3 = le32_to_cpu(msg->param3); + param4 = le32_to_cpu(msg->param4); + + switch (cmd) { + case BGCOM_CMD_VERSION: + glink_bgcom_receive_version(glink, param1, param2); + break; + case BGCOM_CMD_VERSION_ACK: + glink_bgcom_receive_version_ack(glink, param1, param2); + break; + case BGCOM_CMD_CLOSE: + case BGCOM_CMD_CLOSE_ACK: + glink_bgcom_rx_defer(glink, + rx_data + offset - sizeof(*msg), + rx_size + offset - sizeof(*msg), 0); + break; + case BGCOM_CMD_RX_INTENT_REQ: + glink_bgcom_handle_intent_req(glink, param1, param2); + break; + case BGCOM_CMD_OPEN_ACK: + ret = glink_bgcom_rx_open_ack(glink, param1); + break; + case BGCOM_CMD_OPEN: + name_len = (u16)(param2 & 0xFFFF); + name = rx_data + offset; + glink_bgcom_rx_defer(glink, + rx_data + offset - sizeof(*msg), + rx_size + offset - sizeof(*msg), + ALIGN(name_len, BGCOM_ALIGNMENT)); + + offset += ALIGN(name_len, BGCOM_ALIGNMENT); + break; + case BGCOM_CMD_TX_DATA: + case BGCOM_CMD_TX_DATA_CONT: + ret = glink_bgcom_rx_data(glink, param1, param2, + rx_data + offset, + rx_size - offset); + offset += ALIGN(ret, BGCOM_ALIGNMENT); + break; + case BGCOM_CMD_TX_SHORT_DATA: + ret = glink_bgcom_rx_short_data(glink, + param1, param2, + param3, param4, + rx_data + offset, + rx_size - offset); + offset += ALIGN(ret, BGCOM_ALIGNMENT); + break; + case BGCOM_CMD_READ_NOTIF: + break; + case BGCOM_CMD_INTENT: + ret = glink_bgcom_handle_intent(glink, + param1, param2, + rx_data + offset, + rx_size - offset); + offset += ALIGN(ret, BGCOM_ALIGNMENT); + break; + case BGCOM_CMD_RX_DONE: + glink_bgcom_handle_rx_done(glink, param1, param2, + false); + break; + case BGCOM_CMD_RX_DONE_W_REUSE: + glink_bgcom_handle_rx_done(glink, param1, param2, + true); + break; + case BGCOM_CMD_RX_INTENT_REQ_ACK: + glink_bgcom_handle_intent_req_ack(glink, param1, + param2); + break; + case BGCOM_CMD_SIGNALS: + glink_bgcom_handle_signals(glink, param1, param2); + break; + default: + dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd); + break; + } + } +} + +/** + * __rx_worker() - Receive commands on a specific edge + * @einfo: Edge to process commands on. + * + * This function checks the size of data to be received, allocates the + * buffer for that data and reads the data from the remote subsytem + * into that buffer. This function then calls the glink_bgcom_process_cmd() + * to parse the received G-Link command sequence. This function will also + * poll for the data for a predefined duration for performance reasons. + */ +static void __rx_worker(struct rx_pkt *rx_pkt_info) +{ + struct glink_bgcom *glink = rx_pkt_info->glink; + + if (atomic_read(&glink->in_reset)) + return; + + glink_bgcom_process_cmd(glink, rx_pkt_info->rx_buf, + rx_pkt_info->rx_len*WORD_SIZE); + kfree(rx_pkt_info->rx_buf); + kfree(rx_pkt_info); +} + +/** + * rx_worker() - Worker function to process received commands + * @work: kwork associated with the edge to process commands on. + */ +static void rx_worker(struct kthread_work *work) +{ + struct rx_pkt *rx_pkt_info; + + rx_pkt_info = container_of(work, struct rx_pkt, kwork); + __rx_worker(rx_pkt_info); +}; + +static void glink_bgcom_linkup(struct glink_bgcom *glink) +{ + int ret; + + if (glink->bgcom_status != BGCOM_LINKUP) + return; + atomic_set(&glink->in_reset, 0); + bgcom_reg_read(glink->bgcom_handle, BGCOM_REG_FIFO_SIZE, 1, + &glink->fifo_size); + mutex_lock(&glink->tx_avail_lock); + glink->fifo_fill.tx_avail = glink->fifo_size.to_master; + mutex_unlock(&glink->tx_avail_lock); + + ret = glink_bgcom_send_version(glink); + if (ret) + GLINK_ERR(glink, "Failed to link up %d\n", ret); +} + +static void glink_bgcom_event_handler(void *handle, + void *priv_data, enum bgcom_event_type event, + union bgcom_event_data_type *data) +{ + struct glink_bgcom *glink = (struct glink_bgcom *)priv_data; + struct rx_pkt *rx_pkt_info; + + switch (event) { + case BGCOM_EVENT_APPLICATION_RUNNING: + if (data->application_running && + glink->bgcom_status != BGCOM_LINKUP) { + glink->bgcom_status |= BGCOM_APPLICATION_RUNNING; + glink_bgcom_linkup(glink); + } + break; + case BGCOM_EVENT_TO_SLAVE_FIFO_READY: + if (data->to_slave_fifo_ready && + glink->bgcom_status != BGCOM_LINKUP) { + glink->bgcom_status |= BGCOM_TO_SLAVE_FIFO_READY; + glink_bgcom_linkup(glink); + } + break; + case BGCOM_EVENT_TO_MASTER_FIFO_READY: + if (data->to_master_fifo_ready && + glink->bgcom_status != BGCOM_LINKUP) { + glink->bgcom_status |= BGCOM_TO_MASTER_FIFO_READY; + glink_bgcom_linkup(glink); + } + break; + case BGCOM_EVENT_AHB_READY: + if (data->ahb_ready && + glink->bgcom_status != BGCOM_LINKUP) { + glink->bgcom_status |= BGCOM_AHB_READY; + glink_bgcom_linkup(glink); + } + break; + case BGCOM_EVENT_TO_MASTER_FIFO_USED: + rx_pkt_info = kzalloc(sizeof(struct rx_pkt), GFP_KERNEL); + rx_pkt_info->rx_buf = data->fifo_data.data; + rx_pkt_info->rx_len = data->fifo_data.to_master_fifo_used; + rx_pkt_info->glink = glink; + kthread_init_work(&rx_pkt_info->kwork, rx_worker); + kthread_queue_work(&glink->kworker, &rx_pkt_info->kwork); + break; + case BGCOM_EVENT_TO_SLAVE_FIFO_FREE: + if (glink->water_mark_reached) + tx_wakeup_worker(glink); + break; + case BGCOM_EVENT_RESET_OCCURRED: + glink->bgcom_status = BGCOM_RESET; + atomic_set(&glink->in_reset, 1); + break; + case BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN: + case BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR: + case BGCOM_EVENT_ERROR_WRITE_FIFO_ACCESS: + case BGCOM_EVENT_ERROR_READ_FIFO_UNDERRUN: + case BGCOM_EVENT_ERROR_READ_FIFO_BUS_ERR: + case BGCOM_EVENT_ERROR_READ_FIFO_ACCESS: + case BGCOM_EVENT_ERROR_TRUNCATED_READ: + case BGCOM_EVENT_ERROR_TRUNCATED_WRITE: + case BGCOM_EVENT_ERROR_AHB_ILLEGAL_ADDRESS: + case BGCOM_EVENT_ERROR_AHB_BUS_ERR: + GLINK_ERR(glink, "%s: ERROR %d", __func__, event); + break; + default: + GLINK_ERR(glink, "%s: unhandled event %d", __func__, event); + break; + } +} + +static int glink_bgcom_get_sigs(struct rpmsg_endpoint *ept, + u32 *lsigs, u32 *rsigs) +{ + struct glink_bgcom_channel *channel = to_glink_channel(ept); + + *lsigs = channel->lsigs; + *rsigs = channel->rsigs; + + return 0; +} + +static int glink_bgcom_set_sigs(struct rpmsg_endpoint *ept, u32 sigs) +{ + struct glink_bgcom_channel *channel = to_glink_channel(ept); + struct glink_bgcom *glink = channel->glink; + + channel->lsigs = sigs; + + return glink_bgcom_send_signals(glink, channel, sigs); +} + +static const struct rpmsg_endpoint_ops glink_endpoint_ops = { + .destroy_ept = glink_bgcom_destroy_ept, + .send = glink_bgcom_send, + .trysend = glink_bgcom_trysend, + .get_sigs = glink_bgcom_get_sigs, + .set_sigs = glink_bgcom_set_sigs, +}; + +static void glink_bgcom_release(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct glink_bgcom *glink = platform_get_drvdata(pdev); + + kfree(glink); +} + +static int glink_bgcom_probe(struct platform_device *pdev) +{ + struct glink_bgcom *glink; + struct device *dev; + int ret; + + glink = kzalloc(sizeof(*glink), GFP_KERNEL); + if (!glink) + return -ENOMEM; + + glink->dev = &pdev->dev; + dev = glink->dev; + dev->of_node = pdev->dev.of_node; + dev->release = glink_bgcom_release; + dev_set_name(dev, "%s", dev->of_node->name); + dev_set_drvdata(dev, glink); + + ret = of_property_read_string(dev->of_node, "label", &glink->name); + if (ret < 0) + glink->name = dev->of_node->name; + + glink->features = GLINK_FEATURE_INTENT_REUSE; + + mutex_init(&glink->tx_lock); + mutex_init(&glink->tx_avail_lock); + spin_lock_init(&glink->rx_lock); + INIT_LIST_HEAD(&glink->rx_queue); + INIT_WORK(&glink->rx_defer_work, glink_bgcom_defer_work); + + kthread_init_worker(&glink->kworker); + + mutex_init(&glink->idr_lock); + idr_init(&glink->lcids); + idr_init(&glink->rcids); + + atomic_set(&glink->in_reset, 1); + atomic_set(&glink->activity_cnt, 0); + + glink->rx_task = kthread_run(kthread_worker_fn, &glink->kworker, + "bgcom_%s", glink->name); + if (IS_ERR(glink->rx_task)) { + ret = PTR_ERR(glink->rx_task); + dev_err(glink->dev, "kthread run failed %d\n", ret); + goto err_put_dev; + } + + glink->ilc = ipc_log_context_create(GLINK_LOG_PAGE_CNT, glink->name, 0); + + glink->bgcom_config.priv = (void *)glink; + glink->bgcom_config.bgcom_notification_cb = glink_bgcom_event_handler; + glink->bgcom_handle = NULL; + if (!strcmp(glink->name, "bg")) { + glink->bgcom_handle = bgcom_open(&glink->bgcom_config); + if (!glink->bgcom_handle) { + GLINK_ERR(glink, "%s: bgcom open failed\n", __func__); + ret = -ENODEV; + goto err_bg_handle; + } + } + + return 0; + +err_bg_handle: + kthread_stop(glink->rx_task); +err_put_dev: + dev_set_drvdata(dev, NULL); + put_device(dev); + + return ret; +} +EXPORT_SYMBOL(glink_bgcom_probe); + +static int glink_bgcom_remove_device(struct device *dev, void *data) +{ + device_unregister(dev); + + return 0; +} + +static int glink_bgcom_remove(struct platform_device *pdev) +{ + struct glink_bgcom *glink = platform_get_drvdata(pdev); + struct glink_bgcom_channel *channel; + int cid; + int ret; + + GLINK_INFO(glink, "\n"); + + atomic_set(&glink->in_reset, 1); + + bgcom_close(glink->bgcom_handle); + + kthread_flush_worker(&glink->kworker); + kthread_stop(glink->rx_task); + cancel_work_sync(&glink->rx_defer_work); + + ret = device_for_each_child(glink->dev, NULL, + glink_bgcom_remove_device); + if (ret) + dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret); + + mutex_lock(&glink->idr_lock); + /* Release any defunct local channels, waiting for close-ack */ + idr_for_each_entry(&glink->lcids, channel, cid) { + /* Wakeup threads waiting for intent*/ + complete(&channel->intent_req_comp); + kref_put(&channel->refcount, glink_bgcom_channel_release); + idr_remove(&glink->lcids, cid); + } + + /* Release any defunct local channels, waiting for close-req */ + idr_for_each_entry(&glink->rcids, channel, cid) { + kref_put(&channel->refcount, glink_bgcom_channel_release); + idr_remove(&glink->rcids, cid); + } + + idr_destroy(&glink->lcids); + idr_destroy(&glink->rcids); + mutex_unlock(&glink->idr_lock); + + return ret; +} +EXPORT_SYMBOL(glink_bgcom_remove); + +static const struct of_device_id glink_bgcom_of_match[] = { + { .compatible = "qcom,glink-bgcom-xprt" }, + {} +}; +MODULE_DEVICE_TABLE(of, glink_bgcom_of_match); + +static struct platform_driver glink_bgcom_driver = { + .probe = glink_bgcom_probe, + .remove = glink_bgcom_remove, + .driver = { + .name = "qcom_glink_bgcom", + .of_match_table = glink_bgcom_of_match, + }, +}; + +static int __init glink_bgcom_init(void) +{ + return platform_driver_register(&glink_bgcom_driver); +} +postcore_initcall(glink_bgcom_init); + +static void __exit glink_bgcom_exit(void) +{ + platform_driver_unregister(&glink_bgcom_driver); +} +module_exit(glink_bgcom_exit); + +MODULE_DESCRIPTION("QTI GLINK BGCOM Transport"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 069b065849691ed1afa6684accea49e6984146f1..2b051b54ae4b5f251e2ee62043dc148681e496cc 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1974,6 +1974,8 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, bool intentless) { struct qcom_glink *glink; + unsigned long irqflags; + bool vm_support; u32 *arr; int size; int irq; @@ -2032,9 +2034,17 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, dev_err(dev, "failed to register early notif %d\n", ret); irq = of_irq_get(dev->of_node, 0); + + /* Use different irq flag option in case of gvm */ + vm_support = of_property_read_bool(dev->of_node, "vm-support"); + if (vm_support) + irqflags = IRQF_TRIGGER_RISING; + else + irqflags = IRQF_NO_SUSPEND | IRQF_SHARED; + ret = devm_request_irq(dev, irq, qcom_glink_native_intr, - IRQF_NO_SUSPEND | IRQF_SHARED, + irqflags, "glink-native", glink); if (ret) { dev_err(dev, "failed to request IRQ\n"); diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index f8b4b24fe736ec350e0746052dc112caf130b40a..c2e338e4e31114ba70eab3ac07ae6fa83e068eab 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2015, Sony Mobile Communications AB. - * Copyright (c) 2012-2013, 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2019-2020 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 @@ -205,7 +206,7 @@ struct qcom_smd_channel { struct smd_channel_info_pair *info; struct smd_channel_info_word_pair *info_word; - struct mutex tx_lock; + spinlock_t tx_lock; wait_queue_head_t fblockread_event; void *tx_fifo; @@ -289,7 +290,9 @@ struct smd_channel_info_word_pair { (GET_RX_CHANNEL_FLAG(channel, fDSR) ? TIOCM_DSR : 0) | \ (GET_RX_CHANNEL_FLAG(channel, fCTS) ? TIOCM_CTS : 0) | \ (GET_RX_CHANNEL_FLAG(channel, fCD) ? TIOCM_CD : 0) | \ - (GET_RX_CHANNEL_FLAG(channel, fRI) ? TIOCM_RI : 0); \ + (GET_RX_CHANNEL_FLAG(channel, fRI) ? TIOCM_RI : 0) | \ + (GET_TX_CHANNEL_FLAG(channel, fDSR) ? TIOCM_DTR : 0) | \ + (GET_TX_CHANNEL_FLAG(channel, fCTS) ? TIOCM_RTS : 0); \ }) #define SET_RX_CHANNEL_FLAG(channel, param, value) \ @@ -746,6 +749,7 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, { __le32 hdr[5] = { cpu_to_le32(len), }; int tlen = sizeof(hdr) + len; + unsigned long flags; int ret; /* Word aligned channels only accept word size aligned data */ @@ -756,9 +760,11 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, if (tlen >= channel->fifo_size) return -EINVAL; - ret = mutex_lock_interruptible(&channel->tx_lock); - if (ret) - return ret; + /* Highlight the fact that if we enter the loop below we might sleep */ + if (wait) + might_sleep(); + + spin_lock_irqsave(&channel->tx_lock, flags); while (qcom_smd_get_tx_avail(channel) < tlen) { if (!wait) { @@ -773,11 +779,16 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 0); + /* Wait without holding the tx_lock */ + spin_unlock_irqrestore(&channel->tx_lock, flags); + ret = wait_event_interruptible(channel->fblockread_event, qcom_smd_get_tx_avail(channel) >= tlen || channel->state != SMD_CHANNEL_OPENED); if (ret) - goto out; + return ret; + + spin_lock_irqsave(&channel->tx_lock, flags); SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1); } @@ -795,7 +806,7 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, qcom_smd_signal_channel(channel); out: - mutex_unlock(&channel->tx_lock); + spin_unlock_irqrestore(&channel->tx_lock, flags); return ret; } @@ -1109,7 +1120,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed goto free_channel; } - mutex_init(&channel->tx_lock); + spin_lock_init(&channel->tx_lock); spin_lock_init(&channel->recv_lock); init_waitqueue_head(&channel->fblockread_event); diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index 466bf7f9a285a5c455a26d199083384d93a4e121..7da2a1fb50f8999dd7df52eb056a83fee0b2a1c6 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -116,12 +116,14 @@ static int pm80x_rtc_read_time(struct device *dev, struct rtc_time *tm) unsigned char buf[4]; unsigned long ticks, base, data; regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); - base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); /* load 32-bit read-only counter */ regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -144,7 +146,8 @@ static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm) /* load 32-bit read-only counter */ regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; base = ticks - data; dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -165,11 +168,13 @@ static int pm80x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) int ret; regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); - base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); regmap_raw_read(info->map, PM800_RTC_EXPIRE1_1, buf, 4); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -192,12 +197,14 @@ static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, 0); regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); - base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); /* load 32-bit read-only counter */ regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 166faae3a59cd10441e68bfe4f69f3adefdaee57..7d3e5168fcefcdb1ad637e9091cb16e3e2893e20 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -115,11 +115,13 @@ static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm) pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) | + (buf[5] << 8) | buf[7]; /* load 32-bit read-only counter */ pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -145,7 +147,8 @@ static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm) /* load 32-bit read-only counter */ pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; base = ticks - data; dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -170,10 +173,12 @@ static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) | + (buf[5] << 8) | buf[7]; pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -198,11 +203,13 @@ static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) | + (buf[5] << 8) | buf[7]; /* load 32-bit read-only counter */ pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index e7d9215c9201b14fe66aaefb8c7379aeb8ae6e00..8d45d93b1db67d68834a7feca656c797d4fc47c6 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -733,8 +733,8 @@ static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t) if (ret < 0) return ret; - ctl[0] &= ~RX8130_REG_EXTENSION_WADA; - ctl[1] |= RX8130_REG_FLAG_AF; + ctl[0] &= RX8130_REG_EXTENSION_WADA; + ctl[1] &= ~RX8130_REG_FLAG_AF; ctl[2] &= ~RX8130_REG_CONTROL0_AIE; ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, @@ -757,8 +757,7 @@ static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t) ctl[2] |= RX8130_REG_CONTROL0_AIE; - return regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, - sizeof(ctl)); + return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, ctl[2]); } static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled) diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 9caaccccaa575f41fb3280f3753d8dea8ec3c9db..b1ebca099b0dffb064d59c8dfa8821f55374f48c 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -58,7 +58,8 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) "%s: raw read data - counters=%02x,%02x,%02x,%02x\n", __func__, buf[0], buf[1], buf[2], buf[3]); - time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + time = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; rtc_time_to_tm(time, tm); diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c index 2f1772a358ca50342d4375de3e69f2fba451ceaf..18a6f15e313d8b33ae6ae2905ea6b364e9ede701 100644 --- a/drivers/rtc/rtc-mc146818-lib.c +++ b/drivers/rtc/rtc-mc146818-lib.c @@ -82,7 +82,7 @@ unsigned int mc146818_get_time(struct rtc_time *time) time->tm_year += real_year - 72; #endif - if (century) + if (century > 20) time->tm_year += (century - 19) * 100; /* diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index c1c5c4e3b3b4715ea250a5b16bfaa49e2ebd688b..c981301efbe5e8c8cf309854cd415260eb93f6be 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c @@ -132,7 +132,8 @@ static int msm6242_read_time(struct device *dev, struct rtc_time *tm) msm6242_read(priv, MSM6242_SECOND1); tm->tm_min = msm6242_read(priv, MSM6242_MINUTE10) * 10 + msm6242_read(priv, MSM6242_MINUTE1); - tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10 & 3)) * 10 + + tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10) & + MSM6242_HOUR10_HR_MASK) * 10 + msm6242_read(priv, MSM6242_HOUR1); tm->tm_mday = msm6242_read(priv, MSM6242_DAY10) * 10 + msm6242_read(priv, MSM6242_DAY1); diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index e82df43e5ca289add3059605e4b41fb417f57cc4..c696d918645181d96e69b342911b5bc2deed5c70 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -55,6 +55,14 @@ #define RTC_AL_SEC 0x0018 +#define RTC_AL_SEC_MASK 0x003f +#define RTC_AL_MIN_MASK 0x003f +#define RTC_AL_HOU_MASK 0x001f +#define RTC_AL_DOM_MASK 0x001f +#define RTC_AL_DOW_MASK 0x0007 +#define RTC_AL_MTH_MASK 0x000f +#define RTC_AL_YEA_MASK 0x007f + #define RTC_PDN2 0x002e #define RTC_PDN2_PWRON_ALARM BIT(4) @@ -111,7 +119,7 @@ static irqreturn_t mtk_rtc_irq_handler_thread(int irq, void *data) irqen = irqsta & ~RTC_IRQ_EN_AL; mutex_lock(&rtc->lock); if (regmap_write(rtc->regmap, rtc->addr_base + RTC_IRQ_EN, - irqen) < 0) + irqen) == 0) mtk_rtc_write_trigger(rtc); mutex_unlock(&rtc->lock); @@ -233,12 +241,12 @@ static int mtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM); mutex_unlock(&rtc->lock); - tm->tm_sec = data[RTC_OFFSET_SEC]; - tm->tm_min = data[RTC_OFFSET_MIN]; - tm->tm_hour = data[RTC_OFFSET_HOUR]; - tm->tm_mday = data[RTC_OFFSET_DOM]; - tm->tm_mon = data[RTC_OFFSET_MTH]; - tm->tm_year = data[RTC_OFFSET_YEAR]; + tm->tm_sec = data[RTC_OFFSET_SEC] & RTC_AL_SEC_MASK; + tm->tm_min = data[RTC_OFFSET_MIN] & RTC_AL_MIN_MASK; + tm->tm_hour = data[RTC_OFFSET_HOUR] & RTC_AL_HOU_MASK; + tm->tm_mday = data[RTC_OFFSET_DOM] & RTC_AL_DOM_MASK; + tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_AL_MTH_MASK; + tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK; tm->tm_year += RTC_MIN_YEAR_OFFSET; tm->tm_mon--; @@ -259,14 +267,25 @@ static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) tm->tm_year -= RTC_MIN_YEAR_OFFSET; tm->tm_mon++; - data[RTC_OFFSET_SEC] = tm->tm_sec; - data[RTC_OFFSET_MIN] = tm->tm_min; - data[RTC_OFFSET_HOUR] = tm->tm_hour; - data[RTC_OFFSET_DOM] = tm->tm_mday; - data[RTC_OFFSET_MTH] = tm->tm_mon; - data[RTC_OFFSET_YEAR] = tm->tm_year; - mutex_lock(&rtc->lock); + ret = regmap_bulk_read(rtc->regmap, rtc->addr_base + RTC_AL_SEC, + data, RTC_OFFSET_COUNT); + if (ret < 0) + goto exit; + + data[RTC_OFFSET_SEC] = ((data[RTC_OFFSET_SEC] & ~(RTC_AL_SEC_MASK)) | + (tm->tm_sec & RTC_AL_SEC_MASK)); + data[RTC_OFFSET_MIN] = ((data[RTC_OFFSET_MIN] & ~(RTC_AL_MIN_MASK)) | + (tm->tm_min & RTC_AL_MIN_MASK)); + data[RTC_OFFSET_HOUR] = ((data[RTC_OFFSET_HOUR] & ~(RTC_AL_HOU_MASK)) | + (tm->tm_hour & RTC_AL_HOU_MASK)); + data[RTC_OFFSET_DOM] = ((data[RTC_OFFSET_DOM] & ~(RTC_AL_DOM_MASK)) | + (tm->tm_mday & RTC_AL_DOM_MASK)); + data[RTC_OFFSET_MTH] = ((data[RTC_OFFSET_MTH] & ~(RTC_AL_MTH_MASK)) | + (tm->tm_mon & RTC_AL_MTH_MASK)); + data[RTC_OFFSET_YEAR] = ((data[RTC_OFFSET_YEAR] & ~(RTC_AL_YEA_MASK)) | + (tm->tm_year & RTC_AL_YEA_MASK)); + if (alm->enabled) { ret = regmap_bulk_write(rtc->regmap, rtc->addr_base + RTC_AL_SEC, diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 9f1b14bf91aeddf6abb6ec51b6614d18032bfd77..367e0f803440c600f1da817f16883bacb3918f7d 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -52,20 +52,14 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) struct pcf2127 *pcf2127 = dev_get_drvdata(dev); unsigned char buf[10]; int ret; - int i; - for (i = 0; i <= PCF2127_REG_CTRL3; i++) { - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1 + i, - (unsigned int *)(buf + i)); - if (ret) { - dev_err(dev, "%s: read error\n", __func__); - return ret; - } - } - - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_SC, - (buf + PCF2127_REG_SC), - ARRAY_SIZE(buf) - PCF2127_REG_SC); + /* + * Avoid reading CTRL2 register as it causes WD_VAL register + * value to reset to 0 which means watchdog is stopped. + */ + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL3, + (buf + PCF2127_REG_CTRL3), + ARRAY_SIZE(buf) - PCF2127_REG_CTRL3); if (ret) { dev_err(dev, "%s: read error\n", __func__); return ret; @@ -86,14 +80,12 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) } dev_dbg(dev, - "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, " - "sec=%02x, min=%02x, hr=%02x, " + "%s: raw data is cr3=%02x, sec=%02x, min=%02x, hr=%02x, " "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", - __func__, - buf[0], buf[1], buf[2], - buf[3], buf[4], buf[5], - buf[6], buf[7], buf[8], buf[9]); - + __func__, buf[PCF2127_REG_CTRL3], buf[PCF2127_REG_SC], + buf[PCF2127_REG_MN], buf[PCF2127_REG_HR], + buf[PCF2127_REG_DM], buf[PCF2127_REG_DW], + buf[PCF2127_REG_MO], buf[PCF2127_REG_YR]); tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F); tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 8c836c51a508f3d266ac1a3a7b23141863169a8e..4d0b81f9805f867a0dfadd1f190d68ac9c8ad516 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -563,7 +563,6 @@ static int pcf8563_probe(struct i2c_client *client, struct pcf8563 *pcf8563; int err; unsigned char buf; - unsigned char alm_pending; dev_dbg(&client->dev, "%s\n", __func__); @@ -587,13 +586,13 @@ static int pcf8563_probe(struct i2c_client *client, return err; } - err = pcf8563_get_alarm_mode(client, NULL, &alm_pending); - if (err) { - dev_err(&client->dev, "%s: read error\n", __func__); + /* Clear flags and disable interrupts */ + buf = 0; + err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf); + if (err < 0) { + dev_err(&client->dev, "%s: write error\n", __func__); return err; } - if (alm_pending) - pcf8563_set_alarm_mode(client, 0); pcf8563->rtc = devm_rtc_device_register(&client->dev, pcf8563_driver.driver.name, @@ -605,7 +604,7 @@ static int pcf8563_probe(struct i2c_client *client, if (client->irq > 0) { err = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf8563_irq, - IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING, + IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, pcf8563_driver.driver.name, client); if (err) { dev_err(&client->dev, "unable to request IRQ %d\n", diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 5309edcee7b7cad5fb76c98bcda2240287df5137..3b619b7b2c530a0a8680bf610b868d0d088b8ec4 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -213,7 +213,8 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) } } - secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); + secs = value[0] | (value[1] << 8) | (value[2] << 16) | + ((unsigned long)value[3] << 24); rtc_time_to_tm(secs, tm); @@ -294,7 +295,8 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) return rc; } - secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); + secs = value[0] | (value[1] << 8) | (value[2] << 16) | + ((unsigned long)value[3] << 24); rtc_time_to_tm(secs, &alarm->time); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 0d5e2d92e05bc31f94d8735b6cffd71e9d64ef15..aa651403546ff41e879b64e6fe66c4e78c075b5b 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1133,7 +1133,8 @@ static u32 get_fcx_max_data(struct dasd_device *device) { struct dasd_eckd_private *private = device->private; int fcx_in_css, fcx_in_gneq, fcx_in_features; - int tpm, mdc; + unsigned int mdc; + int tpm; if (dasd_nofcx) return 0; @@ -1147,7 +1148,7 @@ static u32 get_fcx_max_data(struct dasd_device *device) return 0; mdc = ccw_device_get_mdc(device->cdev, 0); - if (mdc < 0) { + if (mdc == 0) { dev_warn(&device->cdev->dev, "Detecting the maximum supported data size for zHPF requests failed\n"); return 0; } else { @@ -1158,12 +1159,12 @@ static u32 get_fcx_max_data(struct dasd_device *device) static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm) { struct dasd_eckd_private *private = device->private; - int mdc; + unsigned int mdc; u32 fcx_max_data; if (private->fcx_max_data) { mdc = ccw_device_get_mdc(device->cdev, lpm); - if ((mdc < 0)) { + if (mdc == 0) { dev_warn(&device->cdev->dev, "Detecting the maximum data size for zHPF " "requests failed (rc=%d) for a new path %x\n", @@ -1767,7 +1768,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) dasd_free_block(device->block); device->block = NULL; out_err1: - kfree(private->conf_data); + dasd_eckd_clear_conf_data(device); kfree(device->private); device->private = NULL; return rc; @@ -1776,7 +1777,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device) static void dasd_eckd_uncheck_device(struct dasd_device *device) { struct dasd_eckd_private *private = device->private; - int i; if (!private) return; @@ -1786,21 +1786,7 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device) private->sneq = NULL; private->vdsneq = NULL; private->gneq = NULL; - private->conf_len = 0; - for (i = 0; i < 8; i++) { - kfree(device->path[i].conf_data); - if ((__u8 *)device->path[i].conf_data == - private->conf_data) { - private->conf_data = NULL; - private->conf_len = 0; - } - device->path[i].conf_data = NULL; - device->path[i].cssid = 0; - device->path[i].ssid = 0; - device->path[i].chpid = 0; - } - kfree(private->conf_data); - private->conf_data = NULL; + dasd_eckd_clear_conf_data(device); } static struct dasd_ccw_req * diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index b22922ec32d11d1633d1f434f8e2c9f5d8bc0d05..474afec9ab87b5586bd9f740bb993cebe277e4e1 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -595,7 +595,7 @@ EXPORT_SYMBOL(ccw_device_tm_start_timeout); * @mask: mask of paths to use * * Return the number of 64K-bytes blocks all paths at least support - * for a transport command. Return values <= 0 indicate failures. + * for a transport command. Return value 0 indicates failure. */ int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask) { diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index d0a504af5b4f836df14dcbd04908b62a237d2ce0..0a70d54a4df68e572a98d7efa3f555fc072e84a6 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -283,8 +283,10 @@ bfad_im_get_stats(struct Scsi_Host *shost) rc = bfa_port_get_stats(BFA_FCPORT(&bfad->bfa), fcstats, bfad_hcb_comp, &fcomp); spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (rc != BFA_STATUS_OK) + if (rc != BFA_STATUS_OK) { + kfree(fcstats); return NULL; + } wait_for_completion(&fcomp.comp); diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 03c104b47f31c98670d9a80d64e0b986d707d9f0..b832bd0ce2021844f0ce27055b42638d3c094cb5 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -915,12 +915,12 @@ void bnx2i_free_hba(struct bnx2i_hba *hba) INIT_LIST_HEAD(&hba->ep_ofld_list); INIT_LIST_HEAD(&hba->ep_active_list); INIT_LIST_HEAD(&hba->ep_destroy_list); - pci_dev_put(hba->pcidev); if (hba->regview) { pci_iounmap(hba->pcidev, hba->regview); hba->regview = NULL; } + pci_dev_put(hba->pcidev); bnx2i_free_mp_bdt(hba); bnx2i_release_free_cid_que(hba); iscsi_host_free(shost); diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 902f5e03ec94ce63dfcef7903ff05ebb823bc090..0d45658f163af6d0a02b72d0813b8ffdc3017e7e 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -121,7 +121,8 @@ static inline void cxgbi_device_destroy(struct cxgbi_device *cdev) "cdev 0x%p, p# %u.\n", cdev, cdev->nports); cxgbi_hbas_remove(cdev); cxgbi_device_portmap_cleanup(cdev); - cxgbi_ppm_release(cdev->cdev2ppm(cdev)); + if (cdev->cdev2ppm) + cxgbi_ppm_release(cdev->cdev2ppm(cdev)); if (cdev->pmap.max_connect) cxgbi_free_big_mem(cdev->pmap.port_csk); kfree(cdev); diff --git a/drivers/scsi/esas2r/esas2r_flash.c b/drivers/scsi/esas2r/esas2r_flash.c index 7bd376d95ed5225e0490ce4939775aa609eea74f..b02ac389e6c6050fc92696d480131db15678ebb4 100644 --- a/drivers/scsi/esas2r/esas2r_flash.c +++ b/drivers/scsi/esas2r/esas2r_flash.c @@ -1197,6 +1197,7 @@ bool esas2r_nvram_read_direct(struct esas2r_adapter *a) if (!esas2r_read_flash_block(a, a->nvram, FLS_OFFSET_NVR, sizeof(struct esas2r_sas_nvram))) { esas2r_hdebug("NVRAM read failed, using defaults"); + up(&a->nvram_semaphore); return false; } diff --git a/drivers/scsi/fnic/fnic_isr.c b/drivers/scsi/fnic/fnic_isr.c index 4e3a50202e8c5028cc35943004e16af833d0e7eb..d28088218c3644b7733c0e65176d89bc80593242 100644 --- a/drivers/scsi/fnic/fnic_isr.c +++ b/drivers/scsi/fnic/fnic_isr.c @@ -254,7 +254,7 @@ int fnic_set_intr_mode(struct fnic *fnic) int vecs = n + m + o + 1; if (pci_alloc_irq_vectors(fnic->pdev, vecs, vecs, - PCI_IRQ_MSIX) < 0) { + PCI_IRQ_MSIX) == vecs) { fnic->rq_count = n; fnic->raw_wq_count = m; fnic->wq_copy_count = o; @@ -280,7 +280,7 @@ int fnic_set_intr_mode(struct fnic *fnic) fnic->wq_copy_count >= 1 && fnic->cq_count >= 3 && fnic->intr_count >= 1 && - pci_alloc_irq_vectors(fnic->pdev, 1, 1, PCI_IRQ_MSI) < 0) { + pci_alloc_irq_vectors(fnic->pdev, 1, 1, PCI_IRQ_MSI) == 1) { fnic->rq_count = 1; fnic->raw_wq_count = 1; fnic->wq_copy_count = 1; diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 242e2ee494a1cafc2987a133534445da90f71cf8..d79ac0b24f5afa782ef5c68978f1e2d9b8e6e1bb 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -446,6 +446,9 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) return SCSI_MLQUEUE_HOST_BUSY; + if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_FWRESET))) + return SCSI_MLQUEUE_HOST_BUSY; + rport = starget_to_rport(scsi_target(sc->device)); if (!rport) { FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, diff --git a/drivers/scsi/fnic/vnic_dev.c b/drivers/scsi/fnic/vnic_dev.c index ba69d6112fa13d34bc6acda465521797a04ee94c..c5b89a003d2ab0c80082b55d9665a5647d662eff 100644 --- a/drivers/scsi/fnic/vnic_dev.c +++ b/drivers/scsi/fnic/vnic_dev.c @@ -445,26 +445,26 @@ int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done) int vnic_dev_hang_notify(struct vnic_dev *vdev) { - u64 a0, a1; + u64 a0 = 0, a1 = 0; int wait = 1000; return vnic_dev_cmd(vdev, CMD_HANG_NOTIFY, &a0, &a1, wait); } int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr) { - u64 a0, a1; + u64 a[2] = {}; int wait = 1000; int err, i; for (i = 0; i < ETH_ALEN; i++) mac_addr[i] = 0; - err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait); + err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a[0], &a[1], wait); if (err) return err; for (i = 0; i < ETH_ALEN; i++) - mac_addr[i] = ((u8 *)&a0)[i]; + mac_addr[i] = ((u8 *)&a)[i]; return 0; } @@ -489,30 +489,30 @@ void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) { - u64 a0 = 0, a1 = 0; + u64 a[2] = {}; int wait = 1000; int err; int i; for (i = 0; i < ETH_ALEN; i++) - ((u8 *)&a0)[i] = addr[i]; + ((u8 *)&a)[i] = addr[i]; - err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); + err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a[0], &a[1], wait); if (err) pr_err("Can't add addr [%pM], %d\n", addr, err); } void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) { - u64 a0 = 0, a1 = 0; + u64 a[2] = {}; int wait = 1000; int err; int i; for (i = 0; i < ETH_ALEN; i++) - ((u8 *)&a0)[i] = addr[i]; + ((u8 *)&a)[i] = addr[i]; - err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); + err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a[0], &a[1], wait); if (err) pr_err("Can't del addr [%pM], %d\n", addr, err); } diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 42bcf7f3a0f90bf5a8778e21cfe0b5c20f6e6a87..6ba257cbc6d946c677f984d08bf13312dd71543b 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -2603,7 +2603,7 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp) /* lport lock ? */ if (!lport || lport->state == LPORT_ST_DISABLED) { - FC_LPORT_DBG(lport, "Receiving frames for an lport that " + FC_LIBFC_DBG("Receiving frames for an lport that " "has not been initialized correctly\n"); fc_frame_free(fp); return; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 577513649afbe9c424a3aa1547ddbbb0e5abc1fa..6abad63b127affa0a9d352f98cfc0569f5e9d804 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3823,12 +3823,12 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) /* * The cur_state should not last for more than max_wait secs */ - for (i = 0; i < max_wait; i++) { + for (i = 0; i < max_wait * 50; i++) { curr_abs_state = instance->instancet-> read_fw_status_reg(instance->reg_set); if (abs_state == curr_abs_state) { - msleep(1000); + msleep(20); } else break; } diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index bd2421863510cd7e6734444ded9d95214c3ccb4b..a66f7cec797ca190309aa0bcbab9ab045f4ce0ab 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5145,8 +5145,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) break; - if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 || - (fcport->flags & FCF_LOGIN_NEEDED) == 0) + if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) continue; if (fcport->scan_state == QLA_FCPORT_SCAN) { @@ -5171,7 +5170,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) } } - if (fcport->scan_state == QLA_FCPORT_FOUND) + if (fcport->scan_state == QLA_FCPORT_FOUND && + (fcport->flags & FCF_LOGIN_NEEDED) != 0) qla24xx_fcport_handle_login(vha, fcport); } return (rval); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 7f2da56274bdb433957c744ef2592faa984e3a23..648916a9082c09ad8041b7712bebb362e2f95bd8 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3519,7 +3519,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) skip_msix: ql_log(ql_log_info, vha, 0x0037, - "Falling back-to MSI mode -%d.\n", ret); + "Falling back-to MSI mode -- ret=%d.\n", ret); if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) && !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) && @@ -3527,13 +3527,13 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) goto skip_msi; ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI); - if (!ret) { + if (ret > 0) { ql_dbg(ql_dbg_init, vha, 0x0038, "MSI: Enabled.\n"); ha->flags.msi_enabled = 1; } else ql_log(ql_log_warn, vha, 0x0039, - "Falling back-to INTa mode -- %d.\n", ret); + "Falling back-to INTa mode -- ret=%d.\n", ret); skip_msi: /* Skip INTx on ISP82xx. */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5617bb18c2335c5b468bd2bad07b5d269b88b89d..5f9d4dbc4a98e6806b86a2f8a27e57101498fff3 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -6714,8 +6714,7 @@ qla2x00_module_init(void) /* Initialize target kmem_cache and mem_pools */ ret = qlt_init(); if (ret < 0) { - kmem_cache_destroy(srb_cachep); - return ret; + goto destroy_cache; } else if (ret > 0) { /* * If initiator mode is explictly disabled by qlt_init(), @@ -6736,11 +6735,10 @@ qla2x00_module_init(void) qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions); if (!qla2xxx_transport_template) { - kmem_cache_destroy(srb_cachep); ql_log(ql_log_fatal, NULL, 0x0002, "fc_attach_transport failed...Failing load!.\n"); - qlt_exit(); - return -ENODEV; + ret = -ENODEV; + goto qlt_exit; } apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops); @@ -6752,27 +6750,37 @@ qla2x00_module_init(void) qla2xxx_transport_vport_template = fc_attach_transport(&qla2xxx_transport_vport_functions); if (!qla2xxx_transport_vport_template) { - kmem_cache_destroy(srb_cachep); - qlt_exit(); - fc_release_transport(qla2xxx_transport_template); ql_log(ql_log_fatal, NULL, 0x0004, "fc_attach_transport vport failed...Failing load!.\n"); - return -ENODEV; + ret = -ENODEV; + goto unreg_chrdev; } ql_log(ql_log_info, NULL, 0x0005, "QLogic Fibre Channel HBA Driver: %s.\n", qla2x00_version_str); ret = pci_register_driver(&qla2xxx_pci_driver); if (ret) { - kmem_cache_destroy(srb_cachep); - qlt_exit(); - fc_release_transport(qla2xxx_transport_template); - fc_release_transport(qla2xxx_transport_vport_template); ql_log(ql_log_fatal, NULL, 0x0006, "pci_register_driver failed...ret=%d Failing load!.\n", ret); + goto release_vport_transport; } return ret; + +release_vport_transport: + fc_release_transport(qla2xxx_transport_vport_template); + +unreg_chrdev: + if (apidev_major >= 0) + unregister_chrdev(apidev_major, QLA2XXX_APIDEV); + fc_release_transport(qla2xxx_transport_template); + +qlt_exit: + qlt_exit(); + +destroy_cache: + kmem_cache_destroy(srb_cachep); + return ret; } /** diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 55227d20496a070d6539280557e5796682494299..21011c5fddebecee71b63880dce93c1a79acf8de 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2122,14 +2122,14 @@ void qlt_send_resp_ctio(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, ctio->u.status1.scsi_status |= cpu_to_le16(SS_RESIDUAL_UNDER); - /* Response code and sense key */ - put_unaligned_le32(((0x70 << 24) | (sense_key << 8)), - (&ctio->u.status1.sense_data)[0]); + /* Fixed format sense data. */ + ctio->u.status1.sense_data[0] = 0x70; + ctio->u.status1.sense_data[2] = sense_key; /* Additional sense length */ - put_unaligned_le32(0x0a, (&ctio->u.status1.sense_data)[1]); + ctio->u.status1.sense_data[7] = 0xa; /* ASC and ASCQ */ - put_unaligned_le32(((asc << 24) | (ascq << 16)), - (&ctio->u.status1.sense_data)[3]); + ctio->u.status1.sense_data[12] = asc; + ctio->u.status1.sense_data[13] = ascq; /* Memory Barrier */ wmb(); @@ -2179,7 +2179,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) mcmd->orig_iocb.imm_ntfy.u.isp24.status_subcode == ELS_TPRLO) { ql_dbg(ql_dbg_disc, vha, 0x2106, - "TM response logo %phC status %#x state %#x", + "TM response logo %8phC status %#x state %#x", mcmd->sess->port_name, mcmd->fc_tm_rsp, mcmd->flags); qlt_schedule_sess_for_deletion_lock(mcmd->sess); diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 1da04f323d384a220d316beaea4773746537dbd3..c402fc583da33014a251995ebd6d727653dcdc89 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -641,9 +641,6 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != QLA_SUCCESS) { - dma_free_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - init_fw_cb, init_fw_cb_dma); goto exit_init_fw_cb; } diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c index 617a607375908dfd031a0e30e1d126f5d135521c..22472d140ef7c6bce8955edbc37d1c9270eee10a 100644 --- a/drivers/scsi/scsi_trace.c +++ b/drivers/scsi/scsi_trace.c @@ -21,7 +21,7 @@ #include #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) -#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) +#define SERVICE_ACTION32(cdb) (get_unaligned_be16(&cdb[8])) static const char * scsi_trace_misc(struct trace_seq *, unsigned char *, int); @@ -51,17 +51,12 @@ static const char * scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - sector_t lba = 0, txlen = 0; + u32 lba, txlen; - lba |= (cdb[2] << 24); - lba |= (cdb[3] << 16); - lba |= (cdb[4] << 8); - lba |= cdb[5]; - txlen |= (cdb[7] << 8); - txlen |= cdb[8]; + lba = get_unaligned_be32(&cdb[2]); + txlen = get_unaligned_be16(&cdb[7]); - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, + trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen, cdb[1] >> 5); if (cdb[0] == WRITE_SAME) @@ -76,19 +71,12 @@ static const char * scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - sector_t lba = 0, txlen = 0; - - lba |= (cdb[2] << 24); - lba |= (cdb[3] << 16); - lba |= (cdb[4] << 8); - lba |= cdb[5]; - txlen |= (cdb[6] << 24); - txlen |= (cdb[7] << 16); - txlen |= (cdb[8] << 8); - txlen |= cdb[9]; - - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, + u32 lba, txlen; + + lba = get_unaligned_be32(&cdb[2]); + txlen = get_unaligned_be32(&cdb[6]); + + trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen, cdb[1] >> 5); trace_seq_putc(p, 0); @@ -99,23 +87,13 @@ static const char * scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - sector_t lba = 0, txlen = 0; - - lba |= ((u64)cdb[2] << 56); - lba |= ((u64)cdb[3] << 48); - lba |= ((u64)cdb[4] << 40); - lba |= ((u64)cdb[5] << 32); - lba |= (cdb[6] << 24); - lba |= (cdb[7] << 16); - lba |= (cdb[8] << 8); - lba |= cdb[9]; - txlen |= (cdb[10] << 24); - txlen |= (cdb[11] << 16); - txlen |= (cdb[12] << 8); - txlen |= cdb[13]; - - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, + u64 lba; + u32 txlen; + + lba = get_unaligned_be64(&cdb[2]); + txlen = get_unaligned_be32(&cdb[10]); + + trace_seq_printf(p, "lba=%llu txlen=%u protect=%u", lba, txlen, cdb[1] >> 5); if (cdb[0] == WRITE_SAME_16) @@ -130,8 +108,8 @@ static const char * scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p), *cmd; - sector_t lba = 0, txlen = 0; - u32 ei_lbrt = 0; + u64 lba; + u32 ei_lbrt, txlen; switch (SERVICE_ACTION32(cdb)) { case READ_32: @@ -151,26 +129,12 @@ scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) goto out; } - lba |= ((u64)cdb[12] << 56); - lba |= ((u64)cdb[13] << 48); - lba |= ((u64)cdb[14] << 40); - lba |= ((u64)cdb[15] << 32); - lba |= (cdb[16] << 24); - lba |= (cdb[17] << 16); - lba |= (cdb[18] << 8); - lba |= cdb[19]; - ei_lbrt |= (cdb[20] << 24); - ei_lbrt |= (cdb[21] << 16); - ei_lbrt |= (cdb[22] << 8); - ei_lbrt |= cdb[23]; - txlen |= (cdb[28] << 24); - txlen |= (cdb[29] << 16); - txlen |= (cdb[30] << 8); - txlen |= cdb[31]; - - trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", - cmd, (unsigned long long)lba, - (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); + lba = get_unaligned_be64(&cdb[12]); + ei_lbrt = get_unaligned_be32(&cdb[20]); + txlen = get_unaligned_be32(&cdb[28]); + + trace_seq_printf(p, "%s_32 lba=%llu txlen=%u protect=%u ei_lbrt=%u", + cmd, lba, txlen, cdb[10] >> 5, ei_lbrt); if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); @@ -185,7 +149,7 @@ static const char * scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - unsigned int regions = cdb[7] << 8 | cdb[8]; + unsigned int regions = get_unaligned_be16(&cdb[7]); trace_seq_printf(p, "regions=%u", (regions - 8) / 16); trace_seq_putc(p, 0); @@ -197,8 +161,8 @@ static const char * scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p), *cmd; - sector_t lba = 0; - u32 alloc_len = 0; + u64 lba; + u32 alloc_len; switch (SERVICE_ACTION16(cdb)) { case SAI_READ_CAPACITY_16: @@ -212,21 +176,10 @@ scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) goto out; } - lba |= ((u64)cdb[2] << 56); - lba |= ((u64)cdb[3] << 48); - lba |= ((u64)cdb[4] << 40); - lba |= ((u64)cdb[5] << 32); - lba |= (cdb[6] << 24); - lba |= (cdb[7] << 16); - lba |= (cdb[8] << 8); - lba |= cdb[9]; - alloc_len |= (cdb[10] << 24); - alloc_len |= (cdb[11] << 16); - alloc_len |= (cdb[12] << 8); - alloc_len |= cdb[13]; - - trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, - (unsigned long long)lba, alloc_len); + lba = get_unaligned_be64(&cdb[2]); + alloc_len = get_unaligned_be32(&cdb[10]); + + trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, lba, alloc_len); out: trace_seq_putc(p, 0); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index b4d06bd9ed510ad5e6e416090bef691f09b12df9..95d71e301a53420b72f92aee0e2580fed3deb339 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -37,6 +37,8 @@ #define ISCSI_TRANSPORT_VERSION "2.0-870" +#define ISCSI_SEND_MAX_ALLOWED 10 + static int dbg_session; module_param_named(debug_session, dbg_session, int, S_IRUGO | S_IWUSR); @@ -3680,6 +3682,7 @@ iscsi_if_rx(struct sk_buff *skb) struct nlmsghdr *nlh; struct iscsi_uevent *ev; uint32_t group; + int retries = ISCSI_SEND_MAX_ALLOWED; nlh = nlmsg_hdr(skb); if (nlh->nlmsg_len < sizeof(*nlh) + sizeof(*ev) || @@ -3710,6 +3713,10 @@ iscsi_if_rx(struct sk_buff *skb) break; err = iscsi_if_send_reply(portid, nlh->nlmsg_type, ev, sizeof(*ev)); + if (err == -EAGAIN && --retries < 0) { + printk(KERN_WARNING "Send reply failed, error %d\n", err); + break; + } } while (err < 0 && err != -ECONNREFUSED && err != -ESRCH); skb_pull(skb, rlen); } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 61d3fa9844d8109b38aa8c47143890129ce1ce0f..22025a5818dd010b312521284253169f475d42c2 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1623,20 +1623,30 @@ static void sd_rescan(struct device *dev) static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device; + struct gendisk *disk = bdev->bd_disk; + struct scsi_disk *sdkp = scsi_disk(disk); + struct scsi_device *sdev = sdkp->device; + void __user *p = compat_ptr(arg); int error; + error = scsi_verify_blk_ioctl(bdev, cmd); + if (error < 0) + return error; + error = scsi_ioctl_block_when_processing_errors(sdev, cmd, (mode & FMODE_NDELAY) != 0); if (error) return error; + + if (is_sed_ioctl(cmd)) + return sed_ioctl(sdkp->opal_dev, cmd, p); /* * Let the static ioctl translation table take care of it. */ if (!sdev->host->hostt->compat_ioctl) return -ENOIOCTLCMD; - return sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); + return sdev->host->hostt->compat_ioctl(sdev, cmd, p); } #endif @@ -1896,9 +1906,13 @@ static int sd_done(struct scsi_cmnd *SCpnt) } break; case REQ_OP_ZONE_REPORT: + /* To avoid that the block layer performs an incorrect + * bio_advance() call and restart of the remainder of + * incomplete report zone BIOs, always indicate a full + * completion of REQ_OP_ZONE_REPORT. + */ if (!result) { - good_bytes = scsi_bufflen(SCpnt) - - scsi_get_resid(SCpnt); + good_bytes = scsi_bufflen(SCpnt); scsi_set_resid(SCpnt, 0); } else { good_bytes = 0; @@ -2131,8 +2145,10 @@ static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer u8 type; int ret = 0; - if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) + if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) { + sdkp->protection_type = 0; return ret; + } type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c index 3b27075c21a7f41e6fdd2cdd591cac2da8713600..5cbc5ce5ac159aedb0b4452e15f204b9b5255e1a 100644 --- a/drivers/soc/fsl/qe/gpio.c +++ b/drivers/soc/fsl/qe/gpio.c @@ -152,8 +152,10 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index) if (err < 0) goto err0; gc = gpio_to_chip(err); - if (WARN_ON(!gc)) + if (WARN_ON(!gc)) { + err = -ENODEV; goto err0; + } if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) { pr_debug("%s: tried to get a non-qe pin\n", __func__); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index dbd5759e94def53395c5853de208dc0acc368df6..8d9c0e27508f0958ff749857eaa48819495da895 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -525,6 +525,15 @@ config SDX_EXT_IPC If unsure, say N. +config QTI_NOTIFY_SIDEBAND + tristate "QCOM sideband signalling helper" + help + This provides helper APIs and a header file through which + transport layer driver can talk to the sideband driver to + assert appropriate sideband signal. + + If unsure, say N. + config PANIC_ON_GLADIATOR_ERROR depends on MSM_GLADIATOR_ERP bool "Panic on GLADIATOR error report" @@ -673,7 +682,7 @@ config MSM_SPCOM or server is allowed per logical channel. config MSM_TZ_SMMU - depends on ARCH_MSM8953 || ARCH_QCS405 || ARCH_QCS403 + depends on ARCH_MSM8953 || ARCH_QCS405 || ARCH_QCS403 || ARCH_SDM429W bool "Helper functions for SMMU configuration through TZ" help Say 'Y' here for targets that need to call into TZ to configure @@ -723,7 +732,7 @@ config QCOM_GLINK config QCOM_GLINK_PKT tristate "Enable device interface for GLINK packet channels" - depends on QCOM_GLINK + depends on QCOM_GLINK || RPMSG_QCOM_GLINK_BGCOM help G-link packet driver provides the interface for the userspace clients to communicate over G-Link via device nodes. @@ -1005,6 +1014,32 @@ config MSM_BAM_DMUX provides a means to support more logical channels via muxing than BAM could without muxing. + config MSM_BGCOM_INTERFACE + bool "Driver support for Blackghost Communication" + depends on MSM_BGCOM + help + Create a bg_com_dev device node for user space communication. + Single user space client can open device node for communication + from hardware. Hardware will provide access to read + registers and read/write AHB memory in the device. + + + config MSM_BGCOM + bool "Provide APIs to communicate with Blackghost chipset" + help + BGCOM is a thin layer above SPI. It is used whithin a SoC for + communication between G-Link/bg_com_dev and BG processor over SPI. + This handle the interrupts raised by BG and notify the G-link with + interrupt event and event data. +config MSM_PIL_SSR_BG + tristate "MSM Subsystem Blackghost(BG) Support" + depends on MSM_PIL && MSM_SUBSYSTEM_RESTART + help + Support for booting and shutting down Blackghost(BG) SOC which is + an external SOC. This driver communicates with Blackghost(BG) SOC + via pair of IPC GPIOs for inward and outward signals between MSM + and Blackghost(BG) SOC. + config QCOM_SOC_INFO bool "Chip information for QTI SoCs" depends on SOC_BUS diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 53f7674bab111600edeec9d0ba05b0797c78505c..9c2a3fb9fd36a34f1811c1d9a03f99aef3f5d2d7 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -69,6 +69,8 @@ obj-$(CONFIG_MSM_JTAGV8) += jtagv8.o jtagv8-etm.o obj-$(CONFIG_MSM_CDSP_LOADER) += qdsp6v2/ obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o obj-$(CONFIG_SDX_EXT_IPC) += sdx_ext_ipc.o +obj-$(CONFIG_MSM_PIL_SSR_BG) += subsys-pil-bg.o +obj-$(CONFIG_QTI_NOTIFY_SIDEBAND) += sideband_notify.o ifdef CONFIG_MSM_SUBSYSTEM_RESTART obj-y += subsystem_notif.o @@ -95,6 +97,8 @@ ifdef CONFIG_MSM_RPM_SMD obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_master_stat.o endif obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o +obj-$(CONFIG_MSM_BGCOM) += bgcom_spi.o +obj-$(CONFIG_MSM_BGCOM_INTERFACE) += bgcom_interface.o obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o obj-$(CONFIG_MSM_DRM_NOTIFY) += msm_drm_notify.o ifdef CONFIG_DEBUG_FS diff --git a/drivers/soc/qcom/bgcom.h b/drivers/soc/qcom/bgcom.h new file mode 100644 index 0000000000000000000000000000000000000000..56f12d0a973c9cbd96c51b53d0bedb04f92990f3 --- /dev/null +++ b/drivers/soc/qcom/bgcom.h @@ -0,0 +1,214 @@ +/* Copyright (c) 2017-2018,2020 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. + * + */ + +#ifndef BGCOM_H +#define BGCOM_H + +#define BGCOM_REG_TZ_TO_MASTER_STATUS 0x01 +#define BGCOM_REG_TZ_TO_MASTER_DATA 0x03 +#define BGCOM_REG_SLAVE_STATUS 0x05 +#define BGCOM_REG_TIMESTAMP 0x07 +#define BGCOM_REG_SLAVE_STATUS_AUTO_CLEAR 0x09 +#define BGCOM_REG_FIFO_FILL 0x0B +#define BGCOM_REG_FIFO_SIZE 0x0D +#define BGCOM_REG_TZ_TO_SLAVE_COMMAND 0x0E +#define BGCOM_REG_TZ_TO_SLAVE_DATA 0x10 +#define BGCOM_REG_MASTER_STATUS 0x12 +#define BGCOM_REG_MASTER_COMMAND 0x14 +#define BGCOM_REG_MSG_WR_REG_4 0x16 +#define BGCOM_REG_TO_SLAVE_FIFO 0x40 +#define BGCOM_REG_TO_MASTER_FIFO 0x41 +#define BGCOM_REG_TO_SLAVE_AHB 0x42 +#define BGCOM_REG_TO_MASTER_AHB 0x43 + +/* Enum to define the bgcom SPI state */ +enum bgcom_spi_state { + BGCOM_SPI_FREE = 0, + BGCOM_SPI_BUSY, +}; + +/* Enums to identify Blackghost events */ +enum bgcom_event_type { + BGCOM_EVENT_NONE = 0, + BGCOM_EVENT_APPLICATION_RUNNING, + BGCOM_EVENT_TO_SLAVE_FIFO_READY, + BGCOM_EVENT_TO_MASTER_FIFO_READY, + BGCOM_EVENT_AHB_READY, + BGCOM_EVENT_TO_MASTER_FIFO_USED, + BGCOM_EVENT_TO_SLAVE_FIFO_FREE, + BGCOM_EVENT_TIMESTAMP_UPDATE, + BGCOM_EVENT_RESET_OCCURRED, + + BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN, + BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR, + BGCOM_EVENT_ERROR_WRITE_FIFO_ACCESS, + BGCOM_EVENT_ERROR_READ_FIFO_UNDERRUN, + BGCOM_EVENT_ERROR_READ_FIFO_BUS_ERR, + BGCOM_EVENT_ERROR_READ_FIFO_ACCESS, + BGCOM_EVENT_ERROR_TRUNCATED_READ, + BGCOM_EVENT_ERROR_TRUNCATED_WRITE, + BGCOM_EVENT_ERROR_AHB_ILLEGAL_ADDRESS, + BGCOM_EVENT_ERROR_AHB_BUS_ERR, + BGCOM_EVENT_ERROR_UNKNOWN, +}; + +/* Event specific data */ +union bgcom_event_data_type { + uint32_t unused; + bool application_running; /* BGCOM_EVENT_APPLICATION_RUNNING */ + bool to_slave_fifo_ready; /* BGCOM_EVENT_TO_SLAVE_FIFO_READY */ + bool to_master_fifo_ready; /* BGCOM_EVENT_TO_MASTER_FIFO_READY */ + bool ahb_ready; /* BGCOM_EVENT_AHB_READY */ + uint16_t to_slave_fifo_free; /* BGCOM_EVENT_TO_SLAVE_FIFO_FREE */ + struct fifo_event_data { + uint16_t to_master_fifo_used; + void *data; + } fifo_data; +}; + +/* Client specific data */ +struct bgcom_open_config_type { + /** Private data pointer for client to maintain context. + * This data is passed back to client in the notification callbacks. + */ + void *priv; + + /* Notification callbacks to notify the BG events */ + void (*bgcom_notification_cb)(void *handle, void *priv, + enum bgcom_event_type event, + union bgcom_event_data_type *event_data); +}; + +/** + * bgcom_open() - opens a channel to interact with Blackghost + * @open_config: pointer to the open configuration structure + * + * Open a new connection to blackghost + * + * Return a handle on success or NULL on error + */ +void *bgcom_open(struct bgcom_open_config_type *open_config); + +/** + * bgcom_close() - close the exsting with Blackghost + * @handle: pointer to the handle, provided by bgcom at + * bgcom_open + * + * Open a new connection to blackghost + * + * Return 0 on success or error on invalid handle + */ +int bgcom_close(void **handle); + +/** + * bgcom_reg_read() - Read from the one or more contiguous registers from BG + * @handle: BGCOM handle associated with the channel + * @reg_start_addr : 8 bit start address of the registers to read from + * @num_regs : Number of contiguous registers to read, starting + * from reg_start_addr. + * @read_buf : Buffer to read from the registers. + * Return 0 on success or -Ve on error + */ +int bgcom_reg_read(void *handle, uint8_t reg_start_addr, + uint32_t num_regs, void *read_buf); + +/** + * Write into the one or more contiguous registers. + * + * @param[in] handle BGCOM handle associated with the channel. + * @param[in] reg_start_addr 8bit start address of the registers to write into. + * @param[in] num_regs Number of contiguous registers to write, starting + * from reg_start_addr. + * @param[in] write_buf Buffer to write into the registers. + * + * @return + * 0 if function is successful, + * Otherwise returns error code. + * + * @sideeffects Causes the Blackghost SPI slave to wakeup. Depending up on + * the operation, it may also wakeup the complete Blackghost. + */ + +/** + * bgcom_reg_write() - Write to the one or more contiguous registers on BG + * @handle: BGCOM handle associated with the channel + * @reg_start_addr : 8 bit start address of the registers to read from + * @num_regs : Number of contiguous registers to write, starting + * from reg_start_addr. + * @write_buf : Buffer to be written to the registers. + * Return 0 on success or -Ve on error + */ +int bgcom_reg_write(void *handle, uint8_t reg_start_addr, + uint8_t num_regs, void *write_buf); + +/** + * bgcom_fifo_read() - Read data from the TO_MASTER_FIFO. + * @handle: BGCOM handle associated with the channel + * @num_words : number of words to read from FIFO + * @read_buf : Buffer read from FIFO. + * Return 0 on success or -Ve on error + */ +int bgcom_fifo_read(void *handle, uint32_t num_words, + void *read_buf); + +/** + * bgcom_fifo_write() - Write data to the TO_SLAVE_FIFO. + * @handle: BGCOM handle associated with the channel + * @num_words : number of words to write on FIFO + * @write_buf : Buffer written to FIFO. + * Return 0 on success or -Ve on error + */ +int bgcom_fifo_write(void *handle, uint32_t num_words, + void *write_buf); + +/** + * bgcom_ahb_read() - Read data from the AHB memory. + * @handle: BGCOM handle associated with the channel + * @ahb_start_addr : Memory start address from where to read + * @num_words : number of words to read from AHB + * @read_buf : Buffer read from FIFO. + * Return 0 on success or -Ve on error + */ +int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, + uint32_t num_words, void *read_buf); + +/** + * bgcom_ahb_write() - Write data to the AHB memory. + * @handle: BGCOM handle associated with the channel + * @ahb_start_addr : Memory start address from where to start write + * @num_words : number of words to read from AHB + * @write_buf : Buffer to write in AHB. + * Return 0 on success or -Ve on error + */ +int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, + uint32_t num_words, void *write_buf); + +/** + * bgcom_suspend() - Suspends the channel. + * @handle: BGCOM handle associated with the channel + * Return 0 on success or -Ve on error + */ +int bgcom_suspend(void *handle); + +/** + * bgcom_resume() - Resumes the channel. + * @handle: BGCOM handle associated with the channel + * Return 0 on success or -Ve on error + */ +int bgcom_resume(void *handle); + +int bgcom_set_spi_state(enum bgcom_spi_state state); + +void bgcom_bgdown_handler(void); + +#endif /* BGCOM_H */ diff --git a/drivers/soc/qcom/bgcom_interface.c b/drivers/soc/qcom/bgcom_interface.c new file mode 100644 index 0000000000000000000000000000000000000000..bcb51a249e54ee7d1a9d0a3d39724375948194a1 --- /dev/null +++ b/drivers/soc/qcom/bgcom_interface.c @@ -0,0 +1,784 @@ +/* Copyright (c) 2017-2020, 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(msg) "bgcom_dev:" msg + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bgcom.h" +#include "linux/bgcom_interface.h" +#include "bgcom_interface.h" +#include +#include +#include +#include +#include +#include + +#define BGCOM "bg_com_dev" + +#define BGDAEMON_LDO09_LPM_VTG 0 +#define BGDAEMON_LDO09_NPM_VTG 10000 + +#define BGDAEMON_LDO03_LPM_VTG 0 +#define BGDAEMON_LDO03_NPM_VTG 10000 + +#define MPPS_DOWN_EVENT_TO_BG_TIMEOUT 3000 +#define ADSP_DOWN_EVENT_TO_BG_TIMEOUT 3000 +#define SLEEP_FOR_SPI_BUS 2000 + +enum { + SSR_DOMAIN_BG, + SSR_DOMAIN_MODEM, + SSR_DOMAIN_ADSP, + SSR_DOMAIN_MAX, +}; + +enum ldo_task { + ENABLE_LDO03, + ENABLE_LDO09, + DISABLE_LDO03, + DISABLE_LDO09 +}; + +struct bgdaemon_regulator { + struct regulator *regldo03; + struct regulator *regldo09; +}; + +struct bgdaemon_priv { + struct bgdaemon_regulator rgltr; + enum ldo_task ldo_action; + void *pil_h; + bool pending_bg_twm_wear_load; + struct workqueue_struct *bgdaemon_wq; + struct work_struct bgdaemon_load_twm_bg_work; + bool bg_twm_wear_load; +}; + +struct bg_event { + enum bg_event_type e_type; +}; + +struct service_info { + const char name[32]; + int domain_id; + void *handle; + struct notifier_block *nb; +}; + +static char *ssr_domains[] = { + "bg-wear", + "modem", + "adsp", +}; + +static struct bgdaemon_priv *dev; +static unsigned int bgreset_gpio; +static DEFINE_MUTEX(bg_char_mutex); +static struct cdev bg_cdev; +static struct class *bg_class; +struct device *dev_ret; +static dev_t bg_dev; +static int device_open; +static void *handle; +static bool twm_exit; +static bool bg_app_running; +static struct bgcom_open_config_type config_type; +static DECLARE_COMPLETION(bg_modem_down_wait); +static DECLARE_COMPLETION(bg_adsp_down_wait); + +/** + * send_uevent(): send events to user space + * pce : ssr event handle value + * Return: 0 on success, standard Linux error code on error + * + * It adds pce value to event and broadcasts to user space. + */ +static int send_uevent(struct bg_event *pce) +{ + char event_string[32]; + char *envp[2] = { event_string, NULL }; + + snprintf(event_string, ARRAY_SIZE(event_string), + "BG_EVENT=%d", pce->e_type); + return kobject_uevent_env(&dev_ret->kobj, KOBJ_CHANGE, envp); +} + +static void bgcom_load_twm_bg_work(struct work_struct *work) +{ + if (dev->pil_h) { + pr_err("bg-wear is already loaded\n"); + subsystem_put(dev->pil_h); + dev->pil_h = NULL; + bg_soft_reset(); + } else { + dev->bg_twm_wear_load = true; + dev->pil_h = subsystem_get_with_fwname("bg-wear", + "bg-twm-wear"); + if (!dev->pil_h) + pr_err("failed to load bg-twm-wear\n"); + } +} + +static int bgdaemon_configure_regulators(bool state) +{ + int retval; + + if (state == true) { + retval = regulator_enable(dev->rgltr.regldo03); + if (retval) + pr_err("Failed to enable LDO-03 regulator:%d\n", + retval); + retval = regulator_enable(dev->rgltr.regldo09); + if (retval) + pr_err("Failed to enable LDO-09 regulator:%d\n", + retval); + } + if (state == false) { + retval = regulator_disable(dev->rgltr.regldo03); + if (retval) + pr_err("Failed to disable LDO-03 regulator:%d\n", + retval); + retval = regulator_disable(dev->rgltr.regldo09); + if (retval) + pr_err("Failed to disable LDO-09 regulator:%d\n", + retval); + } + return retval; +} + +static int bgdaemon_init_regulators(struct device *pdev) +{ + int rc; + struct regulator *reg03; + struct regulator *reg09; + + reg03 = regulator_get(pdev, "ssr-reg1"); + if (IS_ERR_OR_NULL(reg03)) { + rc = PTR_ERR(reg03); + pr_err("Unable to get regulator for LDO-03\n"); + goto err_ret; + } + reg09 = regulator_get(pdev, "ssr-reg2"); + if (IS_ERR_OR_NULL(reg09)) { + rc = PTR_ERR(reg09); + pr_err("Unable to get regulator for LDO-09\n"); + goto err_ret; + } + dev->rgltr.regldo03 = reg03; + dev->rgltr.regldo09 = reg09; + return 0; +err_ret: + return rc; +} + +static int bgdaemon_ldowork(enum ldo_task do_action) +{ + int ret; + + switch (do_action) { + case ENABLE_LDO03: + ret = regulator_set_load(dev->rgltr.regldo03, + BGDAEMON_LDO03_NPM_VTG); + if (ret < 0) { + pr_err("Failed to request LDO-03 voltage:%d\n", + ret); + goto err_ret; + } + break; + case ENABLE_LDO09: + ret = regulator_set_load(dev->rgltr.regldo09, + BGDAEMON_LDO09_NPM_VTG); + if (ret < 0) { + pr_err("Failed to request LDO-09 voltage:%d\n", + ret); + goto err_ret; + } + break; + case DISABLE_LDO03: + ret = regulator_set_load(dev->rgltr.regldo03, + BGDAEMON_LDO03_LPM_VTG); + if (ret < 0) { + pr_err("Failed to disable LDO-03:%d\n", ret); + goto err_ret; + } + break; + case DISABLE_LDO09: + ret = regulator_set_load(dev->rgltr.regldo09, + BGDAEMON_LDO09_LPM_VTG); + if (ret < 0) { + pr_err("Failed to disable LDO-09:%d\n", ret); + goto err_ret; + } + break; + default: + ret = -EINVAL; + } + +err_ret: + return ret; +} + +static int bgcom_char_open(struct inode *inode, struct file *file) +{ + int ret; + + mutex_lock(&bg_char_mutex); + if (device_open == 1) { + pr_err("device is already open\n"); + mutex_unlock(&bg_char_mutex); + return -EBUSY; + } + device_open++; + handle = bgcom_open(&config_type); + mutex_unlock(&bg_char_mutex); + if (IS_ERR(handle)) { + device_open = 0; + ret = PTR_ERR(handle); + handle = NULL; + return ret; + } + return 0; +} + +static int bgchar_read_cmd(struct bg_ui_data *fui_obj_msg, + int type) +{ + void *read_buf; + int ret; + void __user *result = (void *) + (uintptr_t)fui_obj_msg->result; + + read_buf = kmalloc_array(fui_obj_msg->num_of_words, sizeof(uint32_t), + GFP_KERNEL); + if (read_buf == NULL) + return -ENOMEM; + switch (type) { + case REG_READ: + ret = bgcom_reg_read(handle, fui_obj_msg->cmd, + fui_obj_msg->num_of_words, + read_buf); + break; + case AHB_READ: + ret = bgcom_ahb_read(handle, + fui_obj_msg->bg_address, + fui_obj_msg->num_of_words, + read_buf); + break; + } + if (!ret && copy_to_user(result, read_buf, + fui_obj_msg->num_of_words * sizeof(uint32_t))) { + pr_err("copy to user failed\n"); + ret = -EFAULT; + } + kfree(read_buf); + return ret; +} + +static int bgchar_write_cmd(struct bg_ui_data *fui_obj_msg, int type) +{ + void *write_buf; + int ret = -EINVAL; + void __user *write = (void *) + (uintptr_t)fui_obj_msg->write; + + write_buf = kmalloc_array(fui_obj_msg->num_of_words, sizeof(uint32_t), + GFP_KERNEL); + if (write_buf == NULL) + return -ENOMEM; + write_buf = memdup_user(write, + fui_obj_msg->num_of_words * sizeof(uint32_t)); + if (IS_ERR(write_buf)) { + ret = PTR_ERR(write_buf); + kfree(write_buf); + return ret; + } + switch (type) { + case REG_WRITE: + ret = bgcom_reg_write(handle, fui_obj_msg->cmd, + fui_obj_msg->num_of_words, + write_buf); + break; + case AHB_WRITE: + ret = bgcom_ahb_write(handle, + fui_obj_msg->bg_address, + fui_obj_msg->num_of_words, + write_buf); + break; + } + kfree(write_buf); + return ret; +} + +int bg_soft_reset(void) +{ + pr_debug("do BG reset using gpio %d\n", bgreset_gpio); + if (!gpio_is_valid(bgreset_gpio)) { + pr_err("gpio %d is not valid\n", bgreset_gpio); + return -ENXIO; + } + if (gpio_direction_output(bgreset_gpio, 1)) + pr_err("gpio %d direction not set\n", bgreset_gpio); + + /* Sleep for 50ms for hardware to detect signal as high */ + msleep(50); + + gpio_set_value(bgreset_gpio, 0); + + /* Sleep for 50ms for hardware to detect signal as high */ + msleep(50); + gpio_set_value(bgreset_gpio, 1); + + return 0; +} +EXPORT_SYMBOL(bg_soft_reset); + +static int modem_down2_bg(void) +{ + complete(&bg_modem_down_wait); + return 0; +} + +static int adsp_down2_bg(void) +{ + complete(&bg_adsp_down_wait); + return 0; +} + +static long bg_com_ioctl(struct file *filp, + unsigned int ui_bgcom_cmd, unsigned long arg) +{ + int ret; + struct bg_ui_data ui_obj_msg; + + switch (ui_bgcom_cmd) { + case REG_READ: + case AHB_READ: + if (copy_from_user(&ui_obj_msg, (void __user *) arg, + sizeof(ui_obj_msg))) { + pr_err("The copy from user failed\n"); + ret = -EFAULT; + } + ret = bgchar_read_cmd(&ui_obj_msg, + ui_bgcom_cmd); + if (ret < 0) + pr_err("bgchar_read_cmd failed\n"); + break; + case AHB_WRITE: + case REG_WRITE: + if (copy_from_user(&ui_obj_msg, (void __user *) arg, + sizeof(ui_obj_msg))) { + pr_err("The copy from user failed\n"); + ret = -EFAULT; + } + ret = bgchar_write_cmd(&ui_obj_msg, ui_bgcom_cmd); + if (ret < 0) + pr_err("bgchar_write_cmd failed\n"); + break; + case SET_SPI_FREE: + ret = bgcom_set_spi_state(BGCOM_SPI_FREE); + break; + case SET_SPI_BUSY: + ret = bgcom_set_spi_state(BGCOM_SPI_BUSY); + /* Add sleep for SPI Bus to release*/ + msleep(SLEEP_FOR_SPI_BUS); + break; + case BG_SOFT_RESET: + ret = bg_soft_reset(); + break; + case BG_MODEM_DOWN2_BG_DONE: + ret = modem_down2_bg(); + break; + case BG_ADSP_DOWN2_BG_DONE: + ret = adsp_down2_bg(); + case BG_TWM_EXIT: + twm_exit = true; + ret = 0; + break; + case BG_APP_RUNNING: + bg_app_running = true; + ret = 0; + break; + case BG_WEAR_LOAD: + ret = 0; + if (dev->pil_h) { + pr_err("bg-wear is already loaded\n"); + ret = -EFAULT; + break; + } + dev->bg_twm_wear_load = false; + dev->pil_h = subsystem_get_with_fwname("bg-wear", "bg-wear"); + if (!dev->pil_h) { + pr_err("failed to load bg-wear\n"); + ret = -EFAULT; + } + break; + case BG_WEAR_TWM_LOAD: + dev->pending_bg_twm_wear_load = true; + queue_work(dev->bgdaemon_wq, &dev->bgdaemon_load_twm_bg_work); + ret = 0; + break; + case BG_WEAR_UNLOAD: + if (dev->pil_h) { + subsystem_put(dev->pil_h); + dev->pil_h = NULL; + bg_soft_reset(); + } + ret = 0; + break; + default: + ret = -ENOIOCTLCMD; + break; + } + return ret; +} + +static int bgcom_char_close(struct inode *inode, struct file *file) +{ + int ret; + + mutex_lock(&bg_char_mutex); + ret = bgcom_close(&handle); + device_open = 0; + mutex_unlock(&bg_char_mutex); + return ret; +} + +static int bg_daemon_probe(struct platform_device *pdev) +{ + struct device_node *node; + unsigned int reset_gpio; + int ret; + + node = pdev->dev.of_node; + + pr_info("%s started", __func__); + + dev = kzalloc(sizeof(struct bgdaemon_priv), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + reset_gpio = of_get_named_gpio(node, "qcom,bg-reset-gpio", 0); + if (!gpio_is_valid(reset_gpio)) { + pr_err("gpio %d found is not valid\n", reset_gpio); + goto err_ret; + } + + if (gpio_request(reset_gpio, "bg_reset_gpio")) { + pr_err("gpio %d request failed\n", reset_gpio); + goto err_ret; + } + + if (gpio_direction_output(reset_gpio, 1)) { + pr_err("gpio %d direction not set\n", reset_gpio); + goto err_ret; + } + + pr_info("bg-soft-reset gpio successfully requested\n"); + bgreset_gpio = reset_gpio; + + ret = bgdaemon_init_regulators(&pdev->dev); + if (ret != 0) { + pr_err("Failed to init regulators:%d\n", ret); + goto err_device; + } + ret = bgdaemon_configure_regulators(true); + if (ret) { + pr_err("Failed to confifigure regulators:%d\n", ret); + bgdaemon_configure_regulators(false); + goto err_ret; + } + pr_info("%s success", __func__); + +err_device: + return -ENODEV; +err_ret: + return 0; +} + +static const struct of_device_id bg_daemon_of_match[] = { + { .compatible = "qcom,bg-daemon", }, + { } +}; +MODULE_DEVICE_TABLE(of, bg_daemon_of_match); + +static struct platform_driver bg_daemon_driver = { + .probe = bg_daemon_probe, + .driver = { + .name = "bg-daemon", + .of_match_table = bg_daemon_of_match, + }, +}; + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .open = bgcom_char_open, + .release = bgcom_char_close, + .unlocked_ioctl = bg_com_ioctl, +}; + +static int __init init_bg_com_dev(void) +{ + int ret; + + ret = alloc_chrdev_region(&bg_dev, 0, 1, BGCOM); + if (ret < 0) { + pr_err("failed with error %d\n", ret); + return ret; + } + cdev_init(&bg_cdev, &fops); + ret = cdev_add(&bg_cdev, bg_dev, 1); + if (ret < 0) { + unregister_chrdev_region(bg_dev, 1); + pr_err("device registration failed\n"); + return ret; + } + bg_class = class_create(THIS_MODULE, BGCOM); + if (IS_ERR_OR_NULL(bg_class)) { + cdev_del(&bg_cdev); + unregister_chrdev_region(bg_dev, 1); + pr_err("class creation failed\n"); + return PTR_ERR(bg_class); + } + + dev_ret = device_create(bg_class, NULL, bg_dev, NULL, BGCOM); + if (IS_ERR_OR_NULL(dev_ret)) { + class_destroy(bg_class); + cdev_del(&bg_cdev); + unregister_chrdev_region(bg_dev, 1); + pr_err("device create failed\n"); + return PTR_ERR(dev_ret); + } + + if (platform_driver_register(&bg_daemon_driver)) + pr_err("%s: failed to register bg-daemon register\n", __func__); + + dev->bgdaemon_wq = + create_singlethread_workqueue("bgdaemon-work-queue"); + if (!dev->bgdaemon_wq) { + pr_err("Failed to init BG-DAEMON work-queue\n"); + goto free_wq; + } + INIT_WORK(&dev->bgdaemon_load_twm_bg_work, bgcom_load_twm_bg_work); + + return 0; + +free_wq: + destroy_workqueue(dev->bgdaemon_wq); + return -EFAULT; +} + +static void __exit exit_bg_com_dev(void) +{ + device_destroy(bg_class, bg_dev); + class_destroy(bg_class); + cdev_del(&bg_cdev); + unregister_chrdev_region(bg_dev, 1); + bgdaemon_configure_regulators(false); + platform_driver_unregister(&bg_daemon_driver); +} + +/** + *ssr_bg_cb(): callback function is called + *by ssr framework when BG goes down, up and during ramdump + *collection. It handles BG shutdown and power up events. + */ +static int ssr_bg_cb(struct notifier_block *this, + unsigned long opcode, void *data) +{ + struct bg_event bge; + + switch (opcode) { + case SUBSYS_BEFORE_SHUTDOWN: + bge.e_type = BG_BEFORE_POWER_DOWN; + bgdaemon_ldowork(ENABLE_LDO03); + bgdaemon_ldowork(ENABLE_LDO09); + bgcom_bgdown_handler(); + bgcom_set_spi_state(BGCOM_SPI_BUSY); + send_uevent(&bge); + break; + case SUBSYS_AFTER_SHUTDOWN: + /* Add sleep for SPI Bus to release*/ + msleep(SLEEP_FOR_SPI_BUS); + if (dev->pending_bg_twm_wear_load) { + /* Load bg-twm-wear */ + dev->pending_bg_twm_wear_load = false; + queue_work(dev->bgdaemon_wq, + &dev->bgdaemon_load_twm_bg_work); + } + break; + case SUBSYS_AFTER_POWERUP: + if (dev->bg_twm_wear_load) + bge.e_type = TWM_BG_AFTER_POWER_UP; + else + bge.e_type = BG_AFTER_POWER_UP; + bgdaemon_ldowork(DISABLE_LDO03); + bgdaemon_ldowork(DISABLE_LDO09); + bgcom_set_spi_state(BGCOM_SPI_FREE); + send_uevent(&bge); + break; + } + return NOTIFY_DONE; +} + +/** + *ssr_modem_cb(): callback function is called + *by ssr framework when modem goes down, up and during ramdump + *collection. It handles modem shutdown and power up events. + */ +static int ssr_modem_cb(struct notifier_block *this, + unsigned long opcode, void *data) +{ + struct bg_event modeme; + int ret; + + switch (opcode) { + case SUBSYS_BEFORE_SHUTDOWN: + modeme.e_type = MODEM_BEFORE_POWER_DOWN; + reinit_completion(&bg_modem_down_wait); + send_uevent(&modeme); + ret = wait_for_completion_timeout(&bg_modem_down_wait, + msecs_to_jiffies(MPPS_DOWN_EVENT_TO_BG_TIMEOUT)); + if (!ret) + pr_err("Time out on modem down event\n"); + break; + case SUBSYS_AFTER_POWERUP: + modeme.e_type = MODEM_AFTER_POWER_UP; + send_uevent(&modeme); + break; + } + return NOTIFY_DONE; +} + +static int ssr_adsp_cb(struct notifier_block *this, + unsigned long opcode, void *data) +{ + struct bg_event adspe; + int ret; + + switch (opcode) { + case SUBSYS_BEFORE_SHUTDOWN: + adspe.e_type = ADSP_BEFORE_POWER_DOWN; + reinit_completion(&bg_adsp_down_wait); + send_uevent(&adspe); + ret = wait_for_completion_timeout(&bg_adsp_down_wait, + msecs_to_jiffies(ADSP_DOWN_EVENT_TO_BG_TIMEOUT)); + if (!ret) + pr_err("Time out on adsp down event\n"); + break; + case SUBSYS_AFTER_POWERUP: + adspe.e_type = ADSP_AFTER_POWER_UP; + send_uevent(&adspe); + break; + } + return NOTIFY_DONE; +} +bool is_twm_exit(void) +{ + if (twm_exit) { + twm_exit = false; + return true; + } + return false; +} +EXPORT_SYMBOL(is_twm_exit); + +bool is_bg_running(void) +{ + if (bg_app_running) { + bg_app_running = false; + return true; + } + return false; +} +EXPORT_SYMBOL(is_bg_running); + +static struct notifier_block ssr_modem_nb = { + .notifier_call = ssr_modem_cb, + .priority = 0, +}; + +static struct notifier_block ssr_adsp_nb = { + .notifier_call = ssr_adsp_cb, + .priority = 0, +}; + +static struct notifier_block ssr_bg_nb = { + .notifier_call = ssr_bg_cb, + .priority = 0, +}; + +static struct service_info service_data[3] = { + { + .name = "SSR_BG", + .domain_id = SSR_DOMAIN_BG, + .nb = &ssr_bg_nb, + .handle = NULL, + }, + { + .name = "SSR_MODEM", + .domain_id = SSR_DOMAIN_MODEM, + .nb = &ssr_modem_nb, + .handle = NULL, + }, + { + .name = "SSR_ADSP", + .domain_id = SSR_DOMAIN_ADSP, + .nb = &ssr_adsp_nb, + .handle = NULL, + }, +}; + +/** + * ssr_register checks that domain id should be in range and register + * SSR framework for value at domain id. + */ +static int __init ssr_register(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(service_data); i++) { + if ((service_data[i].domain_id < 0) || + (service_data[i].domain_id >= SSR_DOMAIN_MAX)) { + pr_err("Invalid service ID = %d\n", + service_data[i].domain_id); + } else { + service_data[i].handle = + subsys_notif_register_notifier( + ssr_domains[service_data[i].domain_id], + service_data[i].nb); + if (IS_ERR_OR_NULL(service_data[i].handle)) { + pr_err("subsys register failed for id = %d", + service_data[i].domain_id); + service_data[i].handle = NULL; + } + } + } + return 0; +} + +module_init(init_bg_com_dev); +late_initcall(ssr_register); +module_exit(exit_bg_com_dev); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/bgcom_interface.h b/drivers/soc/qcom/bgcom_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..198cbb71f183be31c9e8af424502b3b8d8c5a516 --- /dev/null +++ b/drivers/soc/qcom/bgcom_interface.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2017-2020 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. + * + */ +#ifndef BGCOM_INTERFACE_H +#define BGCOM_INTERFACE_H + +/* + * bg_soft_reset() - soft reset Blackghost + * Return 0 on success or -Ve on error + */ +int bg_soft_reset(void); + +/* + * is_twm_exit() + * Return true if device is booting up on TWM exit. + * value is auto cleared once read. + */ +bool is_twm_exit(void); + +/* + * is_bg_running() + * Return true if bg is running. + * value is auto cleared once read. + */ +bool is_bg_running(void); + +#endif /* BGCOM_INTERFACE_H */ diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..e7993251a4d8a507b9e8cb37b05ced34efe3b7dc --- /dev/null +++ b/drivers/soc/qcom/bgcom_spi.c @@ -0,0 +1,1131 @@ +/* Copyright (c) 2017-2020, 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(msg) "bgcom: %s: " msg, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bgcom.h" +#include "bgrsb.h" +#include "bgcom_interface.h" + +#define BG_SPI_WORD_SIZE (0x04) +#define BG_SPI_READ_LEN (0x04) +#define BG_SPI_WRITE_CMND_LEN (0x01) +#define BG_SPI_FIFO_READ_CMD (0x41) +#define BG_SPI_FIFO_WRITE_CMD (0x40) +#define BG_SPI_AHB_READ_CMD (0x43) +#define BG_SPI_AHB_WRITE_CMD (0x42) +#define BG_SPI_AHB_CMD_LEN (0x05) +#define BG_SPI_AHB_READ_CMD_LEN (0x08) +#define BG_STATUS_REG (0x05) +#define BG_CMND_REG (0x14) + +#define BG_SPI_MAX_WORDS (0x3FFFFFFD) +#define BG_SPI_MAX_REGS (0x0A) +#define HED_EVENT_ID_LEN (0x02) +#define HED_EVENT_SIZE_LEN (0x02) +#define HED_EVENT_DATA_STRT_LEN (0x05) +#define CMA_BFFR_POOL_SIZE (128*1024) + +#define MAX_RETRY 100 + +enum bgcom_state { + /*BGCOM Staus ready*/ + BGCOM_PROB_SUCCESS = 0, + BGCOM_PROB_WAIT = 1, + BGCOM_STATE_SUSPEND = 2, + BGCOM_STATE_ACTIVE = 3 +}; + +enum bgcom_req_type { + /*BGCOM local requests*/ + BGCOM_READ_REG = 0, + BGCOM_READ_FIFO = 1, + BGCOM_READ_AHB = 2, + BGCOM_WRITE_REG = 3, +}; + +struct bg_spi_priv { + struct spi_device *spi; + /* Transaction related */ + struct mutex xfer_mutex; + void *lhandle; + /* Message for single transfer */ + struct spi_message msg1; + struct spi_transfer xfer1; + int irq_lock; + + enum bgcom_state bg_state; +}; + +struct cb_data { + void *priv; + void *handle; + void (*bgcom_notification_cb)(void *handle, void *priv, + enum bgcom_event_type event, + union bgcom_event_data_type *event_data); + struct list_head list; +}; + +struct bg_context { + struct bg_spi_priv *bg_spi; + enum bgcom_state state; + struct cb_data *cb; +}; + +struct event_list { + struct event *evnt; + struct list_head list; +}; +static void *bg_com_drv; +static uint32_t g_slav_status_reg; + +/* BGCOM client callbacks set-up */ +static void send_input_events(struct work_struct *work); +static struct list_head cb_head = LIST_HEAD_INIT(cb_head); +static struct list_head pr_lst_hd = LIST_HEAD_INIT(pr_lst_hd); +static DEFINE_SPINLOCK(lst_setup_lock); +static enum bgcom_spi_state spi_state; + + +static struct workqueue_struct *wq; +static DECLARE_WORK(input_work, send_input_events); + +static struct mutex bg_resume_mutex; + +static atomic_t bg_is_spi_active; +static int bg_irq; + +static uint8_t *fxd_mem_buffer; +static struct mutex cma_buffer_lock; + +static struct spi_device *get_spi_device(void) +{ + struct bg_spi_priv *bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); + struct spi_device *spi = bg_spi->spi; + return spi; +} + +static void augmnt_fifo(uint8_t *data, int pos) +{ + data[pos] = '\0'; +} + +static void send_input_events(struct work_struct *work) +{ + struct list_head *temp; + struct list_head *pos; + struct event_list *node; + struct event *evnt; + + if (list_empty(&pr_lst_hd)) + return; + + list_for_each_safe(pos, temp, &pr_lst_hd) { + node = list_entry(pos, struct event_list, list); + evnt = node->evnt; +// bgrsb_send_input(evnt); + kfree(evnt); + spin_lock(&lst_setup_lock); + list_del(&node->list); + spin_unlock(&lst_setup_lock); + kfree(node); + } +} + +int bgcom_set_spi_state(enum bgcom_spi_state state) +{ + struct bg_spi_priv *bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); + if (state < 0 || state > 1) + return -EINVAL; + + if (state == spi_state) + return 0; + + mutex_lock(&bg_spi->xfer_mutex); + spi_state = state; + mutex_unlock(&bg_spi->xfer_mutex); + return 0; +} +EXPORT_SYMBOL(bgcom_set_spi_state); + +static inline +void add_to_irq_list(struct cb_data *data) +{ + list_add_tail(&data->list, &cb_head); +} + +static bool is_bgcom_ready(void) +{ + return (bg_com_drv != NULL ? true : false); +} + +static void bg_spi_reinit_xfer(struct spi_transfer *xfer) +{ + xfer->tx_buf = NULL; + xfer->rx_buf = NULL; + xfer->delay_usecs = 0; + xfer->len = 0; +} + +static int read_bg_locl(enum bgcom_req_type req_type, + uint32_t no_of_words, void *buf) +{ + + struct bg_context clnt_handle; + struct bg_spi_priv *spi = + container_of(bg_com_drv, struct bg_spi_priv, lhandle); + int ret = 0; + + if (!buf) + return -EINVAL; + + clnt_handle.bg_spi = spi; + + switch (req_type) { + case BGCOM_READ_REG: + ret = bgcom_reg_read(&clnt_handle, + BG_STATUS_REG, no_of_words, buf); + break; + case BGCOM_READ_FIFO: + ret = bgcom_fifo_read(&clnt_handle, no_of_words, buf); + break; + case BGCOM_WRITE_REG: + ret = bgcom_reg_write(&clnt_handle, BG_CMND_REG, + no_of_words, buf); + break; + case BGCOM_READ_AHB: + break; + } + return ret; +} + +static int bgcom_transfer(void *handle, uint8_t *tx_buf, + uint8_t *rx_buf, uint32_t txn_len) +{ + struct spi_transfer *tx_xfer; + struct bg_spi_priv *bg_spi; + struct bg_context *cntx; + struct spi_device *spi; + int ret; + + if (!handle || !tx_buf) + return -EINVAL; + + cntx = (struct bg_context *)handle; + + if (cntx->state == BGCOM_PROB_WAIT) { + if (!is_bgcom_ready()) + return -ENODEV; + cntx->bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); + cntx->state = BGCOM_PROB_SUCCESS; + } + bg_spi = cntx->bg_spi; + + if (!bg_spi) + return -ENODEV; + + tx_xfer = &bg_spi->xfer1; + spi = bg_spi->spi; + + if (!atomic_read(&bg_is_spi_active)) + return -ECANCELED; + + mutex_lock(&bg_spi->xfer_mutex); + bg_spi_reinit_xfer(tx_xfer); + tx_xfer->tx_buf = tx_buf; + if (rx_buf) + tx_xfer->rx_buf = rx_buf; + + tx_xfer->len = txn_len; + ret = spi_sync(spi, &bg_spi->msg1); + mutex_unlock(&bg_spi->xfer_mutex); + + if (ret) + pr_err("SPI transaction failed: %d\n", ret); + return ret; +} + +/* BG-COM Interrupt handling */ +static inline +void send_event(enum bgcom_event_type event, + void *data) +{ + struct list_head *pos; + struct cb_data *cb; + + /* send interrupt notification for each + * registered call-back + */ + list_for_each(pos, &cb_head) { + cb = list_entry(pos, struct cb_data, list); + cb->bgcom_notification_cb(cb->handle, + cb->priv, event, data); + } +} + +void bgcom_bgdown_handler(void) +{ + send_event(BGCOM_EVENT_RESET_OCCURRED, NULL); + g_slav_status_reg = 0; +} +EXPORT_SYMBOL(bgcom_bgdown_handler); + +static void parse_fifo(uint8_t *data, union bgcom_event_data_type *event_data) +{ + uint16_t p_len; + uint8_t sub_id; + uint32_t evnt_tm; + uint16_t event_id; + void *evnt_data; + struct event *evnt; + struct event_list *data_list; + + while (*data != '\0') { + + event_id = *((uint16_t *) data); + data = data + HED_EVENT_ID_LEN; + p_len = *((uint16_t *) data); + data = data + HED_EVENT_SIZE_LEN; + + if (event_id == 0xFFFE) { + + sub_id = *data; + evnt_tm = *((uint32_t *)(data+1)); + + evnt = kmalloc(sizeof(*evnt), GFP_KERNEL); + evnt->sub_id = sub_id; + evnt->evnt_tm = evnt_tm; + evnt->evnt_data = + *(int16_t *)(data + HED_EVENT_DATA_STRT_LEN); + + data_list = kmalloc(sizeof(*data_list), GFP_KERNEL); + data_list->evnt = evnt; + spin_lock(&lst_setup_lock); + list_add_tail(&data_list->list, &pr_lst_hd); + spin_unlock(&lst_setup_lock); + } else if (event_id == 0x0001) { + evnt_data = kmalloc(p_len, GFP_KERNEL); + if (evnt_data != NULL) { + memcpy(evnt_data, data, p_len); + event_data->fifo_data.to_master_fifo_used = + p_len/BG_SPI_WORD_SIZE; + event_data->fifo_data.data = evnt_data; + send_event(BGCOM_EVENT_TO_MASTER_FIFO_USED, + event_data); + } + } + data = data + p_len; + } + if (!list_empty(&pr_lst_hd)) + queue_work(wq, &input_work); +} + +static void send_back_notification(uint32_t slav_status_reg, + uint32_t slav_status_auto_clear_reg, + uint32_t fifo_fill_reg, uint32_t fifo_size_reg) +{ + uint16_t master_fifo_used; + uint16_t slave_fifo_free; + uint32_t *ptr; + int ret; + union bgcom_event_data_type event_data = { .fifo_data = {0} }; + + master_fifo_used = (uint16_t)fifo_fill_reg; + slave_fifo_free = (uint16_t)(fifo_fill_reg >> 16); + + if (slav_status_auto_clear_reg & BIT(31)) + send_event(BGCOM_EVENT_RESET_OCCURRED, NULL); + + if (slav_status_auto_clear_reg & BIT(30)) + send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN, NULL); + + if (slav_status_auto_clear_reg & BIT(29)) + send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR, NULL); + + if (slav_status_auto_clear_reg & BIT(28)) + send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_ACCESS, NULL); + + if (slav_status_auto_clear_reg & BIT(27)) + send_event(BGCOM_EVENT_ERROR_READ_FIFO_UNDERRUN, NULL); + + if (slav_status_auto_clear_reg & BIT(26)) + send_event(BGCOM_EVENT_ERROR_READ_FIFO_BUS_ERR, NULL); + + if (slav_status_auto_clear_reg & BIT(25)) + send_event(BGCOM_EVENT_ERROR_READ_FIFO_ACCESS, NULL); + + if (slav_status_auto_clear_reg & BIT(24)) + send_event(BGCOM_EVENT_ERROR_TRUNCATED_READ, NULL); + + if (slav_status_auto_clear_reg & BIT(23)) + send_event(BGCOM_EVENT_ERROR_TRUNCATED_WRITE, NULL); + + if (slav_status_auto_clear_reg & BIT(22)) + send_event(BGCOM_EVENT_ERROR_AHB_ILLEGAL_ADDRESS, NULL); + + if (slav_status_auto_clear_reg & BIT(21)) + send_event(BGCOM_EVENT_ERROR_AHB_BUS_ERR, NULL); + + /* check if BG status is changed */ + if (g_slav_status_reg ^ slav_status_reg) { + if (slav_status_reg & BIT(30)) { + event_data.application_running = true; + send_event(BGCOM_EVENT_APPLICATION_RUNNING, + &event_data); + } + + if (slav_status_reg & BIT(29)) { + event_data.to_slave_fifo_ready = true; + send_event(BGCOM_EVENT_TO_SLAVE_FIFO_READY, + &event_data); + } + + if (slav_status_reg & BIT(28)) { + event_data.to_master_fifo_ready = true; + send_event(BGCOM_EVENT_TO_MASTER_FIFO_READY, + &event_data); + } + + if (slav_status_reg & BIT(27)) { + event_data.ahb_ready = true; + send_event(BGCOM_EVENT_AHB_READY, + &event_data); + } + } + + if (master_fifo_used > 0) { + ptr = kzalloc(master_fifo_used*BG_SPI_WORD_SIZE + 1, + GFP_KERNEL | GFP_ATOMIC); + if (ptr != NULL) { + ret = read_bg_locl(BGCOM_READ_FIFO, + master_fifo_used, ptr); + if (!ret) { + augmnt_fifo((uint8_t *)ptr, + master_fifo_used*BG_SPI_WORD_SIZE); + parse_fifo((uint8_t *)ptr, &event_data); + } + kfree(ptr); + } + } + + event_data.to_slave_fifo_free = slave_fifo_free; + send_event(BGCOM_EVENT_TO_SLAVE_FIFO_FREE, &event_data); +} + +static void bg_irq_tasklet_hndlr_l(void) +{ + uint32_t slave_status_reg; + uint32_t glink_isr_reg; + uint32_t slav_status_auto_clear_reg; + uint32_t fifo_fill_reg; + uint32_t fifo_size_reg; + int ret = 0; + uint32_t irq_buf[5] = {0}; + + ret = read_bg_locl(BGCOM_READ_REG, 5, &irq_buf[0]); + if (ret) + return; + + /* save current state */ + slave_status_reg = irq_buf[0]; + glink_isr_reg = irq_buf[1]; + slav_status_auto_clear_reg = irq_buf[2]; + fifo_fill_reg = irq_buf[3]; + fifo_size_reg = irq_buf[4]; + + send_back_notification(slave_status_reg, + slav_status_auto_clear_reg, fifo_fill_reg, fifo_size_reg); + + g_slav_status_reg = slave_status_reg; +} + +int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, + uint32_t num_words, void *read_buf) +{ + uint32_t txn_len; + uint8_t *tx_buf; + uint8_t *rx_buf; + uint32_t size; + int ret; + uint8_t cmnd = 0; + uint32_t ahb_addr = 0; + + if (!handle || !read_buf || num_words == 0 + || num_words > BG_SPI_MAX_WORDS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + size = num_words*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_AHB_READ_CMD_LEN + size; + + tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + if (!tx_buf) + return -ENOMEM; + + rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + if (!rx_buf) { + kfree(tx_buf); + return -ENOMEM; + } + + cmnd |= BG_SPI_AHB_READ_CMD; + ahb_addr |= ahb_start_addr; + + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + memcpy(tx_buf+sizeof(cmnd), &ahb_addr, sizeof(ahb_addr)); + + ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len); + + if (!ret) + memcpy(read_buf, rx_buf+BG_SPI_AHB_READ_CMD_LEN, size); + + kfree(tx_buf); + kfree(rx_buf); + return ret; +} +EXPORT_SYMBOL(bgcom_ahb_read); + +int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, + uint32_t num_words, void *write_buf) +{ + dma_addr_t dma_hndl; + uint32_t txn_len; + uint8_t *tx_buf; + uint32_t size; + int ret; + bool is_cma_used = false; + uint8_t cmnd = 0; + uint32_t ahb_addr = 0; + struct spi_device *spi = get_spi_device(); + + if (!handle || !write_buf || num_words == 0 + || num_words > BG_SPI_MAX_WORDS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + mutex_lock(&cma_buffer_lock); + size = num_words*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_AHB_CMD_LEN + size; + if (fxd_mem_buffer != NULL && txn_len <= CMA_BFFR_POOL_SIZE) { + memset(fxd_mem_buffer, 0, txn_len); + tx_buf = fxd_mem_buffer; + is_cma_used = true; + } else { + pr_info("DMA memory used for size[%d]\n", txn_len); + tx_buf = dma_zalloc_coherent(&spi->dev, txn_len, + &dma_hndl, GFP_KERNEL); + } + + if (!tx_buf) { + mutex_unlock(&cma_buffer_lock); + return -ENOMEM; + } + + cmnd |= BG_SPI_AHB_WRITE_CMD; + ahb_addr |= ahb_start_addr; + + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + memcpy(tx_buf+sizeof(cmnd), &ahb_addr, sizeof(ahb_addr)); + memcpy(tx_buf+BG_SPI_AHB_CMD_LEN, write_buf, size); + + ret = bgcom_transfer(handle, tx_buf, NULL, txn_len); + if (!is_cma_used) + dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl); + mutex_unlock(&cma_buffer_lock); + return ret; +} +EXPORT_SYMBOL(bgcom_ahb_write); + +int bgcom_fifo_write(void *handle, uint32_t num_words, + void *write_buf) +{ + uint32_t txn_len; + uint8_t *tx_buf; + uint32_t size; + int ret; + uint8_t cmnd = 0; + + if (!handle || !write_buf || num_words == 0 + || num_words > BG_SPI_MAX_WORDS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + size = num_words*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_WRITE_CMND_LEN + size; + + tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + + if (!tx_buf) + return -ENOMEM; + + cmnd |= BG_SPI_FIFO_WRITE_CMD; + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + memcpy(tx_buf+sizeof(cmnd), write_buf, size); + + ret = bgcom_transfer(handle, tx_buf, NULL, txn_len); + kfree(tx_buf); + return ret; +} +EXPORT_SYMBOL(bgcom_fifo_write); + +int bgcom_fifo_read(void *handle, uint32_t num_words, + void *read_buf) +{ + uint32_t txn_len; + uint8_t *tx_buf; + uint8_t *rx_buf; + uint32_t size; + uint8_t cmnd = 0; + int ret = 0; + + if (!handle || !read_buf || num_words == 0 + || num_words > BG_SPI_MAX_WORDS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + size = num_words*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_READ_LEN + size; + tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + + if (!tx_buf) + return -ENOMEM; + + rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + + if (!rx_buf) { + kfree(tx_buf); + return -ENOMEM; + } + + cmnd |= BG_SPI_FIFO_READ_CMD; + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + + ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len); + + if (!ret) + memcpy(read_buf, rx_buf+BG_SPI_READ_LEN, size); + kfree(tx_buf); + kfree(rx_buf); + return ret; +} +EXPORT_SYMBOL(bgcom_fifo_read); + +int bgcom_reg_write(void *handle, uint8_t reg_start_addr, + uint8_t num_regs, void *write_buf) +{ + uint32_t txn_len; + uint8_t *tx_buf; + uint32_t size; + uint8_t cmnd = 0; + int ret = 0; + + if (!handle || !write_buf || num_regs == 0 + || num_regs > BG_SPI_MAX_REGS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + size = num_regs*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_WRITE_CMND_LEN + size; + + tx_buf = kzalloc(txn_len, GFP_KERNEL); + + if (!tx_buf) + return -ENOMEM; + + cmnd |= reg_start_addr; + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + memcpy(tx_buf+sizeof(cmnd), write_buf, size); + + ret = bgcom_transfer(handle, tx_buf, NULL, txn_len); + kfree(tx_buf); + return ret; +} +EXPORT_SYMBOL(bgcom_reg_write); + +int bgcom_reg_read(void *handle, uint8_t reg_start_addr, + uint32_t num_regs, void *read_buf) +{ + uint32_t txn_len; + uint8_t *tx_buf; + uint8_t *rx_buf; + uint32_t size; + int ret; + uint8_t cmnd = 0; + + if (!handle || !read_buf || num_regs == 0 + || num_regs > BG_SPI_MAX_REGS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + size = num_regs*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_READ_LEN + size; + + tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + + if (!tx_buf) + return -ENOMEM; + + rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + + if (!rx_buf) { + kfree(tx_buf); + return -ENOMEM; + } + + cmnd |= reg_start_addr; + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + + ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len); + + if (!ret) + memcpy(read_buf, rx_buf+BG_SPI_READ_LEN, size); + kfree(tx_buf); + kfree(rx_buf); + return ret; +} +EXPORT_SYMBOL(bgcom_reg_read); + +static int is_bg_resume(void *handle) +{ + uint32_t txn_len; + int ret; + uint8_t tx_buf[8] = {0}; + uint8_t rx_buf[8] = {0}; + uint32_t cmnd_reg = 0; + + if (spi_state == BGCOM_SPI_BUSY) { + printk_ratelimited("SPI is held by TZ\n"); + goto ret_err; + } + + txn_len = 0x08; + tx_buf[0] = 0x05; + ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len); + if (!ret) + memcpy(&cmnd_reg, rx_buf+BG_SPI_READ_LEN, 0x04); + +ret_err: + return cmnd_reg & BIT(31); +} + +int bgcom_resume(void *handle) +{ + struct bg_spi_priv *bg_spi; + struct bg_context *cntx; + int retry = 0; + + if (handle == NULL) + return -EINVAL; + + if (!atomic_read(&bg_is_spi_active)) + return -ECANCELED; + + cntx = (struct bg_context *)handle; + + /* if client is outside bgcom scope and + * handle is provided before BGCOM probed + */ + if (cntx->state == BGCOM_PROB_WAIT) { + pr_info("handle is provided before BGCOM probed\n"); + if (!is_bgcom_ready()) + return -EAGAIN; + cntx->bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); + cntx->state = BGCOM_PROB_SUCCESS; + } + + bg_spi = cntx->bg_spi; + + mutex_lock(&bg_resume_mutex); + if (bg_spi->bg_state == BGCOM_STATE_ACTIVE) + goto unlock; + enable_irq(bg_irq); + do { + if (is_bg_resume(handle)) { + bg_spi->bg_state = BGCOM_STATE_ACTIVE; + break; + } + udelay(1000); + ++retry; + } while (retry < MAX_RETRY); + +unlock: + mutex_unlock(&bg_resume_mutex); + if (retry == MAX_RETRY) { + /* BG failed to resume. Trigger BG soft reset. */ + pr_err("BG failed to resume\n"); + pr_err("%s: gpio#95 value is: %d\n", + __func__, gpio_get_value(95)); + pr_err("%s: gpio#97 value is: %d\n", + __func__, gpio_get_value(97)); + BUG(); + bg_soft_reset(); + return -ETIMEDOUT; + } + return 0; +} +EXPORT_SYMBOL(bgcom_resume); + +int bgcom_suspend(void *handle) +{ + if (!handle) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(bgcom_suspend); + +void *bgcom_open(struct bgcom_open_config_type *open_config) +{ + struct bg_spi_priv *spi; + struct cb_data *irq_notification; + struct bg_context *clnt_handle = + kzalloc(sizeof(*clnt_handle), GFP_KERNEL); + + if (!clnt_handle) + return NULL; + + /* Client handle Set-up */ + if (!is_bgcom_ready()) { + clnt_handle->bg_spi = NULL; + clnt_handle->state = BGCOM_PROB_WAIT; + } else { + spi = container_of(bg_com_drv, struct bg_spi_priv, lhandle); + clnt_handle->bg_spi = spi; + clnt_handle->state = BGCOM_PROB_SUCCESS; + } + clnt_handle->cb = NULL; + /* Interrupt callback Set-up */ + if (open_config && open_config->bgcom_notification_cb) { + irq_notification = kzalloc(sizeof(*irq_notification), + GFP_KERNEL); + if (!irq_notification) + goto error_ret; + + /* set irq node */ + irq_notification->handle = clnt_handle; + irq_notification->priv = open_config->priv; + irq_notification->bgcom_notification_cb = + open_config->bgcom_notification_cb; + add_to_irq_list(irq_notification); + clnt_handle->cb = irq_notification; + } + return clnt_handle; + +error_ret: + kfree(clnt_handle); + return NULL; +} +EXPORT_SYMBOL(bgcom_open); + +int bgcom_close(void **handle) +{ + struct bg_context *lhandle; + struct cb_data *cb = NULL; + + if (*handle == NULL) + return -EINVAL; + lhandle = *handle; + cb = lhandle->cb; + if (cb) + list_del(&cb->list); + + kfree(*handle); + *handle = NULL; + return 0; +} +EXPORT_SYMBOL(bgcom_close); + +static irqreturn_t bg_irq_tasklet_hndlr(int irq, void *device) +{ + struct bg_spi_priv *bg_spi = device; + + /* check if call-back exists */ + if (!atomic_read(&bg_is_spi_active)) { + pr_debug("Interrupt received in suspend state\n"); + return IRQ_HANDLED; + } else if (list_empty(&cb_head)) { + pr_debug("No callback registered\n"); + return IRQ_HANDLED; + } else if (spi_state == BGCOM_SPI_BUSY) { + /* delay for SPI to be freed */ + msleep(50); + return IRQ_HANDLED; + } else if (!bg_spi->irq_lock) { + bg_spi->irq_lock = 1; + bg_irq_tasklet_hndlr_l(); + bg_spi->irq_lock = 0; + } + return IRQ_HANDLED; +} + +static void bg_spi_init(struct bg_spi_priv *bg_spi) +{ + if (!bg_spi) { + pr_err("device not found\n"); + return; + } + + /* BGCOM SPI set-up */ + mutex_init(&bg_spi->xfer_mutex); + spi_message_init(&bg_spi->msg1); + spi_message_add_tail(&bg_spi->xfer1, &bg_spi->msg1); + + /* BGCOM IRQ set-up */ + bg_spi->irq_lock = 0; + + spi_state = BGCOM_SPI_FREE; + + wq = create_singlethread_workqueue("input_wq"); + + bg_spi->bg_state = BGCOM_STATE_ACTIVE; + + bg_com_drv = &bg_spi->lhandle; + + mutex_init(&bg_resume_mutex); + + fxd_mem_buffer = kmalloc(CMA_BFFR_POOL_SIZE, GFP_KERNEL | GFP_ATOMIC); + + mutex_init(&cma_buffer_lock); +} + +static int bg_spi_probe(struct spi_device *spi) +{ + struct bg_spi_priv *bg_spi; + struct device_node *node; + int irq_gpio = 0; + int ret; + + bg_spi = devm_kzalloc(&spi->dev, sizeof(*bg_spi), + GFP_KERNEL | GFP_ATOMIC); + + pr_info("%s started\n", __func__); + + if (!bg_spi) + return -ENOMEM; + bg_spi->spi = spi; + spi_set_drvdata(spi, bg_spi); + bg_spi_init(bg_spi); + + /* BGCOM Interrupt probe */ + node = spi->dev.of_node; + irq_gpio = of_get_named_gpio(node, "qcom,irq-gpio", 0); + if (!gpio_is_valid(irq_gpio)) { + pr_err("gpio %d found is not valid\n", irq_gpio); + goto err_ret; + } + + ret = gpio_request(irq_gpio, "bgcom_gpio"); + if (ret) { + pr_err("gpio %d request failed\n", irq_gpio); + goto err_ret; + } + + ret = gpio_direction_input(irq_gpio); + if (ret) { + pr_err("gpio_direction_input not set: %d\n", ret); + goto err_ret; + } + + bg_irq = gpio_to_irq(irq_gpio); + ret = request_threaded_irq(bg_irq, NULL, bg_irq_tasklet_hndlr, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "qcom-bg_spi", bg_spi); + + if (ret) + goto err_ret; + + atomic_set(&bg_is_spi_active, 1); + dma_set_coherent_mask(&spi->dev, DMA_BIT_MASK(64)); + pr_info("%s success\n", __func__); + pr_info("Bgcom Probed successfully\n"); + return ret; + +err_ret: + bg_com_drv = NULL; + mutex_destroy(&bg_spi->xfer_mutex); + spi_set_drvdata(spi, NULL); + return -ENODEV; +} + +static int bg_spi_remove(struct spi_device *spi) +{ + struct bg_spi_priv *bg_spi = spi_get_drvdata(spi); + + bg_com_drv = NULL; + mutex_destroy(&bg_spi->xfer_mutex); + devm_kfree(&spi->dev, bg_spi); + spi_set_drvdata(spi, NULL); + if (fxd_mem_buffer != NULL) + kfree(fxd_mem_buffer); + mutex_destroy(&cma_buffer_lock); + return 0; +} + +static void bg_spi_shutdown(struct spi_device *spi) +{ + bg_spi_remove(spi); +} + +static int bgcom_pm_suspend(struct device *dev) +{ + uint32_t cmnd_reg = 0; + struct spi_device *s_dev = to_spi_device(dev); + struct bg_spi_priv *bg_spi = spi_get_drvdata(s_dev); + int ret = 0; + + if (bg_spi->bg_state == BGCOM_STATE_SUSPEND) + return 0; + + cmnd_reg |= BIT(31); + ret = read_bg_locl(BGCOM_WRITE_REG, 1, &cmnd_reg); + if (ret == 0) { + bg_spi->bg_state = BGCOM_STATE_SUSPEND; + atomic_set(&bg_is_spi_active, 0); + disable_irq(bg_irq); + } + pr_info("suspended with : %d\n", ret); + return ret; +} + +static int bgcom_pm_resume(struct device *dev) +{ + struct bg_context clnt_handle; + int ret; + struct bg_spi_priv *spi = + container_of(bg_com_drv, struct bg_spi_priv, lhandle); + + clnt_handle.bg_spi = spi; + atomic_set(&bg_is_spi_active, 1); + ret = bgcom_resume(&clnt_handle); + pr_info("Bgcom resumed with : %d\n", ret); + return ret; +} + +static const struct dev_pm_ops bgcom_pm = { + .suspend = bgcom_pm_suspend, + .resume = bgcom_pm_resume, +}; + +static const struct of_device_id bg_spi_of_match[] = { + { .compatible = "qcom,bg-spi", }, + { } +}; +MODULE_DEVICE_TABLE(of, bg_spi_of_match); + +static struct spi_driver bg_spi_driver = { + .driver = { + .name = "bg-spi", + .of_match_table = bg_spi_of_match, + .pm = &bgcom_pm, + }, + .probe = bg_spi_probe, + .remove = bg_spi_remove, + .shutdown = bg_spi_shutdown, +}; + +module_spi_driver(bg_spi_driver); +MODULE_DESCRIPTION("bg SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/bgrsb.h b/drivers/soc/qcom/bgrsb.h new file mode 100644 index 0000000000000000000000000000000000000000..93a58b34bd28a673d223fb665bc1babde1142047 --- /dev/null +++ b/drivers/soc/qcom/bgrsb.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2017-2018,2020 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. + * + */ + +#ifndef BGRSB_H +#define BGRSB_H + +struct event { + uint8_t sub_id; + int16_t evnt_data; + uint32_t evnt_tm; +}; + + +struct bg_glink_chnl { + char *chnl_name; + char *chnl_edge; + char *chnl_trnsprt; +}; + +/** + * bgrsb_send_input() - send the recived input to input framework + * @evnt: pointer to the event structure + */ +int bgrsb_send_input(struct event *evnt); + +#endif /* BGCOM_H */ diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c index e408cc4b087e6389d64655aa313cca07ffce2454..4ce4eb0bddb3bd4b10915ebf6954a57fc0f37d63 100644 --- a/drivers/soc/qcom/dcc_v2.c +++ b/drivers/soc/qcom/dcc_v2.c @@ -114,6 +114,22 @@ struct rpm_trig_req { uint32_t reserved; }; +/** + * struct dcc_save_state - state to be preserved when dcc is without power + */ +struct dcc_save_state { + uint32_t dcc_exec_ctrl; + uint32_t dcc_cfg; + uint32_t dcc_ll_lock[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_cfg[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_base[DCC_MAX_LINK_LIST]; + uint32_t dcc_fd_base[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_timeout[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_int_enable[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_int_status[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_sw_trigger[DCC_MAX_LINK_LIST]; +}; + struct dcc_config_entry { uint32_t base; uint32_t offset; @@ -150,6 +166,8 @@ struct dcc_drvdata { uint8_t curr_list; uint8_t cti_trig; uint8_t loopoff; + struct dcc_save_state *reg_save_state; + void *sram_save_state; }; static int dcc_sram_writel(struct dcc_drvdata *drvdata, @@ -1843,6 +1861,136 @@ static int dcc_remove(struct platform_device *pdev) return 0; } +static int dcc_v2_freeze(struct device *dev) +{ + int i; + struct dcc_save_state *state; + struct dcc_drvdata *drvdata = dev_get_drvdata(dev); + + if (!drvdata) + return -EINVAL; + + drvdata->reg_save_state = kmalloc(sizeof(struct dcc_save_state), + GFP_KERNEL); + if (!drvdata->reg_save_state) + return -ENOMEM; + + state = drvdata->reg_save_state; + + mutex_lock(&drvdata->mutex); + + state->dcc_exec_ctrl = dcc_readl(drvdata, DCC_EXEC_CTRL); + state->dcc_cfg = dcc_readl(drvdata, DCC_CFG); + + for (i = 0; i < DCC_MAX_LINK_LIST; i++) { + state->dcc_ll_lock[i] = dcc_readl(drvdata, + DCC_LL_LOCK(i)); + state->dcc_ll_cfg[i] = dcc_readl(drvdata, + DCC_LL_CFG(i)); + state->dcc_ll_base[i] = dcc_readl(drvdata, + DCC_LL_BASE(i)); + state->dcc_fd_base[i] = dcc_readl(drvdata, + DCC_FD_BASE(i)); + state->dcc_ll_timeout[i] = dcc_readl(drvdata, + DCC_LL_TIMEOUT(i)); + state->dcc_ll_int_enable[i] = dcc_readl(drvdata, + DCC_LL_INT_ENABLE(i)); + state->dcc_ll_int_status[i] = dcc_readl(drvdata, + DCC_LL_INT_STATUS(i)); + } + + mutex_unlock(&drvdata->mutex); + + drvdata->sram_save_state = kmalloc(drvdata->ram_size, GFP_KERNEL); + if (!drvdata->sram_save_state) + return -ENOMEM; + + if (dcc_sram_memcpy(drvdata->sram_save_state, drvdata->ram_base, + drvdata->ram_size)) { + dev_info(dev, "Failed to copy DCC SRAM contents\n"); + } + + if (drvdata->enable[drvdata->curr_list]) + drvdata->enable[drvdata->curr_list] = 0; + + return 0; +} + +static int dcc_v2_restore(struct device *dev) +{ + int i; + int *data; + struct dcc_save_state *state; + struct dcc_drvdata *drvdata = dev_get_drvdata(dev); + + if (!drvdata || !drvdata->sram_save_state || !drvdata->reg_save_state) + return -EINVAL; + + data = drvdata->sram_save_state; + + for (i = 0; i < drvdata->ram_size / 4; i++) + __raw_writel_no_log(data[i], + drvdata->ram_base + (i * 4)); + + state = drvdata->reg_save_state; + + mutex_lock(&drvdata->mutex); + + dcc_writel(drvdata, state->dcc_exec_ctrl, DCC_EXEC_CTRL); + dcc_writel(drvdata, state->dcc_cfg, DCC_CFG); + + for (i = 0; i < DCC_MAX_LINK_LIST; i++) { + + if (dcc_valid_list(drvdata, i)) + continue; + + dcc_writel(drvdata, BIT(0), DCC_LL_LOCK(i)); + dcc_writel(drvdata, state->dcc_ll_base[i], DCC_LL_BASE(i)); + dcc_writel(drvdata, state->dcc_fd_base[i], DCC_FD_BASE(i)); + dcc_writel(drvdata, state->dcc_ll_timeout[i], + DCC_LL_TIMEOUT(i)); + dcc_writel(drvdata, state->dcc_ll_int_enable[i], + DCC_LL_INT_ENABLE(i)); + dcc_writel(drvdata, state->dcc_ll_int_status[i], + DCC_LL_INT_STATUS(i)); + /* Make sure all config is written in sram */ + mb(); + dcc_writel(drvdata, state->dcc_ll_cfg[i], DCC_LL_CFG(i)); + } + + mutex_unlock(&drvdata->mutex); + + if (drvdata->enable[drvdata->curr_list]) + drvdata->enable[drvdata->curr_list] = 1; + + kfree(drvdata->sram_save_state); + kfree(drvdata->reg_save_state); + + return 0; +} + +static int dcc_v2_thaw(struct device *dev) +{ + struct dcc_drvdata *drvdata = dev_get_drvdata(dev); + + if (!drvdata) + return -EINVAL; + + if (drvdata->enable[drvdata->curr_list]) + drvdata->enable[drvdata->curr_list] = 1; + + kfree(drvdata->sram_save_state); + kfree(drvdata->reg_save_state); + + return 0; +} + +static const struct dev_pm_ops dcc_v2_pm_ops = { + .freeze = dcc_v2_freeze, + .restore = dcc_v2_restore, + .thaw = dcc_v2_thaw, +}; + static const struct of_device_id msm_dcc_match[] = { { .compatible = "qcom,dcc-v2"}, {} @@ -1854,6 +2002,7 @@ static struct platform_driver dcc_driver = { .driver = { .name = "msm-dcc", .owner = THIS_MODULE, + .pm = &dcc_v2_pm_ops, .of_match_table = msm_dcc_match, }, }; diff --git a/drivers/soc/qcom/dfc_qmi.c b/drivers/soc/qcom/dfc_qmi.c index cca126db23f6a79e791ca5c6ca224a0da553da7f..ef4470ea9445762425b672254da9bba311ee6d7a 100644 --- a/drivers/soc/qcom/dfc_qmi.c +++ b/drivers/soc/qcom/dfc_qmi.c @@ -1034,14 +1034,18 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, itm->grant_size = adjusted_grant; /* No further query if the adjusted grant is less - * than 20% of the original grant + * than 20% of the original grant. Add to watch to + * recover if no indication is received. */ if (dfc_qmap && is_query && - itm->grant_size < (fc_info->num_bytes / 5)) + itm->grant_size < (fc_info->num_bytes / 5)) { itm->grant_thresh = itm->grant_size; - else + qmi_rmnet_watchdog_add(itm); + } else { itm->grant_thresh = qmi_rmnet_grant_per(itm->grant_size); + qmi_rmnet_watchdog_remove(itm); + } itm->seq = fc_info->seq_num; itm->ack_req = ack_req; @@ -1143,6 +1147,7 @@ static void dfc_update_tx_link_status(struct net_device *dev, itm->grant_size = 0; itm->tcp_bidir = false; itm->bytes_in_flight = 0; + qmi_rmnet_watchdog_remove(itm); dfc_bearer_flow_ctl(dev, itm, qos); } else if (itm->grant_size == 0 && tx_status && !itm->rat_switch) { itm->grant_size = DEFAULT_GRANT; diff --git a/drivers/soc/qcom/hgsl/hgsl.c b/drivers/soc/qcom/hgsl/hgsl.c index 60070a4c6f017b00856abc24d1a9f42718219722..80f9b7436ca5365d33efcd848e4ca809199f5082 100644 --- a/drivers/soc/qcom/hgsl/hgsl.c +++ b/drivers/soc/qcom/hgsl/hgsl.c @@ -226,7 +226,9 @@ struct hgsl_db_cmds { uint32_t ctx_id; uint32_t cmd_flags; uint32_t timestamp; + uint64_t user_profile_gpuaddr; uint32_t num_ibs; + uint32_t ib_desc_gmuaddr; struct hgsl_fw_ib_desc ib_descs[]; } __packed; diff --git a/drivers/soc/qcom/pil_bg_intf.h b/drivers/soc/qcom/pil_bg_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..d0781d5f5f32104edccb3cd0cfa533bbfcb3bf2e --- /dev/null +++ b/drivers/soc/qcom/pil_bg_intf.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2017-2018, 2020, 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. + */ + +#ifndef __BG_INTF_H_ +#define __BG_INTF_H_ + +#define MAX_APP_NAME_SIZE 100 +#define RESULT_SUCCESS 0 +#define RESULT_FAILURE -1 + +/* tzapp command list.*/ +enum bg_tz_commands { + BGPIL_RAMDUMP, + BGPIL_IMAGE_LOAD, + BGPIL_AUTH_MDT, + BGPIL_DLOAD_CONT, + BGPIL_GET_BG_VERSION, +}; + +/* tzapp bg request.*/ +struct tzapp_bg_req { + uint8_t tzapp_bg_cmd; + uint8_t padding[3]; + phys_addr_t address_fw; + size_t size_fw; +} __attribute__ ((__packed__)); + +/* tzapp bg response.*/ +struct tzapp_bg_rsp { + uint32_t tzapp_bg_cmd; + uint32_t bg_info_len; + int32_t status; + uint32_t bg_info[100]; +} __attribute__ ((__packed__)); + +#endif diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c index 4a2c7449f46f991a4a88b8d7d842fb35abcaff3c..3ff4f8d94c0286bc55af1152f1f54a08104a181c 100644 --- a/drivers/soc/qcom/qmi_rmnet.c +++ b/drivers/soc/qcom/qmi_rmnet.c @@ -55,6 +55,7 @@ MODULE_PARM_DESC(rmnet_wq_frequency, "Frequency of PS check in ms"); 1 : rmnet_wq_frequency/10) * (HZ/100)) #define NO_DELAY (0x0000 * HZ) #define PS_INTERVAL_KT (ms_to_ktime(1000)) +#define WATCHDOG_EXPIRE_JF (msecs_to_jiffies(50)) #ifdef CONFIG_QCOM_QMI_DFC static unsigned int qmi_rmnet_scale_factor = 5; @@ -235,6 +236,89 @@ static void qmi_rmnet_reset_txq(struct net_device *dev, unsigned int txq) } } +/** + * qmi_rmnet_watchdog_fn - watchdog timer func + */ +static void qmi_rmnet_watchdog_fn(struct timer_list *t) +{ + struct rmnet_bearer_map *bearer; + + bearer = container_of(t, struct rmnet_bearer_map, watchdog); + + trace_dfc_watchdog(bearer->qos->mux_id, bearer->bearer_id, 2); + + spin_lock_bh(&bearer->qos->qos_lock); + + if (bearer->watchdog_quit) + goto done; + + /* + * Possible stall, try to recover. Enable 80% query and jumpstart + * the bearer if disabled. + */ + bearer->watchdog_expire_cnt++; + bearer->bytes_in_flight = 0; + if (!bearer->grant_size) { + bearer->grant_size = DEFAULT_GRANT; + bearer->grant_thresh = qmi_rmnet_grant_per(bearer->grant_size); + dfc_bearer_flow_ctl(bearer->qos->vnd_dev, bearer, bearer->qos); + } else { + bearer->grant_thresh = qmi_rmnet_grant_per(bearer->grant_size); + } + +done: + bearer->watchdog_started = false; + spin_unlock_bh(&bearer->qos->qos_lock); +} + +/** + * qmi_rmnet_watchdog_add - add the bearer to watch + * Needs to be called with qos_lock + */ +void qmi_rmnet_watchdog_add(struct rmnet_bearer_map *bearer) +{ + bearer->watchdog_quit = false; + + if (bearer->watchdog_started) + return; + + bearer->watchdog_started = true; + mod_timer(&bearer->watchdog, jiffies + WATCHDOG_EXPIRE_JF); + + trace_dfc_watchdog(bearer->qos->mux_id, bearer->bearer_id, 1); +} + +/** + * qmi_rmnet_watchdog_remove - remove the bearer from watch + * Needs to be called with qos_lock + */ +void qmi_rmnet_watchdog_remove(struct rmnet_bearer_map *bearer) +{ + bearer->watchdog_quit = true; + + if (!bearer->watchdog_started) + return; + + if (try_to_del_timer_sync(&bearer->watchdog) >= 0) + bearer->watchdog_started = false; + + trace_dfc_watchdog(bearer->qos->mux_id, bearer->bearer_id, 0); +} + +/** + * qmi_rmnet_bearer_clean - clean the removed bearer + * Needs to be called with rtn_lock but not qos_lock + */ +static void qmi_rmnet_bearer_clean(struct qos_info *qos) +{ + if (qos->removed_bearer) { + qos->removed_bearer->watchdog_quit = true; + del_timer_sync(&qos->removed_bearer->watchdog); + kfree(qos->removed_bearer); + qos->removed_bearer = NULL; + } +} + static struct rmnet_bearer_map *__qmi_rmnet_bearer_get( struct qos_info *qos_info, u8 bearer_id) { @@ -254,6 +338,8 @@ static struct rmnet_bearer_map *__qmi_rmnet_bearer_get( bearer->grant_thresh = qmi_rmnet_grant_per(bearer->grant_size); bearer->mq_idx = INVALID_MQ; bearer->ack_mq_idx = INVALID_MQ; + bearer->qos = qos_info; + timer_setup(&bearer->watchdog, qmi_rmnet_watchdog_fn, 0); list_add(&bearer->list, &qos_info->bearer_head); } @@ -289,7 +375,7 @@ static void __qmi_rmnet_bearer_put(struct net_device *dev, /* Remove from bearer map */ list_del(&bearer->list); - kfree(bearer); + qos_info->removed_bearer = bearer; } } @@ -420,6 +506,9 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, done: spin_unlock_bh(&qos_info->qos_lock); + + qmi_rmnet_bearer_clean(qos_info); + return rc; } @@ -463,6 +552,9 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, netif_tx_wake_all_queues(dev); spin_unlock_bh(&qos_info->qos_lock); + + qmi_rmnet_bearer_clean(qos_info); + return 0; } @@ -744,6 +836,8 @@ void qmi_rmnet_enable_all_flows(struct net_device *dev) bearer->tcp_bidir = false; bearer->rat_switch = false; + qmi_rmnet_watchdog_remove(bearer); + if (bearer->tx_off) continue; @@ -906,7 +1000,8 @@ inline unsigned int qmi_rmnet_grant_per(unsigned int grant) } EXPORT_SYMBOL(qmi_rmnet_grant_per); -void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) +void *qmi_rmnet_qos_init(struct net_device *real_dev, + struct net_device *vnd_dev, u8 mux_id) { struct qos_info *qos; @@ -916,6 +1011,7 @@ void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) qos->mux_id = mux_id; qos->real_dev = real_dev; + qos->vnd_dev = vnd_dev; qos->tran_num = 0; INIT_LIST_HEAD(&qos->flow_head); INIT_LIST_HEAD(&qos->bearer_head); @@ -927,10 +1023,18 @@ EXPORT_SYMBOL(qmi_rmnet_qos_init); void qmi_rmnet_qos_exit_pre(void *qos) { + struct qos_info *qosi = (struct qos_info *)qos; + struct rmnet_bearer_map *bearer; + if (!qos) return; - list_add(&((struct qos_info *)qos)->list, &qos_cleanup_list); + list_for_each_entry(bearer, &qosi->bearer_head, list) { + bearer->watchdog_quit = true; + del_timer_sync(&bearer->watchdog); + } + + list_add(&qosi->list, &qos_cleanup_list); } EXPORT_SYMBOL(qmi_rmnet_qos_exit_pre); @@ -952,6 +1056,7 @@ EXPORT_SYMBOL(qmi_rmnet_qos_exit_post); static struct workqueue_struct *rmnet_ps_wq; static struct rmnet_powersave_work *rmnet_work; static bool rmnet_work_quit; +static bool rmnet_work_inited; static LIST_HEAD(ps_list); struct rmnet_powersave_work { @@ -1162,7 +1267,7 @@ void qmi_rmnet_work_init(void *port) return; rmnet_ps_wq = alloc_workqueue("rmnet_powersave_work", - WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1); + WQ_CPU_INTENSIVE, 1); if (!rmnet_ps_wq) return; @@ -1182,6 +1287,7 @@ void qmi_rmnet_work_init(void *port) rmnet_work_quit = false; qmi_rmnet_work_set_active(rmnet_work->port, 1); queue_delayed_work(rmnet_ps_wq, &rmnet_work->work, PS_INTERVAL); + rmnet_work_inited = true; } EXPORT_SYMBOL(qmi_rmnet_work_init); @@ -1190,7 +1296,7 @@ void qmi_rmnet_work_maybe_restart(void *port) struct qmi_info *qmi; qmi = (struct qmi_info *)rmnet_get_qmi_pt(port); - if (unlikely(!qmi)) + if (unlikely(!qmi || !rmnet_work_inited)) return; if (!test_and_set_bit(PS_WORK_ACTIVE_BIT, &qmi->ps_work_active)) @@ -1206,6 +1312,7 @@ void qmi_rmnet_work_exit(void *port) rmnet_work_quit = true; synchronize_rcu(); + rmnet_work_inited = false; alarm_cancel(&rmnet_work->atimer); cancel_delayed_work_sync(&rmnet_work->work); destroy_workqueue(rmnet_ps_wq); diff --git a/drivers/soc/qcom/qmi_rmnet_i.h b/drivers/soc/qcom/qmi_rmnet_i.h index 844dafe0b3334b184d8468d79dd4492ebbccf2de..d28c5c99aaeef2cd83dbcc3620467e30f310c961 100644 --- a/drivers/soc/qcom/qmi_rmnet_i.h +++ b/drivers/soc/qcom/qmi_rmnet_i.h @@ -16,6 +16,7 @@ #include #include +#include #define MAX_MQ_NUM 16 #define MAX_CLIENT_NUM 2 @@ -33,6 +34,8 @@ extern int dfc_mode; extern int dfc_qmap; +struct qos_info; + struct rmnet_bearer_map { struct list_head list; u8 bearer_id; @@ -51,6 +54,11 @@ struct rmnet_bearer_map { u32 ack_txid; u32 mq_idx; u32 ack_mq_idx; + struct qos_info *qos; + struct timer_list watchdog; + bool watchdog_started; + bool watchdog_quit; + u32 watchdog_expire_cnt; }; struct rmnet_flow_map { @@ -76,11 +84,13 @@ struct qos_info { struct list_head list; u8 mux_id; struct net_device *real_dev; + struct net_device *vnd_dev; struct list_head flow_head; struct list_head bearer_head; struct mq_map mq[MAX_MQ_NUM]; u32 tran_num; spinlock_t qos_lock; + struct rmnet_bearer_map *removed_bearer; }; struct qmi_info { @@ -151,6 +161,11 @@ void dfc_qmap_send_ack(struct qos_info *qos, u8 bearer_id, u16 seq, u8 type); struct rmnet_bearer_map *qmi_rmnet_get_bearer_noref(struct qos_info *qos_info, u8 bearer_id); + +void qmi_rmnet_watchdog_add(struct rmnet_bearer_map *bearer); + +void qmi_rmnet_watchdog_remove(struct rmnet_bearer_map *bearer); + #else static inline struct rmnet_flow_map * qmi_rmnet_get_flow_map(struct qos_info *qos_info, @@ -194,6 +209,10 @@ dfc_qmap_client_init(void *port, int index, struct svc_info *psvc, static inline void dfc_qmap_client_exit(void *dfc_data) { } + +static inline void qmi_rmnet_watchdog_remove(struct rmnet_bearer_map *bearer) +{ +} #endif #ifdef CONFIG_QCOM_QMI_POWER_COLLAPSE diff --git a/drivers/soc/qcom/sdx_ext_ipc.c b/drivers/soc/qcom/sdx_ext_ipc.c index 0118f4a33fa63eebac201d811d502a7ec7e56963..9e4ee937b03f177c4853e275ea1146fdebb590a1 100644 --- a/drivers/soc/qcom/sdx_ext_ipc.c +++ b/drivers/soc/qcom/sdx_ext_ipc.c @@ -17,7 +17,7 @@ #include #include #include - +#include enum subsys_policies { SUBSYS_PANIC = 0, @@ -30,26 +30,32 @@ static const char * const policies[] = { }; enum gpios { - AP2MDM_STATUS = 0, - MDM2AP_STATUS, - MDM2AP_STATUS2, + STATUS_IN = 0, + STATUS_OUT, + STATUS_OUT2, + WAKEUP_OUT, + WAKEUP_IN, NUM_GPIOS, }; static const char * const gpio_map[] = { - [AP2MDM_STATUS] = "qcom,ap2mdm-status-gpio", - [MDM2AP_STATUS] = "qcom,mdm2ap-status-gpio", - [MDM2AP_STATUS2] = "qcom,mdm2ap-status2-gpio", + [STATUS_IN] = "qcom,status-in-gpio", + [STATUS_OUT] = "qcom,status-out-gpio", + [STATUS_OUT2] = "qcom,status-out2-gpio", + [WAKEUP_OUT] = "qcom,wakeup-gpio-out", + [WAKEUP_IN] = "qcom,wakeup-gpio-in", }; struct gpio_cntrl { unsigned int gpios[NUM_GPIOS]; int status_irq; + int wakeup_irq; int policy; struct device *dev; struct mutex policy_lock; struct mutex e911_lock; struct notifier_block panic_blk; + struct notifier_block sideband_nb; }; static ssize_t policy_show(struct device *dev, struct device_attribute *attr, @@ -94,8 +100,11 @@ static ssize_t e911_show(struct device *dev, struct device_attribute *attr, int ret, state; struct gpio_cntrl *mdm = dev_get_drvdata(dev); + if (mdm->gpios[STATUS_OUT2] < 0) + return -ENXIO; + mutex_lock(&mdm->e911_lock); - state = gpio_get_value(mdm->gpios[MDM2AP_STATUS2]); + state = gpio_get_value(mdm->gpios[STATUS_OUT2]); ret = scnprintf(buf, 2, "%d\n", state); mutex_unlock(&mdm->e911_lock); @@ -111,28 +120,51 @@ static ssize_t e911_store(struct device *dev, struct device_attribute *attr, if (kstrtoint(buf, 0, &e911)) return -EINVAL; + if (mdm->gpios[STATUS_OUT2] < 0) + return -ENXIO; + mutex_lock(&mdm->e911_lock); if (e911) - gpio_set_value(mdm->gpios[MDM2AP_STATUS2], 1); + gpio_set_value(mdm->gpios[STATUS_OUT2], 1); else - gpio_set_value(mdm->gpios[MDM2AP_STATUS2], 0); + gpio_set_value(mdm->gpios[STATUS_OUT2], 0); mutex_unlock(&mdm->e911_lock); return count; } static DEVICE_ATTR_RW(e911); +static int sideband_notify(struct notifier_block *nb, + unsigned long action, void *dev) +{ + struct gpio_cntrl *mdm = container_of(nb, + struct gpio_cntrl, sideband_nb); + + switch (action) { + + case EVT_WAKE_UP: + gpio_set_value(mdm->gpios[WAKEUP_OUT], 1); + usleep_range(10000, 20000); + gpio_set_value(mdm->gpios[WAKEUP_OUT], 0); + break; + default: + dev_info(mdm->dev, "Invalid action passed %d\n", + action); + } + return NOTIFY_OK; +} + static irqreturn_t ap_status_change(int irq, void *dev_id) { struct gpio_cntrl *mdm = dev_id; int state; - struct gpio_desc *gp_status = gpio_to_desc(mdm->gpios[AP2MDM_STATUS]); + struct gpio_desc *gp_status = gpio_to_desc(mdm->gpios[STATUS_IN]); int active_low = 0; if (gp_status) active_low = gpiod_is_active_low(gp_status); - state = gpio_get_value(mdm->gpios[AP2MDM_STATUS]); + state = gpio_get_value(mdm->gpios[STATUS_IN]); if ((!active_low && !state) || (active_low && state)) { if (mdm->policy) dev_info(mdm->dev, "Host undergoing SSR, leaving SDX as it is\n"); @@ -144,6 +176,12 @@ static irqreturn_t ap_status_change(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t sdx_ext_ipc_wakeup_irq(int irq, void *dev_id) +{ + pr_info("%s: Received\n", __func__); + return IRQ_HANDLED; +} + static void remove_ipc(struct gpio_cntrl *mdm) { int i; @@ -162,37 +200,76 @@ static int setup_ipc(struct gpio_cntrl *mdm) node = mdm->dev->of_node; for (i = 0; i < ARRAY_SIZE(gpio_map); i++) { val = of_get_named_gpio(node, gpio_map[i], 0); - if (val >= 0) - mdm->gpios[i] = val; + mdm->gpios[i] = (val >= 0) ? val : -1; } - ret = gpio_request(mdm->gpios[AP2MDM_STATUS], "AP2MDM_STATUS"); - if (ret) { - dev_err(mdm->dev, "Failed to configure AP2MDM_STATUS gpio\n"); - return ret; - } - gpio_direction_input(mdm->gpios[AP2MDM_STATUS]); + if (mdm->gpios[STATUS_IN] >= 0) { + ret = gpio_request(mdm->gpios[STATUS_IN], "STATUS_IN"); + if (ret) { + dev_err(mdm->dev, + "Failed to configure STATUS_IN gpio\n"); + return ret; + } + gpio_direction_input(mdm->gpios[STATUS_IN]); - ret = gpio_request(mdm->gpios[MDM2AP_STATUS], "MDM2AP_STATUS"); - if (ret) { - dev_err(mdm->dev, "Failed to configure MDM2AP_STATUS gpio\n"); - return ret; - } - gpio_direction_output(mdm->gpios[MDM2AP_STATUS], 1); + irq = gpio_to_irq(mdm->gpios[STATUS_IN]); + if (irq < 0) { + dev_err(mdm->dev, "bad STATUS_IN IRQ resource\n"); + return irq; + } + mdm->status_irq = irq; + } else + dev_info(mdm->dev, "STATUS_IN not used\n"); - ret = gpio_request(mdm->gpios[MDM2AP_STATUS2], "MDM2AP_STATUS2"); - if (ret) { - dev_err(mdm->dev, "Failed to configure MDM2AP_STATUS2 gpio\n"); - return ret; - } - gpio_direction_output(mdm->gpios[MDM2AP_STATUS2], 0); + if (mdm->gpios[STATUS_OUT] >= 0) { + ret = gpio_request(mdm->gpios[STATUS_OUT], "STATUS_OUT"); + if (ret) { + dev_err(mdm->dev, "Failed to configure STATUS_OUT gpio\n"); + return ret; + } + gpio_direction_output(mdm->gpios[STATUS_OUT], 1); + } else + dev_info(mdm->dev, "STATUS_OUT not used\n"); + + if (mdm->gpios[STATUS_OUT2] >= 0) { + ret = gpio_request(mdm->gpios[STATUS_OUT2], + "STATUS_OUT2"); + if (ret) { + dev_err(mdm->dev, "Failed to configure STATUS_OUT2 gpio\n"); + return ret; + } + gpio_direction_output(mdm->gpios[STATUS_OUT2], 0); + } else + dev_info(mdm->dev, "STATUS_OUT2 not used\n"); - irq = gpio_to_irq(mdm->gpios[AP2MDM_STATUS]); - if (irq < 0) { - dev_err(mdm->dev, "bad AP2MDM_STATUS IRQ resource\n"); - return irq; - } - mdm->status_irq = irq; + if (mdm->gpios[WAKEUP_OUT] >= 0) { + ret = gpio_request(mdm->gpios[WAKEUP_OUT], "WAKEUP_OUT"); + + if (ret) { + dev_err(mdm->dev, "Failed to configure WAKEUP_OUT gpio\n"); + return ret; + } + gpio_direction_output(mdm->gpios[WAKEUP_OUT], 0); + } else + dev_info(mdm->dev, "WAKEUP_OUT not used\n"); + + if (mdm->gpios[WAKEUP_IN] >= 0) { + ret = gpio_request(mdm->gpios[WAKEUP_IN], "WAKEUP_IN"); + + if (ret) { + dev_warn(mdm->dev, "Failed to configure WAKEUP_IN gpio\n"); + return ret; + } + gpio_direction_input(mdm->gpios[WAKEUP_IN]); + + irq = gpio_to_irq(mdm->gpios[WAKEUP_IN]); + if (irq < 0) { + dev_err(mdm->dev, "bad AP2MDM_STATUS IRQ resource\n"); + return irq; + } + mdm->wakeup_irq = irq; + } else + dev_info(mdm->dev, "WAKEUP_IN not used\n"); return 0; } @@ -203,7 +280,7 @@ static int sdx_ext_ipc_panic(struct notifier_block *this, struct gpio_cntrl *mdm = container_of(this, struct gpio_cntrl, panic_blk); - gpio_set_value(mdm->gpios[MDM2AP_STATUS], 0); + gpio_set_value(mdm->gpios[STATUS_OUT], 0); return NOTIFY_DONE; } @@ -227,8 +304,11 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) return ret; } - mdm->panic_blk.notifier_call = sdx_ext_ipc_panic; - atomic_notifier_chain_register(&panic_notifier_list, &mdm->panic_blk); + if (mdm->gpios[STATUS_OUT] >= 0) { + mdm->panic_blk.notifier_call = sdx_ext_ipc_panic; + atomic_notifier_chain_register(&panic_notifier_list, + &mdm->panic_blk); + } mutex_init(&mdm->policy_lock); mutex_init(&mdm->e911_lock); @@ -251,15 +331,45 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mdm); - ret = devm_request_irq(mdm->dev, mdm->status_irq, ap_status_change, + if (mdm->gpios[STATUS_IN] >= 0) { + ret = devm_request_irq(mdm->dev, mdm->status_irq, + ap_status_change, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "ap status", mdm); - if (ret < 0) { - dev_err(mdm->dev, "%s: AP2MDM_STATUS IRQ#%d request failed,\n", - __func__, mdm->status_irq); - goto irq_fail; + "ap status", mdm); + if (ret < 0) { + dev_err(mdm->dev, + "%s: STATUS_IN IRQ#%d request failed,\n", + __func__, mdm->status_irq); + goto irq_fail; + } + irq_set_irq_wake(mdm->status_irq, 1); + } + + if (mdm->gpios[WAKEUP_IN] >= 0) { + ret = devm_request_threaded_irq(mdm->dev, mdm->wakeup_irq, + NULL, sdx_ext_ipc_wakeup_irq, + IRQF_TRIGGER_FALLING, "sdx_ext_ipc_wakeup", + mdm); + if (ret < 0) { + dev_err(mdm->dev, + "%s: WAKEUP_IN IRQ#%d request failed,\n", + __func__, mdm->status_irq); + goto irq_fail; + } + disable_irq(mdm->wakeup_irq); + } + + if (mdm->gpios[WAKEUP_OUT] >= 0) { + mdm->sideband_nb.notifier_call = sideband_notify; + ret = sb_register_evt_listener(&mdm->sideband_nb); + if (ret) { + dev_err(mdm->dev, + "%s: sb_register_evt_listener failed!\n", + __func__); + goto irq_fail; + } } - irq_set_irq_wake(mdm->status_irq, 1); + return 0; irq_fail: @@ -267,7 +377,9 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) sys_fail1: device_remove_file(mdm->dev, &dev_attr_e911); sys_fail: - atomic_notifier_chain_unregister(&panic_notifier_list, &mdm->panic_blk); + if (mdm->gpios[STATUS_OUT] >= 0) + atomic_notifier_chain_unregister(&panic_notifier_list, + &mdm->panic_blk); remove_ipc(mdm); devm_kfree(&pdev->dev, mdm); return ret; @@ -278,13 +390,41 @@ static int sdx_ext_ipc_remove(struct platform_device *pdev) struct gpio_cntrl *mdm; mdm = dev_get_drvdata(&pdev->dev); - disable_irq_wake(mdm->status_irq); - atomic_notifier_chain_unregister(&panic_notifier_list, &mdm->panic_blk); + if (mdm->gpios[STATUS_IN] >= 0) + disable_irq_wake(mdm->status_irq); + if (mdm->gpios[STATUS_OUT] >= 0) + atomic_notifier_chain_unregister(&panic_notifier_list, + &mdm->panic_blk); remove_ipc(mdm); device_remove_file(mdm->dev, &dev_attr_policy); return 0; } +#ifdef CONFIG_PM +static int sdx_ext_ipc_suspend(struct device *dev) +{ + struct gpio_cntrl *mdm = dev_get_drvdata(dev); + + if (mdm->gpios[WAKEUP_IN] >= 0) + enable_irq_wake(mdm->wakeup_irq); + return 0; +} + +static int sdx_ext_ipc_resume(struct device *dev) +{ + struct gpio_cntrl *mdm = dev_get_drvdata(dev); + + if (mdm->gpios[WAKEUP_IN] >= 0) + disable_irq_wake(mdm->wakeup_irq); + return 0; +} + +static const struct dev_pm_ops sdx_ext_ipc_pm_ops = { + .suspend = sdx_ext_ipc_suspend, + .resume = sdx_ext_ipc_resume, +}; +#endif + static const struct of_device_id sdx_ext_ipc_of_match[] = { { .compatible = "qcom,sdx-ext-ipc"}, { .compatible = "qcom,sa515m-ccard"}, @@ -298,6 +438,9 @@ static struct platform_driver sdx_ext_ipc_driver = { .name = "sdx-ext-ipc", .owner = THIS_MODULE, .of_match_table = sdx_ext_ipc_of_match, +#ifdef CONFIG_PM + .pm = &sdx_ext_ipc_pm_ops, +#endif }, }; diff --git a/drivers/soc/qcom/sideband_notify.c b/drivers/soc/qcom/sideband_notify.c new file mode 100644 index 0000000000000000000000000000000000000000..1907203294054f21e2d20f5bc7a691a1af24f61d --- /dev/null +++ b/drivers/soc/qcom/sideband_notify.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +static BLOCKING_NOTIFIER_HEAD(sb_notifier_list); + +/** + * sb_register_evt_listener - registers a notifier callback + * @nb: pointer to the notifier block for the callback events + */ +int sb_register_evt_listener(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&sb_notifier_list, nb); +} +EXPORT_SYMBOL(sb_register_evt_listener); + +/** + * sb_unregister_evt_listener - un-registers a notifier callback + * registered previously. + * @nb: pointer to the notifier block for the callback events + */ +int sb_unregister_evt_listener(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&sb_notifier_list, nb); +} +EXPORT_SYMBOL(sb_unregister_evt_listener); + +/** + * sb_notifier_call_chain - send events to all registered listeners + * as received from publishers. + * @nb: pointer to the notifier block for the callback events + */ +int sb_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&sb_notifier_list, val, v); +} +EXPORT_SYMBOL(sb_notifier_call_chain); diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index fd350aee267583e7baf5fc77706ecb34028f7fef..0cdd98ca48f33302e71ae3b8563c12960b4fc567 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -280,6 +280,9 @@ struct qcom_smem { /* Pointer to the one and only smem handle */ static struct qcom_smem *__smem; +/* default smem host id for apps is SMEM_HOST_APPS */ +static u32 smem_host_id = SMEM_HOST_APPS; + /* Timeout (ms) for the trylock of remote spinlocks */ #define HWSPINLOCK_TIMEOUT 1000 @@ -986,6 +989,7 @@ static int qcom_smem_probe(struct platform_device *pdev) int hwlock_id; u32 version; int ret; + u32 host_id; num_regions = 1; if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL)) @@ -1007,6 +1011,10 @@ static int qcom_smem_probe(struct platform_device *pdev) "qcom,rpm-msg-ram", 1))) return ret; + ret = of_property_read_u32(pdev->dev.of_node, "smem-host-id", &host_id); + if (!ret) + smem_host_id = host_id; + header = smem->regions[0].virt_base; if (le32_to_cpu(header->initialized) != 1 || le32_to_cpu(header->reserved)) { @@ -1030,7 +1038,7 @@ static int qcom_smem_probe(struct platform_device *pdev) return -EINVAL; } - ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); + ret = qcom_smem_enumerate_partitions(smem, smem_host_id); if (ret < 0) return ret; diff --git a/drivers/soc/qcom/subsys-pil-bg.c b/drivers/soc/qcom/subsys-pil-bg.c new file mode 100644 index 0000000000000000000000000000000000000000..464fa1273505c99afd487bd7ef4fb98add77bde5 --- /dev/null +++ b/drivers/soc/qcom/subsys-pil-bg.c @@ -0,0 +1,840 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "peripheral-loader.h" +#include "../../misc/qseecom_kernel.h" +#include "pil_bg_intf.h" +#include "bgcom_interface.h" + +#define INVALID_GPIO -1 +#define NUM_GPIOS 4 +#define SECURE_APP "bgapp" +#define desc_to_data(d) container_of(d, struct pil_bg_data, desc) +#define subsys_to_data(d) container_of(d, struct pil_bg_data, subsys_desc) +#define BG_RAMDUMP_SZ 0x00102000 +#define BG_VERSION_SZ 32 +#define BG_CRASH_IN_TWM -2 +/** + * struct pil_bg_data + * @qseecom_handle: handle of TZ app + * @bg_queue: private queue to schedule worker threads for bottom half + * @restart_work: work struct for executing ssr + * @reboot_blk: notification block for reboot event + * @subsys_desc: subsystem descriptor + * @subsys: subsystem device pointer + * @gpios: array to hold all gpio handle + * @desc: PIL descriptor + * @address_fw: address where firmware binaries loaded + * @ramdump_dev: ramdump device pointer + * @size_fw: size of bg firmware binaries + * @errfatal_irq: irq number to indicate bg crash or shutdown + * @status_irq: irq to indicate bg status + * @app_status: status of tz app loading + * @is_ready: Is BG chip up + * @err_ready: The error ready signal + */ + +struct pil_bg_data { + struct qseecom_handle *qseecom_handle; + struct workqueue_struct *bg_queue; + struct work_struct restart_work; + struct notifier_block reboot_blk; + struct subsys_desc subsys_desc; + struct subsys_device *subsys; + unsigned int gpios[NUM_GPIOS]; + int errfatal_irq; + int status_irq; + struct pil_desc desc; + phys_addr_t address_fw; + void *ramdump_dev; + u32 cmd_status; + size_t size_fw; + int app_status; + bool is_ready; + struct completion err_ready; +}; + +static irqreturn_t bg_status_change(int irq, void *dev_id); + +/** + * bg_app_shutdown_notify() - Toggle AP2BG err fatal gpio when + * called by SSR framework. + * @subsys: struct containing private BG data. + * + * Return: none. + */ +static void bg_app_shutdown_notify(const struct subsys_desc *subsys) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + + /* Disable irq if already BG is up */ + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } + /* Toggle AP2BG err fatal gpio here to inform apps err fatal event */ + if (gpio_is_valid(bg_data->gpios[2])) { + pr_debug("Sending Apps shutdown signal\n"); + gpio_set_value(bg_data->gpios[2], 1); + } +} + +/** + * bg_app_reboot_notify() - Toggle AP2BG err fatal gpio. + * @nb: struct containing private BG data. + * + * Return: NOTIFY_DONE indicating success. + */ +static int bg_app_reboot_notify(struct notifier_block *nb, + unsigned long code, void *unused) +{ + struct pil_bg_data *bg_data = container_of(nb, + struct pil_bg_data, reboot_blk); + + /* Disable irq if already BG is up */ + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } + /* Toggle AP2BG err fatal gpio here to inform apps err fatal event */ + if (gpio_is_valid(bg_data->gpios[2])) { + pr_debug("Sending reboot signal\n"); + gpio_set_value(bg_data->gpios[2], 1); + } + return NOTIFY_DONE; +} + +/** + * get_cmd_rsp_buffers() - Function sets cmd & rsp buffer pointers and + * aligns buffer lengths + * @hdl: index of qseecom_handle + * @cmd: req buffer - set to qseecom_handle.sbuf + * @cmd_len: ptr to req buffer len + * @rsp: rsp buffer - set to qseecom_handle.sbuf + offset + * @rsp_len: ptr to rsp buffer len + * + * Return: Success always . + */ +static int get_cmd_rsp_buffers(struct qseecom_handle *handle, void **cmd, + uint32_t *cmd_len, void **rsp, uint32_t *rsp_len) +{ + *cmd = handle->sbuf; + if (*cmd_len & QSEECOM_ALIGN_MASK) + *cmd_len = QSEECOM_ALIGN(*cmd_len); + + *rsp = handle->sbuf + *cmd_len; + if (*rsp_len & QSEECOM_ALIGN_MASK) + *rsp_len = QSEECOM_ALIGN(*rsp_len); + + return 0; +} + +/** + * pil_load_bg_tzapp() - Called to load TZ app. + * @pbd: struct containing private BG data. + * + * Return: 0 on success. Error code on failure. + */ +static int pil_load_bg_tzapp(struct pil_bg_data *pbd) +{ + int rc; + + /* return success if already loaded */ + if (pbd->qseecom_handle && !pbd->app_status) + return 0; + /* Load the APP */ + rc = qseecom_start_app(&pbd->qseecom_handle, SECURE_APP, SZ_4K); + if (rc < 0) { + dev_err(pbd->desc.dev, "BG TZ app load failure\n"); + pbd->app_status = RESULT_FAILURE; + return -EIO; + } + pbd->app_status = RESULT_SUCCESS; + return 0; +} + +/** + * bgpil_tzapp_comm() - Function called to communicate with TZ APP. + * @req: struct containing command and parameters. + * + * Return: 0 on success. Error code on failure. + */ +static long bgpil_tzapp_comm(struct pil_bg_data *pbd, + struct tzapp_bg_req *req) +{ + struct tzapp_bg_req *bg_tz_req; + struct tzapp_bg_rsp *bg_tz_rsp; + int rc, req_len, rsp_len; + unsigned char *ascii; + char fiwmare_version[100] = {'\0'}; + char ascii_string[5]; + + /* Fill command structure */ + req_len = sizeof(struct tzapp_bg_req); + rsp_len = sizeof(struct tzapp_bg_rsp); + rc = get_cmd_rsp_buffers(pbd->qseecom_handle, + (void **)&bg_tz_req, &req_len, + (void **)&bg_tz_rsp, &rsp_len); + if (rc) + goto end; + + bg_tz_req->tzapp_bg_cmd = req->tzapp_bg_cmd; + bg_tz_req->address_fw = req->address_fw; + bg_tz_req->size_fw = req->size_fw; + rc = qseecom_send_command(pbd->qseecom_handle, + (void *)bg_tz_req, req_len, (void *)bg_tz_rsp, rsp_len); + pr_debug("BG PIL qseecom returned with value 0x%x and status 0x%x\n", + rc, bg_tz_rsp->status); + if (rc || bg_tz_rsp->status) + pbd->cmd_status = bg_tz_rsp->status; + else + pbd->cmd_status = 0; + /* if last command sent was BG_VERSION print the version*/ + if (req->tzapp_bg_cmd == BGPIL_GET_BG_VERSION) { + int i; + + pr_info("BG FW version "); + for (i = 0; i < bg_tz_rsp->bg_info_len; i++) { + pr_info("0x%08x ", bg_tz_rsp->bg_info[i]); + ascii = (unsigned char *)&bg_tz_rsp->bg_info[i]; + snprintf(ascii_string, PAGE_SIZE, "%c%c%c%c", ascii[0], + ascii[1], ascii[2], ascii[3]); + strlcat(fiwmare_version, ascii_string, + PAGE_SIZE); + } + pr_info("%s\n", fiwmare_version); + } +end: + return rc; +} + +/** + * wait_for_err_ready() - Called in power_up to wait for error ready. + * Signal waiting function. + * @bg_data: BG PIL private structure. + * + * Return: 0 on success. Error code on failure. + */ +static int wait_for_err_ready(struct pil_bg_data *bg_data) +{ + int ret; + + if ((!bg_data->status_irq)) + return 0; + + ret = wait_for_completion_timeout(&bg_data->err_ready, + msecs_to_jiffies(10000)); + if (!ret) { + pr_err("[%s]: Error ready timed out\n", bg_data->desc.name); + return -ETIMEDOUT; + } + return 0; +} + +/** + * bg_powerup() - Called by SSR framework on userspace invocation. + * does load tz app and call peripheral loader. + * @subsys: struct containing private BG data. + * + * Return: 0 on success. Error code on failure. + */ +static int bg_powerup(const struct subsys_desc *subsys) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + int ret; + + if (is_bg_running()) { + pr_debug("bg is already up\n"); + return 0; + } + + init_completion(&bg_data->err_ready); + if (!bg_data->qseecom_handle) { + ret = pil_load_bg_tzapp(bg_data); + if (ret) { + dev_err(bg_data->desc.dev, + "%s: BG TZ app load failure\n", + __func__); + return ret; + } + } + pr_debug("bgapp loaded\n"); + bg_data->desc.fw_name = subsys->fw_name; + + ret = devm_request_irq(bg_data->desc.dev, bg_data->status_irq, + bg_status_change, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "bg2ap_status", bg_data); + if (ret < 0) { + dev_err(bg_data->desc.dev, + "%s: BG2AP_STATUS IRQ#%d re registration failed, err=%d", + __func__, bg_data->status_irq, ret); + return ret; + } + + /* Enable status and err fatal irqs */ + ret = pil_boot(&bg_data->desc); + if (ret) { + dev_err(bg_data->desc.dev, + "%s: BG PIL Boot failed\n", __func__); + return ret; + } + ret = wait_for_err_ready(bg_data); + if (ret) { + dev_err(bg_data->desc.dev, + "[%s:%d]: Timed out waiting for error ready: %s!\n", + current->comm, current->pid, bg_data->desc.name); + return ret; + } + return ret; +} + +/** + * bg_shutdown() - Called by SSR framework on userspace invocation. + * disable status interrupt to avoid spurious signal during PRM exit. + * @subsys: struct containing private BG data. + * @force_stop: unused + * + * Return: always success + */ +static int bg_shutdown(const struct subsys_desc *subsys, bool force_stop) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + devm_free_irq(bg_data->desc.dev, bg_data->status_irq, bg_data); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } + return 0; +} + +/** + * bg_auth_metadata() - Called by Peripheral loader framework + * send command to tz app for authentication of metadata. + * @pil: pil descriptor. + * @metadata: metadata load address + * @size: size of metadata + * + * Return: 0 on success. Error code on failure. + */ +static int bg_auth_metadata(struct pil_desc *pil, + const u8 *metadata, size_t size) +{ + struct pil_bg_data *bg_data = desc_to_data(pil); + struct tzapp_bg_req bg_tz_req; + void *mdata_buf; + dma_addr_t mdata_phys; + unsigned long attrs = 0; + struct device dev = {0}; + int ret; + + arch_setup_dma_ops(&dev, 0, 0, NULL, 0); + + dev.coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8); + attrs |= DMA_ATTR_STRONGLY_ORDERED; + mdata_buf = dma_alloc_attrs(&dev, size, + &mdata_phys, GFP_KERNEL, attrs); + + if (!mdata_buf) { + pr_err("BG_PIL: Allocation for metadata failed.\n"); + return -ENOMEM; + } + + /* Make sure there are no mappings in PKMAP and fixmap */ + kmap_flush_unused(); + kmap_atomic_flush_unused(); + + memcpy(mdata_buf, metadata, size); + + bg_tz_req.tzapp_bg_cmd = BGPIL_AUTH_MDT; + bg_tz_req.address_fw = (phys_addr_t)mdata_phys; + bg_tz_req.size_fw = size; + + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + if (ret || bg_data->cmd_status) { + dev_err(pil->dev, + "%s: BGPIL_AUTH_MDT qseecom call failed\n", + __func__); + return bg_data->cmd_status; + } + dma_free_attrs(&dev, size, mdata_buf, mdata_phys, attrs); + pr_debug("BG MDT Authenticated\n"); + return 0; +} + +/** + * bg_get_firmware_addr() - Called by Peripheral loader framework + * to get address and size of bg firmware binaries. + * @pil: pil descriptor. + * @addr: fw load address + * @size: size of fw + * + * Return: 0 on success. + */ +static int bg_get_firmware_addr(struct pil_desc *pil, + phys_addr_t addr, size_t size) +{ + struct pil_bg_data *bg_data = desc_to_data(pil); + + bg_data->address_fw = addr; + bg_data->size_fw = size; + pr_debug("BG PIL loads firmware blobs at 0x%x with size 0x%x\n", + addr, size); + return 0; +} + +static int bg_get_version(const struct subsys_desc *subsys) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + struct pil_desc desc = bg_data->desc; + struct tzapp_bg_req bg_tz_req; + int ret; + struct device dev = {NULL}; + + arch_setup_dma_ops(&dev, 0, 0, NULL, 0); + + desc.attrs = 0; + desc.attrs |= DMA_ATTR_SKIP_ZEROING; + desc.attrs |= DMA_ATTR_STRONGLY_ORDERED; + + + bg_tz_req.tzapp_bg_cmd = BGPIL_GET_BG_VERSION; + + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + if (ret || bg_data->cmd_status) { + dev_dbg(desc.dev, "%s: BG PIL get BG version failed error %d\n", + __func__, bg_data->cmd_status); + return bg_data->cmd_status; + } + + return 0; +} + +/** + * bg_auth_and_xfer() - Called by Peripheral loader framework + * to signal tz app to authenticate and boot bg chip. + * @pil: pil descriptor. + * + * Return: 0 on success. Error code on failure. + */ +static int bg_auth_and_xfer(struct pil_desc *pil) +{ + struct pil_bg_data *bg_data = desc_to_data(pil); + struct tzapp_bg_req bg_tz_req; + int ret; + + bg_tz_req.tzapp_bg_cmd = BGPIL_IMAGE_LOAD; + bg_tz_req.address_fw = bg_data->address_fw; + bg_tz_req.size_fw = bg_data->size_fw; + + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + if (bg_data->cmd_status == BG_CRASH_IN_TWM) { + /* Do ramdump and resend boot cmd */ + if (is_twm_exit()) + bg_data->subsys_desc.ramdump(true, + &bg_data->subsys_desc); + + bg_tz_req.tzapp_bg_cmd = BGPIL_DLOAD_CONT; + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + } + if (ret || bg_data->cmd_status) { + dev_err(pil->dev, + "%s: BGPIL_IMAGE_LOAD qseecom call failed\n", + __func__); + pil_free_memory(&bg_data->desc); + return bg_data->cmd_status; + } + ret = bg_get_version(&bg_data->subsys_desc); + /* BG Transfer of image is complete, free up the memory */ + pr_debug("BG Firmware authentication and transfer done\n"); + pil_free_memory(&bg_data->desc); + return 0; +} + +/** + * bg_ramdump() - Called by SSR framework to save dump of BG internal + * memory, BG PIL does allocate region from dynamic memory and pass this + * region to tz to dump memory content of BG. + * @subsys: subsystem descriptor. + * + * Return: 0 on success. Error code on failure. + */ +static int bg_ramdump(int enable, const struct subsys_desc *subsys) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + struct pil_desc desc = bg_data->desc; + struct ramdump_segment *ramdump_segments; + struct tzapp_bg_req bg_tz_req; + phys_addr_t start_addr; + void *region; + int ret; + struct device dev = {0}; + + arch_setup_dma_ops(&dev, 0, 0, NULL, 0); + + desc.attrs = 0; + desc.attrs |= DMA_ATTR_SKIP_ZEROING; + desc.attrs |= DMA_ATTR_STRONGLY_ORDERED; + + region = dma_alloc_attrs(desc.dev, BG_RAMDUMP_SZ, + &start_addr, GFP_KERNEL, desc.attrs); + + if (region == NULL) { + dev_dbg(desc.dev, + "BG PIL failure to allocate ramdump region of size %zx\n", + BG_RAMDUMP_SZ); + return -ENOMEM; + } + + ramdump_segments = kcalloc(1, sizeof(*ramdump_segments), GFP_KERNEL); + if (!ramdump_segments) + return -ENOMEM; + + bg_tz_req.tzapp_bg_cmd = BGPIL_RAMDUMP; + bg_tz_req.address_fw = start_addr; + bg_tz_req.size_fw = BG_RAMDUMP_SZ; + + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + if (ret || bg_data->cmd_status) { + dev_dbg(desc.dev, "%s: BG PIL ramdump collection failed\n", + __func__); + return bg_data->cmd_status; + } + + ramdump_segments->address = start_addr; + ramdump_segments->size = BG_RAMDUMP_SZ; + + do_ramdump(bg_data->ramdump_dev, ramdump_segments, 1); + kfree(ramdump_segments); + dma_free_attrs(desc.dev, BG_RAMDUMP_SZ, region, + start_addr, desc.attrs); + return 0; +} + +static struct pil_reset_ops pil_ops_trusted = { + .init_image = bg_auth_metadata, + .mem_setup = bg_get_firmware_addr, + .auth_and_reset = bg_auth_and_xfer, + .shutdown = NULL, + .proxy_vote = NULL, + .proxy_unvote = NULL, +}; + +/** + * bg_restart_work() - scheduled by interrupt handler to carry + * out ssr sequence + * @work: work struct. + * + * Return: none. + */ +static void bg_restart_work(struct work_struct *work) +{ + struct pil_bg_data *drvdata = + container_of(work, struct pil_bg_data, restart_work); + subsystem_restart_dev(drvdata->subsys); +} + +static irqreturn_t bg_errfatal(int irq, void *dev_id) +{ + struct pil_bg_data *drvdata = (struct pil_bg_data *)dev_id; + + if (!drvdata) + return IRQ_HANDLED; + + dev_dbg(drvdata->desc.dev, "BG s/w err fatal\n"); + + queue_work(drvdata->bg_queue, &drvdata->restart_work); + + return IRQ_HANDLED; +} + +static irqreturn_t bg_status_change(int irq, void *dev_id) +{ + bool value; + struct pil_bg_data *drvdata = (struct pil_bg_data *)dev_id; + + if (!drvdata) + return IRQ_HANDLED; + + value = gpio_get_value(drvdata->gpios[0]); + if (value == true && !drvdata->is_ready) { + dev_info(drvdata->desc.dev, + "BG services are up and running: irq state changed 0->1\n"); + drvdata->is_ready = true; + complete(&drvdata->err_ready); + } else if (value == false && drvdata->is_ready) { + dev_err(drvdata->desc.dev, + "BG got unexpected reset: irq state changed 1->0\n"); + queue_work(drvdata->bg_queue, &drvdata->restart_work); + } else { + dev_err(drvdata->desc.dev, + "BG status irq: unknown status\n"); + } + + return IRQ_HANDLED; +} + +/** + * setup_bg_gpio_irq() - called in probe to configure input/ + * output gpio. + * @drvdata: private data struct for BG. + * + * Return: 0 on success. Error code on failure. + */ +static int setup_bg_gpio_irq(struct platform_device *pdev, + struct pil_bg_data *drvdata) +{ + int ret = -1; + int irq, i; + + if (gpio_request(drvdata->gpios[0], "BG2AP_STATUS")) { + dev_err(&pdev->dev, + "%s Failed to configure BG2AP_STATUS gpio\n", + __func__); + goto err; + } + if (gpio_request(drvdata->gpios[1], "BG2AP_ERRFATAL")) { + dev_err(&pdev->dev, + "%s Failed to configure BG2AP_ERRFATAL gpio\n", + __func__); + goto err; + } + gpio_direction_input(drvdata->gpios[0]); + gpio_direction_input(drvdata->gpios[1]); + /* BG2AP STATUS IRQ */ + irq = gpio_to_irq(drvdata->gpios[0]); + if (irq < 0) { + dev_err(&pdev->dev, + "%s: bad BG2AP_STATUS IRQ resource, err = %d\n", + __func__, irq); + goto err; + } + + drvdata->status_irq = irq; + /* BG2AP ERR_FATAL irq. */ + irq = gpio_to_irq(drvdata->gpios[1]); + if (irq < 0) { + dev_err(&pdev->dev, "bad BG2AP_ERRFATAL IRQ resource\n"); + goto err; + } + ret = request_irq(irq, bg_errfatal, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "bg2ap_errfatal", drvdata); + if (ret < 0) { + dev_err(&pdev->dev, + "%s: BG2AP_ERRFATAL IRQ#%d request failed,\n", + __func__, irq); + goto err; + } + drvdata->errfatal_irq = irq; + /* Configure outgoing GPIO's */ + if (gpio_request(drvdata->gpios[2], "AP2BG_ERRFATAL")) { + dev_err(&pdev->dev, + "%s Failed to configure AP2BG_ERRFATAL gpio\n", + __func__); + goto err; + } + if (gpio_request(drvdata->gpios[3], "AP2BG_STATUS")) { + dev_err(&pdev->dev, + "%s Failed to configure AP2BG_STATUS gpio\n", + __func__); + goto err; + } + /* + * Put status gpio in default high state which will + * make transition to low on any sudden reset case of msm + */ + gpio_direction_output(drvdata->gpios[2], 0); + gpio_direction_output(drvdata->gpios[3], 1); + /* Inform BG that AP is up */ + gpio_set_value(drvdata->gpios[3], 1); + return 0; +err: + for (i = 0; i < NUM_GPIOS; ++i) { + if (gpio_is_valid(drvdata->gpios[i])) + gpio_free(drvdata->gpios[i]); + } + return ret; +} + +/** + * bg_dt_parse_gpio() - called in probe to parse gpio's + * @drvdata: private data struct for BG. + * + * Return: 0 on success. Error code on failure. + */ +static int bg_dt_parse_gpio(struct platform_device *pdev, + struct pil_bg_data *drvdata) +{ + int i, val; + + for (i = 0; i < NUM_GPIOS; i++) + drvdata->gpios[i] = INVALID_GPIO; + val = of_get_named_gpio(pdev->dev.of_node, + "qcom,bg2ap-status-gpio", 0); + if (val >= 0) + drvdata->gpios[0] = val; + else { + pr_err("BG status gpio not found, error=%d\n", val); + return -EINVAL; + } + val = of_get_named_gpio(pdev->dev.of_node, + "qcom,bg2ap-errfatal-gpio", 0); + if (val >= 0) + drvdata->gpios[1] = val; + else { + pr_err("BG err-fatal gpio not found, error=%d\n", val); + return -EINVAL; + } + val = of_get_named_gpio(pdev->dev.of_node, + "qcom,ap2bg-errfatal-gpio", 0); + if (val >= 0) + drvdata->gpios[2] = val; + else { + pr_err("ap2bg err-fatal gpio not found, error=%d\n", val); + return -EINVAL; + } + val = of_get_named_gpio(pdev->dev.of_node, + "qcom,ap2bg-status-gpio", 0); + if (val >= 0) + drvdata->gpios[3] = val; + else { + pr_err("ap2bg status gpio not found, error=%d\n", val); + return -EINVAL; + } + return 0; +} + +static int pil_bg_driver_probe(struct platform_device *pdev) +{ + struct pil_bg_data *bg_data; + int rc; + + bg_data = devm_kzalloc(&pdev->dev, sizeof(*bg_data), GFP_KERNEL); + if (!bg_data) + return -ENOMEM; + platform_set_drvdata(pdev, bg_data); + rc = of_property_read_string(pdev->dev.of_node, + "qcom,firmware-name", &bg_data->desc.name); + if (rc) + return rc; + bg_data->desc.dev = &pdev->dev; + bg_data->desc.owner = THIS_MODULE; + bg_data->desc.ops = &pil_ops_trusted; + rc = pil_desc_init(&bg_data->desc); + if (rc) + return rc; + /* Read gpio configuration */ + rc = bg_dt_parse_gpio(pdev, bg_data); + if (rc) + return rc; + rc = setup_bg_gpio_irq(pdev, bg_data); + if (rc < 0) + return rc; + bg_data->subsys_desc.name = bg_data->desc.name; + bg_data->subsys_desc.owner = THIS_MODULE; + bg_data->subsys_desc.dev = &pdev->dev; + bg_data->subsys_desc.shutdown = bg_shutdown; + bg_data->subsys_desc.powerup = bg_powerup; + bg_data->subsys_desc.ramdump = bg_ramdump; + bg_data->subsys_desc.free_memory = NULL; + bg_data->subsys_desc.crash_shutdown = bg_app_shutdown_notify; + bg_data->ramdump_dev = + create_ramdump_device(bg_data->subsys_desc.name, &pdev->dev); + if (!bg_data->ramdump_dev) { + rc = -ENOMEM; + goto err_ramdump; + } + bg_data->subsys = subsys_register(&bg_data->subsys_desc); + if (IS_ERR(bg_data->subsys)) { + rc = PTR_ERR(bg_data->subsys); + goto err_subsys; + } + + bg_data->reboot_blk.notifier_call = bg_app_reboot_notify; + register_reboot_notifier(&bg_data->reboot_blk); + + bg_data->bg_queue = alloc_workqueue("bg_queue", 0, 0); + if (!bg_data->bg_queue) { + dev_err(&pdev->dev, "could not create bg_queue\n"); + subsys_unregister(bg_data->subsys); + goto err_subsys; + } + INIT_WORK(&bg_data->restart_work, bg_restart_work); + return 0; +err_subsys: + destroy_ramdump_device(bg_data->ramdump_dev); +err_ramdump: + pil_desc_release(&bg_data->desc); + return rc; +} + +static int pil_bg_driver_exit(struct platform_device *pdev) +{ + struct pil_bg_data *bg_data = platform_get_drvdata(pdev); + + subsys_unregister(bg_data->subsys); + destroy_ramdump_device(bg_data->ramdump_dev); + pil_desc_release(&bg_data->desc); + + return 0; +} + +const struct of_device_id pil_bg_match_table[] = { + {.compatible = "qcom,pil-blackghost"}, + {} +}; + +static struct platform_driver pil_bg_driver = { + .probe = pil_bg_driver_probe, + .remove = pil_bg_driver_exit, + .driver = { + .name = "subsys-pil-bg", + .of_match_table = pil_bg_match_table, + .owner = THIS_MODULE, + }, +}; + +static int __init pil_bg_init(void) +{ + return platform_driver_register(&pil_bg_driver); +} +module_init(pil_bg_init); + +static void __exit pil_bg_exit(void) +{ + platform_driver_unregister(&pil_bg_driver); +} +module_exit(pil_bg_exit); + +MODULE_DESCRIPTION("Support for booting QTI Blackghost SoC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/wcnss/wcnss_wlan.c b/drivers/soc/qcom/wcnss/wcnss_wlan.c index 5ae9596daab439c09f75ca04bdcacfb40b145efd..2ec29350f6f87bebd315f00e497099ae393bff44 100644 --- a/drivers/soc/qcom/wcnss/wcnss_wlan.c +++ b/drivers/soc/qcom/wcnss/wcnss_wlan.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -475,6 +476,8 @@ static struct { dev_t dev_ctrl, dev_node; struct class *node_class; struct cdev ctrl_dev, node_dev; + unsigned long state; + struct wcnss_driver_ops *ops; } *penv = NULL; static void *wcnss_ipc_log; @@ -1335,6 +1338,12 @@ struct rpmsg_endpoint *wcnss_open_channel(const char *name, rpmsg_rx_cb_t cb, } EXPORT_SYMBOL(wcnss_open_channel); +void wcnss_close_channel(struct rpmsg_endpoint *channel) +{ + rpmsg_destroy_ept(channel); +} +EXPORT_SYMBOL(wcnss_close_channel); + static int wcnss_ctrl_smd_callback(struct rpmsg_device *rpdev, void *data, int count, @@ -1557,6 +1566,8 @@ static int wcnss_ctrl_probe(struct rpmsg_device *rpdev) if (penv->wlan_config.is_pronto_vadc && penv->adc_channel) schedule_work(&penv->wcnss_vadc_work); + penv->state = WCNSS_SMD_OPEN; + return 0; } @@ -1576,6 +1587,8 @@ static int wcnss_rpmsg_resource_init(void) INIT_LIST_HEAD(&penv->event_list); spin_lock_init(&penv->event_lock); + penv->state = WCNSS_SMD_CLOSE; + return 0; } @@ -1691,6 +1704,58 @@ int wcnss_wlan_get_dxe_rx_irq(struct device *dev) } EXPORT_SYMBOL(wcnss_wlan_get_dxe_rx_irq); +int wcnss_register_driver(struct wcnss_driver_ops *ops, void *priv) +{ + int ret = 0; + + if (!penv || !penv->pdev) { + ret = -ENODEV; + goto out; + } + + wcnss_log(ERR, "Registering driver, state: 0x%lx\n", penv->state); + + if (penv->ops) { + wcnss_log(ERR, "Driver already registered\n"); + ret = -EEXIST; + goto out; + } + + penv->ops = ops; + penv->ops->priv_data = priv; + + if (penv->state == WCNSS_SMD_OPEN) + ops->driver_state(ops->priv_data, WCNSS_SMD_OPEN); + +out: + return ret; +} +EXPORT_SYMBOL(wcnss_register_driver); + +int wcnss_unregister_driver(struct wcnss_driver_ops *ops) +{ + int ret; + + if (!penv || !penv->pdev) { + ret = -ENODEV; + goto out; + } + + wcnss_log(ERR, "Unregistering driver, state: 0x%lx\n", penv->state); + + if (!penv->ops) { + wcnss_log(ERR, "Driver not registered\n"); + ret = -ENOENT; + goto out; + } + + penv->ops = NULL; + +out: + return ret; +} +EXPORT_SYMBOL(wcnss_unregister_driver); + void wcnss_wlan_register_pm_ops(struct device *dev, const struct dev_pm_ops *pm_ops) { @@ -1963,15 +2028,16 @@ int wcnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 buffer_size, } EXPORT_SYMBOL(wcnss_get_wlan_unsafe_channel); -static int wcnss_smd_tx(void *data, int len) +int wcnss_smd_tx(struct rpmsg_endpoint *channel, void *data, int len) { int ret = 0; - ret = rpmsg_send(penv->channel, data, len); + ret = rpmsg_send(channel, data, len); if (ret < 0) return ret; return 0; } +EXPORT_SYMBOL(wcnss_smd_tx); static int wcnss_get_battery_volt(u32 *result_uv) { @@ -2088,7 +2154,7 @@ static void wcnss_send_vbatt_indication(struct work_struct *work) wcnss_log(DBG, "send curr_volt: %d to FW\n", vbatt_msg.vbatt.curr_volt); - ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len); + ret = wcnss_smd_tx(penv->channel, &vbatt_msg, vbatt_msg.hdr.msg_len); if (ret < 0) wcnss_log(ERR, "smd tx failed\n"); } @@ -2120,7 +2186,7 @@ static void wcnss_update_vbatt(struct work_struct *work) return; } mutex_unlock(&penv->vbat_monitor_mutex); - ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len); + ret = wcnss_smd_tx(penv->channel, &vbatt_msg, vbatt_msg.hdr.msg_len); if (ret < 0) wcnss_log(ERR, "smd tx failed\n"); } @@ -2140,7 +2206,7 @@ static void wcnss_send_cal_rsp(unsigned char fw_status) rsphdr->msg_len = sizeof(struct smd_msg_hdr) + 1; memcpy(msg + sizeof(struct smd_msg_hdr), &fw_status, 1); - rc = wcnss_smd_tx(msg, rsphdr->msg_len); + rc = wcnss_smd_tx(penv->channel, msg, rsphdr->msg_len); if (rc < 0) wcnss_log(ERR, "smd tx failed\n"); @@ -2270,7 +2336,8 @@ static void wcnss_process_smd_msg(void *buf, int len) case WCNSS_PRONTO_HW: smd_msg.msg_type = WCNSS_BUILD_VER_REQ; smd_msg.msg_len = sizeof(smd_msg); - rc = wcnss_smd_tx(&smd_msg, smd_msg.msg_len); + rc = wcnss_smd_tx(penv->channel, &smd_msg, + smd_msg.msg_len); if (rc < 0) wcnss_log(ERR, "smd tx failed: %s\n", __func__); @@ -2291,8 +2358,8 @@ static void wcnss_process_smd_msg(void *buf, int len) break; case WCNSS_BUILD_VER_RSP: - /* ToDo: WCNSS_MAX_BUILD_VER_LEN + sizeof(struct smd_msg_hdr) */ - if (len > WCNSS_MAX_BUILD_VER_LEN) { + if (len > sizeof(struct smd_msg_hdr) + + WCNSS_MAX_BUILD_VER_LEN) { wcnss_log(ERR, "invalid build version:%d\n", len); return; @@ -2310,6 +2377,11 @@ static void wcnss_process_smd_msg(void *buf, int len) nvresp->status); if (nvresp->status != WAIT_FOR_CBC_IND) penv->is_cbc_done = 1; + + if (penv->ops) + penv->ops->driver_state(penv->ops->priv_data, + WCNSS_SMD_OPEN); + wcnss_setup_vbat_monitoring(); break; @@ -2357,7 +2429,7 @@ static void wcnss_send_version_req(struct work_struct *worker) smd_msg.msg_type = WCNSS_VERSION_REQ; smd_msg.msg_len = sizeof(smd_msg); - ret = wcnss_smd_tx(&smd_msg, smd_msg.msg_len); + ret = wcnss_smd_tx(penv->channel, &smd_msg, smd_msg.msg_len); if (ret < 0) wcnss_log(ERR, "smd tx failed\n"); } @@ -2397,7 +2469,7 @@ static void wcnss_send_pm_config(struct work_struct *worker) hdr->msg_type = WCNSS_PM_CONFIG_REQ; hdr->msg_len = sizeof(struct smd_msg_hdr) + (prop_len * sizeof(int)); - rc = wcnss_smd_tx(msg, hdr->msg_len); + rc = wcnss_smd_tx(penv->channel, msg, hdr->msg_len); if (rc < 0) wcnss_log(ERR, "smd tx failed\n"); @@ -2488,7 +2560,8 @@ static void wcnss_nvbin_dnld(void) (nv_blob_addr + count * NV_FRAGMENT_SIZE), cur_frag_size); - ret = wcnss_smd_tx(outbuffer, dnld_req_msg->hdr.msg_len); + ret = wcnss_smd_tx(penv->channel, outbuffer, + dnld_req_msg->hdr.msg_len); retry_count = 0; while ((ret == -ENOSPC) && (retry_count <= 3)) { @@ -2502,7 +2575,7 @@ static void wcnss_nvbin_dnld(void) /* wait and try again */ msleep(20); retry_count++; - ret = wcnss_smd_tx(outbuffer, + ret = wcnss_smd_tx(penv->channel, outbuffer, dnld_req_msg->hdr.msg_len); } @@ -2581,7 +2654,9 @@ static void wcnss_caldata_dnld(const void *cal_data, (cal_data + count * NV_FRAGMENT_SIZE), cur_frag_size); - ret = wcnss_smd_tx(outbuffer, cal_msg->hdr.msg_len); + ret = wcnss_smd_tx(penv->channel, outbuffer, + cal_msg->hdr.msg_len); + retry_count = 0; while ((ret == -ENOSPC) && (retry_count <= 3)) { @@ -2595,7 +2670,7 @@ static void wcnss_caldata_dnld(const void *cal_data, /* wait and try again */ msleep(20); retry_count++; - ret = wcnss_smd_tx(outbuffer, + ret = wcnss_smd_tx(penv->channel, outbuffer, cal_msg->hdr.msg_len); } @@ -3395,6 +3470,7 @@ static int wcnss_notif_cb(struct notifier_block *this, unsigned long code, struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config(); struct notif_data *data = (struct notif_data *)ss_handle; int ret, xo_mode; + void *priv; if (!(code >= SUBSYS_NOTIF_MIN_INDEX) && (code <= SUBSYS_NOTIF_MAX_INDEX)) { @@ -3430,6 +3506,12 @@ static int wcnss_notif_cb(struct notifier_block *this, unsigned long code, schedule_delayed_work(&penv->wcnss_pm_qos_del_req, msecs_to_jiffies(WCNSS_PM_QOS_TIMEOUT)); penv->is_shutdown = 1; + + if (penv->ops) { + priv = penv->ops->priv_data; + penv->ops->driver_state(priv, WCNSS_SMD_CLOSE); + } + wcnss_log_debug_regs_on_bite(); } else if (code == SUBSYS_POWERUP_FAILURE) { if (pdev && pwlanconfig) diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 369aef5e7228e959883c58d0870737d860fbf8a4..651827c6ee6f9905f7963de32b88a36accb2c35f 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -375,6 +375,8 @@ static void wkup_m3_rproc_boot_thread(struct wkup_m3_ipc *m3_ipc) ret = rproc_boot(m3_ipc->rproc); if (ret) dev_err(dev, "rproc_boot failed\n"); + else + m3_ipc_state = m3_ipc; do_exit(0); } @@ -461,8 +463,6 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) goto err_put_rproc; } - m3_ipc_state = m3_ipc; - return 0; err_put_rproc: diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index d19331b6622269bd56d5f42f72b5e67aaf0e0e34..7b739c449227fd3e4f11a2d014a44ab1291c94fa 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -301,7 +301,6 @@ struct atmel_spi { bool use_cs_gpios; bool keep_cs; - bool cs_active; u32 fifo_size; }; @@ -1338,11 +1337,9 @@ static int atmel_spi_one_transfer(struct spi_master *master, &msg->transfers)) { as->keep_cs = true; } else { - as->cs_active = !as->cs_active; - if (as->cs_active) - cs_activate(as, msg->spi); - else - cs_deactivate(as, msg->spi); + cs_deactivate(as, msg->spi); + udelay(10); + cs_activate(as, msg->spi); } } @@ -1365,7 +1362,6 @@ static int atmel_spi_transfer_one_message(struct spi_master *master, atmel_spi_lock(as); cs_activate(as, spi); - as->cs_active = true; as->keep_cs = false; msg->status = 0; diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 5c89bbb05441bd3c8076e8359019811585a97a3a..e075712c501e87abc98fe66a75527c446ffd6f0f 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -416,7 +416,18 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS); master->bits_per_word_mask = SPI_BPW_MASK(8); - master->num_chipselect = -1; + /* even though the driver never officially supported native CS + * allow a single native CS for legacy DT support purposes when + * no cs-gpio is configured. + * Known limitations for native cs are: + * * multiple chip-selects: cs0-cs2 are all simultaniously asserted + * whenever there is a transfer - this even includes SPI_NO_CS + * * SPI_CS_HIGH: is ignores - cs are always asserted low + * * cs_change: cs is deasserted after each spi_transfer + * * cs_delay_usec: cs is always deasserted one SCK cycle after + * a spi_transfer + */ + master->num_chipselect = 1; master->transfer_one = bcm2835aux_spi_transfer_one; master->handle_err = bcm2835aux_spi_handle_err; master->prepare_message = bcm2835aux_spi_prepare_message; diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 02bd1eba045b8b6bc915ff44b076481971c7d1d6..d08ad93d97a1558c3d2cbca94f3f7f070bbdd4e5 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -584,11 +584,6 @@ static int cdns_spi_probe(struct platform_device *pdev) goto clk_dis_apb; } - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); if (ret < 0) master->num_chipselect = CDNS_SPI_DEFAULT_NUM_CS; @@ -603,8 +598,10 @@ static int cdns_spi_probe(struct platform_device *pdev) /* SPI controller initializations */ cdns_spi_init_hw(xspi); - pm_runtime_mark_last_busy(&pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); irq = platform_get_irq(pdev, 0); if (irq <= 0) { diff --git a/drivers/spi/spi-cavium-thunderx.c b/drivers/spi/spi-cavium-thunderx.c index 87793770624086892d57515605f5931e6939bd94..828fbbebc3c48d861d026288920d52e842cb88c4 100644 --- a/drivers/spi/spi-cavium-thunderx.c +++ b/drivers/spi/spi-cavium-thunderx.c @@ -81,6 +81,7 @@ static int thunderx_spi_probe(struct pci_dev *pdev, error: clk_disable_unprepare(p->clk); + pci_release_regions(pdev); spi_master_put(master); return ret; } @@ -95,6 +96,7 @@ static void thunderx_spi_remove(struct pci_dev *pdev) return; clk_disable_unprepare(p->clk); + pci_release_regions(pdev); /* Put everything in a known state. */ writeq(0, p->register_base + OCTEON_SPI_CFG(p)); } diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index b217c22ff72fe9a2284f59f8c1cd62aca58680aa..b461200871f8917b0be062a250459156bf18f6b0 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -180,9 +180,11 @@ static inline u32 rx_max(struct dw_spi *dws) static void dw_writer(struct dw_spi *dws) { - u32 max = tx_max(dws); + u32 max; u16 txw = 0; + spin_lock(&dws->buf_lock); + max = tx_max(dws); while (max--) { /* Set the tx word if the transfer's original "tx" is not null */ if (dws->tx_end - dws->len) { @@ -194,13 +196,16 @@ static void dw_writer(struct dw_spi *dws) dw_write_io_reg(dws, DW_SPI_DR, txw); dws->tx += dws->n_bytes; } + spin_unlock(&dws->buf_lock); } static void dw_reader(struct dw_spi *dws) { - u32 max = rx_max(dws); + u32 max; u16 rxw; + spin_lock(&dws->buf_lock); + max = rx_max(dws); while (max--) { rxw = dw_read_io_reg(dws, DW_SPI_DR); /* Care rx only if the transfer's original "rx" is not null */ @@ -212,6 +217,7 @@ static void dw_reader(struct dw_spi *dws) } dws->rx += dws->n_bytes; } + spin_unlock(&dws->buf_lock); } static void int_error_stop(struct dw_spi *dws, const char *msg) @@ -284,18 +290,20 @@ static int dw_spi_transfer_one(struct spi_master *master, { struct dw_spi *dws = spi_master_get_devdata(master); struct chip_data *chip = spi_get_ctldata(spi); + unsigned long flags; u8 imask = 0; u16 txlevel = 0; u32 cr0; int ret; dws->dma_mapped = 0; - + spin_lock_irqsave(&dws->buf_lock, flags); dws->tx = (void *)transfer->tx_buf; dws->tx_end = dws->tx + transfer->len; dws->rx = transfer->rx_buf; dws->rx_end = dws->rx + transfer->len; dws->len = transfer->len; + spin_unlock_irqrestore(&dws->buf_lock, flags); spi_enable_chip(dws, 0); @@ -486,6 +494,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->type = SSI_MOTO_SPI; dws->dma_inited = 0; dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); + spin_lock_init(&dws->buf_lock); ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), master); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 5c07cf8f19e00607c0f4d17f94c4a8d419658df1..45fbf3ad591cc6ee19f2be5f73fba8f49da941b3 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -117,6 +117,7 @@ struct dw_spi { size_t len; void *tx; void *tx_end; + spinlock_t buf_lock; void *rx; void *rx_end; int dma_mapped; diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 8b79e36fab21c478d673d6f654e4df590483da66..cd784552de7f15048537ddcd78cf43f8822bb12d 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -407,7 +407,6 @@ static int fsl_spi_do_one_msg(struct spi_master *master, } m->status = status; - spi_finalize_current_message(master); if (status || !cs_change) { ndelay(nsecs); @@ -415,6 +414,7 @@ static int fsl_spi_do_one_msg(struct spi_master *master, } fsl_spi_setup_transfer(spi, NULL); + spi_finalize_current_message(master); return 0; } diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 27aebbc4d5c4bfff8b151d3d39b2afa9615367dc..897a74354419719772c15ae9da74f452e0a39092 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -938,16 +938,24 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) /* Transmit an entire FIFO worth of data per IRQ */ mas->tx_wm = 1; - mas->tx = dma_request_slave_channel(mas->dev, "tx"); - if (IS_ERR_OR_NULL(mas->tx)) { - dev_info(mas->dev, "Failed to get tx DMA ch %ld", + + mas->shared_se = + (geni_read_reg(mas->base, GENI_IF_FIFO_DISABLE_RO) & + FIFO_IF_DISABLE); + if (mas->shared_se) { + mas->tx = dma_request_slave_channel(mas->dev, "tx"); + if (IS_ERR_OR_NULL(mas->tx)) { + dev_info(mas->dev, + "Failed to get tx DMA ch %ld", PTR_ERR(mas->tx)); - } else { + goto setup_ipc; + } mas->rx = dma_request_slave_channel(mas->dev, "rx"); if (IS_ERR_OR_NULL(mas->rx)) { dev_info(mas->dev, "Failed to get rx DMA ch %ld", PTR_ERR(mas->rx)); dma_release_channel(mas->tx); + goto setup_ipc; } mas->gsi = devm_kzalloc(mas->dev, (sizeof(struct spi_geni_gsi) * NUM_SPI_XFER), @@ -1006,9 +1014,6 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) "%s:Major:%d Minor:%d step:%dos%d\n", __func__, major, minor, step, mas->oversampling); } - mas->shared_se = - (geni_read_reg(mas->base, GENI_IF_FIFO_DISABLE_RO) & - FIFO_IF_DISABLE); if (mas->dis_autosuspend) GENI_SE_DBG(mas->ipc, false, mas->dev, "Auto Suspend is disabled\n"); @@ -1226,12 +1231,30 @@ static void handle_fifo_timeout(struct spi_master *spi, } dma_unprep: if (mas->cur_xfer_mode == SE_DMA) { - if (xfer->tx_buf) + if (xfer->tx_buf) { + reinit_completion(&mas->xfer_done); + writel_relaxed(1, mas->base + + SE_DMA_TX_FSM_RST); + timeout = + wait_for_completion_timeout(&mas->xfer_done, HZ); + if (!timeout) + dev_err(mas->dev, + "DMA TX RESET failed\n"); geni_se_tx_dma_unprep(mas->wrapper_dev, - xfer->tx_dma, xfer->len); - if (xfer->rx_buf) + xfer->tx_dma, xfer->len); + } + if (xfer->rx_buf) { + reinit_completion(&mas->xfer_done); + writel_relaxed(1, mas->base + + SE_DMA_RX_FSM_RST); + timeout = + wait_for_completion_timeout(&mas->xfer_done, HZ); + if (!timeout) + dev_err(mas->dev, + "DMA RX RESET failed\n"); geni_se_rx_dma_unprep(mas->wrapper_dev, - xfer->rx_dma, xfer->len); + xfer->rx_dma, xfer->len); + } } if (spi->slave && !mas->dis_autosuspend) pm_runtime_put_sync_suspend(mas->dev); @@ -1257,6 +1280,12 @@ static int spi_geni_transfer_one(struct spi_master *spi, return -EINVAL; } + /* Check for zero length transfer */ + if (xfer->len < 1) { + dev_err(mas->dev, "Zero length transfer\n"); + return -EINVAL; + } + if (mas->cur_xfer_mode != GSI_DMA) { reinit_completion(&mas->xfer_done); setup_fifo_xfer(xfer, mas, slv->mode, spi); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 2ad04796ef298a3b426f8a9f6a7ca2a76cc50440..84ff0c507f0b69e42cb360a3605b92724b3766d5 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -307,10 +307,16 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( x |= (u32)(*tx_buf++) << (i * 8); tegra_spi_writel(tspi, x, SPI_TX_FIFO); } + + tspi->cur_tx_pos += written_words * tspi->bytes_per_word; } else { + unsigned int write_bytes; max_n_32bit = min(tspi->curr_dma_words, tx_empty_count); written_words = max_n_32bit; nbytes = written_words * tspi->bytes_per_word; + if (nbytes > t->len - tspi->cur_pos) + nbytes = t->len - tspi->cur_pos; + write_bytes = nbytes; for (count = 0; count < max_n_32bit; count++) { u32 x = 0; @@ -319,8 +325,10 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( x |= (u32)(*tx_buf++) << (i * 8); tegra_spi_writel(tspi, x, SPI_TX_FIFO); } + + tspi->cur_tx_pos += write_bytes; } - tspi->cur_tx_pos += written_words * tspi->bytes_per_word; + return written_words; } @@ -344,20 +352,27 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf( for (i = 0; len && (i < 4); i++, len--) *rx_buf++ = (x >> i*8) & 0xFF; } - tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; read_words += tspi->curr_dma_words; + tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; } else { u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; + u8 bytes_per_word = tspi->bytes_per_word; + unsigned int read_bytes; + len = rx_full_count * bytes_per_word; + if (len > t->len - tspi->cur_pos) + len = t->len - tspi->cur_pos; + read_bytes = len; for (count = 0; count < rx_full_count; count++) { u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO) & rx_mask; - for (i = 0; (i < tspi->bytes_per_word); i++) + for (i = 0; len && (i < bytes_per_word); i++, len--) *rx_buf++ = (x >> (i*8)) & 0xFF; } - tspi->cur_rx_pos += rx_full_count * tspi->bytes_per_word; read_words += rx_full_count; + tspi->cur_rx_pos += read_bytes; } + return read_words; } @@ -372,12 +387,17 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len); + tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word; } else { unsigned int i; unsigned int count; u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos; unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word; + unsigned int write_bytes; + if (consume > t->len - tspi->cur_pos) + consume = t->len - tspi->cur_pos; + write_bytes = consume; for (count = 0; count < tspi->curr_dma_words; count++) { u32 x = 0; @@ -386,8 +406,9 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( x |= (u32)(*tx_buf++) << (i * 8); tspi->tx_dma_buf[count] = x; } + + tspi->cur_tx_pos += write_bytes; } - tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word; /* Make the dma buffer to read by dma */ dma_sync_single_for_device(tspi->dev, tspi->tx_dma_phys, @@ -405,20 +426,28 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf( unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len); + tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; } else { unsigned int i; unsigned int count; unsigned char *rx_buf = t->rx_buf + tspi->cur_rx_pos; u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; + unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word; + unsigned int read_bytes; + if (consume > t->len - tspi->cur_pos) + consume = t->len - tspi->cur_pos; + read_bytes = consume; for (count = 0; count < tspi->curr_dma_words; count++) { u32 x = tspi->rx_dma_buf[count] & rx_mask; - for (i = 0; (i < tspi->bytes_per_word); i++) + for (i = 0; consume && (i < tspi->bytes_per_word); + i++, consume--) *rx_buf++ = (x >> (i*8)) & 0xFF; } + + tspi->cur_rx_pos += read_bytes; } - tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; /* Make the dma buffer to read by dma */ dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys, @@ -470,22 +499,39 @@ static int tegra_spi_start_rx_dma(struct tegra_spi_data *tspi, int len) return 0; } -static int tegra_spi_start_dma_based_transfer( - struct tegra_spi_data *tspi, struct spi_transfer *t) +static int tegra_spi_flush_fifos(struct tegra_spi_data *tspi) { - u32 val; - unsigned int len; - int ret = 0; + unsigned long timeout = jiffies + HZ; u32 status; - /* Make sure that Rx and Tx fifo are empty */ status = tegra_spi_readl(tspi, SPI_FIFO_STATUS); if ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) { - dev_err(tspi->dev, "Rx/Tx fifo are not empty status 0x%08x\n", - (unsigned)status); - return -EIO; + status |= SPI_RX_FIFO_FLUSH | SPI_TX_FIFO_FLUSH; + tegra_spi_writel(tspi, status, SPI_FIFO_STATUS); + while ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) { + status = tegra_spi_readl(tspi, SPI_FIFO_STATUS); + if (time_after(jiffies, timeout)) { + dev_err(tspi->dev, + "timeout waiting for fifo flush\n"); + return -EIO; + } + + udelay(1); + } } + return 0; +} + +static int tegra_spi_start_dma_based_transfer( + struct tegra_spi_data *tspi, struct spi_transfer *t) +{ + u32 val; + unsigned int len; + int ret = 0; + u8 dma_burst; + struct dma_slave_config dma_sconfig = {0}; + val = SPI_DMA_BLK_SET(tspi->curr_dma_words - 1); tegra_spi_writel(tspi, val, SPI_DMA_BLK); @@ -496,12 +542,16 @@ static int tegra_spi_start_dma_based_transfer( len = tspi->curr_dma_words * 4; /* Set attention level based on length of transfer */ - if (len & 0xF) + if (len & 0xF) { val |= SPI_TX_TRIG_1 | SPI_RX_TRIG_1; - else if (((len) >> 4) & 0x1) + dma_burst = 1; + } else if (((len) >> 4) & 0x1) { val |= SPI_TX_TRIG_4 | SPI_RX_TRIG_4; - else + dma_burst = 4; + } else { val |= SPI_TX_TRIG_8 | SPI_RX_TRIG_8; + dma_burst = 8; + } if (tspi->cur_direction & DATA_DIR_TX) val |= SPI_IE_TX; @@ -512,7 +562,18 @@ static int tegra_spi_start_dma_based_transfer( tegra_spi_writel(tspi, val, SPI_DMA_CTL); tspi->dma_control_reg = val; + dma_sconfig.device_fc = true; if (tspi->cur_direction & DATA_DIR_TX) { + dma_sconfig.dst_addr = tspi->phys + SPI_TX_FIFO; + dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_sconfig.dst_maxburst = dma_burst; + ret = dmaengine_slave_config(tspi->tx_dma_chan, &dma_sconfig); + if (ret < 0) { + dev_err(tspi->dev, + "DMA slave config failed: %d\n", ret); + return ret; + } + tegra_spi_copy_client_txbuf_to_spi_txbuf(tspi, t); ret = tegra_spi_start_tx_dma(tspi, len); if (ret < 0) { @@ -523,6 +584,16 @@ static int tegra_spi_start_dma_based_transfer( } if (tspi->cur_direction & DATA_DIR_RX) { + dma_sconfig.src_addr = tspi->phys + SPI_RX_FIFO; + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_sconfig.src_maxburst = dma_burst; + ret = dmaengine_slave_config(tspi->rx_dma_chan, &dma_sconfig); + if (ret < 0) { + dev_err(tspi->dev, + "DMA slave config failed: %d\n", ret); + return ret; + } + /* Make the dma buffer to read by dma */ dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys, tspi->dma_buf_size, DMA_FROM_DEVICE); @@ -582,7 +653,6 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi, u32 *dma_buf; dma_addr_t dma_phys; int ret; - struct dma_slave_config dma_sconfig; dma_chan = dma_request_slave_channel_reason(tspi->dev, dma_to_memory ? "rx" : "tx"); @@ -602,19 +672,6 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi, return -ENOMEM; } - if (dma_to_memory) { - dma_sconfig.src_addr = tspi->phys + SPI_RX_FIFO; - dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dma_sconfig.src_maxburst = 0; - } else { - dma_sconfig.dst_addr = tspi->phys + SPI_TX_FIFO; - dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dma_sconfig.dst_maxburst = 0; - } - - ret = dmaengine_slave_config(dma_chan, &dma_sconfig); - if (ret) - goto scrub; if (dma_to_memory) { tspi->rx_dma_chan = dma_chan; tspi->rx_dma_buf = dma_buf; @@ -625,11 +682,6 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi, tspi->tx_dma_phys = dma_phys; } return 0; - -scrub: - dma_free_coherent(tspi->dev, tspi->dma_buf_size, dma_buf, dma_phys); - dma_release_channel(dma_chan); - return ret; } static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, @@ -730,6 +782,8 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, if (tspi->is_packed) command1 |= SPI_PACKED; + else + command1 &= ~SPI_PACKED; command1 &= ~(SPI_CS_SEL_MASK | SPI_TX_EN | SPI_RX_EN); tspi->cur_direction = 0; @@ -748,6 +802,9 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, dev_dbg(tspi->dev, "The def 0x%x and written 0x%x\n", tspi->def_command1_reg, (unsigned)command1); + ret = tegra_spi_flush_fifos(tspi); + if (ret < 0) + return ret; if (total_fifo_words > SPI_FIFO_DEPTH) ret = tegra_spi_start_dma_based_transfer(tspi, t); else @@ -838,7 +895,17 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, if (WARN_ON(ret == 0)) { dev_err(tspi->dev, "spi transfer timeout, err %d\n", ret); + if (tspi->is_curr_dma_xfer && + (tspi->cur_direction & DATA_DIR_TX)) + dmaengine_terminate_all(tspi->tx_dma_chan); + if (tspi->is_curr_dma_xfer && + (tspi->cur_direction & DATA_DIR_RX)) + dmaengine_terminate_all(tspi->rx_dma_chan); ret = -EIO; + tegra_spi_flush_fifos(tspi); + reset_control_assert(tspi->rst); + udelay(2); + reset_control_deassert(tspi->rst); goto complete_xfer; } @@ -889,6 +956,7 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi) tspi->status_reg); dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x\n", tspi->command1_reg, tspi->dma_control_reg); + tegra_spi_flush_fifos(tspi); reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); @@ -961,6 +1029,7 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi) tspi->status_reg); dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x\n", tspi->command1_reg, tspi->dma_control_reg); + tegra_spi_flush_fifos(tspi); reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 4389ab80c23e6cdbaeba15d8ccc5cfba736d7fa2..fa730a871d25276cc9293d8e57e01b6fd95294ec 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1008,6 +1008,9 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) /* RX */ dma->sg_rx_p = kcalloc(num, sizeof(*dma->sg_rx_p), GFP_ATOMIC); + if (!dma->sg_rx_p) + return; + sg_init_table(dma->sg_rx_p, num); /* Initialize SG table */ /* offset, length setting */ sg = dma->sg_rx_p; @@ -1068,6 +1071,9 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) } dma->sg_tx_p = kcalloc(num, sizeof(*dma->sg_tx_p), GFP_ATOMIC); + if (!dma->sg_tx_p) + return; + sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */ /* offset, length setting */ sg = dma->sg_tx_p; diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index e7d7efacfda79812f4b1c29542442e75c9b9f86e..1cca65f186eb7207ed20570b30f11ce9c87753aa 100644 --- a/drivers/spi/spi_qsd.c +++ b/drivers/spi/spi_qsd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, 2020 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 @@ -1703,28 +1703,82 @@ static int msm_spi_transfer_one(struct spi_master *master, return status_error; } -static int msm_spi_prepare_transfer_hardware(struct spi_master *master) +static int msm_spi_pm_get_sync(struct device *dev) { - struct msm_spi *dd = spi_master_get_devdata(master); - int resume_state = 0; - - resume_state = pm_runtime_get_sync(dd->dev); - if (resume_state < 0) - goto spi_finalize; + int ret; /* * Counter-part of system-suspend when runtime-pm is not enabled. * This way, resume can be left empty and device will be put in * active mode only if client requests anything on the bus */ - if (!pm_runtime_enabled(dd->dev)) - resume_state = msm_spi_pm_resume_runtime(dd->dev); + if (!pm_runtime_enabled(dev)) { + dev_info(dev, "%s: pm_runtime not enabled\n", __func__); + ret = msm_spi_pm_resume_runtime(dev); + } else { + ret = pm_runtime_get_sync(dev); + } + + return ret; +} + +static int msm_spi_pm_put_sync(struct device *dev) +{ + int ret = 0; + + if (!pm_runtime_enabled(dev)) { + dev_info(dev, "%s: pm_runtime not enabled\n", __func__); + ret = msm_spi_pm_suspend_runtime(dev); + } else { + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + } + + return ret; +} + +static int msm_spi_prepare_message(struct spi_master *master, + struct spi_message *spi_msg) +{ + struct msm_spi *dd = spi_master_get_devdata(master); + int resume_state; + + resume_state = msm_spi_pm_get_sync(dd->dev); if (resume_state < 0) - goto spi_finalize; - if (dd->suspended) { - resume_state = -EBUSY; - goto spi_finalize; + return resume_state; + + return 0; +} + +static int msm_spi_unprepare_message(struct spi_master *master, + struct spi_message *spi_msg) +{ + struct msm_spi *dd = spi_master_get_devdata(master); + int ret; + + ret = msm_spi_pm_put_sync(dd->dev); + if (ret < 0) + return ret; + + return 0; +} + +static int msm_spi_prepare_transfer_hardware(struct spi_master *master) +{ + struct msm_spi *dd = spi_master_get_devdata(master); + int resume_state; + + if (!dd->pdata->shared_ee) { + resume_state = msm_spi_pm_get_sync(dd->dev); + if (resume_state < 0) + goto spi_finalize; + + if (dd->suspended) { + resume_state = -EBUSY; + goto spi_finalize; + } } + return 0; spi_finalize: @@ -1735,9 +1789,14 @@ static int msm_spi_prepare_transfer_hardware(struct spi_master *master) static int msm_spi_unprepare_transfer_hardware(struct spi_master *master) { struct msm_spi *dd = spi_master_get_devdata(master); + int ret; + + if (!dd->pdata->shared_ee) { + ret = msm_spi_pm_put_sync(dd->dev); + if (ret < 0) + return ret; + } - pm_runtime_mark_last_busy(dd->dev); - pm_runtime_put_autosuspend(dd->dev); return 0; } @@ -2233,6 +2292,8 @@ static struct msm_spi_platform_data *msm_spi_dt_to_pdata( &pdata->rt_priority, DT_OPT, DT_BOOL, 0}, {"qcom,shared", &pdata->is_shared, DT_OPT, DT_BOOL, 0}, + {"qcom,shared_ee", + &pdata->shared_ee, DT_OPT, DT_BOOL, 0}, {NULL, NULL, 0, 0, 0}, }; @@ -2558,6 +2619,12 @@ static int msm_spi_probe(struct platform_device *pdev) goto err_probe_reqmem; } + /* This property is required for Dual EE use case of spi */ + if (dd->pdata->shared_ee) { + master->prepare_message = msm_spi_prepare_message; + master->unprepare_message = msm_spi_unprepare_message; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, MSEC_PER_SEC); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 8f92df270d43cda94047cb2c915773edd0cc8744..bc0679ec4d20aa81b7b2dc08b0f907504ee8a3b5 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1130,6 +1130,7 @@ struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, if (!((1 << heap->id) & heap_id_mask)) continue; if (heap->type == ION_HEAP_TYPE_SYSTEM || + heap->type == ION_HEAP_TYPE_CARVEOUT || heap->type == (enum ion_heap_type)ION_HEAP_TYPE_HYP_CMA || heap->type == (enum ion_heap_type)ION_HEAP_TYPE_SYSTEM_SECURE) { diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index 2c1b6de30da8c4d74e085aaeac64d1c376c53a9f..385e14269870da4d1ca35af7e774bd138421f153 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -45,8 +45,8 @@ #define PCI171X_RANGE_UNI BIT(4) #define PCI171X_RANGE_GAIN(x) (((x) & 0x7) << 0) #define PCI171X_MUX_REG 0x04 /* W: A/D multiplexor control */ -#define PCI171X_MUX_CHANH(x) (((x) & 0xf) << 8) -#define PCI171X_MUX_CHANL(x) (((x) & 0xf) << 0) +#define PCI171X_MUX_CHANH(x) (((x) & 0xff) << 8) +#define PCI171X_MUX_CHANL(x) (((x) & 0xff) << 0) #define PCI171X_MUX_CHAN(x) (PCI171X_MUX_CHANH(x) | PCI171X_MUX_CHANL(x)) #define PCI171X_STATUS_REG 0x06 /* R: status register */ #define PCI171X_STATUS_IRQ BIT(11) /* 1=IRQ occurred */ diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 36361bdf934acbcf92db878895dbd3f9b510effc..2f82dcb1fd062a3cc16277282eae2732ab5538f4 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -4991,7 +4991,10 @@ static int ni_valid_rtsi_output_source(struct comedi_device *dev, case NI_RTSI_OUTPUT_G_SRC0: case NI_RTSI_OUTPUT_G_GATE0: case NI_RTSI_OUTPUT_RGOUT0: - case NI_RTSI_OUTPUT_RTSI_BRD_0: + case NI_RTSI_OUTPUT_RTSI_BRD(0): + case NI_RTSI_OUTPUT_RTSI_BRD(1): + case NI_RTSI_OUTPUT_RTSI_BRD(2): + case NI_RTSI_OUTPUT_RTSI_BRD(3): return 1; case NI_RTSI_OUTPUT_RTSI_OSC: return (devpriv->is_m_series) ? 1 : 0; @@ -5012,11 +5015,18 @@ static int ni_set_rtsi_routing(struct comedi_device *dev, devpriv->rtsi_trig_a_output_reg |= NISTC_RTSI_TRIG(chan, src); ni_stc_writew(dev, devpriv->rtsi_trig_a_output_reg, NISTC_RTSI_TRIGA_OUT_REG); - } else if (chan < 8) { + } else if (chan < NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series)) { devpriv->rtsi_trig_b_output_reg &= ~NISTC_RTSI_TRIG_MASK(chan); devpriv->rtsi_trig_b_output_reg |= NISTC_RTSI_TRIG(chan, src); ni_stc_writew(dev, devpriv->rtsi_trig_b_output_reg, NISTC_RTSI_TRIGB_OUT_REG); + } else if (chan != NISTC_RTSI_TRIG_OLD_CLK_CHAN) { + /* probably should never reach this, since the + * ni_valid_rtsi_output_source above errors out if chan is too + * high + */ + dev_err(dev->class_dev, "%s: unknown rtsi channel\n", __func__); + return -EINVAL; } return 2; } @@ -5032,12 +5042,12 @@ static unsigned int ni_get_rtsi_routing(struct comedi_device *dev, } else if (chan < NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series)) { return NISTC_RTSI_TRIG_TO_SRC(chan, devpriv->rtsi_trig_b_output_reg); - } else { - if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN) - return NI_RTSI_OUTPUT_RTSI_OSC; - dev_err(dev->class_dev, "bug! should never get here?\n"); - return 0; + } else if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN) { + return NI_RTSI_OUTPUT_RTSI_OSC; } + + dev_err(dev->class_dev, "%s: unknown rtsi channel\n", __func__); + return -EINVAL; } static int ni_rtsi_insn_config(struct comedi_device *dev, diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c index 0f538b8c3a07629f56f85b92737472018553c0b8..4e7575147775dadc34dc3c48aa639e63c92ecf67 100644 --- a/drivers/staging/greybus/light.c +++ b/drivers/staging/greybus/light.c @@ -1103,21 +1103,21 @@ static void gb_lights_channel_release(struct gb_channel *channel) static void gb_lights_light_release(struct gb_light *light) { int i; - int count; light->ready = false; - count = light->channels_count; - if (light->has_flash) gb_lights_light_v4l2_unregister(light); + light->has_flash = false; - for (i = 0; i < count; i++) { + for (i = 0; i < light->channels_count; i++) gb_lights_channel_release(&light->channels[i]); - light->channels_count--; - } + light->channels_count = 0; + kfree(light->channels); + light->channels = NULL; kfree(light->name); + light->name = NULL; } static void gb_lights_release(struct gb_lights *glights) diff --git a/drivers/staging/most/aim-cdev/cdev.c b/drivers/staging/most/aim-cdev/cdev.c index 1e5cbc893496a441b7a85c35027882abfdc16450..d000b6ff8a7d23ea451dede49a8cf0585b1e62ff 100644 --- a/drivers/staging/most/aim-cdev/cdev.c +++ b/drivers/staging/most/aim-cdev/cdev.c @@ -455,7 +455,9 @@ static int aim_probe(struct most_interface *iface, int channel_id, c->devno = MKDEV(major, current_minor); cdev_init(&c->cdev, &channel_fops); c->cdev.owner = THIS_MODULE; - cdev_add(&c->cdev, c->devno, 1); + retval = cdev_add(&c->cdev, c->devno, 1); + if (retval < 0) + goto err_free_c; c->iface = iface; c->cfg = cfg; c->channel_id = channel_id; @@ -491,6 +493,7 @@ static int aim_probe(struct most_interface *iface, int channel_id, list_del(&c->list); error_alloc_kfifo: cdev_del(&c->cdev); +err_free_c: kfree(c); error_alloc_channel: ida_simple_remove(&minor_id, current_minor); diff --git a/drivers/staging/most/aim-network/networking.c b/drivers/staging/most/aim-network/networking.c index 936f013c350edad586548f033d2aafe880bc7ac6..6398c27563c9ef7e8c57e4b88838b8d6868ae2cc 100644 --- a/drivers/staging/most/aim-network/networking.c +++ b/drivers/staging/most/aim-network/networking.c @@ -85,6 +85,11 @@ static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo) unsigned int payload_len = skb->len - ETH_HLEN; unsigned int mdp_len = payload_len + MDP_HDR_LEN; + if (mdp_len < skb->len) { + pr_err("drop: too large packet! (%u)\n", skb->len); + return -EINVAL; + } + if (mbo->buffer_length < mdp_len) { pr_err("drop: too small buffer! (%d for %d)\n", mbo->buffer_length, mdp_len); @@ -132,6 +137,11 @@ static int skb_to_mep(const struct sk_buff *skb, struct mbo *mbo) u8 *buff = mbo->virt_address; unsigned int mep_len = skb->len + MEP_HDR_LEN; + if (mep_len < skb->len) { + pr_err("drop: too large packet! (%u)\n", skb->len); + return -EINVAL; + } + if (mbo->buffer_length < mep_len) { pr_err("drop: too small buffer! (%d for %d)\n", mbo->buffer_length, mep_len); diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 3733b73863b67e9c733b2044882aa4a8512a488d..5364533585685e46af5513c3499aa5e1aa19488b 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -45,6 +45,7 @@ static const struct usb_device_id rtw_usb_id_tbl[] = { {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */ {USB_DEVICE(0x2001, 0x331B)}, /* D-Link DWA-121 rev B1 */ {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */ + {USB_DEVICE(0x2357, 0x0111)}, /* TP-Link TL-WN727N v5.21 */ {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */ {} /* Terminating entry */ diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c index 544f638ed3efb94a6639e214da9bc10f2c6aee23..65edd14a1147a8440f5c33db7098ea672826b508 100644 --- a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c @@ -2492,8 +2492,11 @@ halmac_parse_psd_data_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, segment_size = (u8)PSD_DATA_GET_SEGMENT_SIZE(c2h_buf); psd_set->data_size = total_size; - if (!psd_set->data) + if (!psd_set->data) { psd_set->data = kzalloc(psd_set->data_size, GFP_KERNEL); + if (!psd_set->data) + return HALMAC_RET_MALLOC_FAIL; + } if (segment_id == 0) psd_set->segment_size = segment_size; diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index 377da037f31c3071499c43516395a0bd2745592f..b521752d9aa01aaeeaa2e9aff1478b624c1187e2 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -1849,6 +1849,12 @@ static int __init bm2835_mmal_init(void) num_cameras = get_num_cameras(instance, resolutions, MAX_BCM2835_CAMERAS); + + if (num_cameras < 1) { + ret = -ENODEV; + goto cleanup_mmal; + } + if (num_cameras > MAX_BCM2835_CAMERAS) num_cameras = MAX_BCM2835_CAMERAS; @@ -1948,6 +1954,9 @@ static int __init bm2835_mmal_init(void) pr_info("%s: error %d while loading driver\n", BM2835_MMAL_MODULE_NAME, ret); +cleanup_mmal: + vchiq_mmal_finalise(instance); + return ret; } diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h index 74715c85485600c27b34b303e11b6c389698d9ba..41a4f9555d07ec9dc2b8f93ae2cf54e2b08cc4dd 100644 --- a/drivers/staging/vt6656/device.h +++ b/drivers/staging/vt6656/device.h @@ -62,6 +62,8 @@ #define RATE_AUTO 12 #define MAX_RATE 12 +#define VNT_B_RATES (BIT(RATE_1M) | BIT(RATE_2M) |\ + BIT(RATE_5M) | BIT(RATE_11M)) /* * device specific @@ -269,6 +271,7 @@ struct vnt_private { u8 mac_hw; /* netdev */ struct usb_device *usb; + struct usb_interface *intf; u64 tsf_time; u8 rx_rate; diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c index c6ffbe0e2728c29250bee442afab8cddacf1bc8f..c521729c4192cb500198a3252001d363211f026b 100644 --- a/drivers/staging/vt6656/int.c +++ b/drivers/staging/vt6656/int.c @@ -107,9 +107,11 @@ static int vnt_int_report_rate(struct vnt_private *priv, u8 pkt_no, u8 tsr) info->status.rates[0].count = tx_retry; - if (!(tsr & (TSR_TMO | TSR_RETRYTMO))) { + if (!(tsr & TSR_TMO)) { info->status.rates[0].idx = idx; - info->flags |= IEEE80211_TX_STAT_ACK; + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_ACK; } ieee80211_tx_status_irqsafe(priv->hw, context->skb); diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index cc6d8778fe5ba89220dd60e5b878a7bf5dc7c5f6..e8ccd800c94fde6a504eec428291f7ab6f61cf4c 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -954,6 +954,7 @@ vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id) priv = hw->priv; priv->hw = hw; priv->usb = udev; + priv->intf = intf; vnt_set_options(priv); @@ -976,6 +977,7 @@ vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id) ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS); ieee80211_hw_set(priv->hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(priv->hw, SUPPORTS_PS); + ieee80211_hw_set(priv->hw, PS_NULLFUNC_STACK); priv->hw->max_signal = 100; diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index a44abcce6fb4504add5b871d7580304781dd988a..f78f31ce64437f81056ed2529b6e68b02388c5f4 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -288,11 +288,9 @@ static u16 vnt_rxtx_datahead_g(struct vnt_usb_send_context *tx_context, PK_TYPE_11B, &buf->b); /* Get Duration and TimeStamp */ - if (ieee80211_is_pspoll(hdr->frame_control)) { - __le16 dur = cpu_to_le16(priv->current_aid | BIT(14) | BIT(15)); - - buf->duration_a = dur; - buf->duration_b = dur; + if (ieee80211_is_nullfunc(hdr->frame_control)) { + buf->duration_a = hdr->duration_id; + buf->duration_b = hdr->duration_id; } else { buf->duration_a = vnt_get_duration_le(priv, tx_context->pkt_type, need_ack); @@ -381,10 +379,8 @@ static u16 vnt_rxtx_datahead_ab(struct vnt_usb_send_context *tx_context, tx_context->pkt_type, &buf->ab); /* Get Duration and TimeStampOff */ - if (ieee80211_is_pspoll(hdr->frame_control)) { - __le16 dur = cpu_to_le16(priv->current_aid | BIT(14) | BIT(15)); - - buf->duration = dur; + if (ieee80211_is_nullfunc(hdr->frame_control)) { + buf->duration = hdr->duration_id; } else { buf->duration = vnt_get_duration_le(priv, tx_context->pkt_type, need_ack); @@ -825,10 +821,14 @@ int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) if (info->band == NL80211_BAND_5GHZ) { pkt_type = PK_TYPE_11A; } else { - if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - pkt_type = PK_TYPE_11GB; - else - pkt_type = PK_TYPE_11GA; + if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + if (priv->basic_rates & VNT_B_RATES) + pkt_type = PK_TYPE_11GB; + else + pkt_type = PK_TYPE_11GA; + } else { + pkt_type = PK_TYPE_11A; + } } } else { pkt_type = PK_TYPE_11B; diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c index b2fc17f1381b2543484491f3cfefea75f93fd486..3f6ccdeb6decdfa1a16dedb94ea5a24e6ee4bb5a 100644 --- a/drivers/staging/vt6656/wcmd.c +++ b/drivers/staging/vt6656/wcmd.c @@ -109,6 +109,7 @@ void vnt_run_command(struct work_struct *work) if (vnt_init(priv)) { /* If fail all ends TODO retry */ dev_err(&priv->usb->dev, "failed to start\n"); + usb_set_intfdata(priv->intf, NULL); ieee80211_free_hw(priv->hw); return; } diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c index c4aa9e7e7003cb669ea9e888791391df588ebeb7..be89a0ee44bf997871735b7e0bb58e752d6e2b20 100644 --- a/drivers/staging/wlan-ng/prism2mgmt.c +++ b/drivers/staging/wlan-ng/prism2mgmt.c @@ -945,7 +945,7 @@ int prism2mgmt_flashdl_state(struct wlandevice *wlandev, void *msgp) } } - return 0; + return result; } /*---------------------------------------------------------------- diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 21ce92ee16527d5c532988dc8d6e129ee80b8ca3..37d64acea5e1ea166c6f78c8ce24fd33cf0495d5 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -4155,9 +4155,6 @@ int iscsit_close_connection( iscsit_stop_nopin_response_timer(conn); iscsit_stop_nopin_timer(conn); - if (conn->conn_transport->iscsit_wait_conn) - conn->conn_transport->iscsit_wait_conn(conn); - /* * During Connection recovery drop unacknowledged out of order * commands for this connection, and prepare the other commands @@ -4243,6 +4240,9 @@ int iscsit_close_connection( target_sess_cmd_list_set_waiting(sess->se_sess); target_wait_for_sess_cmds(sess->se_sess); + if (conn->conn_transport->iscsit_wait_conn) + conn->conn_transport->iscsit_wait_conn(conn); + ahash_request_free(conn->conn_tx_hash); if (conn->conn_rx_hash) { struct crypto_ahash *tfm; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 92b52d2314b5359ed31f1789a874fbed0120cf59..cebef8e5a43d16d61e67ea4a8a58faedebe41e6d 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -85,7 +85,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun) goto out_unlock; } - se_cmd->se_lun = rcu_dereference(deve->se_lun); + se_cmd->se_lun = se_lun; se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; @@ -176,7 +176,7 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u64 unpacked_lun) goto out_unlock; } - se_cmd->se_lun = rcu_dereference(deve->se_lun); + se_cmd->se_lun = se_lun; se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 508da345b73fdb3561a434d8ed320469081ded5a..95aa47ac4dcd2b923a996e709611d0fd52469718 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -131,7 +131,7 @@ static int srp_get_pr_transport_id( memset(buf + 8, 0, leading_zero_bytes); rc = hex2bin(buf + 8 + leading_zero_bytes, p, count); if (rc < 0) { - pr_debug("hex2bin failed for %s: %d\n", __func__, rc); + pr_debug("hex2bin failed for %s: %d\n", p, rc); return rc; } diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index 0126de898036cdb6eacb51cc672232b7de9060d7..108600c6eb5641f013682d13c231f2b8ac0fc07e 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -2,6 +2,7 @@ config OPTEE tristate "OP-TEE" depends on HAVE_ARM_SMCCC + depends on MMU help This implements the OP-TEE Trusted Execution Environment (TEE) driver. diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index a40ec378e950314cd8bb54227f1eaea0c6df6a5b..40c7ae9822030743e147b957c0001b27b2f82f90 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -786,7 +786,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, load = 0; total_load += load; - if (trace_thermal_power_cpu_limit_enabled() && load_cpu) + if (load_cpu) load_cpu[i] = load; i++; diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index 7db6a4b9aa2d4705aadf134ec341f6cd3c083f16..fc50f2b684eba4cfeb5e73fbf842a72724d3ddc5 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -253,7 +253,7 @@ static void tsens_therm_fwk_notify(struct work_struct *work) } TSENS_DBG(tmdev, "Calling trip_temp for sensor %d\n", i); - of_thermal_handle_trip_temp(tmdev->sensor[i].tzd, temp); + of_thermal_handle_trip(tmdev->sensor[i].tzd); } } } diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c index 1e61c09153c9abf0d02eb43d4ff21ba925da9415..76b92083744c9cb9582565f9ac7ecb59016e88f5 100644 --- a/drivers/thermal/mtk_thermal.c +++ b/drivers/thermal/mtk_thermal.c @@ -407,7 +407,8 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank) u32 raw; for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) { - raw = readl(mt->thermal_base + conf->msr[i]); + raw = readl(mt->thermal_base + + conf->msr[conf->bank_data[bank->id].sensors[i]]); temp = raw_to_mcelsius(mt, conf->bank_data[bank->id].sensors[i], @@ -544,7 +545,8 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, for (i = 0; i < conf->bank_data[num].num_sensors; i++) writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]], - mt->thermal_base + conf->adcpnp[i]); + mt->thermal_base + + conf->adcpnp[conf->bank_data[num].sensors[i]]); writel((1 << conf->bank_data[num].num_sensors) - 1, mt->thermal_base + TEMP_MONCTL0); diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c index 29aca6f3d2d830d2a4dadb139b692f3ea6495358..209ba04bcc8c449c1a9957ec2f06d5d6772c5e4c 100644 --- a/drivers/thermal/tsens2xxx.c +++ b/drivers/thermal/tsens2xxx.c @@ -83,12 +83,70 @@ static void msm_tsens_convert_temp(int last_temp, int *temp) *temp = last_temp * TSENS_TM_SCALE_DECI_MILLIDEG; } +static int __tsens2xxx_hw_init(struct tsens_device *tmdev) +{ + void __iomem *srot_addr; + void __iomem *sensor_int_mask_addr; + unsigned int srot_val, crit_mask, crit_val; + void __iomem *int_mask_addr; + + srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4); + srot_val = readl_relaxed(srot_addr); + if (!(srot_val & TSENS_EN)) { + pr_err("TSENS device is not enabled\n"); + return -ENODEV; + } + + if (tmdev->ctrl_data->cycle_monitor) { + sensor_int_mask_addr = + TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); + crit_mask = readl_relaxed(sensor_int_mask_addr); + crit_val = TSENS_TM_CRITICAL_CYCLE_MONITOR; + if (tmdev->ctrl_data->cycle_compltn_monitor_mask) + writel_relaxed((crit_mask | crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + else + writel_relaxed((crit_mask & ~crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + /*Update critical cycle monitoring*/ + mb(); + } + + if (tmdev->ctrl_data->wd_bark) { + sensor_int_mask_addr = + TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); + crit_mask = readl_relaxed(sensor_int_mask_addr); + crit_val = TSENS_TM_CRITICAL_WD_BARK; + if (tmdev->ctrl_data->wd_bark_mask) + writel_relaxed((crit_mask | crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + else + writel_relaxed((crit_mask & ~crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + /*Update watchdog monitoring*/ + mb(); + } + + int_mask_addr = TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_tm_addr); + writel_relaxed(TSENS_TM_UPPER_LOWER_INT_DISABLE, int_mask_addr); + + writel_relaxed(TSENS_TM_CRITICAL_INT_EN | + TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN, + TSENS_TM_INT_EN(tmdev->tsens_tm_addr)); + + return 0; +} + static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) { struct tsens_device *tmdev = NULL, *tmdev_itr; unsigned int code, ret, tsens_ret; void __iomem *sensor_addr, *trdy; - int last_temp = 0, last_temp2 = 0, last_temp3 = 0, count = 0; + int rc = 0, last_temp = 0, last_temp2 = 0, last_temp3 = 0, count = 0; static atomic_t in_tsens_reinit; if (!sensor) @@ -173,6 +231,13 @@ static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) /* Notify thermal fwk */ list_for_each_entry(tmdev_itr, &tsens_device_list, list) { + rc = __tsens2xxx_hw_init(tmdev_itr); + if (rc) { + pr_err( + "%s: Failed to re-initialize TSENS controller\n", + __func__); + BUG(); + } queue_work(tmdev_itr->tsens_reinit_work, &tmdev_itr->therm_fwk_notify); } @@ -620,58 +685,11 @@ static int tsens2xxx_hw_sensor_en(struct tsens_device *tmdev, static int tsens2xxx_hw_init(struct tsens_device *tmdev) { - void __iomem *srot_addr; - void __iomem *sensor_int_mask_addr; - unsigned int srot_val, crit_mask, crit_val; - void __iomem *int_mask_addr; - - srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4); - srot_val = readl_relaxed(srot_addr); - if (!(srot_val & TSENS_EN)) { - pr_err("TSENS device is not enabled\n"); - return -ENODEV; - } - - if (tmdev->ctrl_data->cycle_monitor) { - sensor_int_mask_addr = - TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); - crit_mask = readl_relaxed(sensor_int_mask_addr); - crit_val = TSENS_TM_CRITICAL_CYCLE_MONITOR; - if (tmdev->ctrl_data->cycle_compltn_monitor_mask) - writel_relaxed((crit_mask | crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - else - writel_relaxed((crit_mask & ~crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - /*Update critical cycle monitoring*/ - mb(); - } - - if (tmdev->ctrl_data->wd_bark) { - sensor_int_mask_addr = - TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); - crit_mask = readl_relaxed(sensor_int_mask_addr); - crit_val = TSENS_TM_CRITICAL_WD_BARK; - if (tmdev->ctrl_data->wd_bark_mask) - writel_relaxed((crit_mask | crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - else - writel_relaxed((crit_mask & ~crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - /*Update watchdog monitoring*/ - mb(); - } - - int_mask_addr = TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_tm_addr); - writel_relaxed(TSENS_TM_UPPER_LOWER_INT_DISABLE, int_mask_addr); + int rc = 0; - writel_relaxed(TSENS_TM_CRITICAL_INT_EN | - TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN, - TSENS_TM_INT_EN(tmdev->tsens_tm_addr)); + rc = __tsens2xxx_hw_init(tmdev); + if (rc) + return rc; spin_lock_init(&tmdev->tsens_crit_lock); spin_lock_init(&tmdev->tsens_upp_low_lock); diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c index a6b8240af6cdd6dcfb6bbb07e39e39bc13bf4f7b..960e9375a1a9e856c88d29529879c5266808b35a 100644 --- a/drivers/tty/ipwireless/hardware.c +++ b/drivers/tty/ipwireless/hardware.c @@ -1516,6 +1516,8 @@ static void ipw_send_setup_packet(struct ipw_hardware *hw) sizeof(struct ipw_setup_get_version_query_packet), ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, TL_SETUP_SIGNO_GET_VERSION_QRY); + if (!ver_packet) + return; ver_packet->header.length = sizeof(struct tl_setup_get_version_qry); /* diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index a23c7da42ea81342efc26fb35a92a69d535b7cd0..7bbcae75e6519b73b368967ce869d50122d56bea 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -119,7 +119,7 @@ static int bcm2835aux_serial_remove(struct platform_device *pdev) { struct bcm2835aux_data *data = platform_get_drvdata(pdev); - serial8250_unregister_port(data->uart.port.line); + serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk); return 0; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index fb2dcb3f859110b584c20226dbd7d5d94e4ed818..16422987ab0f3f87c90556222decf2864aeacf58 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -532,26 +532,26 @@ static int lpuart32_poll_init(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); /* Disable Rx & Tx */ - writel(0, sport->port.membase + UARTCTRL); + lpuart32_write(&sport->port, UARTCTRL, 0); - temp = readl(sport->port.membase + UARTFIFO); + temp = lpuart32_read(&sport->port, UARTFIFO); /* Enable Rx and Tx FIFO */ - writel(temp | UARTFIFO_RXFE | UARTFIFO_TXFE, - sport->port.membase + UARTFIFO); + lpuart32_write(&sport->port, UARTFIFO, + temp | UARTFIFO_RXFE | UARTFIFO_TXFE); /* flush Tx and Rx FIFO */ - writel(UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, - sport->port.membase + UARTFIFO); + lpuart32_write(&sport->port, UARTFIFO, + UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH); /* explicitly clear RDRF */ - if (readl(sport->port.membase + UARTSTAT) & UARTSTAT_RDRF) { - readl(sport->port.membase + UARTDATA); - writel(UARTFIFO_RXUF, sport->port.membase + UARTFIFO); + if (lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_RDRF) { + lpuart32_read(&sport->port, UARTDATA); + lpuart32_write(&sport->port, UARTFIFO, UARTFIFO_RXUF); } /* Enable Rx and Tx */ - writel(UARTCTRL_RE | UARTCTRL_TE, sport->port.membase + UARTCTRL); + lpuart32_write(&sport->port, UARTCTRL, UARTCTRL_RE | UARTCTRL_TE); spin_unlock_irqrestore(&sport->port.lock, flags); return 0; @@ -559,18 +559,18 @@ static int lpuart32_poll_init(struct uart_port *port) static void lpuart32_poll_put_char(struct uart_port *port, unsigned char c) { - while (!(readl(port->membase + UARTSTAT) & UARTSTAT_TDRE)) + while (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)) barrier(); - writel(c, port->membase + UARTDATA); + lpuart32_write(port, UARTDATA, c); } static int lpuart32_poll_get_char(struct uart_port *port) { - if (!(readl(port->membase + UARTSTAT) & UARTSTAT_RDRF)) + if (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF)) return NO_POLL_CHAR; - return readl(port->membase + UARTDATA); + return lpuart32_read(port, UARTDATA); } #endif diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index aae68230fb7b8841fa35d863a5f389948d4c8555..a81a5be0cf7a2a6740806b13d449d5c86630e0c4 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -542,7 +542,7 @@ static void imx_dma_tx(struct imx_port *sport) dev_err(dev, "DMA mapping error for TX.\n"); return; } - desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents, + desc = dmaengine_prep_slave_sg(chan, sgl, ret, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); if (!desc) { dma_unmap_sg(dev, sgl, sport->dma_tx_nents, diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index cd4ce95f30215b3db1ab92f8f00d42c86d8d4d3d..b0d04569847c2879ca82d8389d3eccfe3e0f61d0 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -1613,7 +1613,7 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx) struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned int rx_bytes = 0; struct tty_port *tport; - int ret; + int ret = 0; unsigned int geni_status; if (msm_port->uart_ssr.is_ssr_down) { @@ -1726,6 +1726,10 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) SE_GENI_M_IRQ_CLEAR); geni_write_reg_nolog(s_irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR); + dma_tx_status = geni_read_reg_nolog(uport->membase, + SE_DMA_TX_IRQ_STAT); + dma_rx_status = geni_read_reg_nolog(uport->membase, + SE_DMA_RX_IRQ_STAT); if (dma_tx_status) geni_write_reg_nolog(dma_tx_status, uport->membase, SE_DMA_TX_IRQ_CLR); @@ -3081,8 +3085,7 @@ static int msm_geni_serial_probe(struct platform_device *pdev) return 0; exit_geni_serial_probe: - IPC_LOG_MSG(dev_port->ipc_log_misc, "%s: fail port:%s ret:%d\n", - __func__, uport->name, ret); + IPC_LOG_MSG(dev_port->ipc_log_misc, "%s: ret:%d\n", __func__, ret); return ret; } diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index d9123f9957058f4870008f2a5e1cf57368b377aa..15ddcbd1f9d23a3fd8a8afe2dca27cdd0a2fc2ea 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -247,6 +247,7 @@ struct eg20t_port { struct dma_chan *chan_rx; struct scatterlist *sg_tx_p; int nent; + int orig_nent; struct scatterlist sg_rx; int tx_dma_use; void *rx_buf_virt; @@ -801,9 +802,10 @@ static void pch_dma_tx_complete(void *arg) } xmit->tail &= UART_XMIT_SIZE - 1; async_tx_ack(priv->desc_tx); - dma_unmap_sg(port->dev, sg, priv->nent, DMA_TO_DEVICE); + dma_unmap_sg(port->dev, sg, priv->orig_nent, DMA_TO_DEVICE); priv->tx_dma_use = 0; priv->nent = 0; + priv->orig_nent = 0; kfree(priv->sg_tx_p); pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT); } @@ -1027,6 +1029,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) dev_err(priv->port.dev, "%s:dma_map_sg Failed\n", __func__); return 0; } + priv->orig_nent = num; priv->nent = nent; for (i = 0; i < nent; i++, sg++) { diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 15e5bf3f1d7813d7b1b570d27b6188fc9bad84a6..dbec0f6063f8b1c1bb028de2500fcbda16ea4234 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2813,6 +2813,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) if (uport->cons && uport->dev) of_console_check(uport->dev->of_node, uport->cons->name, uport->line); + tty_port_link_device(port, drv->tty_driver, uport->line); uart_configure_port(drv, state, uport); port->console = uart_console(uport); diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 03a583264d9ec78eec786930c7783b1047c82596..1e854e1851fbbf52a08a0c667694d0a94420cceb 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -118,35 +118,51 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { sr |= USART_SR_DUMMY_RX; - c = stm32_get_char(port, &sr, &stm32_port->last_res); flag = TTY_NORMAL; - port->icount.rx++; + /* + * Status bits has to be cleared before reading the RDR: + * In FIFO mode, reading the RDR will pop the next data + * (if any) along with its status bits into the SR. + * Not doing so leads to misalignement between RDR and SR, + * and clear status bits of the next rx data. + * + * Clear errors flags for stm32f7 and stm32h7 compatible + * devices. On stm32f4 compatible devices, the error bit is + * cleared by the sequence [read SR - read DR]. + */ + if ((sr & USART_SR_ERR_MASK) && ofs->icr != UNDEF_REG) + writel_relaxed(sr & USART_SR_ERR_MASK, + port->membase + ofs->icr); + + c = stm32_get_char(port, &sr, &stm32_port->last_res); + port->icount.rx++; if (sr & USART_SR_ERR_MASK) { - if (sr & USART_SR_LBD) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (sr & USART_SR_ORE) { - if (ofs->icr != UNDEF_REG) - writel_relaxed(USART_ICR_ORECF, - port->membase + - ofs->icr); + if (sr & USART_SR_ORE) { port->icount.overrun++; } else if (sr & USART_SR_PE) { port->icount.parity++; } else if (sr & USART_SR_FE) { - port->icount.frame++; + /* Break detection if character is null */ + if (!c) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else { + port->icount.frame++; + } } sr &= port->read_status_mask; - if (sr & USART_SR_LBD) - flag = TTY_BREAK; - else if (sr & USART_SR_PE) + if (sr & USART_SR_PE) { flag = TTY_PARITY; - else if (sr & USART_SR_FE) - flag = TTY_FRAME; + } else if (sr & USART_SR_FE) { + if (!c) + flag = TTY_BREAK; + else + flag = TTY_FRAME; + } } if (uart_handle_sysrq_char(port, c)) @@ -164,21 +180,6 @@ static void stm32_tx_dma_complete(void *arg) struct uart_port *port = arg; struct stm32_port *stm32port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32port->info->ofs; - unsigned int isr; - int ret; - - ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, - isr, - (isr & USART_SR_TC), - 10, 100000); - - if (ret) - dev_err(port->dev, "terminal count not set\n"); - - if (ofs->icr == UNDEF_REG) - stm32_clr_bits(port, ofs->isr, USART_SR_TC); - else - stm32_set_bits(port, ofs->icr, USART_CR_TC); stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); stm32port->tx_dma_busy = false; @@ -270,7 +271,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port) /* Issue pending DMA TX requests */ dma_async_issue_pending(stm32port->tx_ch); - stm32_clr_bits(port, ofs->isr, USART_SR_TC); stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); @@ -294,15 +294,15 @@ static void stm32_transmit_chars(struct uart_port *port) return; } - if (uart_tx_stopped(port)) { - stm32_stop_tx(port); + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); return; } - if (uart_circ_empty(xmit)) { - stm32_stop_tx(port); - return; - } + if (ofs->icr == UNDEF_REG) + stm32_clr_bits(port, ofs->isr, USART_SR_TC); + else + writel_relaxed(USART_ICR_TCCF, port->membase + ofs->icr); if (stm32_port->tx_ch) stm32_transmit_chars_dma(port); @@ -313,7 +313,7 @@ static void stm32_transmit_chars(struct uart_port *port) uart_write_wakeup(port); if (uart_circ_empty(xmit)) - stm32_stop_tx(port); + stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); } static irqreturn_t stm32_interrupt(int irq, void *ptr) @@ -447,7 +447,6 @@ static int stm32_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; u32 val; int ret; @@ -458,15 +457,6 @@ static int stm32_startup(struct uart_port *port) if (ret) return ret; - if (cfg->has_wakeup && stm32_port->wakeirq >= 0) { - ret = dev_pm_set_dedicated_wake_irq(port->dev, - stm32_port->wakeirq); - if (ret) { - free_irq(port->irq, port); - return ret; - } - } - val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; if (stm32_port->fifoen) val |= USART_CR1_FIFOEN; @@ -480,15 +470,23 @@ static void stm32_shutdown(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_config *cfg = &stm32_port->info->cfg; - u32 val; + u32 val, isr; + int ret; val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; val |= BIT(cfg->uart_enable_bit); if (stm32_port->fifoen) val |= USART_CR1_FIFOEN; + + ret = readl_relaxed_poll_timeout(port->membase + ofs->isr, + isr, (isr & USART_SR_TC), + 10, 100000); + + if (ret) + dev_err(port->dev, "transmission complete not set\n"); + stm32_clr_bits(port, ofs->cr1, val); - dev_pm_clear_wake_irq(port->dev); free_irq(port->irq, port); } @@ -569,14 +567,14 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_iflag & INPCK) port->read_status_mask |= USART_SR_PE | USART_SR_FE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= USART_SR_LBD; + port->read_status_mask |= USART_SR_FE; /* Characters to ignore */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask = USART_SR_PE | USART_SR_FE; if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= USART_SR_LBD; + port->ignore_status_mask |= USART_SR_FE; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). @@ -895,11 +893,18 @@ static int stm32_serial_probe(struct platform_device *pdev) ret = device_init_wakeup(&pdev->dev, true); if (ret) goto err_uninit; + + ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, + stm32port->wakeirq); + if (ret) + goto err_nowup; + + device_set_wakeup_enable(&pdev->dev, false); } ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); if (ret) - goto err_nowup; + goto err_wirq; ret = stm32_of_dma_rx_probe(stm32port, pdev); if (ret) @@ -913,6 +918,10 @@ static int stm32_serial_probe(struct platform_device *pdev) return 0; +err_wirq: + if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) + dev_pm_clear_wake_irq(&pdev->dev); + err_nowup: if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) device_init_wakeup(&pdev->dev, false); @@ -950,8 +959,10 @@ static int stm32_serial_remove(struct platform_device *pdev) TX_BUF_L, stm32_port->tx_buf, stm32_port->tx_dma_buf); - if (cfg->has_wakeup && stm32_port->wakeirq >= 0) + if (cfg->has_wakeup && stm32_port->wakeirq >= 0) { + dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); + } clk_disable_unprepare(stm32_port->clk); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index ffc0c5285e511ea6863473723c9343f8d9ddf1d4..9d087881913aad439d5612572fe5b38e668ff275 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -108,7 +108,6 @@ struct stm32_usart_info stm32h7_info = { #define USART_SR_RXNE BIT(5) #define USART_SR_TC BIT(6) #define USART_SR_TXE BIT(7) -#define USART_SR_LBD BIT(8) #define USART_SR_CTSIF BIT(9) #define USART_SR_CTS BIT(10) /* F7 */ #define USART_SR_RTOF BIT(11) /* F7 */ @@ -120,8 +119,7 @@ struct stm32_usart_info stm32h7_info = { #define USART_SR_SBKF BIT(18) /* F7 */ #define USART_SR_WUF BIT(20) /* H7 */ #define USART_SR_TEACK BIT(21) /* F7 */ -#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ - USART_SR_FE | USART_SR_PE) +#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE) /* Dummy bits */ #define USART_SR_DUMMY_RX BIT(16) @@ -166,8 +164,6 @@ struct stm32_usart_info stm32h7_info = { /* USART_CR2 */ #define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */ #define USART_CR2_ADDM7 BIT(4) /* F7 */ -#define USART_CR2_LBDL BIT(5) -#define USART_CR2_LBDIE BIT(6) #define USART_CR2_LBCL BIT(8) #define USART_CR2_CPHA BIT(9) #define USART_CR2_CPOL BIT(10) @@ -224,12 +220,10 @@ struct stm32_usart_info stm32h7_info = { /* USART_ICR */ #define USART_ICR_PECF BIT(0) /* F7 */ -#define USART_ICR_FFECF BIT(1) /* F7 */ -#define USART_ICR_NCF BIT(2) /* F7 */ +#define USART_ICR_FECF BIT(1) /* F7 */ #define USART_ICR_ORECF BIT(3) /* F7 */ #define USART_ICR_IDLECF BIT(4) /* F7 */ #define USART_ICR_TCCF BIT(6) /* F7 */ -#define USART_ICR_LBDCF BIT(8) /* F7 */ #define USART_ICR_CTSCF BIT(9) /* F7 */ #define USART_ICR_RTOCF BIT(11) /* F7 */ #define USART_ICR_EOBCF BIT(12) /* F7 */ diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index fb5c9701b1fbdb611b1e4f11906cded421478442..7c18536a3742aa89e5ca50455b7a3e4d1691fc2e 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -939,9 +939,12 @@ int __uio_register_device(struct module *owner, atomic_set(&idev->event, 0); ret = uio_get_minor(idev); - if (ret) + if (ret) { + kfree(idev); return ret; + } + device_initialize(&idev->dev); idev->dev.devt = MKDEV(uio_major, idev->minor); idev->dev.class = &uio_class; idev->dev.parent = parent; @@ -952,7 +955,7 @@ int __uio_register_device(struct module *owner, if (ret) goto err_device_create; - ret = device_register(&idev->dev); + ret = device_add(&idev->dev); if (ret) goto err_device_create; @@ -984,9 +987,10 @@ int __uio_register_device(struct module *owner, err_request_irq: uio_dev_del_attributes(idev); err_uio_dev_add_attributes: - device_unregister(&idev->dev); + device_del(&idev->dev); err_device_create: uio_free_minor(idev); + put_device(&idev->dev); return ret; } EXPORT_SYMBOL_GPL(__uio_register_device); diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 18cb8e46262d3ed3492d1045b7e15b9b4496f479..83683a5627f30237ed1ae6dd9bb93265938f268e 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -37,6 +37,7 @@ static int (*orig_bus_suspend)(struct usb_hcd *hcd); struct ehci_ci_priv { struct regulator *reg_vbus; + bool enabled; }; static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) @@ -48,7 +49,7 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) int ret = 0; int port = HCS_N_PORTS(ehci->hcs_params); - if (priv->reg_vbus) { + if (priv->reg_vbus && enable != priv->enabled) { if (port > 1) { dev_warn(dev, "Not support multi-port regulator control\n"); @@ -64,6 +65,7 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) enable ? "enable" : "disable", ret); return ret; } + priv->enabled = enable; } if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) { diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index a593cdfc897fd2fb9ddfdf68813beb8ac19a1b12..d5d42dccda10af1a39cb6951de7a3f64c567be48 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -1085,7 +1085,7 @@ static int wdm_post_reset(struct usb_interface *intf) rv = recover_from_urb_loss(desc); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); - return 0; + return rv; } static struct usb_driver wdm_driver = { diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 81312e28c96221e98f6661b5131b1885b8ffeac8..623f996305819b8eb12527b8ce650d5dd760d1a6 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -203,9 +203,58 @@ static const unsigned short super_speed_maxpacket_maxes[4] = { [USB_ENDPOINT_XFER_INT] = 1024, }; -static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, - int asnum, struct usb_host_interface *ifp, int num_ep, - unsigned char *buffer, int size) +static bool endpoint_is_duplicate(struct usb_endpoint_descriptor *e1, + struct usb_endpoint_descriptor *e2) +{ + if (e1->bEndpointAddress == e2->bEndpointAddress) + return true; + + if (usb_endpoint_xfer_control(e1) || usb_endpoint_xfer_control(e2)) { + if (usb_endpoint_num(e1) == usb_endpoint_num(e2)) + return true; + } + + return false; +} + +/* + * Check for duplicate endpoint addresses in other interfaces and in the + * altsetting currently being parsed. + */ +static bool config_endpoint_is_duplicate(struct usb_host_config *config, + int inum, int asnum, struct usb_endpoint_descriptor *d) +{ + struct usb_endpoint_descriptor *epd; + struct usb_interface_cache *intfc; + struct usb_host_interface *alt; + int i, j, k; + + for (i = 0; i < config->desc.bNumInterfaces; ++i) { + intfc = config->intf_cache[i]; + + for (j = 0; j < intfc->num_altsetting; ++j) { + alt = &intfc->altsetting[j]; + + if (alt->desc.bInterfaceNumber == inum && + alt->desc.bAlternateSetting != asnum) + continue; + + for (k = 0; k < alt->desc.bNumEndpoints; ++k) { + epd = &alt->endpoint[k].desc; + + if (endpoint_is_duplicate(epd, d)) + return true; + } + } + } + + return false; +} + +static int usb_parse_endpoint(struct device *ddev, int cfgno, + struct usb_host_config *config, int inum, int asnum, + struct usb_host_interface *ifp, int num_ep, + unsigned char *buffer, int size) { unsigned char *buffer0 = buffer; struct usb_endpoint_descriptor *d; @@ -242,13 +291,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, goto skip_to_next_endpoint_or_interface_descriptor; /* Check for duplicate endpoint addresses */ - for (i = 0; i < ifp->desc.bNumEndpoints; ++i) { - if (ifp->endpoint[i].desc.bEndpointAddress == - d->bEndpointAddress) { - dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", - cfgno, inum, asnum, d->bEndpointAddress); - goto skip_to_next_endpoint_or_interface_descriptor; - } + if (config_endpoint_is_duplicate(config, inum, asnum, d)) { + dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", + cfgno, inum, asnum, d->bEndpointAddress); + goto skip_to_next_endpoint_or_interface_descriptor; } endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; @@ -346,12 +392,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, endpoint->desc.wMaxPacketSize = cpu_to_le16(8); } - /* Validate the wMaxPacketSize field */ + /* + * Validate the wMaxPacketSize field. + * Some devices have isochronous endpoints in altsetting 0; + * the USB-2 spec requires such endpoints to have wMaxPacketSize = 0 + * (see the end of section 5.6.3), so don't warn about them. + */ maxp = usb_endpoint_maxp(&endpoint->desc); - if (maxp == 0) { - dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has wMaxPacketSize 0, skipping\n", + if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) { + dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n", cfgno, inum, asnum, d->bEndpointAddress); - goto skip_to_next_endpoint_or_interface_descriptor; } /* Find the highest legal maxpacket size for this endpoint */ @@ -522,8 +572,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno, if (((struct usb_descriptor_header *) buffer)->bDescriptorType == USB_DT_INTERFACE) break; - retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt, - num_ep, buffer, size); + retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum, + alt, num_ep, buffer, size); if (retval < 0) return retval; ++n; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6ecf9ff250d14983bd5369bcb925a3cf9163a6c2..7f2ff4fa7e4ef13b64c2988ec434671ad90b98cd 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1175,6 +1176,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) * PORT_OVER_CURRENT is not. So check for any of them. */ if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || + (portchange & USB_PORT_STAT_C_CONNECTION) || (portstatus & USB_PORT_STAT_OVERCURRENT) || (portchange & USB_PORT_STAT_C_OVERCURRENT)) set_bit(port1, hub->change_bits); @@ -5210,6 +5212,8 @@ static void hub_event(struct work_struct *work) hub_dev = hub->intfdev; intf = to_usb_interface(hub_dev); + kcov_remote_start_usb((u64)hdev->bus->busnum); + dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", hdev->state, hdev->maxchild, /* NOTE: expects max 15 ports... */ @@ -5316,6 +5320,8 @@ static void hub_event(struct work_struct *work) /* Balance the stuff in kick_hub_wq() and allow autosuspend */ usb_autopm_put_interface(intf); kref_put(&hub->kref, hub_release); + + kcov_remote_stop(); } static const struct usb_device_id hub_id_table[] = { diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index e164439b215429492ce414bd8d088109397ea639..4af9a1c652edb56b3bcf87c67d6568561f496d16 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2276,6 +2276,7 @@ static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep) if (status & DEV_DMA_STS_MASK) dev_err(hsotg->dev, "descriptor %d closed with %x\n", i, status & DEV_DMA_STS_MASK); + desc++; } return bytes_rem; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 5637024fcadedaf48f14f1d0dbc1ee08c5d48aa4..ecc696189967a8e315c4c124e757361fde8680a2 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -59,6 +59,9 @@ void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend) { u32 reg; + if (dwc->dis_u3_susphy_quirk) + return; + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); if (suspend) @@ -67,6 +70,17 @@ void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend) reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + + if (dwc->dual_port) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(1)); + + if (suspend) + reg |= DWC3_GUSB3PIPECTL_SUSPHY; + else + reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(1), reg); + } } /** @@ -143,6 +157,12 @@ void dwc3_en_sleep_mode(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_ENBLSLPM; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + + if (dwc->dual_port) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(1)); + reg |= DWC3_GUSB2PHYCFG_ENBLSLPM; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(1), reg); + } } void dwc3_dis_sleep_mode(struct dwc3 *dwc) @@ -198,6 +218,14 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) return ret; } + usb_phy_reset(dwc->usb2_phy1); + ret = usb_phy_init(dwc->usb2_phy1); + if (ret) { + pr_err("%s: usb_phy_init(dwc->usb2_phy1) returned %d\n", + __func__, ret); + return ret; + } + if (dwc->maximum_speed <= USB_SPEED_HIGH) goto generic_phy_init; @@ -215,6 +243,14 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) return ret; } + usb_phy_reset(dwc->usb3_phy1); + ret = usb_phy_init(dwc->usb3_phy1); + if (ret) { + pr_err("%s: usb_phy_init(dwc->usb3_phy1) returned %d\n", + __func__, ret); + return ret; + } + generic_phy_init: ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) @@ -549,6 +585,10 @@ static int dwc3_phy_setup(struct dwc3 *dwc) u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + if (dwc->dual_port) { + if (reg != dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(1))) + dev_warn(dwc->dev, "Reset values of pipectl registers are different!\n"); + } /* * Make sure UX_EXIT_PX is cleared as that causes issues with some @@ -600,8 +640,14 @@ static int dwc3_phy_setup(struct dwc3 *dwc) DWC3_GUSB3PIPECTL_P3EXSIGP2); dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + if (dwc->dual_port) + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(1), reg); reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + if (dwc->dual_port) { + if (reg != dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(1))) + dev_warn(dwc->dev, "Reset values of usb2phycfg registers are different!\n"); + } /* Select the HS PHY interface */ switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) { @@ -662,6 +708,8 @@ static int dwc3_phy_setup(struct dwc3 *dwc) reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + if (dwc->dual_port) + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(1), reg); return 0; } @@ -670,12 +718,16 @@ static void dwc3_core_exit(struct dwc3 *dwc) { dwc3_event_buffers_cleanup(dwc); + usb_phy_shutdown(dwc->usb2_phy1); usb_phy_shutdown(dwc->usb2_phy); + usb_phy_shutdown(dwc->usb3_phy1); usb_phy_shutdown(dwc->usb3_phy); phy_exit(dwc->usb2_generic_phy); phy_exit(dwc->usb3_generic_phy); + usb_phy_set_suspend(dwc->usb2_phy1, 1); usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy1, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); phy_power_off(dwc->usb2_generic_phy); phy_power_off(dwc->usb3_generic_phy); @@ -854,8 +906,11 @@ int dwc3_core_init(struct dwc3 *dwc) dwc3_frame_length_adjustment(dwc); usb_phy_set_suspend(dwc->usb2_phy, 0); - if (dwc->maximum_speed >= USB_SPEED_SUPER) + usb_phy_set_suspend(dwc->usb2_phy1, 0); + if (dwc->maximum_speed >= USB_SPEED_SUPER) { usb_phy_set_suspend(dwc->usb3_phy, 0); + usb_phy_set_suspend(dwc->usb3_phy1, 0); + } ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) @@ -958,11 +1013,15 @@ int dwc3_core_init(struct dwc3 *dwc) phy_power_off(dwc->usb2_generic_phy); err2: + usb_phy_set_suspend(dwc->usb2_phy1, 1); + usb_phy_set_suspend(dwc->usb3_phy1, 1); usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); dwc3_free_scratch_buffers(dwc); err1: + usb_phy_shutdown(dwc->usb2_phy1); + usb_phy_shutdown(dwc->usb3_phy1); usb_phy_shutdown(dwc->usb2_phy); usb_phy_shutdown(dwc->usb3_phy); phy_exit(dwc->usb2_generic_phy); @@ -984,6 +1043,12 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) if (node) { dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); + if (dwc->dual_port) { + dwc->usb2_phy1 = devm_usb_get_phy_by_phandle(dev, + "usb-phy", 2); + dwc->usb3_phy1 = devm_usb_get_phy_by_phandle(dev, + "usb-phy", 3); + } } else { dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); @@ -1013,6 +1078,30 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) } } + if (dwc->dual_port) { + if (IS_ERR(dwc->usb2_phy1)) { + ret = PTR_ERR(dwc->usb2_phy1); + if (ret == -ENXIO || ret == -ENODEV) { + dwc->usb2_phy1 = NULL; + } else { + if (ret != -EPROBE_DEFER) + dev_err(dev, "no usb2 phy1 configured\n"); + return ret; + } + } + + if (IS_ERR(dwc->usb3_phy1)) { + ret = PTR_ERR(dwc->usb3_phy1); + if (ret == -ENXIO || ret == -ENODEV) { + dwc->usb3_phy1 = NULL; + } else { + if (ret != -EPROBE_DEFER) + dev_err(dev, "no usb3 phy1 configured\n"); + return ret; + } + } + } + dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); if (IS_ERR(dwc->usb2_generic_phy)) { ret = PTR_ERR(dwc->usb2_generic_phy); @@ -1058,6 +1147,9 @@ static void __maybe_unused dwc3_core_exit_mode(struct dwc3 *dwc) /* do nothing */ break; } + + /* de-assert DRVVBUS for HOST and OTG mode */ + dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); } static void (*notify_event)(struct dwc3 *, unsigned int, unsigned int); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 2f0c4d4cc548c041bd5442925cc4b45f3fcc8712..ae63ee62491fa34b7cbdd6df50490e5c9c3565df 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -167,7 +167,7 @@ #define GEN2_U3_EXIT_RSP_RX_CLK_MASK GEN2_U3_EXIT_RSP_RX_CLK(0xff) #define GEN1_U3_EXIT_RSP_RX_CLK(n) (n) #define GEN1_U3_EXIT_RSP_RX_CLK_MASK GEN1_U3_EXIT_RSP_RX_CLK(0xff) -#define DWC31_LINK_GDBGLTSSM 0xd050 +#define DWC31_LINK_GDBGLTSSM(n) (0xd050 + ((n) * 0x80)) /* Bit fields */ @@ -904,8 +904,10 @@ struct dwc3_scratchpad_array { * @hsphy_mode: UTMI phy mode, one of following: * - USBPHY_INTERFACE_MODE_UTMI * - USBPHY_INTERFACE_MODE_UTMIW - * @usb2_phy: pointer to USB2 PHY - * @usb3_phy: pointer to USB3 PHY + * @usb2_phy: pointer to USB2 PHY 0 + * @usb2_phy1: pointer to USB2 PHY 1 + * @usb3_phy: pointer to USB3 PHY 0 + * @usb3_phy1: pointer to USB3 PHY 1 * @usb2_generic_phy: pointer to USB2 PHY * @usb3_generic_phy: pointer to USB3 PHY * @phys_ready: flag to indicate that PHYs are ready @@ -998,6 +1000,7 @@ struct dwc3_scratchpad_array { * @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt * @last_run_stop: timestamp denoting the last run_stop update * @num_gsi_eps: number of GSI based hardware accelerated endpoints + * @dual_port: If true, this core supports two ports */ struct dwc3 { struct work_struct drd_work; @@ -1026,8 +1029,8 @@ struct dwc3 { struct usb_gadget gadget; struct usb_gadget_driver *gadget_driver; - struct usb_phy *usb2_phy; - struct usb_phy *usb3_phy; + struct usb_phy *usb2_phy, *usb2_phy1; + struct usb_phy *usb3_phy, *usb3_phy1; struct phy *usb2_generic_phy; struct phy *usb3_generic_phy; @@ -1219,6 +1222,7 @@ struct dwc3 { int retries_on_error; ktime_t last_run_stop; u32 num_gsi_eps; + bool dual_port; }; #define work_to_dwc(w) (container_of((w), struct dwc3, drd_work)) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 66895aa7e9f489a411e3aedc45bb2ea7d3ccfc29..9bfad4bfbb02a27ce7ffa6dcb859f65724683c7d 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -79,6 +79,7 @@ #define CGCTL_REG (QSCRATCH_REG_OFFSET + 0x28) #define PWR_EVNT_IRQ_STAT_REG (QSCRATCH_REG_OFFSET + 0x58) #define PWR_EVNT_IRQ_MASK_REG (QSCRATCH_REG_OFFSET + 0x5C) +#define PWR_EVNT_IRQ_STAT_REG1 (QSCRATCH_REG_OFFSET + 0x1DC) #define PWR_EVNT_POWERDOWN_IN_P3_MASK BIT(2) #define PWR_EVNT_POWERDOWN_OUT_P3_MASK BIT(3) @@ -185,6 +186,9 @@ enum msm_usb_irq { DP_HS_PHY_IRQ, DM_HS_PHY_IRQ, SS_PHY_IRQ, + DP_HS_PHY_IRQ_1, + DM_HS_PHY_IRQ_1, + SS_PHY_IRQ_1, USB_MAX_IRQ }; @@ -208,6 +212,9 @@ static const struct usb_irq usb_irq_info[USB_MAX_IRQ] = { {"dp_hs_phy_irq", 0}, {"dm_hs_phy_irq", 0}, {"ss_phy_irq", 0}, + {"dp_hs_phy_irq1", 0}, + {"dm_hs_phy_irq1", 0}, + {"ss_phy_irq1", 0}, }; static const char * const gsi_op_strings[] = { @@ -262,6 +269,7 @@ struct dwc3_msm { struct regulator *dwc3_gdsc; struct usb_phy *hs_phy, *ss_phy; + struct usb_phy *hs_phy1, *ss_phy1; struct dbm *dbm; @@ -333,6 +341,7 @@ struct dwc3_msm { struct device_node *dwc3_node; struct property *num_gsi_eps; + bool dual_port; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -448,17 +457,37 @@ static bool dwc3_msm_is_host_superspeed(struct dwc3_msm *mdwc) { int i, num_ports; u32 reg; + bool is_host_ss = false; reg = dwc3_msm_read_reg(mdwc->base, USB3_HCSPARAMS1); num_ports = HCS_MAX_PORTS(reg); + /* + * For single port controller, PORTSC register 1 is for SS bus, hence it + * maps to the only SSPHY. But for dual port controllers, PORTSC + * registers 2 and 3 are for SS busses 0 and 1 respectively. Hence, + * PORTSC register 2 maps to SSPHY0 and 3 maps to SSPHY1. Handle the + * flag setting using the below logic which will also maintain single + * port core. + * num_ports = 2 (or) 4 (depending on no. of ports) + * ->num_ports/2 = 1 (or) 2 + * So, for single port core, i % (num_ports/2) = 0, hence we will always + * be updating SSPHY0 flags. + * For dual port, i % (num_ports/2) = 0 for port 0 (or) 1 for port 1. + * Hence we update SSPHY0 for reg 0 and 2; and SSPHY1 for reg 1 and 3. + */ for (i = 0; i < num_ports; i++) { reg = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC + i*0x10); - if ((reg & PORT_PE) && DEV_SUPERSPEED_ANY(reg)) - return true; + if ((reg & PORT_PE) && DEV_SUPERSPEED_ANY(reg)) { + is_host_ss = true; + if (i % (num_ports / 2)) + mdwc->ss_phy1->flags |= DEVICE_IN_SS_MODE; + else + mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE; + } } - return false; + return is_host_ss; } static inline bool dwc3_msm_is_dev_superspeed(struct dwc3_msm *mdwc) @@ -2224,7 +2253,7 @@ static void dwc3_msm_block_reset(struct dwc3_msm *mdwc, bool core_reset) static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) { struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); - u32 val; + u32 val, val1; int ret; /* Configure AHB2PHY for one wait state read/write */ @@ -2247,15 +2276,27 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) __func__, ret); /* Get initial P3 status and enable IN_P3 event */ - if (dwc3_is_usb31(dwc)) + if (dwc3_is_usb31(dwc)) { val = dwc3_msm_read_reg_field(mdwc->base, - DWC31_LINK_GDBGLTSSM, + DWC31_LINK_GDBGLTSSM(0), DWC3_GDBGLTSSM_LINKSTATE_MASK); - else + if (mdwc->dual_port) + val1 = dwc3_msm_read_reg_field(mdwc->base, + DWC31_LINK_GDBGLTSSM(1), + DWC3_GDBGLTSSM_LINKSTATE_MASK); + } else { val = dwc3_msm_read_reg_field(mdwc->base, DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); - atomic_set(&mdwc->in_p3, val == DWC3_LINK_STATE_U3); - dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, + } + + if (!mdwc->dual_port) + val1 = DWC3_LINK_STATE_U3; + + atomic_set(&mdwc->in_p3, (val == DWC3_LINK_STATE_U3) && + (val1 == DWC3_LINK_STATE_U3)); + + if (!mdwc->dual_port) + dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); /* Set the core in host mode if it was in host mode during pm_suspend */ @@ -2266,6 +2307,44 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) } +static void dwc3_msm_dp_ssphy_autosuspend(struct dwc3_msm *mdwc) +{ + unsigned long timeout; + u32 reg = 0, reg1 = 0; + + /* Clear previous P3 events */ + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, + PWR_EVNT_POWERDOWN_IN_P3_MASK | PWR_EVNT_POWERDOWN_OUT_P3_MASK); + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1, + PWR_EVNT_POWERDOWN_IN_P3_MASK | PWR_EVNT_POWERDOWN_OUT_P3_MASK); + + /* Prepare SSPHYs for suspend */ + reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(0)); + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(0), + reg | DWC3_GUSB3PIPECTL_SUSPHY); + reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(1)); + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(1), + reg | DWC3_GUSB3PIPECTL_SUSPHY); + + /* Wait for PHYs to go into P3 */ + timeout = jiffies + msecs_to_jiffies(5); + while (!time_after(jiffies, timeout)) { + reg = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG); + reg1 = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1); + if ((reg & PWR_EVNT_POWERDOWN_IN_P3_MASK) && + (reg1 & PWR_EVNT_POWERDOWN_IN_P3_MASK)) { + atomic_set(&mdwc->in_p3, 1); + break; + } + } + + /* Clear P3 event bit */ + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, + PWR_EVNT_POWERDOWN_IN_P3_MASK); + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1, + PWR_EVNT_POWERDOWN_IN_P3_MASK); +} + static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) { unsigned long timeout; @@ -2273,6 +2352,9 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) if (!ignore_p3_state && ((mdwc->in_host_mode || mdwc->in_device_mode) && dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart)) { + /* Allow SSPHYs to go to P3 for dual port controllers */ + if (mdwc->dual_port) + dwc3_msm_dp_ssphy_autosuspend(mdwc); if (!atomic_read(&mdwc->in_p3)) { dev_err(mdwc->dev, "Not in P3,aborting LPM sequence\n"); return -EBUSY; @@ -2302,16 +2384,88 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, PWR_EVNT_LPM_IN_L2_MASK); + /* Handling for dual port core */ + if (!mdwc->dual_port) + return 0; + + /* Clear previous L2 events */ + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1, + PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK); + + /* Prepare HSPHY for suspend */ + reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(1)); + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(1), + reg | DWC3_GUSB2PHYCFG_ENBLSLPM | DWC3_GUSB2PHYCFG_SUSPHY); + + /* Wait for PHY to go into L2 */ + timeout = jiffies + msecs_to_jiffies(5); + while (!time_after(jiffies, timeout)) { + reg = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1); + if (reg & PWR_EVNT_LPM_IN_L2_MASK) + break; + } + if (!(reg & PWR_EVNT_LPM_IN_L2_MASK)) + dev_err(mdwc->dev, "could not transition HS PHY1 to L2\n"); + + /* Clear L2 event bit */ + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1, + PWR_EVNT_LPM_IN_L2_MASK); + return 0; } +/* Generic functions to set/clear PHY flags */ +static void dwc3_msm_set_hsphy_flags(struct dwc3_msm *mdwc, int set) +{ + mdwc->hs_phy->flags |= set; + if (mdwc->hs_phy1) + mdwc->hs_phy1->flags |= set; +} + +static void dwc3_msm_clear_hsphy_flags(struct dwc3_msm *mdwc, int clear) +{ + mdwc->hs_phy->flags &= ~clear; + if (mdwc->hs_phy1) + mdwc->hs_phy1->flags &= ~clear; +} + +static void dwc3_msm_set_ssphy_flags(struct dwc3_msm *mdwc, int set) +{ + mdwc->ss_phy->flags |= set; + if (mdwc->ss_phy1) + mdwc->ss_phy1->flags |= set; +} + +static void dwc3_msm_clear_ssphy_flags(struct dwc3_msm *mdwc, int clear) +{ + mdwc->ss_phy->flags &= ~clear; + if (mdwc->ss_phy1) + mdwc->ss_phy1->flags &= ~clear; +} + static void dwc3_set_phy_speed_flags(struct dwc3_msm *mdwc) { struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); int i, num_ports; u32 reg; - mdwc->hs_phy->flags &= ~(PHY_HSFS_MODE | PHY_LS_MODE); + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HSFS_MODE | PHY_LS_MODE); + + /* + * For single port controller, there are 2 PORTSC registers, one for + * HS bus and other for SS bus, hence both mapping to the only HSPHY. + * But for dual port controllers, there are 4 PORTSC registers: 0 and 1 + * for HS busses 0 and 1 respectively; and registers 2 and 3 for SS + * busses 0 and 1 respectively. Hence, PORTSC registers 0 and 2 map to + * HSPHY 0 and registers 1 and 3 map to HSPHY1. Handle the flag setting + * using the below logic which will also maintain single port core. + * num_ports = 2 (or) 4 (depending on no. of ports) + * ->num_ports/2 = 1 (or) 2 + * So, for single port core, i % (num_ports/2) = 0, hence we will always + * be updating HSPHY0 flags. + * For dual port, i % (num_ports/2) = 0 for port 0 (or) 1 for port 1. + * Hence we update HSPHY0 for reg 0 and 2; and HSPHY1 for reg 1 and 3. + */ if (mdwc->in_host_mode) { reg = dwc3_msm_read_reg(mdwc->base, USB3_HCSPARAMS1); num_ports = HCS_MAX_PORTS(reg); @@ -2319,10 +2473,21 @@ static void dwc3_set_phy_speed_flags(struct dwc3_msm *mdwc) reg = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC + i*0x10); if (reg & PORT_PE) { - if (DEV_HIGHSPEED(reg) || DEV_FULLSPEED(reg)) - mdwc->hs_phy->flags |= PHY_HSFS_MODE; - else if (DEV_LOWSPEED(reg)) - mdwc->hs_phy->flags |= PHY_LS_MODE; + if (DEV_HIGHSPEED(reg) || DEV_FULLSPEED(reg)) { + if (i % (num_ports / 2)) + mdwc->hs_phy1->flags |= + PHY_HSFS_MODE; + else + mdwc->hs_phy->flags |= + PHY_HSFS_MODE; + } else if (DEV_LOWSPEED(reg)) { + if (i % (num_ports / 2)) + mdwc->hs_phy1->flags |= + PHY_LS_MODE; + else + mdwc->hs_phy->flags |= + PHY_LS_MODE; + } } } } else { @@ -2383,12 +2548,40 @@ static void enable_usb_pdc_interrupt(struct dwc3_msm *mdwc, bool enable) IRQ_TYPE_EDGE_RISING, true); } + if (mdwc->dual_port) { + if (mdwc->hs_phy1->flags & PHY_LS_MODE) { + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DM_HS_PHY_IRQ_1], + IRQ_TYPE_EDGE_FALLING, enable); + } else if (mdwc->hs_phy1->flags & PHY_HSFS_MODE) { + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DP_HS_PHY_IRQ_1], + IRQ_TYPE_EDGE_FALLING, enable); + } else { + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DP_HS_PHY_IRQ_1], + IRQ_TYPE_EDGE_RISING, true); + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DM_HS_PHY_IRQ_1], + IRQ_TYPE_EDGE_RISING, true); + } + } + configure_usb_wakeup_interrupt(mdwc, &mdwc->wakeup_irq[SS_PHY_IRQ], IRQF_TRIGGER_HIGH | IRQ_TYPE_LEVEL_HIGH, enable); + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[SS_PHY_IRQ_1], + IRQF_TRIGGER_HIGH | IRQ_TYPE_LEVEL_HIGH, enable); return; disable_usb_irq: + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DP_HS_PHY_IRQ_1], 0, enable); + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DM_HS_PHY_IRQ_1], 0, enable); + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[SS_PHY_IRQ_1], 0, enable); configure_usb_wakeup_interrupt(mdwc, &mdwc->wakeup_irq[DP_HS_PHY_IRQ], 0, enable); configure_usb_wakeup_interrupt(mdwc, @@ -2556,6 +2749,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, dwc3_set_phy_speed_flags(mdwc); /* Suspend HS PHY */ usb_phy_set_suspend(mdwc->hs_phy, 1); + usb_phy_set_suspend(mdwc->hs_phy1, 1); /* * Synopsys Superspeed PHY does not support ss_phy_irq, so to detect @@ -2577,11 +2771,20 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, reg |= DWC3_GUSB3PIPECTL_DISRXDETU3; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + + if (mdwc->dual_port) { + reg = dwc3_readl(dwc->regs, + DWC3_GUSB3PIPECTL(1)); + reg |= DWC3_GUSB3PIPECTL_DISRXDETU3; + dwc3_writel(dwc->regs, + DWC3_GUSB3PIPECTL(1), reg); + } } /* indicate phy about SS mode */ - if (dwc3_msm_is_superspeed(mdwc)) - mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE; + dwc3_msm_is_superspeed(mdwc); + usb_phy_set_suspend(mdwc->ss_phy, 1); + usb_phy_set_suspend(mdwc->ss_phy1, 1); mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND; } else if (mdwc->use_pwr_event_for_wakeup) { dwc3_msm_set_ss_pwr_events(mdwc, true); @@ -2770,13 +2973,14 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) /* Resume SS PHY */ if (dwc->maximum_speed >= USB_SPEED_SUPER && mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) { - mdwc->ss_phy->flags &= ~(PHY_LANE_A | PHY_LANE_B); + dwc3_msm_clear_ssphy_flags(mdwc, PHY_LANE_A | PHY_LANE_B); if (mdwc->typec_orientation == ORIENTATION_CC1) mdwc->ss_phy->flags |= PHY_LANE_A; if (mdwc->typec_orientation == ORIENTATION_CC2) mdwc->ss_phy->flags |= PHY_LANE_B; + usb_phy_set_suspend(mdwc->ss_phy1, 0); usb_phy_set_suspend(mdwc->ss_phy, 0); - mdwc->ss_phy->flags &= ~DEVICE_IN_SS_MODE; + dwc3_msm_clear_ssphy_flags(mdwc, DEVICE_IN_SS_MODE); mdwc->lpm_flags &= ~MDWC3_SS_PHY_SUSPEND; if (mdwc->in_host_mode) { @@ -2784,11 +2988,20 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) reg &= ~DWC3_GUSB3PIPECTL_DISRXDETU3; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + + if (mdwc->dual_port) { + reg = dwc3_readl(dwc->regs, + DWC3_GUSB3PIPECTL(1)); + reg &= ~DWC3_GUSB3PIPECTL_DISRXDETU3; + dwc3_writel(dwc->regs, + DWC3_GUSB3PIPECTL(1), reg); + } } } - mdwc->hs_phy->flags &= ~(PHY_HSFS_MODE | PHY_LS_MODE); + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HSFS_MODE | PHY_LS_MODE); /* Resume HS PHY */ + usb_phy_set_suspend(mdwc->hs_phy1, 0); usb_phy_set_suspend(mdwc->hs_phy, 0); /* Recover from controller power collapse */ @@ -2820,6 +3033,21 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) & ~DWC3_GUSB2PHYCFG_SUSPHY); + if (mdwc->dual_port) + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(1), + dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(1)) & + ~DWC3_GUSB2PHYCFG_SUSPHY); + + if (dwc->dis_u3_susphy_quirk) { + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(0), + dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(0)) & + ~DWC3_GUSB3PIPECTL_SUSPHY); + if (mdwc->dual_port) + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(1), + dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(1)) & + ~DWC3_GUSB3PIPECTL_SUSPHY); + } + /* Disable wakeup capable for HS_PHY IRQ & SS_PHY_IRQ if enabled */ if (mdwc->lpm_flags & MDWC3_ASYNC_IRQ_WAKE_CAPABILITY) { if (mdwc->use_pdc_interrupts) { @@ -2996,7 +3224,7 @@ static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc) /* Can't tell if entered or exit P3, so check LINKSTATE */ if (dwc3_is_usb31(dwc)) ls = dwc3_msm_read_reg_field(mdwc->base, - DWC31_LINK_GDBGLTSSM, + DWC31_LINK_GDBGLTSSM(0), DWC3_GDBGLTSSM_LINKSTATE_MASK); else ls = dwc3_msm_read_reg_field(mdwc->base, @@ -3021,7 +3249,7 @@ static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc) /* Clear L2 exit */ if (irq_stat & PWR_EVNT_LPM_OUT_L2_MASK) { irq_stat &= ~PWR_EVNT_LPM_OUT_L2_MASK; - irq_stat |= PWR_EVNT_LPM_OUT_L2_MASK; + irq_clear |= PWR_EVNT_LPM_OUT_L2_MASK; } /* Handle exit from L1 events */ @@ -3720,6 +3948,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) mdwc->charging_disabled = of_property_read_bool(node, "qcom,charging-disabled"); + mdwc->dual_port = of_property_read_bool(node, "qcom,dual-port"); ret = of_property_read_u32(node, "qcom,lpm-to-suspend-delay-ms", &mdwc->lpm_to_suspend_delay); @@ -3734,9 +3963,10 @@ static int dwc3_msm_probe(struct platform_device *pdev) IRQF_ONESHOT; mdwc->wakeup_irq[i].irq = platform_get_irq_byname(pdev, mdwc->wakeup_irq[i].name); + /* pwr_evnt_irq is only mandatory irq for single port core */ if (mdwc->wakeup_irq[i].irq < 0) { - /* pwr_evnt_irq is only mandatory irq */ - if (!strcmp(mdwc->wakeup_irq[i].name, + if (!mdwc->dual_port && + !strcmp(mdwc->wakeup_irq[i].name, "pwr_event_irq")) { dev_err(&pdev->dev, "get_irq for %s failed\n\n", mdwc->wakeup_irq[i].name); @@ -3748,7 +3978,8 @@ static int dwc3_msm_probe(struct platform_device *pdev) irq_set_status_flags(mdwc->wakeup_irq[i].irq, IRQ_NOAUTOEN); /* ss_phy_irq is level trigger interrupt */ - if (!strcmp(mdwc->wakeup_irq[i].name, "ss_phy_irq")) + if (!strncmp(mdwc->wakeup_irq[i].name, + "ss_phy_irq", 10)) irq_type = IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQ_TYPE_LEVEL_HIGH | IRQF_EARLY_RESUME; @@ -3820,7 +4051,8 @@ static int dwc3_msm_probe(struct platform_device *pdev) /* Add power event if the dbm indicates coming out of L1 by interrupt */ if (mdwc->dbm && dbm_l1_lpm_interrupt(mdwc->dbm)) { - if (!mdwc->wakeup_irq[PWR_EVNT_IRQ].irq) { + /* Dual port core does not need pwr_evnt_irq */ + if (!mdwc->dual_port && !mdwc->wakeup_irq[PWR_EVNT_IRQ].irq) { dev_err(&pdev->dev, "need pwr_event_irq exiting L1\n"); ret = -EINVAL; @@ -3909,6 +4141,24 @@ static int dwc3_msm_probe(struct platform_device *pdev) goto put_dwc3; } + if (mdwc->dual_port) { + mdwc->hs_phy1 = devm_usb_get_phy_by_phandle(&mdwc->dwc3->dev, + "usb-phy", 2); + if (IS_ERR(mdwc->hs_phy1)) { + dev_err(&pdev->dev, "unable to get hsphy1 device\n"); + ret = PTR_ERR(mdwc->hs_phy1); + goto put_dwc3; + } + + mdwc->ss_phy1 = devm_usb_get_phy_by_phandle(&mdwc->dwc3->dev, + "usb-phy", 3); + if (IS_ERR(mdwc->ss_phy1)) { + dev_err(&pdev->dev, "unable to get ssphy1 device\n"); + ret = PTR_ERR(mdwc->ss_phy1); + goto put_dwc3; + } + } + /* use default as nominal bus voting */ mdwc->default_bus_vote = BUS_VOTE_NOMINAL; ret = of_property_read_u32(node, "qcom,default-bus-vote", @@ -3969,6 +4219,13 @@ static int dwc3_msm_probe(struct platform_device *pdev) __func__); } + if (mdwc->dual_port && dwc->dr_mode != USB_DR_MODE_HOST) { + dev_err(&pdev->dev, "Dual port not allowed for DRD core\n"); + goto err_get_extcon; + } + + dwc->dual_port = mdwc->dual_port; + mutex_init(&mdwc->suspend_resume_mutex); if (of_property_read_bool(node, "extcon")) { @@ -4102,8 +4359,7 @@ static int dwc3_msm_remove(struct platform_device *pdev) cancel_delayed_work_sync(&mdwc->perf_vote_work); cancel_delayed_work_sync(&mdwc->sm_work); - if (mdwc->hs_phy) - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HOST_MODE); dbg_event(0xFF, "Remov put", 0); platform_device_put(mdwc->dwc3); of_platform_depopulate(&pdev->dev); @@ -4134,6 +4390,12 @@ static int dwc3_msm_remove(struct platform_device *pdev) disable_irq(mdwc->wakeup_irq[DM_HS_PHY_IRQ].irq); if (mdwc->wakeup_irq[SS_PHY_IRQ].irq) disable_irq(mdwc->wakeup_irq[SS_PHY_IRQ].irq); + if (mdwc->wakeup_irq[DP_HS_PHY_IRQ_1].irq) + disable_irq(mdwc->wakeup_irq[DP_HS_PHY_IRQ_1].irq); + if (mdwc->wakeup_irq[DM_HS_PHY_IRQ_1].irq) + disable_irq(mdwc->wakeup_irq[DM_HS_PHY_IRQ_1].irq); + if (mdwc->wakeup_irq[SS_PHY_IRQ_1].irq) + disable_irq(mdwc->wakeup_irq[SS_PHY_IRQ_1].irq); disable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); clk_disable_unprepare(mdwc->utmi_clk); @@ -4168,6 +4430,18 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, if (event != USB_DEVICE_ADD && event != USB_DEVICE_REMOVE) return NOTIFY_DONE; + /* + * STAR: 9001378493: SSPHY1 going in and out of P3 when HS transfers + * being done on port 0. We do not need the below workaround of + * corresponding SSPHY powerdown for multiport controller. Instead, we + * will keep the SSPHY autosuspend disabled when USB is in resumed + * state. Since dual port controller is present only on automotive + * platforms, power leakage is not a concern. Also, as a part of USB + * suspend sequence, we will enable autosuspend for SSPHYs to go to P3. + */ + if (mdwc->dual_port) + return NOTIFY_DONE; + /* * For direct-attach devices, new udev is direct child of root hub * i.e. dwc -> xhci -> root_hub -> udev @@ -4287,23 +4561,26 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) if (on) { dev_dbg(mdwc->dev, "%s: turn on host\n", __func__); - mdwc->hs_phy->flags |= PHY_HOST_MODE; + dwc3_msm_set_hsphy_flags(mdwc, PHY_HOST_MODE); pm_runtime_get_sync(mdwc->dev); dbg_event(0xFF, "StrtHost gync", atomic_read(&mdwc->dev->power.usage_count)); if (dwc->maximum_speed >= USB_SPEED_SUPER) { - mdwc->ss_phy->flags |= PHY_HOST_MODE; + dwc3_msm_set_ssphy_flags(mdwc, PHY_HOST_MODE); usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER); + usb_phy_notify_connect(mdwc->ss_phy1, + USB_SPEED_SUPER); } usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); + usb_phy_notify_connect(mdwc->hs_phy1, USB_SPEED_HIGH); if (!IS_ERR_OR_NULL(mdwc->vbus_reg)) ret = regulator_enable(mdwc->vbus_reg); if (ret) { dev_err(mdwc->dev, "unable to enable vbus_reg\n"); - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; - mdwc->ss_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HOST_MODE); + dwc3_msm_clear_ssphy_flags(mdwc, PHY_HOST_MODE); pm_runtime_put_sync(mdwc->dev); dbg_event(0xFF, "vregerr psync", atomic_read(&mdwc->dev->power.usage_count)); @@ -4326,8 +4603,8 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) if (!IS_ERR_OR_NULL(mdwc->vbus_reg)) regulator_disable(mdwc->vbus_reg); - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; - mdwc->ss_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HOST_MODE); + dwc3_msm_clear_ssphy_flags(mdwc, PHY_HOST_MODE); pm_runtime_put_sync(mdwc->dev); dbg_event(0xFF, "pdeverr psync", atomic_read(&mdwc->dev->power.usage_count)); @@ -4348,9 +4625,21 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) dwc3_msm_write_reg_field(mdwc->base, DWC31_LINK_LU3LFPSRXTIM(0), GEN1_U3_EXIT_RSP_RX_CLK_MASK, 5); - dev_dbg(mdwc->dev, "LU3:%08x\n", + dev_dbg(mdwc->dev, "link0 LU3:%08x\n", dwc3_msm_read_reg(mdwc->base, DWC31_LINK_LU3LFPSRXTIM(0))); + + if (mdwc->dual_port) { + dwc3_msm_write_reg_field(mdwc->base, + DWC31_LINK_LU3LFPSRXTIM(1), + GEN2_U3_EXIT_RSP_RX_CLK_MASK, 6); + dwc3_msm_write_reg_field(mdwc->base, + DWC31_LINK_LU3LFPSRXTIM(1), + GEN1_U3_EXIT_RSP_RX_CLK_MASK, 5); + dev_dbg(mdwc->dev, "link1 LU3:%08x\n", + dwc3_msm_read_reg(mdwc->base, + DWC31_LINK_LU3LFPSRXTIM(1))); + } } /* xHCI should have incremented child count as necessary */ @@ -4386,14 +4675,17 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) pm_runtime_get_sync(mdwc->dev); dbg_event(0xFF, "StopHost gsync", atomic_read(&mdwc->dev->power.usage_count)); + usb_phy_notify_disconnect(mdwc->hs_phy1, USB_SPEED_HIGH); usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); - if (mdwc->ss_phy->flags & PHY_HOST_MODE) { + if (dwc->maximum_speed >= USB_SPEED_SUPER) { + usb_phy_notify_disconnect(mdwc->ss_phy1, + USB_SPEED_SUPER); usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); - mdwc->ss_phy->flags &= ~PHY_HOST_MODE; } - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_ssphy_flags(mdwc, PHY_HOST_MODE); + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HOST_MODE); dwc3_host_exit(dwc); usb_unregister_notify(&mdwc->host_nb); @@ -4918,10 +5210,12 @@ static int dwc3_msm_pm_freeze(struct device *dev) * PHYs also need to be power collapsed, so call notify_disconnect * before suspend to ensure it. */ + usb_phy_notify_disconnect(mdwc->hs_phy1, USB_SPEED_HIGH); usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HOST_MODE); + usb_phy_notify_disconnect(mdwc->ss_phy1, USB_SPEED_SUPER); usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); - mdwc->ss_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_ssphy_flags(mdwc, PHY_HOST_MODE); /* * Power collapse the core. Hence call dwc3_msm_suspend with @@ -4960,12 +5254,16 @@ static int dwc3_msm_pm_restore(struct device *dev) pm_runtime_enable(dev); /* Restore PHY flags if hibernated in host mode */ - mdwc->hs_phy->flags |= PHY_HOST_MODE; + dwc3_msm_set_hsphy_flags(mdwc, PHY_HOST_MODE); usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); + usb_phy_notify_connect(mdwc->hs_phy1, USB_SPEED_HIGH); + if (dwc->maximum_speed >= USB_SPEED_SUPER) { - mdwc->ss_phy->flags |= PHY_HOST_MODE; + dwc3_msm_set_ssphy_flags(mdwc, PHY_HOST_MODE); usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER); + usb_phy_notify_connect(mdwc->ss_phy1, + USB_SPEED_SUPER); } /* kick in otg state machine */ diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9052518ff92525602bd83c5777497f44ca00935b..c6f0ce788048552b1046fe34c83656f494cb7e27 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1684,17 +1684,18 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, goto out0; if (r->num_pending_sgs) { - struct dwc3_trb *trb; + struct dwc3_trb *trb = r->trb; int i = 0; for (i = 0; i < r->num_pending_sgs; i++) { - trb = r->trb + i; trb->ctrl &= ~DWC3_TRB_CTRL_HWO; dwc3_ep_inc_deq(dep); + trb++; + if (trb->ctrl & DWC3_TRBCTL_LINK_TRB) + trb = dep->trb_pool; } if (r->unaligned || r->zero) { - trb = r->trb + r->num_pending_sgs + 1; trb->ctrl &= ~DWC3_TRB_CTRL_HWO; dwc3_ep_inc_deq(dep); } @@ -1705,7 +1706,9 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, dwc3_ep_inc_deq(dep); if (r->unaligned || r->zero) { - trb = r->trb + 1; + trb++; + if (trb->ctrl & DWC3_TRBCTL_LINK_TRB) + trb = dep->trb_pool; trb->ctrl &= ~DWC3_TRB_CTRL_HWO; dwc3_ep_inc_deq(dep); } diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index be3172e385b5f53af9f3c4b2c9a6d7ea98f148d7..3a61ee06e201844e20535f951ba0162b5c22e580 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -3543,6 +3543,15 @@ static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_active) hw_device_state(udc->ep0out.qh.dma); } else { hw_device_state(0); + if (udc->suspended) { + if (udc->udc_driver->notify_event) + udc->udc_driver->notify_event(udc, + CI13XXX_CONTROLLER_RESUME_EVENT); + if (udc->transceiver) + usb_phy_set_suspend(udc->transceiver, 0); + udc->driver->resume(&udc->gadget); + udc->suspended = 0; + } spin_unlock_irqrestore(udc->lock, flags); _gadget_stop_activity(&udc->gadget); spin_lock_irqsave(udc->lock, flags); diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 0d3e8c6f15cb5dafaaad401396bdb3fb6e380f88..2451aab593ba9771d8d1dd56c3c1ceea6489178c 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -110,6 +110,7 @@ struct f_cdev { struct list_head read_pool; struct list_head read_queued; struct list_head write_pool; + struct list_head write_pending; /* current active USB RX request */ struct usb_request *current_rx_req; @@ -133,6 +134,8 @@ struct f_cdev { struct workqueue_struct *fcdev_wq; bool is_connected; bool port_open; + bool is_suspended; + bool pending_state_notify; unsigned long nbytes_from_host; unsigned long nbytes_to_host; @@ -541,6 +544,52 @@ static int usb_cser_set_alt(struct usb_function *f, unsigned int intf, return rc; } +static int port_notify_serial_state(struct cserial *cser); + +static void usb_cser_resume(struct usb_function *f) +{ + struct f_cdev *port = func_to_port(f); + unsigned long flags; + int ret; + + struct usb_request *req, *t; + struct usb_ep *in; + + pr_debug("%s\n", __func__); + port->is_suspended = false; + + /* process pending state notifications */ + if (port->pending_state_notify) + port_notify_serial_state(&port->port_usb); + + spin_lock_irqsave(&port->port_lock, flags); + in = port->port_usb.in; + /* process any pending requests */ + list_for_each_entry_safe(req, t, &port->write_pending, list) { + list_del_init(&req->list); + spin_unlock_irqrestore(&port->port_lock, flags); + + ret = usb_ep_queue(in, req, GFP_KERNEL); + spin_lock_irqsave(&port->port_lock, flags); + if (ret) { + pr_err("EP QUEUE failed:%d\n", ret); + list_add(&req->list, &port->write_pool); + } else { + port->nbytes_from_port_bridge += req->length; + } + } + + spin_unlock_irqrestore(&port->port_lock, flags); +} + +static void usb_cser_suspend(struct usb_function *f) +{ + struct f_cdev *port = func_to_port(f); + + pr_debug("%s\n", __func__); + port->is_suspended = true; +} + static int usb_cser_func_suspend(struct usb_function *f, u8 options) { bool func_wakeup_allowed; @@ -550,15 +599,28 @@ static int usb_cser_func_suspend(struct usb_function *f, u8 options) f->func_wakeup_allowed = func_wakeup_allowed; if (options & FUNC_SUSPEND_OPT_SUSP_MASK) { - if (!f->func_is_suspended) + if (!f->func_is_suspended) { + usb_cser_suspend(f); f->func_is_suspended = true; + } } else { - if (f->func_is_suspended) + if (f->func_is_suspended) { f->func_is_suspended = false; + usb_cser_resume(f); + } } return 0; } +static int usb_cser_get_remote_wakeup_capable(struct usb_function *f, + struct usb_gadget *g) +{ + + return ((g->speed >= USB_SPEED_SUPER && f->func_wakeup_allowed) || + (g->speed < USB_SPEED_SUPER && g->remote_wakeup)); + +} + static int usb_cser_get_status(struct usb_function *f) { bool remote_wakeup_en_status = f->func_wakeup_allowed ? 1 : 0; @@ -633,7 +695,17 @@ static int port_notify_serial_state(struct cserial *cser) unsigned long flags; struct usb_composite_dev *cdev = port->port_usb.func.config->cdev; + + if (port->is_suspended) { + port->pending_state_notify = true; + pr_debug("%s: port is suspended\n", __func__); + return 0; + } + spin_lock_irqsave(&port->port_lock, flags); + if (port->pending_state_notify) + port->pending_state_notify = false; + if (!port->port_usb.pending) { port->port_usb.pending = true; spin_unlock_irqrestore(&port->port_lock, flags); @@ -898,6 +970,9 @@ static void usb_cser_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_cdev *port = func_to_port(f); + /* Reset string id */ + cser_string_defs[0].id = 0; + usb_free_all_descriptors(f); usb_cser_free_req(port->port_usb.notify, port->port_usb.notify_req); } @@ -1098,6 +1173,7 @@ static void usb_cser_stop_io(struct f_cdev *port) usb_cser_free_requests(out, &port->read_queued); usb_cser_free_requests(out, &port->read_pool); usb_cser_free_requests(in, &port->write_pool); + usb_cser_free_requests(in, &port->write_pending); spin_unlock_irqrestore(&port->port_lock, flags); } @@ -1269,6 +1345,9 @@ ssize_t f_cdev_write(struct file *file, struct list_head *pool; unsigned int xfer_size; struct usb_ep *in; + struct cserial *cser; + struct usb_function *func; + struct usb_gadget *gadget; port = file->private_data; if (!port) { @@ -1276,6 +1355,9 @@ ssize_t f_cdev_write(struct file *file, return -EINVAL; } + cser = &port->port_usb; + func = &cser->func; + spin_lock_irqsave(&port->port_lock, flags); pr_debug("write on port(%s)(%pK)\n", port->name, port); @@ -1307,9 +1389,40 @@ ssize_t f_cdev_write(struct file *file, if (ret) { pr_err("copy_from_user failed: err %d\n", ret); ret = -EFAULT; - } else { - req->length = xfer_size; - req->zero = 1; + goto err_exit; + } + + req->length = xfer_size; + req->zero = 1; + if (port->is_suspended) { + gadget = cser->func.config->cdev->gadget; + if (!usb_cser_get_remote_wakeup_capable(func, gadget)) { + pr_debug("%s remote-wakeup not capable\n", + __func__); + ret = -EOPNOTSUPP; + goto err_exit; + } + + spin_lock_irqsave(&port->port_lock, flags); + list_add(&req->list, &port->write_pending); + spin_unlock_irqrestore(&port->port_lock, flags); + + if (gadget->speed >= USB_SPEED_SUPER + && func->func_is_suspended) + ret = usb_func_wakeup(func); + else + ret = usb_gadget_wakeup(gadget); + + if (ret < 0 && ret != -EACCES) { + pr_err("Remote wakeup failed:%d\n", ret); + spin_lock_irqsave(&port->port_lock, flags); + req = list_first_entry(&port->write_pending, + struct usb_request, list); + list_del(&req->list); + spin_unlock_irqrestore(&port->port_lock, flags); + goto err_exit; + } + } else { ret = usb_ep_queue(in, req, GFP_KERNEL); if (ret) { pr_err("EP QUEUE failed:%d\n", ret); @@ -1321,19 +1434,18 @@ ssize_t f_cdev_write(struct file *file, spin_unlock_irqrestore(&port->port_lock, flags); } + return xfer_size; + err_exit: - if (ret) { - spin_lock_irqsave(&port->port_lock, flags); - /* USB cable is connected, add it back otherwise free request */ - if (port->is_connected) - list_add(&req->list, &port->write_pool); - else - usb_cser_free_req(in, req); - spin_unlock_irqrestore(&port->port_lock, flags); - return ret; - } + spin_lock_irqsave(&port->port_lock, flags); + /* USB cable is connected, add it back otherwise free request */ + if (port->is_connected) + list_add(&req->list, &port->write_pool); + else + usb_cser_free_req(in, req); + spin_unlock_irqrestore(&port->port_lock, flags); - return xfer_size; + return ret; } static unsigned int f_cdev_poll(struct file *file, poll_table *wait) @@ -1569,6 +1681,8 @@ int usb_cser_connect(struct f_cdev *port) cser->pending = false; cser->q_again = false; port->is_connected = true; + port->pending_state_notify = false; + port->is_suspended = false; spin_unlock_irqrestore(&port->port_lock, flags); usb_cser_start_io(port); @@ -1762,6 +1876,7 @@ static struct f_cdev *f_cdev_alloc(char *func_name, int portno) INIT_LIST_HEAD(&port->read_pool); INIT_LIST_HEAD(&port->read_queued); INIT_LIST_HEAD(&port->write_pool); + INIT_LIST_HEAD(&port->write_pending); port->fcdev_wq = create_singlethread_workqueue(port->name); if (!port->fcdev_wq) { @@ -2056,6 +2171,8 @@ static struct usb_function *cser_alloc(struct usb_function_instance *fi) port->port_usb.func.func_suspend = usb_cser_func_suspend; port->port_usb.func.get_status = usb_cser_get_status; port->port_usb.func.free_func = usb_cser_free_func; + port->port_usb.func.resume = usb_cser_resume; + port->port_usb.func.suspend = usb_cser_suspend; return &port->port_usb.func; } diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 4a8da48b76dd1d0b7b4519e97871a51f42b2c68e..5a2b8ab2b95cfc2f7191a36554e035c37df38210 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -3359,6 +3359,13 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) drain_workqueue(gsi->d_port.ipa_usb_wq); ipa_usb_deinit_teth_prot((enum ipa_usb_teth_prot)gsi->prot_id); + /* Reset string ids */ + rndis_gsi_string_defs[0].id = 0; + ecm_gsi_string_defs[0].id = 0; + rmnet_gsi_string_defs[0].id = 0; + mbim_gsi_string_defs[0].id = 0; + qdss_gsi_string_defs[0].id = 0; + skip_ipa_dinit: if (gsi->prot_id == USB_PROT_RNDIS_IPA) { gsi->d_port.sm_state = STATE_UNINITIALIZED; diff --git a/drivers/usb/gadget/function/f_ipc.c b/drivers/usb/gadget/function/f_ipc.c index 1b99e9962305742ae31648438f38fd3fe62d062e..1e6a1b4ac822eee507e56366e45b624a3700791a 100644 --- a/drivers/usb/gadget/function/f_ipc.c +++ b/drivers/usb/gadget/function/f_ipc.c @@ -794,10 +794,6 @@ static int ipc_set_inst_name(struct usb_function_instance *fi, if (name_len > MAX_INST_NAME_LEN) return -ENAMETOOLONG; - ipc_dev = kzalloc(sizeof(*ipc_dev), GFP_KERNEL); - if (!ipc_dev) - return -ENOMEM; - spin_lock_init(&ipc_dev->lock); init_waitqueue_head(&ipc_dev->state_wq); init_completion(&ipc_dev->read_done); @@ -813,7 +809,6 @@ static void ipc_free_inst(struct usb_function_instance *f) { struct ipc_opts *opts = container_of(f, struct ipc_opts, func_inst); - kfree(opts->ctxt); kfree(opts); } @@ -844,9 +839,17 @@ static int __init ipc_init(void) { int ret; + ipc_dev = kzalloc(sizeof(*ipc_dev), GFP_KERNEL); + if (!ipc_dev) + return -ENOMEM; + ret = usb_function_register(&ipcusb_func); - if (ret) + if (ret) { + kfree(ipc_dev); + ipc_dev = NULL; pr_err("%s: failed to register ipc %d\n", __func__, ret); + return ret; + } fipc_debugfs_init(); @@ -857,6 +860,8 @@ static void __exit ipc_exit(void) { fipc_debugfs_remove(); usb_function_unregister(&ipcusb_func); + kfree(ipc_dev); + ipc_dev = NULL; } module_init(ipc_init); diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index f6beba60ea28195cc083ed554a1c615e488b7b85..34928a0a00df3170440d8a3b34807a3f27afa1de 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -1125,18 +1125,15 @@ static long mtp_send_receive_ioctl(struct file *fp, unsigned int code, * in kernel context, which is necessary for vfs_read and * vfs_write to use our buffers in the kernel address space. */ - dev->xfer_result = 0; - if (dev->xfer_file_length) { - queue_work(dev->wq, work); - /* wait for operation to complete */ - flush_workqueue(dev->wq); - - /* read the result */ - smp_rmb(); - } - ret = dev->xfer_result; + queue_work(dev->wq, work); + /* wait for operation to complete */ + flush_workqueue(dev->wq); fput(filp); + /* read the result */ + smp_rmb(); + ret = dev->xfer_result; + fail: spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 41c92e8e6198f138b5e3261bc96eabcfdb34e543..d557e2bbe4bae0e8ae44ee9ce5ce40c51d1577f9 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -2,7 +2,6 @@ * f_qdss.c -- QDSS function Driver * * Copyright (c) 2012-2018, 2020, 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. @@ -423,11 +422,13 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) qdss_data_intf_desc.bInterfaceNumber = iface; qdss->data_iface_id = iface; - id = usb_string_id(c->cdev); - if (id < 0) - return id; - qdss_string_defs[QDSS_DATA_IDX].id = id; - qdss_data_intf_desc.iInterface = id; + if (!qdss_string_defs[QDSS_DATA_IDX].id) { + id = usb_string_id(c->cdev); + if (id < 0) + return id; + qdss_string_defs[QDSS_DATA_IDX].id = id; + qdss_data_intf_desc.iInterface = id; + } if (qdss->debug_inface_enabled) { /* Allocate ctrl I/F */ @@ -438,11 +439,14 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) } qdss_ctrl_intf_desc.bInterfaceNumber = iface; qdss->ctrl_iface_id = iface; - id = usb_string_id(c->cdev); - if (id < 0) - return id; - qdss_string_defs[QDSS_CTRL_IDX].id = id; - qdss_ctrl_intf_desc.iInterface = id; + + if (!qdss_string_defs[QDSS_CTRL_IDX].id) { + id = usb_string_id(c->cdev); + if (id < 0) + return id; + qdss_string_defs[QDSS_CTRL_IDX].id = id; + qdss_ctrl_intf_desc.iInterface = id; + } } /* for non-accelerated path keep tx fifo size 1k */ @@ -526,6 +530,10 @@ static void qdss_unbind(struct usb_configuration *c, struct usb_function *f) flush_workqueue(qdss->wq); + /* Reset string ids */ + qdss_string_defs[QDSS_DATA_IDX].id = 0; + qdss_string_defs[QDSS_CTRL_IDX].id = 0; + qdss->debug_inface_enabled = 0; clear_eps(f); diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 7e90f786d923e7e302fa65d97e76485c3ad576b8..8ee76524a0b7800e42030123094e7045f9aa56c1 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -980,8 +980,18 @@ static int dummy_udc_start(struct usb_gadget *g, struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); struct dummy *dum = dum_hcd->dum; - if (driver->max_speed == USB_SPEED_UNKNOWN) + switch (g->speed) { + /* All the speeds we support */ + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + break; + default: + dev_err(dummy_dev(dum_hcd), "Unsupported driver max speed %d\n", + driver->max_speed); return -EINVAL; + } /* * SLAVE side init ... the layer above hardware, which @@ -1325,7 +1335,7 @@ static int dummy_perform_transfer(struct urb *urb, struct dummy_request *req, u32 this_sg; bool next_sg; - to_host = usb_pipein(urb->pipe); + to_host = usb_urb_dir_in(urb); rbuf = req->req.buf + req->req.actual; if (!urb->num_sgs) { @@ -1413,7 +1423,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, /* FIXME update emulated data toggle too */ - to_host = usb_pipein(urb->pipe); + to_host = usb_urb_dir_in(urb); if (unlikely(len == 0)) is_short = 1; else { @@ -1770,6 +1780,7 @@ static void dummy_timer(unsigned long _dum_hcd) int i; /* simplistic model for one frame's bandwidth */ + /* FIXME: account for transaction and packet overhead */ switch (dum->gadget.speed) { case USB_SPEED_LOW: total = 8/*bytes*/ * 12/*packets*/; @@ -1784,9 +1795,10 @@ static void dummy_timer(unsigned long _dum_hcd) /* Bus speed is 500000 bytes/ms, so use a little less */ total = 490000; break; - default: + default: /* Can't happen */ dev_err(dummy_dev(dum_hcd), "bogus device speed\n"); - return; + total = 0; + break; } /* FIXME if HZ != 1000 this will probably misbehave ... */ @@ -1814,7 +1826,6 @@ static void dummy_timer(unsigned long _dum_hcd) struct dummy_request *req; u8 address; struct dummy_ep *ep = NULL; - int type; int status = -EINPROGRESS; /* stop when we reach URBs queued after the timer interrupt */ @@ -1826,18 +1837,14 @@ static void dummy_timer(unsigned long _dum_hcd) goto return_urb; else if (dum_hcd->rh_state != DUMMY_RH_RUNNING) continue; - type = usb_pipetype(urb->pipe); - /* used up this frame's non-periodic bandwidth? - * FIXME there's infinite bandwidth for control and - * periodic transfers ... unrealistic. - */ - if (total <= 0 && type == PIPE_BULK) + /* Used up this frame's bandwidth? */ + if (total <= 0) continue; /* find the gadget's ep for this request (if configured) */ address = usb_pipeendpoint (urb->pipe); - if (usb_pipein(urb->pipe)) + if (usb_urb_dir_in(urb)) address |= USB_DIR_IN; ep = find_endpoint(dum, address); if (!ep) { @@ -2390,7 +2397,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb) s = "?"; break; } s; }), - ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "", + ep, ep ? (usb_urb_dir_in(urb) ? "in" : "out") : "", ({ char *s; \ switch (usb_pipetype(urb->pipe)) { \ case PIPE_CONTROL: \ @@ -2734,7 +2741,7 @@ static struct platform_driver dummy_hcd_driver = { }; /*-------------------------------------------------------------------------*/ -#define MAX_NUM_UDC 2 +#define MAX_NUM_UDC 32 static struct platform_device *the_udc_pdev[MAX_NUM_UDC]; static struct platform_device *the_hcd_pdev[MAX_NUM_UDC]; diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 008010e9ad5ab9a7467c776094c85dd6d5761af4..fdf62862056f38cf4b3455884f4ba142614f9ce0 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1265,7 +1265,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } port_li = readl(port_array[wIndex] + PORTLI); status = xhci_get_ext_port_status(temp, port_li); - put_unaligned_le32(cpu_to_le32(status), &buf[4]); + put_unaligned_le32(status, &buf[4]); } break; case SetPortFeature: diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 36aa810668576de423cfedc35e6ba9a25ddafa03..85b3c924f25a8c0bab78bca0ceb7b1df549573e1 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -159,7 +159,7 @@ static ssize_t config_imod_store(struct device *pdev, u32 imod; unsigned long flags; - if (kstrtouint(buff, 10, &imod) != 1) + if (kstrtouint(buff, 10, &imod) < 0) return 0; imod &= ER_IRQ_INTERVAL_MASK; diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c index f54e3aa1ca67daab039bee972843c9e6bea562b3..5a0dc78be31ffb8c13f568b11f4bbd56a95be2bf 100644 --- a/drivers/usb/misc/diag_bridge.c +++ b/drivers/usb/misc/diag_bridge.c @@ -588,34 +588,8 @@ static int diag_bridge_resume(struct usb_interface *ifc) static const struct usb_device_id diag_bridge_ids[] = { { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x901F, 0), .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90EF, 4), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90F0, 4), - .driver_info = DEV_ID(0), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90F3, 0), .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90FD, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9102, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9103, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9104, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9105, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9106, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9107, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x910A, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x910B, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x910C, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x910D, 0), - .driver_info = DEV_ID(0), }, {} /* terminating entry */ }; diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c index 427d41193ca80661e01a63a92f0c46ef49b31a98..9bd5a1f00d3fd2de665408de943906fa6571b250 100644 --- a/drivers/usb/misc/mdm_data_bridge.c +++ b/drivers/usb/misc/mdm_data_bridge.c @@ -970,34 +970,60 @@ static void bridge_disconnect(struct usb_interface *intf) static const struct usb_device_id bridge_ids[] = { { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9008, 0), .driver_info = (kernel_ulong_t)("edl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x90EF, 4), + .driver_info = (kernel_ulong_t)("diag"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x90F0, 4), + .driver_info = (kernel_ulong_t)("diag"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x90FD, 0), + .driver_info = (kernel_ulong_t)("diag"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9102, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9102, 6), .driver_info = (kernel_ulong_t)("qdss"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9102, 7), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9103, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9103, 6), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9104, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9104, 1), .driver_info = (kernel_ulong_t)("qdss"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9104, 2), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9105, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9105, 1), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9106, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9106, 5), .driver_info = (kernel_ulong_t)("qdss"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9106, 6), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9107, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9107, 5), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910A, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910A, 2), .driver_info = (kernel_ulong_t)("dpl"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910A, 3), .driver_info = (kernel_ulong_t)("qdss"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910B, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910B, 2), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910C, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910C, 1), .driver_info = (kernel_ulong_t)("dpl"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910C, 2), .driver_info = (kernel_ulong_t)("qdss"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910D, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910D, 1), .driver_info = (kernel_ulong_t)("dpl"), }, diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index ff17e94ef465cd86cef3e6e1970d3710d9717a5e..dca39c9a13b0e8cfa98418847d18fe1ec5cca963 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1838,6 +1838,9 @@ static const struct attribute_group musb_attr_group = { #define MUSB_QUIRK_B_INVALID_VBUS_91 (MUSB_DEVCTL_BDEVICE | \ (2 << MUSB_DEVCTL_VBUS_SHIFT) | \ MUSB_DEVCTL_SESSION) +#define MUSB_QUIRK_B_DISCONNECT_99 (MUSB_DEVCTL_BDEVICE | \ + (3 << MUSB_DEVCTL_VBUS_SHIFT) | \ + MUSB_DEVCTL_SESSION) #define MUSB_QUIRK_A_DISCONNECT_19 ((3 << MUSB_DEVCTL_VBUS_SHIFT) | \ MUSB_DEVCTL_SESSION) @@ -1860,6 +1863,11 @@ static void musb_pm_runtime_check_session(struct musb *musb) s = MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV | MUSB_DEVCTL_HR; switch (devctl & ~s) { + case MUSB_QUIRK_B_DISCONNECT_99: + musb_dbg(musb, "Poll devctl in case of suspend after disconnect\n"); + schedule_delayed_work(&musb->irq_work, + msecs_to_jiffies(1000)); + break; case MUSB_QUIRK_B_INVALID_VBUS_91: if (musb->quirk_retries && !musb->flush_irq_work) { musb_dbg(musb, @@ -2320,6 +2328,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb_disable_interrupts(musb); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + /* MUSB_POWER_SOFTCONN might be already set, JZ4740 does this. */ + musb_writeb(musb->mregs, MUSB_POWER, 0); + /* Init IRQ workqueue before request_irq */ INIT_DELAYED_WORK(&musb->irq_work, musb_irq_work); INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 512108e22d2bd8afe9f96642dfeac16c5115df7a..1dc35ab31275324391ab53592f9699fa1f3dfa10 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -399,7 +399,7 @@ struct dma_controller *musbhs_dma_controller_create(struct musb *musb, controller->controller.channel_abort = dma_channel_abort; if (request_irq(irq, dma_controller_irq, 0, - dev_name(musb->controller), &controller->controller)) { + dev_name(musb->controller), controller)) { dev_err(dev, "request_irq %d failed!\n", irq); musb_dma_controller_destroy(&controller->controller); diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index ba49796d2fd5fde4f2a2973f86a9317d5cb5b138..7e0e4d83f16b47f6de7d2522210145217943edf7 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -388,6 +388,7 @@ struct usbpd { struct workqueue_struct *wq; struct work_struct sm_work; struct work_struct start_periph_work; + struct work_struct restart_host_work; struct hrtimer timer; bool sm_queued; @@ -415,6 +416,7 @@ struct usbpd { bool peer_usb_comm; bool peer_pr_swap; bool peer_dr_swap; + bool no_usb3dp_concurrency; u32 sink_caps[7]; int num_sink_caps; @@ -583,6 +585,26 @@ static void start_usb_peripheral_work(struct work_struct *w) dual_role_instance_changed(pd->dual_role); } +static void restart_usb_host_work(struct work_struct *w) +{ + struct usbpd *pd = container_of(w, struct usbpd, restart_host_work); + int ret; + + if (!pd->no_usb3dp_concurrency) + return; + + stop_usb_host(pd); + + /* blocks until USB host is completely stopped */ + ret = extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0); + if (ret) { + usbpd_err(&pd->dev, "err(%d) stopping host", ret); + return; + } + + start_usb_host(pd, false); +} + /** * This API allows client driver to request for releasing SS lanes. It should * not be called from atomic context. @@ -1889,6 +1911,7 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) /* Set to USB and DP cocurrency mode */ extcon_blocking_sync(pd->extcon, EXTCON_DISP_DP, 2); + queue_work(pd->wq, &pd->restart_host_work); } /* if it's a supported SVID, pass the message to the handler */ @@ -4526,6 +4549,7 @@ struct usbpd *usbpd_create(struct device *parent) } INIT_WORK(&pd->sm_work, usbpd_sm); INIT_WORK(&pd->start_periph_work, start_usb_peripheral_work); + INIT_WORK(&pd->restart_host_work, restart_usb_host_work); hrtimer_init(&pd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); pd->timer.function = pd_timeout; mutex_init(&pd->swap_lock); @@ -4619,6 +4643,8 @@ struct usbpd *usbpd_create(struct device *parent) pd->num_sink_caps = ARRAY_SIZE(default_snk_caps); } + if (device_property_read_bool(parent, "qcom,no-usb3-dp-concurrency")) + pd->no_usb3dp_concurrency = true; /* * Register the Android dual-role class (/sys/class/dual_role_usb/). * The first instance should be named "otg_default" as that's what diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index a7d2cc4eea77fe3d68733d8c454a6057a441f952..c9061ad0d26af0f60982499bc54271b9818751ac 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -28,7 +28,7 @@ config AB8500_USB in host mode, low speed. config FSL_USB2_OTG - bool "Freescale USB OTG Transceiver Driver" + tristate "Freescale USB OTG Transceiver Driver" depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM=y && PM depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index b5dc077ed7d3c6fa4b262798cc7c8dc467069f5c..8e14fa221191264f1d651f0705f4462d79db8320 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -413,7 +413,7 @@ static int twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); - cancel_delayed_work(&twl->get_status_work); + cancel_delayed_work_sync(&twl->get_status_work); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 578596d301b8f5dfde537eaab701e32996eaa7e1..31cd798d2dac5ca6338df392fb32487c93b7ba22 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -592,9 +592,13 @@ static int ch341_tiocmget(struct tty_struct *tty) static int ch341_reset_resume(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; - struct ch341_private *priv = usb_get_serial_port_data(port); + struct ch341_private *priv; int ret; + priv = usb_get_serial_port_data(port); + if (!priv) + return 0; + /* reconfigure ch341 serial port after bus-reset */ ch341_configure(serial->dev, priv); diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 51b61545ccf2eb3a90819a413ed1733044746aef..3705b64ab948323740aaba443e8079ec5b1d8c97 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -652,6 +652,7 @@ static void edge_interrupt_callback(struct urb *urb) struct usb_serial_port *port; unsigned char *data = urb->transfer_buffer; int length = urb->actual_length; + unsigned long flags; int bytes_avail; int position; int txCredits; @@ -683,7 +684,7 @@ static void edge_interrupt_callback(struct urb *urb) if (length > 1) { bytes_avail = data[0] | (data[1] << 8); if (bytes_avail) { - spin_lock(&edge_serial->es_lock); + spin_lock_irqsave(&edge_serial->es_lock, flags); edge_serial->rxBytesAvail += bytes_avail; dev_dbg(dev, "%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d\n", @@ -706,7 +707,8 @@ static void edge_interrupt_callback(struct urb *urb) edge_serial->read_in_progress = false; } } - spin_unlock(&edge_serial->es_lock); + spin_unlock_irqrestore(&edge_serial->es_lock, + flags); } } /* grab the txcredits for the ports if available */ @@ -718,10 +720,12 @@ static void edge_interrupt_callback(struct urb *urb) if (txCredits) { port = edge_serial->serial->port[portNumber]; edge_port = usb_get_serial_port_data(port); - if (edge_port->open) { - spin_lock(&edge_port->ep_lock); + if (edge_port && edge_port->open) { + spin_lock_irqsave(&edge_port->ep_lock, + flags); edge_port->txCredits += txCredits; - spin_unlock(&edge_port->ep_lock); + spin_unlock_irqrestore(&edge_port->ep_lock, + flags); dev_dbg(dev, "%s - txcredits for port%d = %d\n", __func__, portNumber, edge_port->txCredits); @@ -762,6 +766,7 @@ static void edge_bulk_in_callback(struct urb *urb) int retval; __u16 raw_data_length; int status = urb->status; + unsigned long flags; if (status) { dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", @@ -781,7 +786,7 @@ static void edge_bulk_in_callback(struct urb *urb) usb_serial_debug_data(dev, __func__, raw_data_length, data); - spin_lock(&edge_serial->es_lock); + spin_lock_irqsave(&edge_serial->es_lock, flags); /* decrement our rxBytes available by the number that we just got */ edge_serial->rxBytesAvail -= raw_data_length; @@ -805,7 +810,7 @@ static void edge_bulk_in_callback(struct urb *urb) edge_serial->read_in_progress = false; } - spin_unlock(&edge_serial->es_lock); + spin_unlock_irqrestore(&edge_serial->es_lock, flags); } @@ -1733,7 +1738,8 @@ static void edge_break(struct tty_struct *tty, int break_state) static void process_rcvd_data(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength) { - struct device *dev = &edge_serial->serial->dev->dev; + struct usb_serial *serial = edge_serial->serial; + struct device *dev = &serial->dev->dev; struct usb_serial_port *port; struct edgeport_port *edge_port; __u16 lastBufferLength; @@ -1838,11 +1844,10 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, /* spit this data back into the tty driver if this port is open */ - if (rxLen) { - port = edge_serial->serial->port[ - edge_serial->rxPort]; + if (rxLen && edge_serial->rxPort < serial->num_ports) { + port = serial->port[edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); - if (edge_port->open) { + if (edge_port && edge_port->open) { dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n", __func__, rxLen, edge_serial->rxPort); @@ -1850,8 +1855,8 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, rxLen); edge_port->port->icount.rx += rxLen; } - buffer += rxLen; } + buffer += rxLen; break; case EXPECT_HDR3: /* Expect 3rd byte of status header */ @@ -1886,6 +1891,8 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, __u8 code = edge_serial->rxStatusCode; /* switch the port pointer to the one being currently talked about */ + if (edge_serial->rxPort >= edge_serial->serial->num_ports) + return; port = edge_serial->serial->port[edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); if (edge_port == NULL) { diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index f9734a96d51681d689c5028e6777fec03c401d5a..a3e3b4703f38072cf651df0ef4b6c02588b20e74 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -49,9 +49,10 @@ static int buffer_size; static int xbof = -1; static int ir_startup (struct usb_serial *serial); -static int ir_open(struct tty_struct *tty, struct usb_serial_port *port); -static int ir_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size); +static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count); +static int ir_write_room(struct tty_struct *tty); +static void ir_write_bulk_callback(struct urb *urb); static void ir_process_read_urb(struct urb *urb); static void ir_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); @@ -81,8 +82,9 @@ static struct usb_serial_driver ir_device = { .num_ports = 1, .set_termios = ir_set_termios, .attach = ir_startup, - .open = ir_open, - .prepare_write_buffer = ir_prepare_write_buffer, + .write = ir_write, + .write_room = ir_write_room, + .write_bulk_callback = ir_write_bulk_callback, .process_read_urb = ir_process_read_urb, }; @@ -199,6 +201,9 @@ static int ir_startup(struct usb_serial *serial) struct usb_irda_cs_descriptor *irda_desc; int rates; + if (serial->num_bulk_in < 1 || serial->num_bulk_out < 1) + return -ENODEV; + irda_desc = irda_usb_find_class_desc(serial, 0); if (!irda_desc) { dev_err(&serial->dev->dev, @@ -255,35 +260,102 @@ static int ir_startup(struct usb_serial *serial) return 0; } -static int ir_open(struct tty_struct *tty, struct usb_serial_port *port) +static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) { - int i; + struct urb *urb = NULL; + unsigned long flags; + int ret; - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET; + if (port->bulk_out_size == 0) + return -EINVAL; - /* Start reading from the device */ - return usb_serial_generic_open(tty, port); -} + if (count == 0) + return 0; -static int ir_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size) -{ - unsigned char *buf = dest; - int count; + count = min(count, port->bulk_out_size - 1); + + spin_lock_irqsave(&port->lock, flags); + if (__test_and_clear_bit(0, &port->write_urbs_free)) { + urb = port->write_urbs[0]; + port->tx_bytes += count; + } + spin_unlock_irqrestore(&port->lock, flags); + + if (!urb) + return 0; /* * The first byte of the packet we send to the device contains an - * inbound header which indicates an additional number of BOFs and + * outbound header which indicates an additional number of BOFs and * a baud rate change. * * See section 5.4.2.2 of the USB IrDA spec. */ - *buf = ir_xbof | ir_baud; + *(u8 *)urb->transfer_buffer = ir_xbof | ir_baud; + + memcpy(urb->transfer_buffer + 1, buf, count); + + urb->transfer_buffer_length = count + 1; + urb->transfer_flags = URB_ZERO_PACKET; + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + dev_err(&port->dev, "failed to submit write urb: %d\n", ret); + + spin_lock_irqsave(&port->lock, flags); + __set_bit(0, &port->write_urbs_free); + port->tx_bytes -= count; + spin_unlock_irqrestore(&port->lock, flags); + + return ret; + } + + return count; +} + +static void ir_write_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + int status = urb->status; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + __set_bit(0, &port->write_urbs_free); + port->tx_bytes -= urb->transfer_buffer_length - 1; + spin_unlock_irqrestore(&port->lock, flags); + + switch (status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + dev_dbg(&port->dev, "write urb stopped: %d\n", status); + return; + case -EPIPE: + dev_err(&port->dev, "write urb stopped: %d\n", status); + return; + default: + dev_err(&port->dev, "nonzero write-urb status: %d\n", status); + break; + } + + usb_serial_port_softint(port); +} + +static int ir_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + int count = 0; + + if (port->bulk_out_size == 0) + return 0; + + if (test_bit(0, &port->write_urbs_free)) + count = port->bulk_out_size - 1; - count = kfifo_out_locked(&port->write_fifo, buf + 1, size - 1, - &port->lock); - return count + 1; + return count; } static void ir_process_read_urb(struct urb *urb) @@ -336,34 +408,34 @@ static void ir_set_termios(struct tty_struct *tty, switch (baud) { case 2400: - ir_baud = USB_IRDA_BR_2400; + ir_baud = USB_IRDA_LS_2400; break; case 9600: - ir_baud = USB_IRDA_BR_9600; + ir_baud = USB_IRDA_LS_9600; break; case 19200: - ir_baud = USB_IRDA_BR_19200; + ir_baud = USB_IRDA_LS_19200; break; case 38400: - ir_baud = USB_IRDA_BR_38400; + ir_baud = USB_IRDA_LS_38400; break; case 57600: - ir_baud = USB_IRDA_BR_57600; + ir_baud = USB_IRDA_LS_57600; break; case 115200: - ir_baud = USB_IRDA_BR_115200; + ir_baud = USB_IRDA_LS_115200; break; case 576000: - ir_baud = USB_IRDA_BR_576000; + ir_baud = USB_IRDA_LS_576000; break; case 1152000: - ir_baud = USB_IRDA_BR_1152000; + ir_baud = USB_IRDA_LS_1152000; break; case 4000000: - ir_baud = USB_IRDA_BR_4000000; + ir_baud = USB_IRDA_LS_4000000; break; default: - ir_baud = USB_IRDA_BR_9600; + ir_baud = USB_IRDA_LS_9600; baud = 9600; } diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 2c5a53bdccd4dbe26f06588066584e9f8ae67080..55a76848799067a0e0b937026ad1f9c7c2078905 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -1062,6 +1062,8 @@ static void usa49_glocont_callback(struct urb *urb) for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; p_priv = usb_get_serial_port_data(port); + if (!p_priv) + continue; if (p_priv->resend_cont) { dev_dbg(&port->dev, "%s - sending setup\n", __func__); @@ -1463,6 +1465,8 @@ static void usa67_glocont_callback(struct urb *urb) for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; p_priv = usb_get_serial_port_data(port); + if (!p_priv) + continue; if (p_priv->resend_cont) { dev_dbg(&port->dev, "%s - sending setup\n", __func__); diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 58657d64678ba06eff913acec8c7584a19502db9..c37572a8bb06d1c47ddc6e15a8a2d2091ab12839 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -116,7 +116,7 @@ static int send_control_msg(struct usb_serial_port *port, u8 requesttype, retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), requesttype, USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, - 0, 0, buffer, 1, 0); + 0, 0, buffer, 1, USB_CTRL_SET_TIMEOUT); kfree(buffer); if (retval < 0) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 8d349f2e56566469d01995b49097b520c9387cd7..eff353de47cd5b60a3b48d547eda970d48e84ff9 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -251,6 +251,7 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_BG96 0x0296 #define QUECTEL_PRODUCT_EP06 0x0306 #define QUECTEL_PRODUCT_EM12 0x0512 +#define QUECTEL_PRODUCT_RM500Q 0x0800 #define CMOTECH_VENDOR_ID 0x16d8 #define CMOTECH_PRODUCT_6001 0x6001 @@ -570,6 +571,9 @@ static void option_instat_callback(struct urb *urb); /* Interface must have two endpoints */ #define NUMEP2 BIT(16) +/* Device needs ZLP */ +#define ZLP BIT(17) + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, @@ -1104,6 +1108,11 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff), .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x10), + .driver_info = ZLP }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), @@ -1175,6 +1184,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */ .driver_info = NCTRL(0) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x110a, 0xff), /* Telit ME910G1 */ + .driver_info = NCTRL(0) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), @@ -1199,6 +1210,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1901, 0xff), /* Telit LN940 (MBIM) */ .driver_info = NCTRL(0) }, + { USB_DEVICE(TELIT_VENDOR_ID, 0x9010), /* Telit SBL FN980 flashing device */ + .driver_info = NCTRL(0) | ZLP }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), .driver_info = RSVD(1) }, @@ -2107,6 +2120,9 @@ static int option_attach(struct usb_serial *serial) if (!(device_flags & NCTRL(iface_desc->bInterfaceNumber))) data->use_send_setup = 1; + if (device_flags & ZLP) + data->use_zlp = 1; + spin_lock_init(&data->susp_lock); usb_set_serial_data(serial, data); diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 60e17d1444c39fc50f4fbd85a579e967ba823775..f16e0b8c1ed42b0c0fc204eb0cbb01aa1302f236 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -867,7 +867,10 @@ static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch) u8 newMSR = (u8) *ch; unsigned long flags; + /* May be called from qt2_process_read_urb() for an unbound port. */ port_priv = usb_get_serial_port_data(port); + if (!port_priv) + return; spin_lock_irqsave(&port_priv->lock, flags); port_priv->shadowMSR = newMSR; @@ -895,7 +898,10 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch) unsigned long flags; u8 newLSR = (u8) *ch; + /* May be called from qt2_process_read_urb() for an unbound port. */ port_priv = usb_get_serial_port_data(port); + if (!port_priv) + return; if (newLSR & UART_LSR_BI) newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI); diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 51124211140395c627869f9bff9dd14e9aa1565b..15e05ebf37ac475d09edda610028ac7db3d94a37 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -89,6 +89,8 @@ DEVICE(moto_modem, MOTO_IDS); #define MOTOROLA_TETRA_IDS() \ { USB_DEVICE(0x0cad, 0x9011) }, /* Motorola Solutions TETRA PEI */ \ { USB_DEVICE(0x0cad, 0x9012) }, /* MTP6550 */ \ + { USB_DEVICE(0x0cad, 0x9013) }, /* MTP3xxx */ \ + { USB_DEVICE(0x0cad, 0x9015) }, /* MTP85xx */ \ { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 8115b7cccf1af8f802ac2a9125d287eac07825f9..3dc3464626fb7aa654e2c04890f7df3ab641974b 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1332,6 +1332,9 @@ static int usb_serial_register(struct usb_serial_driver *driver) return -EINVAL; } + /* Prevent individual ports from being unbound. */ + driver->driver.suppress_bind_attrs = true; + usb_serial_operations_init(driver); /* Add this device to our list of devices */ diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index d28dab4b9effcd5d766bb76fa2e2d92de7dcd4f1..9879773fb39ea9afa54ecf66e9dde36b9ada513b 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h @@ -36,6 +36,7 @@ struct usb_wwan_intf_private { spinlock_t susp_lock; unsigned int suspended:1; unsigned int use_send_setup:1; + unsigned int use_zlp:1; int in_flight; unsigned int open_ports; void *private; diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 59bfcb3da116c4a49398750a1678f1d0349678fd..95e9576c2fe6741fb01cf040edda63feae7fdbb8 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -492,6 +492,7 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, void (*callback) (struct urb *)) { struct usb_serial *serial = port->serial; + struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); struct urb *urb; urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ @@ -502,6 +503,9 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, usb_sndbulkpipe(serial->dev, endpoint) | dir, buf, len, callback, ctx); + if (intfdata->use_zlp && dir == USB_DIR_OUT) + urb->transfer_flags |= URB_ZERO_PACKET; + return urb; } diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index f15aa47c54a9dccc6238faed23d6de6b8f43cfb5..0eb8c67ee13821f34e7b9c44c55eb9f8b330c116 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -163,12 +163,15 @@ UNUSUAL_DEV(0x2537, 0x1068, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_UAS), -/* Reported-by: Takeo Nakayama */ +/* + * Initially Reported-by: Takeo Nakayama + * UAS Ignore Reported by Steven Ellis + */ UNUSUAL_DEV(0x357d, 0x7788, 0x0000, 0x9999, "JMicron", "JMS566", USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_REPORT_OPCODES), + US_FL_NO_REPORT_OPCODES | US_FL_IGNORE_UAS), /* Reported-by: Hans de Goede */ UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999, diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index 0212f0ee8aea7577246c01c99821e0ba12cf9373..e052f62fdea7e8151cf4fd2b3d650805161da341 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -150,10 +150,10 @@ static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove) static int mdev_device_remove_cb(struct device *dev, void *data) { - if (!dev_is_mdev(dev)) - return 0; + if (dev_is_mdev(dev)) + mdev_device_remove(dev, true); - return mdev_device_remove(dev, data ? *(bool *)data : true); + return 0; } /* @@ -182,6 +182,7 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops) /* Check for duplicate */ parent = __find_parent_device(dev); if (parent) { + parent = NULL; ret = -EEXIST; goto add_dev_err; } @@ -240,7 +241,6 @@ EXPORT_SYMBOL(mdev_register_device); void mdev_unregister_device(struct device *dev) { struct mdev_parent *parent; - bool force_remove = true; mutex_lock(&parent_list_lock); parent = __find_parent_device(dev); @@ -254,8 +254,7 @@ void mdev_unregister_device(struct device *dev) list_del(&parent->next); class_compat_remove_link(mdev_bus_compat_class, dev, NULL); - device_for_each_child(dev, (void *)&force_remove, - mdev_device_remove_cb); + device_for_each_child(dev, NULL, mdev_device_remove_cb); parent_remove_sysfs_files(parent); diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 9bd3e7911af2b41cf1ba5cb31d81692737aa322f..550ab7707b57fb69084357cf20b60452bfa11f0c 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -717,6 +717,7 @@ static long vfio_pci_ioctl(void *device_data, { void __iomem *io; size_t size; + u16 orig_cmd; info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); info.flags = 0; @@ -732,15 +733,23 @@ static long vfio_pci_ioctl(void *device_data, break; } - /* Is it really there? */ + /* + * Is it really there? Enable memory decode for + * implicit access in pci_map_rom(). + */ + pci_read_config_word(pdev, PCI_COMMAND, &orig_cmd); + pci_write_config_word(pdev, PCI_COMMAND, + orig_cmd | PCI_COMMAND_MEMORY); + io = pci_map_rom(pdev, &size); - if (!io || !size) { + if (io) { + info.flags = VFIO_REGION_INFO_FLAG_READ; + pci_unmap_rom(pdev, io); + } else { info.size = 0; - break; } - pci_unmap_rom(pdev, io); - info.flags = VFIO_REGION_INFO_FLAG_READ; + pci_write_config_word(pdev, PCI_COMMAND, orig_cmd); break; } case VFIO_PCI_VGA_REGION_INDEX: diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 3d7bea15c57bccd13c1a670b4b4f8220e5f90d45..85edacc0be47f0b80561e9090f4a2822a7902d70 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "vhost.h" @@ -361,7 +362,9 @@ static int vhost_worker(void *data) llist_for_each_entry_safe(work, work_next, node, node) { clear_bit(VHOST_WORK_QUEUED, &work->flags); __set_current_state(TASK_RUNNING); + kcov_remote_start_common(dev->kcov_handle); work->fn(work); + kcov_remote_stop(); if (need_resched()) schedule(); } @@ -521,6 +524,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev) /* No owner, become one */ dev->mm = get_task_mm(current); + dev->kcov_handle = kcov_common_handle(); worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid); if (IS_ERR(worker)) { err = PTR_ERR(worker); @@ -546,6 +550,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev) if (dev->mm) mmput(dev->mm); dev->mm = NULL; + dev->kcov_handle = 0; err_mm: return err; } @@ -665,6 +670,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked) if (dev->worker) { kthread_stop(dev->worker); dev->worker = NULL; + dev->kcov_handle = 0; } if (dev->mm) mmput(dev->mm); diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 950c5c4e4ee3d97cd91ee5454bd36c5e1510d28b..6e8f67ff1e1c1f8d4233ffe2d8a926ade166afec 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -175,6 +175,7 @@ struct vhost_dev { wait_queue_head_t wait; int weight; int byte_weight; + u64 kcov_handle; }; bool vhost_exceeds_weight(struct vhost_virtqueue *vq, int pkts, int total_len); diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c index 2030a6b77a09725e97bb1618b2695aea5c55f2a0..ef2553f452ca998b6df35175d4d4a84b3f13a782 100644 --- a/drivers/video/backlight/lm3630a_bl.c +++ b/drivers/video/backlight/lm3630a_bl.c @@ -201,7 +201,7 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl) LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE); if (ret < 0) goto out_i2c_err; - return bl->props.brightness; + return 0; out_i2c_err: dev_err(pchip->dev, "i2c failed to access\n"); @@ -278,7 +278,7 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl) LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE); if (ret < 0) goto out_i2c_err; - return bl->props.brightness; + return 0; out_i2c_err: dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c index f103665cad431c449422b87bea145934444a46e4..f9b366d1758758417d8d069518488a93e878724b 100644 --- a/drivers/video/fbdev/chipsfb.c +++ b/drivers/video/fbdev/chipsfb.c @@ -350,7 +350,7 @@ static void init_chips(struct fb_info *p, unsigned long addr) static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) { struct fb_info *p; - unsigned long addr, size; + unsigned long addr; unsigned short cmd; int rc = -ENODEV; @@ -362,7 +362,6 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) goto err_disable; addr = pci_resource_start(dp, 0); - size = pci_resource_len(dp, 0); if (addr == 0) goto err_disable; diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index cff773f15b7e2e6bbabe904c8370206e4a1714b9..89bc931de8dfd437c556f581f5b29316e6ec0362 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -38,6 +38,17 @@ config VIRTIO_PCI_LEGACY If unsure, say Y. +config VIRTIO_PMEM + tristate "Support for virtio pmem driver" + depends on VIRTIO + depends on LIBNVDIMM + help + This driver provides access to virtio-pmem devices, storage devices + that are mapped into the physical address space - similar to NVDIMMs + - with a virtio-based flushing interface. + + If unsure, say Y. + config VIRTIO_BALLOON tristate "Virtio balloon driver" depends on VIRTIO diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index f55328a31629801cf437a1d6154a4c3f72bbed3d..fa15a683ae2d4d299eea9f1ea6f2d8981d314b6b 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -563,6 +563,7 @@ config MAX63XX_WATCHDOG config MAX77620_WATCHDOG tristate "Maxim Max77620 Watchdog Timer" depends on MFD_MAX77620 || COMPILE_TEST + select WATCHDOG_CORE help This is the driver for the Max77620 watchdog timer. Say 'Y' here to enable the watchdog timer support for diff --git a/drivers/watchdog/rn5t618_wdt.c b/drivers/watchdog/rn5t618_wdt.c index e60f55702ab79d111078dae1b253799dfdc4684d..d2e79cf70e774c4676e258d1f95ed4041bfa16c9 100644 --- a/drivers/watchdog/rn5t618_wdt.c +++ b/drivers/watchdog/rn5t618_wdt.c @@ -193,6 +193,7 @@ static struct platform_driver rn5t618_wdt_driver = { module_platform_driver(rn5t618_wdt_driver); +MODULE_ALIAS("platform:rn5t618-wdt"); MODULE_AUTHOR("Beniamino Galvani "); MODULE_DESCRIPTION("RN5T618 watchdog driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c index b1357aa4bc552eb3a5989dab5eeacf9295d2a2d8..f192b6f42da9f7eb856c34f2baac0a6a7a4c4c45 100644 --- a/drivers/xen/cpu_hotplug.c +++ b/drivers/xen/cpu_hotplug.c @@ -54,7 +54,7 @@ static int vcpu_online(unsigned int cpu) } static void vcpu_hotplug(unsigned int cpu) { - if (!cpu_possible(cpu)) + if (cpu >= nr_cpu_ids || !cpu_possible(cpu)) return; switch (vcpu_online(cpu)) { diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c index abd6dbc29ac28ae049475124df0b89515226a99c..58be15c27b6d6d340c065d43daf7fcd98c0ee293 100644 --- a/drivers/xen/pvcalls-back.c +++ b/drivers/xen/pvcalls-back.c @@ -792,7 +792,7 @@ static int pvcalls_back_poll(struct xenbus_device *dev, mappass->reqcopy = *req; icsk = inet_csk(mappass->sock->sk); queue = &icsk->icsk_accept_queue; - data = queue->rskq_accept_head != NULL; + data = READ_ONCE(queue->rskq_accept_head) != NULL; if (data) { mappass->reqcopy.cmd = 0; ret = 0; diff --git a/firmware/Makefile b/firmware/Makefile index 168094a3fae7ebb109c1ead9fe3b8c3e38201444..30e6b738839e3d95ede7f0c69d5906777f8cd41d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -19,7 +19,7 @@ quiet_cmd_fwbin = MK_FW $@ PROGBITS=$(if $(CONFIG_ARM),%,@)progbits; \ echo "/* Generated by firmware/Makefile */" > $@;\ echo " .section .rodata" >>$@;\ - echo " .p2align $${ASM_ALIGN}" >>$@;\ + echo " .p2align 4" >>$@;\ echo "_fw_$${FWSTR}_bin:" >>$@;\ echo " .incbin \"$(2)\"" >>$@;\ echo "_fw_end:" >>$@;\ diff --git a/fs/Kconfig b/fs/Kconfig index 3b381a0f6418034a43617b08b513b7b4b14173cc..7363d6b87d9b6e99f28902573b69b650be63ac56 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -106,6 +106,7 @@ source "fs/quota/Kconfig" source "fs/autofs4/Kconfig" source "fs/fuse/Kconfig" source "fs/overlayfs/Kconfig" +source "fs/incfs/Kconfig" menu "Caches" diff --git a/fs/Makefile b/fs/Makefile index 3204be31dad1627720119943995a16c7ec02b00e..580e49be1219c260f7a6104a3e67f19bd0f2dbaf 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -111,6 +111,7 @@ obj-$(CONFIG_ADFS_FS) += adfs/ obj-$(CONFIG_FUSE_FS) += fuse/ obj-$(CONFIG_OVERLAY_FS) += overlayfs/ obj-$(CONFIG_ORANGEFS_FS) += orangefs/ +obj-$(CONFIG_INCREMENTAL_FS) += incfs/ obj-$(CONFIG_UDF_FS) += udf/ obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ obj-$(CONFIG_OMFS_FS) += omfs/ diff --git a/fs/affs/super.c b/fs/affs/super.c index 884bedab7266a528b60884c7ab3d91e9a703724d..789a1c7db5d8cf326635efb526c6699c03a78a8f 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -559,14 +559,9 @@ affs_remount(struct super_block *sb, int *flags, char *data) int root_block; unsigned long mount_flags; int res = 0; - char *new_opts; char volume[32]; char *prefix = NULL; - new_opts = kstrdup(data, GFP_KERNEL); - if (data && !new_opts) - return -ENOMEM; - pr_debug("%s(flags=0x%x,opts=\"%s\")\n", __func__, *flags, data); sync_filesystem(sb); @@ -577,7 +572,6 @@ affs_remount(struct super_block *sb, int *flags, char *data) &blocksize, &prefix, volume, &mount_flags)) { kfree(prefix); - kfree(new_opts); return -EINVAL; } diff --git a/fs/afs/super.c b/fs/afs/super.c index 689173c0a682fd2861a6836bc097e49e15696abc..f8529ddbd587f8c330b42b83af14bff83f159469 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -359,6 +359,7 @@ static int afs_fill_super(struct super_block *sb, /* fill in the superblock */ sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; + sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_magic = AFS_FS_MAGIC; sb->s_op = &afs_super_ops; sb->s_xattr = afs_xattr_handlers; diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c index 2830e4f48d85445b18f0cd6a39c3a22a35daac79..7c6b62a94e7e7e5986ef925bde8674fe15ace1e2 100644 --- a/fs/afs/xattr.c +++ b/fs/afs/xattr.c @@ -50,7 +50,7 @@ static int afs_xattr_get_cell(const struct xattr_handler *handler, return namelen; if (namelen > size) return -ERANGE; - memcpy(buffer, cell->name, size); + memcpy(buffer, cell->name, namelen); return namelen; } @@ -104,7 +104,7 @@ static int afs_xattr_get_volume(const struct xattr_handler *handler, return namelen; if (namelen > size) return -ERANGE; - memcpy(buffer, volname, size); + memcpy(buffer, volname, namelen); return namelen; } diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index bf654d48eb469bb9b55a429f43dc29e3293ec8f0..c68ce3412dc1152e6da4d5000c715f4d813d10e1 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1882,7 +1882,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, bool sync = (file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host); ssize_t err; loff_t pos; - size_t count = iov_iter_count(from); + size_t count; loff_t oldsize; int clean_page = 0; @@ -1890,9 +1890,10 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, (iocb->ki_flags & IOCB_NOWAIT)) return -EOPNOTSUPP; - if (!inode_trylock(inode)) { - if (iocb->ki_flags & IOCB_NOWAIT) + if (iocb->ki_flags & IOCB_NOWAIT) { + if (!inode_trylock(inode)) return -EAGAIN; + } else { inode_lock(inode); } @@ -1903,6 +1904,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, } pos = iocb->ki_pos; + count = iov_iter_count(from); if (iocb->ki_flags & IOCB_NOWAIT) { /* * We will allocate space in case nodatacow is not set, diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index d02019747d001d7b118d54b19d6cc89b5d68e9ab..2ae32451fb5b020034cc5cf47699a2004ccb5679 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -26,6 +26,19 @@ #include "inode-map.h" #include "transaction.h" +static void fail_caching_thread(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + + btrfs_warn(fs_info, "failed to start inode caching task"); + btrfs_clear_pending_and_info(fs_info, INODE_MAP_CACHE, + "disabling inode map caching"); + spin_lock(&root->ino_cache_lock); + root->ino_cache_state = BTRFS_CACHE_ERROR; + spin_unlock(&root->ino_cache_lock); + wake_up(&root->ino_cache_wait); +} + static int caching_kthread(void *data) { struct btrfs_root *root = data; @@ -42,8 +55,10 @@ static int caching_kthread(void *data) return 0; path = btrfs_alloc_path(); - if (!path) + if (!path) { + fail_caching_thread(root); return -ENOMEM; + } /* Since the commit root is read-only, we can safely skip locking. */ path->skip_locking = 1; @@ -159,6 +174,7 @@ static void start_caching(struct btrfs_root *root) spin_lock(&root->ino_cache_lock); root->ino_cache_state = BTRFS_CACHE_FINISHED; spin_unlock(&root->ino_cache_lock); + wake_up(&root->ino_cache_wait); return; } @@ -177,11 +193,8 @@ static void start_caching(struct btrfs_root *root) tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu", root->root_key.objectid); - if (IS_ERR(tsk)) { - btrfs_warn(fs_info, "failed to start inode caching task"); - btrfs_clear_pending_and_info(fs_info, INODE_MAP_CACHE, - "disabling inode map caching"); - } + if (IS_ERR(tsk)) + fail_caching_thread(root); } int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid) @@ -199,11 +212,14 @@ int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid) wait_event(root->ino_cache_wait, root->ino_cache_state == BTRFS_CACHE_FINISHED || + root->ino_cache_state == BTRFS_CACHE_ERROR || root->free_ino_ctl->free_space > 0); if (root->ino_cache_state == BTRFS_CACHE_FINISHED && root->free_ino_ctl->free_space == 0) return -ENOSPC; + else if (root->ino_cache_state == BTRFS_CACHE_ERROR) + return btrfs_find_free_objectid(root, objectid); else goto again; } diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index cb6e8cb0de9433ad22f72ec1e035834b491747f3..39a00b57ff016c1e334808123b39c33c192e1757 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1928,8 +1928,12 @@ btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 nr_old_roots = 0; int ret = 0; + /* + * If quotas get disabled meanwhile, the resouces need to be freed and + * we can't just exit here. + */ if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) - return 0; + goto out_free; if (new_roots) { if (!maybe_fs_roots(new_roots)) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 204d585e012a85c2fc04677c935b4bd327cff03e..3ab79fa00dc7bc02bfd6df57ef5f36488a21a657 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2114,7 +2114,15 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) */ thresh = 4 * 1024 * 1024; - if (!mixed && total_free_meta - thresh < block_rsv->size) + /* + * We only want to claim there's no available space if we can no longer + * allocate chunks for our metadata profile and our global reserve will + * not fit in the free metadata space. If we aren't ->full then we + * still can allocate chunks and thus are fine using the currently + * calculated f_bavail. + */ + if (!mixed && block_rsv->space_info->full && + total_free_meta - thresh < block_rsv->size) buf->f_bavail = 0; buf->f_type = BTRFS_SUPER_MAGIC; diff --git a/fs/char_dev.c b/fs/char_dev.c index 20ce45c7c57c7d2ca6e6bcb2ba1c0a1806e3f728..715d76b0010806c452e53b01f267eeb7840e6c76 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -361,7 +361,7 @@ static struct kobject *cdev_get(struct cdev *p) if (owner && !try_module_get(owner)) return NULL; - kobj = kobject_get(&p->kobj); + kobj = kobject_get_unless_zero(&p->kobj); if (!kobj) module_put(owner); return kobj; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f523a9ca9574f17aa058b17232243ac10079cfe9..f0b1279a7de66716ecde8d3329784f5aba031127 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -921,6 +921,7 @@ cifs_demultiplex_thread(void *p) mempool_resize(cifs_req_poolp, length + cifs_min_rcv); set_freezable(); + allow_kernel_signal(SIGKILL); while (server->tcpStatus != CifsExiting) { if (try_to_freeze()) continue; @@ -2320,7 +2321,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) task = xchg(&server->tsk, NULL); if (task) - force_sig(SIGKILL, task); + send_sig(SIGKILL, task, 1); } static struct TCP_Server_Info * diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index 2c809233084bba34ecbac90a4392e5f53145fbe8..e270812927cfe6678d1c7e36422e1eeb5765063f 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -69,7 +69,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, goto out; - if (oparms->tcon->use_resilient) { + if (oparms->tcon->use_resilient) { nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */ nr_ioctl_req.Reserved = 0; rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid, diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 0e1c36c92f609224565eb4e4a690a22314125727..4eb0a9e7194b1ce8bc237a57ca702614023ed4c4 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -575,6 +575,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) { /* ops set to 3.0 by default for default so update */ ses->server->ops = &smb21_operations; + ses->server->vals = &smb21_values; } } else if (le16_to_cpu(rsp->DialectRevision) != ses->server->vals->protocol_id) { diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index aee586d32b0236663c23e0e9745968087eaa6173..b0033880d8c96a20e8a578b51f61fd8c6c280e6e 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -26,7 +26,7 @@ #include #include "fscrypt_private.h" -static void __fscrypt_decrypt_bio(struct bio *bio, bool done) +void fscrypt_decrypt_bio(struct bio *bio) { struct bio_vec *bv; int i; @@ -40,38 +40,11 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) bv->bv_len, bv->bv_offset); if (ret) SetPageError(page); - else if (done) - SetPageUptodate(page); } - if (done) - unlock_page(page); } } - -void fscrypt_decrypt_bio(struct bio *bio) -{ - __fscrypt_decrypt_bio(bio, false); -} EXPORT_SYMBOL(fscrypt_decrypt_bio); -static void completion_pages(struct work_struct *work) -{ - struct fscrypt_ctx *ctx = container_of(work, struct fscrypt_ctx, work); - struct bio *bio = ctx->bio; - - __fscrypt_decrypt_bio(bio, true); - fscrypt_release_ctx(ctx); - bio_put(bio); -} - -void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, struct bio *bio) -{ - INIT_WORK(&ctx->work, completion_pages); - ctx->bio = bio; - fscrypt_enqueue_decrypt_work(&ctx->work); -} -EXPORT_SYMBOL(fscrypt_enqueue_decrypt_bio); - int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, sector_t pblk, unsigned int len) { diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 35efeae24efc488c4ab6f07829fdb4436c9a47b1..6e6f39ea18a7987c2919a0f9b10972bcd91140b2 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -26,29 +26,20 @@ #include #include #include -#include #include #include "fscrypt_private.h" static unsigned int num_prealloc_crypto_pages = 32; -static unsigned int num_prealloc_crypto_ctxs = 128; module_param(num_prealloc_crypto_pages, uint, 0444); MODULE_PARM_DESC(num_prealloc_crypto_pages, "Number of crypto pages to preallocate"); -module_param(num_prealloc_crypto_ctxs, uint, 0444); -MODULE_PARM_DESC(num_prealloc_crypto_ctxs, - "Number of crypto contexts to preallocate"); static mempool_t *fscrypt_bounce_page_pool = NULL; -static LIST_HEAD(fscrypt_free_ctxs); -static DEFINE_SPINLOCK(fscrypt_ctx_lock); - static struct workqueue_struct *fscrypt_read_workqueue; static DEFINE_MUTEX(fscrypt_init_mutex); -static struct kmem_cache *fscrypt_ctx_cachep; struct kmem_cache *fscrypt_info_cachep; void fscrypt_enqueue_decrypt_work(struct work_struct *work) @@ -57,62 +48,6 @@ void fscrypt_enqueue_decrypt_work(struct work_struct *work) } EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work); -/** - * fscrypt_release_ctx() - Release a decryption context - * @ctx: The decryption context to release. - * - * If the decryption context was allocated from the pre-allocated pool, return - * it to that pool. Else, free it. - */ -void fscrypt_release_ctx(struct fscrypt_ctx *ctx) -{ - unsigned long flags; - - if (ctx->flags & FS_CTX_REQUIRES_FREE_ENCRYPT_FL) { - kmem_cache_free(fscrypt_ctx_cachep, ctx); - } else { - spin_lock_irqsave(&fscrypt_ctx_lock, flags); - list_add(&ctx->free_list, &fscrypt_free_ctxs); - spin_unlock_irqrestore(&fscrypt_ctx_lock, flags); - } -} -EXPORT_SYMBOL(fscrypt_release_ctx); - -/** - * fscrypt_get_ctx() - Get a decryption context - * @gfp_flags: The gfp flag for memory allocation - * - * Allocate and initialize a decryption context. - * - * Return: A new decryption context on success; an ERR_PTR() otherwise. - */ -struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags) -{ - struct fscrypt_ctx *ctx; - unsigned long flags; - - /* - * First try getting a ctx from the free list so that we don't have to - * call into the slab allocator. - */ - spin_lock_irqsave(&fscrypt_ctx_lock, flags); - ctx = list_first_entry_or_null(&fscrypt_free_ctxs, - struct fscrypt_ctx, free_list); - if (ctx) - list_del(&ctx->free_list); - spin_unlock_irqrestore(&fscrypt_ctx_lock, flags); - if (!ctx) { - ctx = kmem_cache_zalloc(fscrypt_ctx_cachep, gfp_flags); - if (!ctx) - return ERR_PTR(-ENOMEM); - ctx->flags |= FS_CTX_REQUIRES_FREE_ENCRYPT_FL; - } else { - ctx->flags &= ~FS_CTX_REQUIRES_FREE_ENCRYPT_FL; - } - return ctx; -} -EXPORT_SYMBOL(fscrypt_get_ctx); - struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags) { return mempool_alloc(fscrypt_bounce_page_pool, gfp_flags); @@ -137,14 +72,17 @@ EXPORT_SYMBOL(fscrypt_free_bounce_page); void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, const struct fscrypt_info *ci) { + u8 flags = fscrypt_policy_flags(&ci->ci_policy); + memset(iv, 0, ci->ci_mode->ivsize); - iv->lblk_num = cpu_to_le64(lblk_num); - if (fscrypt_is_direct_key_policy(&ci->ci_policy)) + if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { + WARN_ON_ONCE((u32)lblk_num != lblk_num); + lblk_num |= (u64)ci->ci_inode->i_ino << 32; + } else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE); - - if (ci->ci_essiv_tfm != NULL) - crypto_cipher_encrypt_one(ci->ci_essiv_tfm, iv->raw, iv->raw); + } + iv->lblk_num = cpu_to_le64(lblk_num); } /* Encrypt or decrypt a single filesystem block of file contents */ @@ -395,17 +333,6 @@ const struct dentry_operations fscrypt_d_ops = { .d_revalidate = fscrypt_d_revalidate, }; -static void fscrypt_destroy(void) -{ - struct fscrypt_ctx *pos, *n; - - list_for_each_entry_safe(pos, n, &fscrypt_free_ctxs, free_list) - kmem_cache_free(fscrypt_ctx_cachep, pos); - INIT_LIST_HEAD(&fscrypt_free_ctxs); - mempool_destroy(fscrypt_bounce_page_pool); - fscrypt_bounce_page_pool = NULL; -} - /** * fscrypt_initialize() - allocate major buffers for fs encryption. * @cop_flags: fscrypt operations flags @@ -413,11 +340,11 @@ static void fscrypt_destroy(void) * We only call this when we start accessing encrypted files, since it * results in memory getting allocated that wouldn't otherwise be used. * - * Return: Zero on success, non-zero otherwise. + * Return: 0 on success; -errno on failure */ int fscrypt_initialize(unsigned int cop_flags) { - int i, res = -ENOMEM; + int err = 0; /* No need to allocate a bounce page pool if this FS won't use it. */ if (cop_flags & FS_CFLG_OWN_PAGES) @@ -425,29 +352,18 @@ int fscrypt_initialize(unsigned int cop_flags) mutex_lock(&fscrypt_init_mutex); if (fscrypt_bounce_page_pool) - goto already_initialized; - - for (i = 0; i < num_prealloc_crypto_ctxs; i++) { - struct fscrypt_ctx *ctx; - - ctx = kmem_cache_zalloc(fscrypt_ctx_cachep, GFP_NOFS); - if (!ctx) - goto fail; - list_add(&ctx->free_list, &fscrypt_free_ctxs); - } + goto out_unlock; + err = -ENOMEM; fscrypt_bounce_page_pool = mempool_create_page_pool(num_prealloc_crypto_pages, 0); if (!fscrypt_bounce_page_pool) - goto fail; + goto out_unlock; -already_initialized: - mutex_unlock(&fscrypt_init_mutex); - return 0; -fail: - fscrypt_destroy(); + err = 0; +out_unlock: mutex_unlock(&fscrypt_init_mutex); - return res; + return err; } void fscrypt_msg(const struct inode *inode, const char *level, @@ -493,13 +409,9 @@ static int __init fscrypt_init(void) if (!fscrypt_read_workqueue) goto fail; - fscrypt_ctx_cachep = KMEM_CACHE(fscrypt_ctx, SLAB_RECLAIM_ACCOUNT); - if (!fscrypt_ctx_cachep) - goto fail_free_queue; - fscrypt_info_cachep = KMEM_CACHE(fscrypt_info, SLAB_RECLAIM_ACCOUNT); if (!fscrypt_info_cachep) - goto fail_free_ctx; + goto fail_free_queue; err = fscrypt_init_keyring(); if (err) @@ -509,8 +421,6 @@ static int __init fscrypt_init(void) fail_free_info: kmem_cache_destroy(fscrypt_info_cachep); -fail_free_ctx: - kmem_cache_destroy(fscrypt_ctx_cachep); fail_free_queue: destroy_workqueue(fscrypt_read_workqueue); fail: diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index b7ee440492fdec0829474f79ef18aea2cdd2f517..d6134d07ccdb47793357e77b11f7319f917d3d5a 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -164,11 +164,8 @@ struct fscrypt_info { /* The actual crypto transform used for encryption and decryption */ struct crypto_skcipher *ci_ctfm; - /* - * Cipher for ESSIV IV generation. Only set for CBC contents - * encryption, otherwise is NULL. - */ - struct crypto_cipher *ci_essiv_tfm; + /* True if the key should be freed when this fscrypt_info is freed */ + bool ci_owns_key; /* * Encryption mode used for this inode. It corresponds to either the @@ -211,8 +208,6 @@ typedef enum { FS_ENCRYPT, } fscrypt_direction_t; -#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 - static inline bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode) { @@ -295,7 +290,8 @@ extern int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key, */ #define HKDF_CONTEXT_KEY_IDENTIFIER 1 #define HKDF_CONTEXT_PER_FILE_KEY 2 -#define HKDF_CONTEXT_PER_MODE_KEY 3 +#define HKDF_CONTEXT_DIRECT_KEY 3 +#define HKDF_CONTEXT_IV_INO_LBLK_64_KEY 4 extern int fscrypt_hkdf_expand(struct fscrypt_hkdf *hkdf, u8 context, const u8 *info, unsigned int infolen, @@ -392,8 +388,14 @@ struct fscrypt_master_key { struct list_head mk_decrypted_inodes; spinlock_t mk_decrypted_inodes_lock; - /* Per-mode tfms for DIRECT_KEY policies, allocated on-demand */ - struct crypto_skcipher *mk_mode_keys[__FSCRYPT_MODE_MAX + 1]; + /* Crypto API transforms for DIRECT_KEY policies, allocated on-demand */ + struct crypto_skcipher *mk_direct_tfms[__FSCRYPT_MODE_MAX + 1]; + + /* + * Crypto API transforms for filesystem-layer implementation of + * IV_INO_LBLK_64 policies, allocated on-demand. + */ + struct crypto_skcipher *mk_iv_ino_lblk_64_tfms[__FSCRYPT_MODE_MAX + 1]; } __randomize_layout; @@ -449,8 +451,7 @@ struct fscrypt_mode { const char *cipher_str; int keysize; int ivsize; - bool logged_impl_name; - bool needs_essiv; + int logged_impl_name; }; static inline bool diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index 80650fb76ff79dd8a58cb7faac557bc9583cac68..687f7659076176a5938b1304dfd6cca02e3437e3 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -43,8 +43,10 @@ static void free_master_key(struct fscrypt_master_key *mk) wipe_master_key_secret(&mk->mk_secret); - for (i = 0; i < ARRAY_SIZE(mk->mk_mode_keys); i++) - crypto_free_skcipher(mk->mk_mode_keys[i]); + for (i = 0; i <= __FSCRYPT_MODE_MAX; i++) { + crypto_free_skcipher(mk->mk_direct_tfms[i]); + crypto_free_skcipher(mk->mk_iv_ino_lblk_64_tfms[i]); + } key_put(mk->mk_users); kzfree(mk); diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 9e1a7715064a7b4e472d51eec01b4b0855cf997c..16413b728b2be8b4c2add99e186635f227e8fefa 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -8,16 +8,12 @@ * Heavily modified since then. */ -#include -#include #include #include #include "fscrypt_private.h" #include "fscrypt_ice.h" -static struct crypto_shash *essiv_hash_tfm; - static struct fscrypt_mode available_modes[] = { [FSCRYPT_MODE_AES_256_XTS] = { .friendly_name = "AES-256-XTS", @@ -32,11 +28,10 @@ static struct fscrypt_mode available_modes[] = { .ivsize = 16, }, [FSCRYPT_MODE_AES_128_CBC] = { - .friendly_name = "AES-128-CBC", - .cipher_str = "cbc(aes)", + .friendly_name = "AES-128-CBC-ESSIV", + .cipher_str = "essiv(cbc(aes),sha256)", .keysize = 16, .ivsize = 16, - .needs_essiv = true, }, [FSCRYPT_MODE_AES_128_CTS] = { .friendly_name = "AES-128-CTS-CBC", @@ -98,15 +93,13 @@ struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode, mode->cipher_str, PTR_ERR(tfm)); return tfm; } - if (unlikely(!mode->logged_impl_name)) { + if (!xchg(&mode->logged_impl_name, 1)) { /* * fscrypt performance can vary greatly depending on which * crypto algorithm implementation is used. Help people debug * performance problems by logging the ->cra_driver_name the - * first time a mode is used. Note that multiple threads can - * race here, but it doesn't really matter. + * first time a mode is used. */ - mode->logged_impl_name = true; pr_info("fscrypt: %s using implementation \"%s\"\n", mode->friendly_name, crypto_skcipher_alg(tfm)->base.cra_driver_name); @@ -123,132 +116,64 @@ struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode, return ERR_PTR(err); } -static int derive_essiv_salt(const u8 *key, int keysize, u8 *salt) -{ - struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm); - - /* init hash transform on demand */ - if (unlikely(!tfm)) { - struct crypto_shash *prev_tfm; - - tfm = crypto_alloc_shash("sha256", 0, 0); - if (IS_ERR(tfm)) { - if (PTR_ERR(tfm) == -ENOENT) { - fscrypt_warn(NULL, - "Missing crypto API support for SHA-256"); - return -ENOPKG; - } - fscrypt_err(NULL, - "Error allocating SHA-256 transform: %ld", - PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm); - if (prev_tfm) { - crypto_free_shash(tfm); - tfm = prev_tfm; - } - } - - { - SHASH_DESC_ON_STACK(desc, tfm); - desc->tfm = tfm; - desc->flags = 0; - - return crypto_shash_digest(desc, key, keysize, salt); - } -} - -static int init_essiv_generator(struct fscrypt_info *ci, const u8 *raw_key, - int keysize) -{ - int err; - struct crypto_cipher *essiv_tfm; - u8 salt[SHA256_DIGEST_SIZE]; - - if (WARN_ON(ci->ci_mode->ivsize != AES_BLOCK_SIZE)) - return -EINVAL; - - essiv_tfm = crypto_alloc_cipher("aes", 0, 0); - if (IS_ERR(essiv_tfm)) - return PTR_ERR(essiv_tfm); - - ci->ci_essiv_tfm = essiv_tfm; - - err = derive_essiv_salt(raw_key, keysize, salt); - if (err) - goto out; - - /* - * Using SHA256 to derive the salt/key will result in AES-256 being - * used for IV generation. File contents encryption will still use the - * configured keysize (AES-128) nevertheless. - */ - err = crypto_cipher_setkey(essiv_tfm, salt, sizeof(salt)); - if (err) - goto out; - -out: - memzero_explicit(salt, sizeof(salt)); - return err; -} - -/* Given the per-file key, set up the file's crypto transform object(s) */ +/* Given the per-file key, set up the file's crypto transform object */ int fscrypt_set_derived_key(struct fscrypt_info *ci, const u8 *derived_key) { - struct fscrypt_mode *mode = ci->ci_mode; - struct crypto_skcipher *ctfm; - int err; - - ctfm = fscrypt_allocate_skcipher(mode, derived_key, ci->ci_inode); - if (IS_ERR(ctfm)) - return PTR_ERR(ctfm); + struct crypto_skcipher *tfm; - ci->ci_ctfm = ctfm; + tfm = fscrypt_allocate_skcipher(ci->ci_mode, derived_key, ci->ci_inode); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); - if (mode->needs_essiv) { - err = init_essiv_generator(ci, derived_key, mode->keysize); - if (err) { - fscrypt_warn(ci->ci_inode, - "Error initializing ESSIV generator: %d", - err); - return err; - } - } + ci->ci_ctfm = tfm; + ci->ci_owns_key = true; return 0; } static int setup_per_mode_key(struct fscrypt_info *ci, - struct fscrypt_master_key *mk) + struct fscrypt_master_key *mk, + struct crypto_skcipher **tfms, + u8 hkdf_context, bool include_fs_uuid) { + const struct inode *inode = ci->ci_inode; + const struct super_block *sb = inode->i_sb; struct fscrypt_mode *mode = ci->ci_mode; u8 mode_num = mode - available_modes; struct crypto_skcipher *tfm, *prev_tfm; u8 mode_key[FSCRYPT_MAX_KEY_SIZE]; + u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)]; + unsigned int hkdf_infolen = 0; int err; - if (WARN_ON(mode_num >= ARRAY_SIZE(mk->mk_mode_keys))) + if (WARN_ON(mode_num > __FSCRYPT_MODE_MAX)) return -EINVAL; /* pairs with cmpxchg() below */ - tfm = READ_ONCE(mk->mk_mode_keys[mode_num]); + tfm = READ_ONCE(tfms[mode_num]); if (likely(tfm != NULL)) goto done; BUILD_BUG_ON(sizeof(mode_num) != 1); + BUILD_BUG_ON(sizeof(sb->s_uuid) != 16); + BUILD_BUG_ON(sizeof(hkdf_info) != 17); + hkdf_info[hkdf_infolen++] = mode_num; + if (include_fs_uuid) { + memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid, + sizeof(sb->s_uuid)); + hkdf_infolen += sizeof(sb->s_uuid); + } err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, - HKDF_CONTEXT_PER_MODE_KEY, - &mode_num, sizeof(mode_num), + hkdf_context, hkdf_info, hkdf_infolen, mode_key, mode->keysize); if (err) return err; - tfm = fscrypt_allocate_skcipher(mode, mode_key, ci->ci_inode); + tfm = fscrypt_allocate_skcipher(mode, mode_key, inode); memzero_explicit(mode_key, mode->keysize); if (IS_ERR(tfm)) return PTR_ERR(tfm); /* pairs with READ_ONCE() above */ - prev_tfm = cmpxchg(&mk->mk_mode_keys[mode_num], NULL, tfm); + prev_tfm = cmpxchg(&tfms[mode_num], NULL, tfm); if (prev_tfm != NULL) { crypto_free_skcipher(tfm); tfm = prev_tfm; @@ -279,7 +204,19 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, ci->ci_mode->friendly_name); return -EINVAL; } - return setup_per_mode_key(ci, mk); + return setup_per_mode_key(ci, mk, mk->mk_direct_tfms, + HKDF_CONTEXT_DIRECT_KEY, false); + } else if (ci->ci_policy.v2.flags & + FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { + /* + * IV_INO_LBLK_64: encryption keys are derived from (master_key, + * mode_num, filesystem_uuid), and inode number is included in + * the IVs. This format is optimized for use with inline + * encryption hardware compliant with the UFS or eMMC standards. + */ + return setup_per_mode_key(ci, mk, mk->mk_iv_ino_lblk_64_tfms, + HKDF_CONTEXT_IV_INO_LBLK_64_KEY, + true); } err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, @@ -401,13 +338,10 @@ static void put_crypt_info(struct fscrypt_info *ci) if (!ci) return; - if (ci->ci_direct_key) { + if (ci->ci_direct_key) fscrypt_put_direct_key(ci->ci_direct_key); - } else if ((ci->ci_ctfm != NULL || ci->ci_essiv_tfm != NULL) && - !fscrypt_is_direct_key_policy(&ci->ci_policy)) { + else if (ci->ci_owns_key) crypto_free_skcipher(ci->ci_ctfm); - crypto_free_cipher(ci->ci_essiv_tfm); - } key = ci->ci_master_key; if (key) { @@ -428,6 +362,7 @@ static void put_crypt_info(struct fscrypt_info *ci) key_invalidate(key); key_put(key); } + memzero_explicit(ci, sizeof(*ci)); kmem_cache_free(fscrypt_info_cachep, ci); } diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index 21d15d7ead4a191b48823d6265d9a78436cf99f1..b217970ef3928312c15037163fa621f0be0ce117 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -270,10 +270,6 @@ static int setup_v1_file_key_direct(struct fscrypt_info *ci, return -EINVAL; } - /* ESSIV implies 16-byte IVs which implies !DIRECT_KEY */ - if (WARN_ON(mode->needs_essiv)) - return -EINVAL; - dk = fscrypt_get_direct_key(ci, raw_master_key); if (IS_ERR(dk)) return PTR_ERR(dk); diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 4072ba644595b917ccd128a8ffc5b145513582a0..96f528071bed3f8ea401e38b90ae622d7a261745 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -29,6 +29,40 @@ bool fscrypt_policies_equal(const union fscrypt_policy *policy1, return !memcmp(policy1, policy2, fscrypt_policy_size(policy1)); } +static bool supported_iv_ino_lblk_64_policy( + const struct fscrypt_policy_v2 *policy, + const struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + int ino_bits = 64, lblk_bits = 64; + + if (policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { + fscrypt_warn(inode, + "The DIRECT_KEY and IV_INO_LBLK_64 flags are mutually exclusive"); + return false; + } + /* + * It's unsafe to include inode numbers in the IVs if the filesystem can + * potentially renumber inodes, e.g. via filesystem shrinking. + */ + if (!sb->s_cop->has_stable_inodes || + !sb->s_cop->has_stable_inodes(sb)) { + fscrypt_warn(inode, + "Can't use IV_INO_LBLK_64 policy on filesystem '%s' because it doesn't have stable inode numbers", + sb->s_id); + return false; + } + if (sb->s_cop->get_ino_and_lblk_bits) + sb->s_cop->get_ino_and_lblk_bits(sb, &ino_bits, &lblk_bits); + if (ino_bits > 32 || lblk_bits > 32) { + fscrypt_warn(inode, + "Can't use IV_INO_LBLK_64 policy on filesystem '%s' because it doesn't use 32-bit inode and block numbers", + sb->s_id); + return false; + } + return true; +} + /** * fscrypt_supported_policy - check whether an encryption policy is supported * @@ -55,7 +89,8 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u, return false; } - if (policy->flags & ~FSCRYPT_POLICY_FLAGS_VALID) { + if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK | + FSCRYPT_POLICY_FLAG_DIRECT_KEY)) { fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)", policy->flags); @@ -83,6 +118,10 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u, return false; } + if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) && + !supported_iv_ino_lblk_64_policy(policy, inode)) + return false; + if (memchr_inv(policy->__reserved, 0, sizeof(policy->__reserved))) { fscrypt_warn(inode, diff --git a/fs/drop_caches.c b/fs/drop_caches.c index d31b6c72b47646fd8ae2ebd3746de307f8017fa0..dc1a1d5d825b48de17f3192f8d0c50829dd07885 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c @@ -35,11 +35,11 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) spin_unlock(&inode->i_lock); spin_unlock(&sb->s_inode_list_lock); - cond_resched(); invalidate_mapping_pages(inode->i_mapping, 0, -1); iput(toput_inode); toput_inode = inode; + cond_resched(); spin_lock(&sb->s_inode_list_lock); } spin_unlock(&sb->s_inode_list_lock); diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index a561ae17cf4356d7c2596bec97c3fff7a06cc2f4..c08960040dd0501841301e8eaec4ed05623ea3da 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -147,6 +147,7 @@ static struct dentry *reconnect_one(struct vfsmount *mnt, tmp = lookup_one_len_unlocked(nbuf, parent, strlen(nbuf)); if (IS_ERR(tmp)) { dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp)); + err = PTR_ERR(tmp); goto out_err; } if (tmp != dentry) { diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 523e6d7f1bb7ebe71b77f48cf5c5327f069bd326..3bab4b55fa3ccc3a5a35bd0141b4f27dc99326da 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1688,6 +1688,7 @@ static inline bool ext4_verity_in_progress(struct inode *inode) #define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010 #define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020 #define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200 +#define EXT4_FEATURE_COMPAT_STABLE_INODES 0x0800 #define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 @@ -1784,6 +1785,7 @@ EXT4_FEATURE_COMPAT_FUNCS(xattr, EXT_ATTR) EXT4_FEATURE_COMPAT_FUNCS(resize_inode, RESIZE_INODE) EXT4_FEATURE_COMPAT_FUNCS(dir_index, DIR_INDEX) EXT4_FEATURE_COMPAT_FUNCS(sparse_super2, SPARSE_SUPER2) +EXT4_FEATURE_COMPAT_FUNCS(stable_inodes, STABLE_INODES) EXT4_FEATURE_RO_COMPAT_FUNCS(sparse_super, SPARSE_SUPER) EXT4_FEATURE_RO_COMPAT_FUNCS(large_file, LARGE_FILE) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index b3248f444f482cd0e616eef3ad0314f4657ceca2..f737d5b1ca3b4e691442f614c92df61dbb572cba 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -1439,7 +1439,7 @@ int htree_inlinedir_to_tree(struct file *dir_file, err = ext4_htree_store_dirent(dir_file, hinfo->hash, hinfo->minor_hash, de, &tmp_str); if (err) { - count = err; + ret = err; goto out; } count++; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 15533ab9786cb2be8f14512720d298a40871d79d..48660fbb21a9a6dd14685de67f04efa6eca25582 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -5664,12 +5664,15 @@ int ext4_getattr(const struct path *path, struct kstat *stat, stat->attributes |= STATX_ATTR_IMMUTABLE; if (flags & EXT4_NODUMP_FL) stat->attributes |= STATX_ATTR_NODUMP; + if (flags & EXT4_VERITY_FL) + stat->attributes |= STATX_ATTR_VERITY; stat->attributes_mask |= (STATX_ATTR_APPEND | STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED | STATX_ATTR_IMMUTABLE | - STATX_ATTR_NODUMP); + STATX_ATTR_NODUMP | + STATX_ATTR_VERITY); generic_fillattr(inode, stat); return 0; diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 3ba07ccb24d27e304f0beb647b9e87e044ba7c2e..f852d90a15629b2dfe061c7ff3978cd667481596 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -1247,6 +1247,8 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case FS_IOC_GETFSMAP: case FS_IOC_ENABLE_VERITY: case FS_IOC_MEASURE_VERITY: + case EXT4_IOC_FSGETXATTR: + case EXT4_IOC_FSSETXATTR: break; default: return -ENOIOCTLCMD; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 028c381800094f5f85118728001f06dd49b22e07..e889ae6bd23953383291095856df347850103a32 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1286,6 +1286,18 @@ static bool ext4_dummy_context(struct inode *inode) return DUMMY_ENCRYPTION_ENABLED(EXT4_SB(inode->i_sb)); } +static bool ext4_has_stable_inodes(struct super_block *sb) +{ + return ext4_has_feature_stable_inodes(sb); +} + +static void ext4_get_ino_and_lblk_bits(struct super_block *sb, + int *ino_bits_ret, int *lblk_bits_ret) +{ + *ino_bits_ret = 8 * sizeof(EXT4_SB(sb)->s_es->s_inodes_count); + *lblk_bits_ret = 8 * sizeof(ext4_lblk_t); +} + static const struct fscrypt_operations ext4_cryptops = { .key_prefix = "ext4:", .get_context = ext4_get_context, @@ -1293,6 +1305,8 @@ static const struct fscrypt_operations ext4_cryptops = { .dummy_context = ext4_dummy_context, .empty_dir = ext4_empty_dir, .max_namelen = EXT4_NAME_LEN, + .has_stable_inodes = ext4_has_stable_inodes, + .get_ino_and_lblk_bits = ext4_get_ino_and_lblk_bits, }; #endif @@ -1816,6 +1830,13 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, arg = JBD2_DEFAULT_MAX_COMMIT_AGE; sbi->s_commit_interval = HZ * arg; } else if (token == Opt_debug_want_extra_isize) { + if ((arg & 1) || + (arg < 4) || + (arg > (sbi->s_inode_size - EXT4_GOOD_OLD_INODE_SIZE))) { + ext4_msg(sb, KERN_ERR, + "Invalid want_extra_isize %d", arg); + return -1; + } sbi->s_want_extra_isize = arg; } else if (token == Opt_max_batch_time) { sbi->s_max_batch_time = arg; @@ -3497,40 +3518,6 @@ int ext4_calculate_overhead(struct super_block *sb) return 0; } -static void ext4_clamp_want_extra_isize(struct super_block *sb) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - unsigned def_extra_isize = sizeof(struct ext4_inode) - - EXT4_GOOD_OLD_INODE_SIZE; - - if (sbi->s_inode_size == EXT4_GOOD_OLD_INODE_SIZE) { - sbi->s_want_extra_isize = 0; - return; - } - if (sbi->s_want_extra_isize < 4) { - sbi->s_want_extra_isize = def_extra_isize; - if (ext4_has_feature_extra_isize(sb)) { - if (sbi->s_want_extra_isize < - le16_to_cpu(es->s_want_extra_isize)) - sbi->s_want_extra_isize = - le16_to_cpu(es->s_want_extra_isize); - if (sbi->s_want_extra_isize < - le16_to_cpu(es->s_min_extra_isize)) - sbi->s_want_extra_isize = - le16_to_cpu(es->s_min_extra_isize); - } - } - /* Check if enough inode space is available */ - if ((sbi->s_want_extra_isize > sbi->s_inode_size) || - (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize > - sbi->s_inode_size)) { - sbi->s_want_extra_isize = def_extra_isize; - ext4_msg(sb, KERN_INFO, - "required extra inode space not available"); - } -} - static void ext4_set_resv_clusters(struct super_block *sb) { ext4_fsblk_t resv_clusters; @@ -3738,6 +3725,65 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) */ sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT; + if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { + sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; + sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO; + } else { + sbi->s_inode_size = le16_to_cpu(es->s_inode_size); + sbi->s_first_ino = le32_to_cpu(es->s_first_ino); + if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) { + ext4_msg(sb, KERN_ERR, "invalid first ino: %u", + sbi->s_first_ino); + goto failed_mount; + } + if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || + (!is_power_of_2(sbi->s_inode_size)) || + (sbi->s_inode_size > blocksize)) { + ext4_msg(sb, KERN_ERR, + "unsupported inode size: %d", + sbi->s_inode_size); + goto failed_mount; + } + /* + * i_atime_extra is the last extra field available for + * [acm]times in struct ext4_inode. Checking for that + * field should suffice to ensure we have extra space + * for all three. + */ + if (sbi->s_inode_size >= offsetof(struct ext4_inode, i_atime_extra) + + sizeof(((struct ext4_inode *)0)->i_atime_extra)) { + sb->s_time_gran = 1; + } else { + sb->s_time_gran = NSEC_PER_SEC; + } + } + if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { + sbi->s_want_extra_isize = sizeof(struct ext4_inode) - + EXT4_GOOD_OLD_INODE_SIZE; + if (ext4_has_feature_extra_isize(sb)) { + unsigned v, max = (sbi->s_inode_size - + EXT4_GOOD_OLD_INODE_SIZE); + + v = le16_to_cpu(es->s_want_extra_isize); + if (v > max) { + ext4_msg(sb, KERN_ERR, + "bad s_want_extra_isize: %d", v); + goto failed_mount; + } + if (sbi->s_want_extra_isize < v) + sbi->s_want_extra_isize = v; + + v = le16_to_cpu(es->s_min_extra_isize); + if (v > max) { + ext4_msg(sb, KERN_ERR, + "bad s_min_extra_isize: %d", v); + goto failed_mount; + } + if (sbi->s_want_extra_isize < v) + sbi->s_want_extra_isize = v; + } + } + if (sbi->s_es->s_mount_opts[0]) { char *s_mount_opts = kstrndup(sbi->s_es->s_mount_opts, sizeof(sbi->s_es->s_mount_opts), @@ -3973,29 +4019,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) has_huge_files); sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files); - if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { - sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; - sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO; - } else { - sbi->s_inode_size = le16_to_cpu(es->s_inode_size); - sbi->s_first_ino = le32_to_cpu(es->s_first_ino); - if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) { - ext4_msg(sb, KERN_ERR, "invalid first ino: %u", - sbi->s_first_ino); - goto failed_mount; - } - if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || - (!is_power_of_2(sbi->s_inode_size)) || - (sbi->s_inode_size > blocksize)) { - ext4_msg(sb, KERN_ERR, - "unsupported inode size: %d", - sbi->s_inode_size); - goto failed_mount; - } - if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) - sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2); - } - sbi->s_desc_size = le16_to_cpu(es->s_desc_size); if (ext4_has_feature_64bit(sb)) { if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT || @@ -4450,8 +4473,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) if (ext4_setup_super(sb, es, sb_rdonly(sb))) sb->s_flags |= MS_RDONLY; - ext4_clamp_want_extra_isize(sb); - ext4_set_resv_clusters(sb); err = ext4_setup_system_zone(sb); @@ -5259,8 +5280,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) goto restore_opts; } - ext4_clamp_want_extra_isize(sb); - if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^ test_opt(sb, JOURNAL_CHECKSUM)) { ext4_msg(sb, KERN_ERR, "changing journal_checksum " diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index f2e7337375e5452965298f950e788c20cdfd11fd..2b64e03d8865f6a242cd17d6eedf10ca9fe67da1 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -737,11 +737,14 @@ int f2fs_getattr(const struct path *path, struct kstat *stat, stat->attributes |= STATX_ATTR_IMMUTABLE; if (flags & F2FS_NODUMP_FL) stat->attributes |= STATX_ATTR_NODUMP; + if (IS_VERITY(inode)) + stat->attributes |= STATX_ATTR_VERITY; stat->attributes_mask |= (STATX_ATTR_APPEND | STATX_ATTR_ENCRYPTED | STATX_ATTR_IMMUTABLE | - STATX_ATTR_NODUMP); + STATX_ATTR_NODUMP | + STATX_ATTR_VERITY); generic_fillattr(inode, stat); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index bfd1adf539011c81ca3f23c49240f4b0495494a3..f06bac3a503e426e9190991fc6aa6f88b19ca88d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2346,13 +2346,27 @@ static bool f2fs_dummy_context(struct inode *inode) return DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(inode)); } +static bool f2fs_has_stable_inodes(struct super_block *sb) +{ + return true; +} + +static void f2fs_get_ino_and_lblk_bits(struct super_block *sb, + int *ino_bits_ret, int *lblk_bits_ret) +{ + *ino_bits_ret = 8 * sizeof(nid_t); + *lblk_bits_ret = 8 * sizeof(block_t); +} + static const struct fscrypt_operations f2fs_cryptops = { - .key_prefix = "f2fs:", - .get_context = f2fs_get_context, - .set_context = f2fs_set_context, - .dummy_context = f2fs_dummy_context, - .empty_dir = f2fs_empty_dir, - .max_namelen = F2FS_NAME_LEN, + .key_prefix = "f2fs:", + .get_context = f2fs_get_context, + .set_context = f2fs_set_context, + .dummy_context = f2fs_dummy_context, + .empty_dir = f2fs_empty_dir, + .max_namelen = F2FS_NAME_LEN, + .has_stable_inodes = f2fs_has_stable_inodes, + .get_ino_and_lblk_bits = f2fs_get_ino_and_lblk_bits, }; #endif diff --git a/fs/filesystems.c b/fs/filesystems.c index f2728a4a03a1dccd2fe67353ed9bceeccd5392cd..931925d6aeed39fd2666ddb2cbe364e53963caf4 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -221,6 +221,25 @@ int __init get_filesystem_list(char *buf) return len; } +#ifdef CONFIG_EARLY_SERVICES +int get_filesystem_list_runtime(char *buf) +{ + int len = 0; + struct file_system_type *tmp; + + read_lock(&file_systems_lock); + tmp = file_systems; + while (tmp && len < PAGE_SIZE - 80) { + len += scnprintf(buf+len, PAGE_SIZE, "%s\t%s\n", + (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", + tmp->name); + tmp = tmp->next; + } + read_unlock(&file_systems_lock); + return len; +} +#endif + #ifdef CONFIG_PROC_FS static int filesystems_proc_show(struct seq_file *m, void *v) { diff --git a/fs/incfs/Kconfig b/fs/incfs/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..a655d599ea46cd1b71f3398a41eaaacdc6fa9cb0 --- /dev/null +++ b/fs/incfs/Kconfig @@ -0,0 +1,19 @@ +config INCREMENTAL_FS + tristate "Incremental file system support" + depends on BLOCK + select DECOMPRESS_LZ4 + select CRC32 + select CRYPTO + select CRYPTO_RSA + select CRYPTO_SHA256 + select X509_CERTIFICATE_PARSER + select ASYMMETRIC_KEY_TYPE + select ASYMMETRIC_PUBLIC_KEY_SUBTYPE + select PKCS7_MESSAGE_PARSER + help + Incremental FS is a read-only virtual file system that facilitates execution + of programs while their binaries are still being lazily downloaded over the + network, USB or pigeon post. + + To compile this file system support as a module, choose M here: the + module will be called incrementalfs. diff --git a/fs/incfs/Makefile b/fs/incfs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8d734bf91ecdc67a726a288eca1dacf815790d67 --- /dev/null +++ b/fs/incfs/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_INCREMENTAL_FS) += incrementalfs.o + +incrementalfs-y := \ + data_mgmt.o \ + format.o \ + integrity.o \ + main.o \ + vfs.o diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c new file mode 100644 index 0000000000000000000000000000000000000000..109329e0a180ec5ec1966f25ac0e14c4cf1523e7 --- /dev/null +++ b/fs/incfs/data_mgmt.c @@ -0,0 +1,1136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "data_mgmt.h" +#include "format.h" +#include "integrity.h" + +struct mount_info *incfs_alloc_mount_info(struct super_block *sb, + struct mount_options *options, + struct path *backing_dir_path) +{ + struct mount_info *mi = NULL; + int error = 0; + + mi = kzalloc(sizeof(*mi), GFP_NOFS); + if (!mi) + return ERR_PTR(-ENOMEM); + + mi->mi_sb = sb; + mi->mi_options = *options; + mi->mi_backing_dir_path = *backing_dir_path; + mi->mi_owner = get_current_cred(); + path_get(&mi->mi_backing_dir_path); + mutex_init(&mi->mi_dir_struct_mutex); + mutex_init(&mi->mi_pending_reads_mutex); + init_waitqueue_head(&mi->mi_pending_reads_notif_wq); + INIT_LIST_HEAD(&mi->mi_reads_list_head); + + if (options->read_log_pages != 0) { + size_t buf_size = PAGE_SIZE * options->read_log_pages; + + spin_lock_init(&mi->mi_log.rl_writer_lock); + init_waitqueue_head(&mi->mi_log.ml_notif_wq); + + mi->mi_log.rl_size = buf_size / sizeof(*mi->mi_log.rl_ring_buf); + mi->mi_log.rl_ring_buf = kzalloc(buf_size, GFP_NOFS); + if (!mi->mi_log.rl_ring_buf) { + error = -ENOMEM; + goto err; + } + } + + return mi; + +err: + incfs_free_mount_info(mi); + return ERR_PTR(error); +} + +void incfs_free_mount_info(struct mount_info *mi) +{ + if (!mi) + return; + + dput(mi->mi_index_dir); + path_put(&mi->mi_backing_dir_path); + mutex_destroy(&mi->mi_dir_struct_mutex); + mutex_destroy(&mi->mi_pending_reads_mutex); + put_cred(mi->mi_owner); + kfree(mi->mi_log.rl_ring_buf); + kfree(mi); +} + +static void data_file_segment_init(struct data_file_segment *segment) +{ + init_waitqueue_head(&segment->new_data_arrival_wq); + mutex_init(&segment->blockmap_mutex); + INIT_LIST_HEAD(&segment->reads_list_head); +} + +static void data_file_segment_destroy(struct data_file_segment *segment) +{ + mutex_destroy(&segment->blockmap_mutex); +} + +struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf) +{ + struct data_file *df = NULL; + struct backing_file_context *bfc = NULL; + int md_records; + u64 size; + int error = 0; + int i; + + if (!bf || !mi) + return ERR_PTR(-EFAULT); + + if (!S_ISREG(bf->f_inode->i_mode)) + return ERR_PTR(-EBADF); + + bfc = incfs_alloc_bfc(bf); + if (IS_ERR(bfc)) + return ERR_CAST(bfc); + + df = kzalloc(sizeof(*df), GFP_NOFS); + if (!df) { + error = -ENOMEM; + goto out; + } + + df->df_backing_file_context = bfc; + df->df_mount_info = mi; + for (i = 0; i < ARRAY_SIZE(df->df_segments); i++) + data_file_segment_init(&df->df_segments[i]); + + error = mutex_lock_interruptible(&bfc->bc_mutex); + if (error) + goto out; + error = incfs_read_file_header(bfc, &df->df_metadata_off, + &df->df_id, &size); + mutex_unlock(&bfc->bc_mutex); + + if (error) + goto out; + + df->df_size = size; + if (size > 0) + df->df_block_count = get_blocks_count_for_size(size); + + md_records = incfs_scan_metadata_chain(df); + if (md_records < 0) + error = md_records; + +out: + if (error) { + incfs_free_bfc(bfc); + df->df_backing_file_context = NULL; + incfs_free_data_file(df); + return ERR_PTR(error); + } + return df; +} + +void incfs_free_data_file(struct data_file *df) +{ + int i; + + if (!df) + return; + + incfs_free_mtree(df->df_hash_tree); + for (i = 0; i < ARRAY_SIZE(df->df_segments); i++) + data_file_segment_destroy(&df->df_segments[i]); + incfs_free_bfc(df->df_backing_file_context); + kfree(df); +} + +int make_inode_ready_for_data_ops(struct mount_info *mi, + struct inode *inode, + struct file *backing_file) +{ + struct inode_info *node = get_incfs_node(inode); + struct data_file *df = NULL; + int err = 0; + + inode_lock(inode); + if (S_ISREG(inode->i_mode)) { + if (!node->n_file) { + df = incfs_open_data_file(mi, backing_file); + + if (IS_ERR(df)) + err = PTR_ERR(df); + else + node->n_file = df; + } + } else + err = -EBADF; + inode_unlock(inode); + return err; +} + +struct dir_file *incfs_open_dir_file(struct mount_info *mi, struct file *bf) +{ + struct dir_file *dir = NULL; + + if (!S_ISDIR(bf->f_inode->i_mode)) + return ERR_PTR(-EBADF); + + dir = kzalloc(sizeof(*dir), GFP_NOFS); + if (!dir) + return ERR_PTR(-ENOMEM); + + dir->backing_dir = get_file(bf); + dir->mount_info = mi; + return dir; +} + +void incfs_free_dir_file(struct dir_file *dir) +{ + if (!dir) + return; + if (dir->backing_dir) + fput(dir->backing_dir); + kfree(dir); +} + +static ssize_t decompress(struct mem_range src, struct mem_range dst) +{ + int result = LZ4_decompress_safe(src.data, dst.data, src.len, dst.len); + + if (result < 0) + return -EBADMSG; + + return result; +} + +static void log_block_read(struct mount_info *mi, incfs_uuid_t *id, + int block_index, bool timed_out) +{ + struct read_log *log = &mi->mi_log; + struct read_log_state state; + s64 now_us = ktime_to_us(ktime_get()); + struct read_log_record record = { + .file_id = *id, + .block_index = block_index, + .timed_out = timed_out, + .timestamp_us = now_us + }; + + if (log->rl_size == 0) + return; + + spin_lock(&log->rl_writer_lock); + state = READ_ONCE(log->rl_state); + log->rl_ring_buf[state.next_index] = record; + if (++state.next_index == log->rl_size) { + state.next_index = 0; + ++state.current_pass_no; + } + WRITE_ONCE(log->rl_state, state); + spin_unlock(&log->rl_writer_lock); + + wake_up_all(&log->ml_notif_wq); +} + +static int validate_hash_tree(struct file *bf, struct data_file *df, + int block_index, struct mem_range data, u8 *buf) +{ + u8 digest[INCFS_MAX_HASH_SIZE] = {}; + struct mtree *tree = NULL; + struct ondisk_signature *sig = NULL; + struct mem_range calc_digest_rng; + struct mem_range saved_digest_rng; + struct mem_range root_hash_rng; + int digest_size; + int hash_block_index = block_index; + int hash_per_block; + int lvl = 0; + int res; + + tree = df->df_hash_tree; + sig = df->df_signature; + if (!tree || !sig) + return 0; + + digest_size = tree->alg->digest_size; + hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size; + calc_digest_rng = range(digest, digest_size); + res = incfs_calc_digest(tree->alg, data, calc_digest_rng); + if (res) + return res; + + for (lvl = 0; lvl < tree->depth; lvl++) { + loff_t lvl_off = tree->hash_level_suboffset[lvl] + + sig->mtree_offset; + loff_t hash_block_off = lvl_off + + round_down(hash_block_index * digest_size, + INCFS_DATA_FILE_BLOCK_SIZE); + size_t hash_off_in_block = hash_block_index * digest_size + % INCFS_DATA_FILE_BLOCK_SIZE; + struct mem_range buf_range = range(buf, + INCFS_DATA_FILE_BLOCK_SIZE); + ssize_t read_res = incfs_kread(bf, buf, + INCFS_DATA_FILE_BLOCK_SIZE, hash_block_off); + + if (read_res < 0) + return read_res; + if (read_res != INCFS_DATA_FILE_BLOCK_SIZE) + return -EIO; + + saved_digest_rng = range(buf + hash_off_in_block, digest_size); + if (!incfs_equal_ranges(calc_digest_rng, saved_digest_rng)) { + int i; + bool zero = true; + + pr_debug("incfs: Hash mismatch lvl:%d blk:%d\n", + lvl, block_index); + for (i = 0; i < saved_digest_rng.len; ++i) + if (saved_digest_rng.data[i]) { + zero = false; + break; + } + + if (zero) + pr_debug("incfs: Note saved_digest all zero - did you forget to load the hashes?\n"); + return -EBADMSG; + } + + res = incfs_calc_digest(tree->alg, buf_range, calc_digest_rng); + if (res) + return res; + hash_block_index /= hash_per_block; + } + + root_hash_rng = range(tree->root_hash, digest_size); + if (!incfs_equal_ranges(calc_digest_rng, root_hash_rng)) { + pr_debug("incfs: Root hash mismatch blk:%d\n", block_index); + return -EBADMSG; + } + return 0; +} + +static int revalidate_signature(struct file *bf, struct data_file *df) +{ + struct ondisk_signature *sig = df->df_signature; + struct mem_range root_hash = {}; + int result = 0; + u8 *sig_buf = NULL; + u8 *add_data_buf = NULL; + ssize_t read_res; + + /* File has no signature. */ + if (!sig || !df->df_hash_tree || sig->sig_size == 0) + return 0; + + /* Signature has already been validated. */ + if (df->df_signature_validated) + return 0; + + add_data_buf = kzalloc(sig->add_data_size, GFP_NOFS); + if (!add_data_buf) { + result = -ENOMEM; + goto out; + } + + read_res = incfs_kread(bf, add_data_buf, sig->add_data_size, + sig->add_data_offset); + if (read_res < 0) { + result = read_res; + goto out; + } + if (read_res != sig->add_data_size) { + result = -EIO; + goto out; + } + + sig_buf = kzalloc(sig->sig_size, GFP_NOFS); + if (!sig_buf) { + result = -ENOMEM; + goto out; + } + + read_res = incfs_kread(bf, sig_buf, sig->sig_size, sig->sig_offset); + if (read_res < 0) { + result = read_res; + goto out; + } + if (read_res != sig->sig_size) { + result = -EIO; + goto out; + } + + root_hash = range(df->df_hash_tree->root_hash, + df->df_hash_tree->alg->digest_size); + + result = incfs_validate_pkcs7_signature( + range(sig_buf, sig->sig_size), + root_hash, + range(add_data_buf, sig->add_data_size)); + + if (result == 0) + df->df_signature_validated = true; +out: + kfree(sig_buf); + kfree(add_data_buf); + return result; +} + +static struct data_file_segment *get_file_segment(struct data_file *df, + int block_index) +{ + int seg_idx = block_index % ARRAY_SIZE(df->df_segments); + + return &df->df_segments[seg_idx]; +} + +static bool is_data_block_present(struct data_file_block *block) +{ + return (block->db_backing_file_data_offset != 0) && + (block->db_stored_size != 0); +} + +static int get_data_file_block(struct data_file *df, int index, + struct data_file_block *res_block) +{ + struct incfs_blockmap_entry bme = {}; + struct backing_file_context *bfc = NULL; + loff_t blockmap_off = 0; + u16 flags = 0; + int error = 0; + + if (!df || !res_block) + return -EFAULT; + + blockmap_off = df->df_blockmap_off; + bfc = df->df_backing_file_context; + + if (index < 0 || index >= df->df_block_count || blockmap_off == 0) + return -EINVAL; + + error = incfs_read_blockmap_entry(bfc, index, blockmap_off, &bme); + if (error) + return error; + + flags = le16_to_cpu(bme.me_flags); + res_block->db_backing_file_data_offset = + le16_to_cpu(bme.me_data_offset_hi); + res_block->db_backing_file_data_offset <<= 32; + res_block->db_backing_file_data_offset |= + le32_to_cpu(bme.me_data_offset_lo); + res_block->db_stored_size = le16_to_cpu(bme.me_data_size); + res_block->db_comp_alg = (flags & INCFS_BLOCK_COMPRESSED_LZ4) ? + COMPRESSION_LZ4 : + COMPRESSION_NONE; + return 0; +} + +static bool is_read_done(struct pending_read *read) +{ + return atomic_read_acquire(&read->done) != 0; +} + +static void set_read_done(struct pending_read *read) +{ + atomic_set_release(&read->done, 1); +} + +/* + * Notifies a given data file about pending read from a given block. + * Returns a new pending read entry. + */ +static struct pending_read *add_pending_read(struct data_file *df, + int block_index) +{ + struct pending_read *result = NULL; + struct data_file_segment *segment = NULL; + struct mount_info *mi = NULL; + + segment = get_file_segment(df, block_index); + mi = df->df_mount_info; + + result = kzalloc(sizeof(*result), GFP_NOFS); + if (!result) + return NULL; + + result->file_id = df->df_id; + result->block_index = block_index; + result->timestamp_us = ktime_to_us(ktime_get()); + + mutex_lock(&mi->mi_pending_reads_mutex); + + result->serial_number = ++mi->mi_last_pending_read_number; + mi->mi_pending_reads_count++; + + list_add(&result->mi_reads_list, &mi->mi_reads_list_head); + list_add(&result->segment_reads_list, &segment->reads_list_head); + mutex_unlock(&mi->mi_pending_reads_mutex); + + wake_up_all(&mi->mi_pending_reads_notif_wq); + return result; +} + +/* Notifies a given data file that pending read is completed. */ +static void remove_pending_read(struct data_file *df, struct pending_read *read) +{ + struct mount_info *mi = NULL; + + if (!df || !read) { + WARN_ON(!df); + WARN_ON(!read); + return; + } + + mi = df->df_mount_info; + + mutex_lock(&mi->mi_pending_reads_mutex); + list_del(&read->mi_reads_list); + list_del(&read->segment_reads_list); + + mi->mi_pending_reads_count--; + mutex_unlock(&mi->mi_pending_reads_mutex); + + kfree(read); +} + +static void notify_pending_reads(struct mount_info *mi, + struct data_file_segment *segment, + int index) +{ + struct pending_read *entry = NULL; + + /* Notify pending reads waiting for this block. */ + mutex_lock(&mi->mi_pending_reads_mutex); + list_for_each_entry(entry, &segment->reads_list_head, + segment_reads_list) { + if (entry->block_index == index) + set_read_done(entry); + } + mutex_unlock(&mi->mi_pending_reads_mutex); + wake_up_all(&segment->new_data_arrival_wq); +} + +static int wait_for_data_block(struct data_file *df, int block_index, + int timeout_ms, + struct data_file_block *res_block) +{ + struct data_file_block block = {}; + struct data_file_segment *segment = NULL; + struct pending_read *read = NULL; + struct mount_info *mi = NULL; + int error = 0; + int wait_res = 0; + + if (!df || !res_block) + return -EFAULT; + + if (block_index < 0 || block_index >= df->df_block_count) + return -EINVAL; + + if (df->df_blockmap_off <= 0) + return -ENODATA; + + segment = get_file_segment(df, block_index); + error = mutex_lock_interruptible(&segment->blockmap_mutex); + if (error) + return error; + + /* Look up the given block */ + error = get_data_file_block(df, block_index, &block); + + /* If it's not found, create a pending read */ + if (!error && !is_data_block_present(&block) && timeout_ms != 0) + read = add_pending_read(df, block_index); + + mutex_unlock(&segment->blockmap_mutex); + if (error) + return error; + + /* If the block was found, just return it. No need to wait. */ + if (is_data_block_present(&block)) { + *res_block = block; + return 0; + } + + mi = df->df_mount_info; + + if (timeout_ms == 0) { + log_block_read(mi, &df->df_id, block_index, + true /*timed out*/); + return -ETIME; + } + + if (!read) + return -ENOMEM; + + /* Wait for notifications about block's arrival */ + wait_res = + wait_event_interruptible_timeout(segment->new_data_arrival_wq, + (is_read_done(read)), + msecs_to_jiffies(timeout_ms)); + + /* Woke up, the pending read is no longer needed. */ + remove_pending_read(df, read); + read = NULL; + + if (wait_res == 0) { + /* Wait has timed out */ + log_block_read(mi, &df->df_id, block_index, + true /*timed out*/); + return -ETIME; + } + if (wait_res < 0) { + /* + * Only ERESTARTSYS is really expected here when a signal + * comes while we wait. + */ + return wait_res; + } + + error = mutex_lock_interruptible(&segment->blockmap_mutex); + if (error) + return error; + + /* + * Re-read block's info now, it has just arrived and + * should be available. + */ + error = get_data_file_block(df, block_index, &block); + if (!error) { + if (is_data_block_present(&block)) + *res_block = block; + else { + /* + * Somehow wait finished successfully bug block still + * can't be found. It's not normal. + */ + pr_warn("incfs:Wait succeeded, but block not found.\n"); + error = -ENODATA; + } + } + + mutex_unlock(&segment->blockmap_mutex); + return error; +} + +ssize_t incfs_read_data_file_block(struct mem_range dst, struct data_file *df, + int index, int timeout_ms, + struct mem_range tmp) +{ + loff_t pos; + ssize_t result; + size_t bytes_to_read; + struct mount_info *mi = NULL; + struct file *bf = NULL; + struct data_file_block block = {}; + + if (!dst.data || !df) + return -EFAULT; + + if (tmp.len < 2 * INCFS_DATA_FILE_BLOCK_SIZE) + return -ERANGE; + + mi = df->df_mount_info; + bf = df->df_backing_file_context->bc_file; + + result = wait_for_data_block(df, index, timeout_ms, &block); + if (result < 0) + goto out; + + pos = block.db_backing_file_data_offset; + if (block.db_comp_alg == COMPRESSION_NONE) { + bytes_to_read = min(dst.len, block.db_stored_size); + result = incfs_kread(bf, dst.data, bytes_to_read, pos); + + /* Some data was read, but not enough */ + if (result >= 0 && result != bytes_to_read) + result = -EIO; + } else { + bytes_to_read = min(tmp.len, block.db_stored_size); + result = incfs_kread(bf, tmp.data, bytes_to_read, pos); + if (result == bytes_to_read) { + result = + decompress(range(tmp.data, bytes_to_read), dst); + if (result < 0) { + const char *name = + bf->f_path.dentry->d_name.name; + + pr_warn_once("incfs: Decompression error. %s", + name); + } + } else if (result >= 0) { + /* Some data was read, but not enough */ + result = -EIO; + } + } + + if (result > 0) { + int err = validate_hash_tree(bf, df, index, dst, tmp.data); + + if (err < 0) + result = err; + } + + if (result > 0) { + int err = revalidate_signature(bf, df); + + if (err < 0) + result = err; + } + + if (result >= 0) + log_block_read(mi, &df->df_id, index, false /*timed out*/); + +out: + return result; +} + +int incfs_process_new_data_block(struct data_file *df, + struct incfs_new_data_block *block, u8 *data) +{ + struct mount_info *mi = NULL; + struct backing_file_context *bfc = NULL; + struct data_file_segment *segment = NULL; + struct data_file_block existing_block = {}; + u16 flags = 0; + int error = 0; + + if (!df || !block) + return -EFAULT; + + bfc = df->df_backing_file_context; + mi = df->df_mount_info; + + if (block->block_index >= df->df_block_count) + return -ERANGE; + + segment = get_file_segment(df, block->block_index); + if (!segment) + return -EFAULT; + if (block->compression == COMPRESSION_LZ4) + flags |= INCFS_BLOCK_COMPRESSED_LZ4; + + error = mutex_lock_interruptible(&segment->blockmap_mutex); + if (error) + return error; + + error = get_data_file_block(df, block->block_index, &existing_block); + if (error) + goto unlock; + if (is_data_block_present(&existing_block)) { + /* Block is already present, nothing to do here */ + goto unlock; + } + + error = mutex_lock_interruptible(&bfc->bc_mutex); + if (!error) { + error = incfs_write_data_block_to_backing_file( + bfc, range(data, block->data_len), block->block_index, + df->df_blockmap_off, flags); + mutex_unlock(&bfc->bc_mutex); + } + if (!error) + notify_pending_reads(mi, segment, block->block_index); + +unlock: + mutex_unlock(&segment->blockmap_mutex); + if (error) + pr_debug("incfs: %s %d error: %d\n", __func__, + block->block_index, error); + return error; +} + +int incfs_read_file_signature(struct data_file *df, struct mem_range dst) +{ + struct file *bf = df->df_backing_file_context->bc_file; + struct ondisk_signature *sig; + int read_res = 0; + + if (!dst.data) + return -EFAULT; + + sig = df->df_signature; + if (!sig) + return 0; + + if (dst.len < sig->sig_size) + return -E2BIG; + + read_res = incfs_kread(bf, dst.data, sig->sig_size, sig->sig_offset); + + if (read_res < 0) + return read_res; + + if (read_res != sig->sig_size) + return -EIO; + + return read_res; +} + +int incfs_process_new_hash_block(struct data_file *df, + struct incfs_new_data_block *block, u8 *data) +{ + struct backing_file_context *bfc = NULL; + struct mount_info *mi = NULL; + struct mtree *hash_tree = NULL; + struct ondisk_signature *sig = NULL; + loff_t hash_area_base = 0; + loff_t hash_area_size = 0; + int error = 0; + + if (!df || !block) + return -EFAULT; + + if (!(block->flags & INCFS_BLOCK_FLAGS_HASH)) + return -EINVAL; + + bfc = df->df_backing_file_context; + mi = df->df_mount_info; + + if (!df) + return -ENOENT; + + hash_tree = df->df_hash_tree; + sig = df->df_signature; + if (!hash_tree || !sig || sig->mtree_offset == 0) + return -ENOTSUPP; + + hash_area_base = sig->mtree_offset; + hash_area_size = sig->mtree_size; + if (hash_area_size < block->block_index * INCFS_DATA_FILE_BLOCK_SIZE + + block->data_len) { + /* Hash block goes beyond dedicated hash area of this file. */ + return -ERANGE; + } + + error = mutex_lock_interruptible(&bfc->bc_mutex); + if (!error) + error = incfs_write_hash_block_to_backing_file( + bfc, range(data, block->data_len), block->block_index, + hash_area_base); + mutex_unlock(&bfc->bc_mutex); + return error; +} + +static int process_blockmap_md(struct incfs_blockmap *bm, + struct metadata_handler *handler) +{ + struct data_file *df = handler->context; + int error = 0; + loff_t base_off = le64_to_cpu(bm->m_base_offset); + u32 block_count = le32_to_cpu(bm->m_block_count); + + if (!df) + return -EFAULT; + + if (df->df_block_count != block_count) + return -EBADMSG; + + df->df_blockmap_off = base_off; + return error; +} + +static int process_file_attr_md(struct incfs_file_attr *fa, + struct metadata_handler *handler) +{ + struct data_file *df = handler->context; + u16 attr_size = le16_to_cpu(fa->fa_size); + + if (!df) + return -EFAULT; + + if (attr_size > INCFS_MAX_FILE_ATTR_SIZE) + return -E2BIG; + + df->n_attr.fa_value_offset = le64_to_cpu(fa->fa_offset); + df->n_attr.fa_value_size = attr_size; + df->n_attr.fa_crc = le32_to_cpu(fa->fa_crc); + + return 0; +} + +static int process_file_signature_md(struct incfs_file_signature *sg, + struct metadata_handler *handler) +{ + struct data_file *df = handler->context; + struct mtree *hash_tree = NULL; + struct ondisk_signature *signature = NULL; + int error = 0; + loff_t base_tree_off = le64_to_cpu(sg->sg_hash_tree_offset); + u32 tree_size = le32_to_cpu(sg->sg_hash_tree_size); + loff_t sig_off = le64_to_cpu(sg->sg_sig_offset); + u32 sig_size = le32_to_cpu(sg->sg_sig_size); + loff_t add_data_off = le64_to_cpu(sg->sg_add_data_offset); + u32 add_data_size = le32_to_cpu(sg->sg_add_data_size); + + if (!df) + return -ENOENT; + + signature = kzalloc(sizeof(*signature), GFP_NOFS); + if (!signature) { + error = -ENOMEM; + goto out; + } + + signature->add_data_offset = add_data_off; + signature->add_data_size = add_data_size; + signature->sig_offset = sig_off; + signature->sig_size = sig_size; + signature->mtree_offset = base_tree_off; + signature->mtree_size = tree_size; + + hash_tree = incfs_alloc_mtree(sg->sg_hash_alg, df->df_block_count, + range(sg->sg_root_hash, sizeof(sg->sg_root_hash))); + if (IS_ERR(hash_tree)) { + error = PTR_ERR(hash_tree); + hash_tree = NULL; + goto out; + } + if (hash_tree->hash_tree_area_size != tree_size) { + error = -EINVAL; + goto out; + } + if (tree_size > 0 && handler->md_record_offset <= base_tree_off) { + error = -EINVAL; + goto out; + } + if (handler->md_record_offset <= signature->add_data_offset || + handler->md_record_offset <= signature->sig_offset) { + error = -EINVAL; + goto out; + } + df->df_hash_tree = hash_tree; + df->df_signature = signature; +out: + if (error) { + incfs_free_mtree(hash_tree); + kfree(signature); + } + + return error; +} + +int incfs_scan_metadata_chain(struct data_file *df) +{ + struct metadata_handler *handler = NULL; + int result = 0; + int records_count = 0; + int error = 0; + struct backing_file_context *bfc = NULL; + + if (!df || !df->df_backing_file_context) + return -EFAULT; + + bfc = df->df_backing_file_context; + + handler = kzalloc(sizeof(*handler), GFP_NOFS); + if (!handler) + return -ENOMEM; + + /* No writing to the backing file while it's being scanned. */ + error = mutex_lock_interruptible(&bfc->bc_mutex); + if (error) + goto out; + + /* Reading superblock */ + handler->md_record_offset = df->df_metadata_off; + handler->context = df; + handler->handle_blockmap = process_blockmap_md; + handler->handle_file_attr = process_file_attr_md; + handler->handle_signature = process_file_signature_md; + + pr_debug("incfs: Starting reading incfs-metadata records at offset %lld\n", + handler->md_record_offset); + while (handler->md_record_offset > 0) { + error = incfs_read_next_metadata_record(bfc, handler); + if (error) { + pr_warn("incfs: Error during reading incfs-metadata record. Offset: %lld Record #%d Error code: %d\n", + handler->md_record_offset, records_count + 1, + -error); + break; + } + records_count++; + } + if (error) { + pr_debug("incfs: Error %d after reading %d incfs-metadata records.\n", + -error, records_count); + result = error; + } else { + pr_debug("incfs: Finished reading %d incfs-metadata records.\n", + records_count); + result = records_count; + } + mutex_unlock(&bfc->bc_mutex); +out: + kfree(handler); + return result; +} + +/* + * Quickly checks if there are pending reads with a serial number larger + * than a given one. + */ +bool incfs_fresh_pending_reads_exist(struct mount_info *mi, int last_number) +{ + bool result = false; + + mutex_lock(&mi->mi_pending_reads_mutex); + result = (mi->mi_last_pending_read_number > last_number) && + (mi->mi_pending_reads_count > 0); + mutex_unlock(&mi->mi_pending_reads_mutex); + return result; +} + +int incfs_collect_pending_reads(struct mount_info *mi, int sn_lowerbound, + struct incfs_pending_read_info *reads, + int reads_size) +{ + int reported_reads = 0; + struct pending_read *entry = NULL; + + if (!mi) + return -EFAULT; + + if (reads_size <= 0) + return 0; + + mutex_lock(&mi->mi_pending_reads_mutex); + + if (mi->mi_last_pending_read_number <= sn_lowerbound + || mi->mi_pending_reads_count == 0) + goto unlock; + + list_for_each_entry(entry, &mi->mi_reads_list_head, mi_reads_list) { + if (entry->serial_number <= sn_lowerbound) + continue; + + reads[reported_reads].file_id = entry->file_id; + reads[reported_reads].block_index = entry->block_index; + reads[reported_reads].serial_number = entry->serial_number; + reads[reported_reads].timestamp_us = entry->timestamp_us; + /* reads[reported_reads].kind = INCFS_READ_KIND_PENDING; */ + + reported_reads++; + if (reported_reads >= reads_size) + break; + } + +unlock: + mutex_unlock(&mi->mi_pending_reads_mutex); + + return reported_reads; +} + +struct read_log_state incfs_get_log_state(struct mount_info *mi) +{ + struct read_log *log = &mi->mi_log; + struct read_log_state result; + + spin_lock(&log->rl_writer_lock); + result = READ_ONCE(log->rl_state); + spin_unlock(&log->rl_writer_lock); + return result; +} + +static u64 calc_record_count(const struct read_log_state *state, int rl_size) +{ + return state->current_pass_no * (u64)rl_size + state->next_index; +} + +int incfs_get_uncollected_logs_count(struct mount_info *mi, + struct read_log_state state) +{ + struct read_log *log = &mi->mi_log; + + u64 count = calc_record_count(&log->rl_state, log->rl_size) - + calc_record_count(&state, log->rl_size); + return min_t(int, count, log->rl_size); +} + +static void fill_pending_read_from_log_record( + struct incfs_pending_read_info *dest, const struct read_log_record *src, + struct read_log_state *state, u64 log_size) +{ + dest->file_id = src->file_id; + dest->block_index = src->block_index; + dest->serial_number = + state->current_pass_no * log_size + state->next_index; + dest->timestamp_us = src->timestamp_us; +} + +int incfs_collect_logged_reads(struct mount_info *mi, + struct read_log_state *reader_state, + struct incfs_pending_read_info *reads, + int reads_size) +{ + struct read_log *log = &mi->mi_log; + struct read_log_state live_state = incfs_get_log_state(mi); + u64 read_count = calc_record_count(reader_state, log->rl_size); + u64 written_count = calc_record_count(&live_state, log->rl_size); + int dst_idx; + + if (reader_state->next_index >= log->rl_size || + read_count > written_count) + return -ERANGE; + + if (read_count == written_count) + return 0; + + if (read_count > written_count) { + /* This reader is somehow ahead of the writer. */ + pr_debug("incfs: Log reader is ahead of writer\n"); + *reader_state = live_state; + } + + if (written_count - read_count > log->rl_size) { + /* + * Reading pointer is too far behind, + * start from the record following the write pointer. + */ + pr_debug("incfs: read pointer is behind, moving: %u/%u -> %u/%u / %u\n", + (u32)reader_state->next_index, + (u32)reader_state->current_pass_no, + (u32)live_state.next_index, + (u32)live_state.current_pass_no - 1, (u32)log->rl_size); + + *reader_state = (struct read_log_state){ + .next_index = live_state.next_index, + .current_pass_no = live_state.current_pass_no - 1, + }; + } + + for (dst_idx = 0; dst_idx < reads_size; dst_idx++) { + if (reader_state->next_index == live_state.next_index && + reader_state->current_pass_no == live_state.current_pass_no) + break; + + fill_pending_read_from_log_record( + &reads[dst_idx], + &log->rl_ring_buf[reader_state->next_index], + reader_state, log->rl_size); + + reader_state->next_index++; + if (reader_state->next_index == log->rl_size) { + reader_state->next_index = 0; + reader_state->current_pass_no++; + } + } + return dst_idx; +} + +bool incfs_equal_ranges(struct mem_range lhs, struct mem_range rhs) +{ + if (lhs.len != rhs.len) + return false; + return memcmp(lhs.data, rhs.data, lhs.len) == 0; +} diff --git a/fs/incfs/data_mgmt.h b/fs/incfs/data_mgmt.h new file mode 100644 index 0000000000000000000000000000000000000000..82ccab3be4bb17bdb6bf22cd64dffebd59bd7978 --- /dev/null +++ b/fs/incfs/data_mgmt.h @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ +#ifndef _INCFS_DATA_MGMT_H +#define _INCFS_DATA_MGMT_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "internal.h" + +#define SEGMENTS_PER_FILE 3 + +struct read_log_record { + u32 block_index : 31; + + u32 timed_out : 1; + + u64 timestamp_us; + + incfs_uuid_t file_id; +} __packed; + +struct read_log_state { + /* Next slot in rl_ring_buf to write to. */ + u32 next_index; + + /* Current number of writer pass over rl_ring_buf */ + u32 current_pass_no; +}; + +/* A ring buffer to save records about data blocks which were recently read. */ +struct read_log { + struct read_log_record *rl_ring_buf; + + struct read_log_state rl_state; + + spinlock_t rl_writer_lock; + + int rl_size; + + /* + * A queue of waiters who want to be notified about reads. + */ + wait_queue_head_t ml_notif_wq; +}; + +struct mount_options { + unsigned int read_timeout_ms; + unsigned int readahead_pages; + unsigned int read_log_pages; + unsigned int read_log_wakeup_count; + bool no_backing_file_cache; + bool no_backing_file_readahead; +}; + +struct mount_info { + struct super_block *mi_sb; + + struct path mi_backing_dir_path; + + struct dentry *mi_index_dir; + + const struct cred *mi_owner; + + struct mount_options mi_options; + + /* This mutex is to be taken before create, rename, delete */ + struct mutex mi_dir_struct_mutex; + + /* + * A queue of waiters who want to be notified about new pending reads. + */ + wait_queue_head_t mi_pending_reads_notif_wq; + + /* + * Protects: + * - reads_list_head + * - mi_pending_reads_count + * - mi_last_pending_read_number + * - data_file_segment.reads_list_head + */ + struct mutex mi_pending_reads_mutex; + + /* List of active pending_read objects */ + struct list_head mi_reads_list_head; + + /* Total number of items in reads_list_head */ + int mi_pending_reads_count; + + /* + * Last serial number that was assigned to a pending read. + * 0 means no pending reads have been seen yet. + */ + int mi_last_pending_read_number; + + /* Temporary buffer for read logger. */ + struct read_log mi_log; +}; + +struct data_file_block { + loff_t db_backing_file_data_offset; + + size_t db_stored_size; + + enum incfs_compression_alg db_comp_alg; +}; + +struct pending_read { + incfs_uuid_t file_id; + + s64 timestamp_us; + + atomic_t done; + + int block_index; + + int serial_number; + + struct list_head mi_reads_list; + + struct list_head segment_reads_list; +}; + +struct data_file_segment { + wait_queue_head_t new_data_arrival_wq; + + /* Protects reads and writes from the blockmap */ + /* Good candidate for read/write mutex */ + struct mutex blockmap_mutex; + + /* List of active pending_read objects belonging to this segment */ + /* Protected by mount_info.pending_reads_mutex */ + struct list_head reads_list_head; +}; + +/* + * Extra info associated with a file. Just a few bytes set by a user. + */ +struct file_attr { + loff_t fa_value_offset; + + size_t fa_value_size; + + u32 fa_crc; +}; + + +struct data_file { + struct backing_file_context *df_backing_file_context; + + struct mount_info *df_mount_info; + + incfs_uuid_t df_id; + + /* + * Array of segments used to reduce lock contention for the file. + * Segment is chosen for a block depends on the block's index. + */ + struct data_file_segment df_segments[SEGMENTS_PER_FILE]; + + /* Base offset of the first metadata record. */ + loff_t df_metadata_off; + + /* Base offset of the block map. */ + loff_t df_blockmap_off; + + /* File size in bytes */ + loff_t df_size; + + int df_block_count; /* File size in DATA_FILE_BLOCK_SIZE blocks */ + + struct file_attr n_attr; + + struct mtree *df_hash_tree; + + struct ondisk_signature *df_signature; + + /* True, if file signature has already been validated. */ + bool df_signature_validated; +}; + +struct dir_file { + struct mount_info *mount_info; + + struct file *backing_dir; +}; + +struct inode_info { + struct mount_info *n_mount_info; /* A mount, this file belongs to */ + + struct inode *n_backing_inode; + + struct data_file *n_file; + + struct inode n_vfs_inode; +}; + +struct dentry_info { + struct path backing_path; +}; + +struct mount_info *incfs_alloc_mount_info(struct super_block *sb, + struct mount_options *options, + struct path *backing_dir_path); + +void incfs_free_mount_info(struct mount_info *mi); + +struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf); +void incfs_free_data_file(struct data_file *df); + +int incfs_scan_metadata_chain(struct data_file *df); + +struct dir_file *incfs_open_dir_file(struct mount_info *mi, struct file *bf); +void incfs_free_dir_file(struct dir_file *dir); + +ssize_t incfs_read_data_file_block(struct mem_range dst, struct data_file *df, + int index, int timeout_ms, + struct mem_range tmp); + +int incfs_read_file_signature(struct data_file *df, struct mem_range dst); + +int incfs_process_new_data_block(struct data_file *df, + struct incfs_new_data_block *block, u8 *data); + +int incfs_process_new_hash_block(struct data_file *df, + struct incfs_new_data_block *block, u8 *data); + + +bool incfs_fresh_pending_reads_exist(struct mount_info *mi, int last_number); + +/* + * Collects pending reads and saves them into the array (reads/reads_size). + * Only reads with serial_number > sn_lowerbound are reported. + * Returns how many reads were saved into the array. + */ +int incfs_collect_pending_reads(struct mount_info *mi, int sn_lowerbound, + struct incfs_pending_read_info *reads, + int reads_size); + +int incfs_collect_logged_reads(struct mount_info *mi, + struct read_log_state *start_state, + struct incfs_pending_read_info *reads, + int reads_size); +struct read_log_state incfs_get_log_state(struct mount_info *mi); +int incfs_get_uncollected_logs_count(struct mount_info *mi, + struct read_log_state state); + +static inline struct inode_info *get_incfs_node(struct inode *inode) +{ + if (!inode) + return NULL; + + if (inode->i_sb->s_magic != INCFS_MAGIC_NUMBER) { + /* This inode doesn't belong to us. */ + pr_warn_once("incfs: %s on an alien inode.", __func__); + return NULL; + } + + return container_of(inode, struct inode_info, n_vfs_inode); +} + +static inline struct data_file *get_incfs_data_file(struct file *f) +{ + struct inode_info *node = NULL; + + if (!f) + return NULL; + + if (!S_ISREG(f->f_inode->i_mode)) + return NULL; + + node = get_incfs_node(f->f_inode); + if (!node) + return NULL; + + return node->n_file; +} + +static inline struct dir_file *get_incfs_dir_file(struct file *f) +{ + if (!f) + return NULL; + + if (!S_ISDIR(f->f_inode->i_mode)) + return NULL; + + return (struct dir_file *)f->private_data; +} + +/* + * Make sure that inode_info.n_file is initialized and inode can be used + * for reading and writing data from/to the backing file. + */ +int make_inode_ready_for_data_ops(struct mount_info *mi, + struct inode *inode, + struct file *backing_file); + +static inline struct dentry_info *get_incfs_dentry(const struct dentry *d) +{ + if (!d) + return NULL; + + return (struct dentry_info *)d->d_fsdata; +} + +static inline void get_incfs_backing_path(const struct dentry *d, + struct path *path) +{ + struct dentry_info *di = get_incfs_dentry(d); + + if (!di) { + *path = (struct path) {}; + return; + } + + *path = di->backing_path; + path_get(path); +} + +static inline int get_blocks_count_for_size(u64 size) +{ + if (size == 0) + return 0; + return 1 + (size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; +} + +bool incfs_equal_ranges(struct mem_range lhs, struct mem_range rhs); + +#endif /* _INCFS_DATA_MGMT_H */ diff --git a/fs/incfs/format.c b/fs/incfs/format.c new file mode 100644 index 0000000000000000000000000000000000000000..db71f527cf3637b357ef527e692a772b78fa4837 --- /dev/null +++ b/fs/incfs/format.c @@ -0,0 +1,687 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "format.h" + +struct backing_file_context *incfs_alloc_bfc(struct file *backing_file) +{ + struct backing_file_context *result = NULL; + + result = kzalloc(sizeof(*result), GFP_NOFS); + if (!result) + return ERR_PTR(-ENOMEM); + + result->bc_file = get_file(backing_file); + mutex_init(&result->bc_mutex); + return result; +} + +void incfs_free_bfc(struct backing_file_context *bfc) +{ + if (!bfc) + return; + + if (bfc->bc_file) + fput(bfc->bc_file); + + mutex_destroy(&bfc->bc_mutex); + kfree(bfc); +} + +loff_t incfs_get_end_offset(struct file *f) +{ + /* + * This function assumes that file size and the end-offset + * are the same. This is not always true. + */ + return i_size_read(file_inode(f)); +} + +/* + * Truncate the tail of the file to the given length. + * Used to rollback partially successful multistep writes. + */ +static int truncate_backing_file(struct backing_file_context *bfc, + loff_t new_end) +{ + struct inode *inode = NULL; + struct dentry *dentry = NULL; + loff_t old_end = 0; + struct iattr attr; + int result = 0; + + if (!bfc) + return -EFAULT; + + LOCK_REQUIRED(bfc->bc_mutex); + + if (!bfc->bc_file) + return -EFAULT; + + old_end = incfs_get_end_offset(bfc->bc_file); + if (old_end == new_end) + return 0; + if (old_end < new_end) + return -EINVAL; + + inode = bfc->bc_file->f_inode; + dentry = bfc->bc_file->f_path.dentry; + + attr.ia_size = new_end; + attr.ia_valid = ATTR_SIZE; + + inode_lock(inode); + result = notify_change(dentry, &attr, NULL); + inode_unlock(inode); + + return result; +} + +/* Append a given number of zero bytes to the end of the backing file. */ +static int append_zeros(struct backing_file_context *bfc, size_t len) +{ + loff_t file_size = 0; + loff_t new_last_byte_offset = 0; + int res = 0; + + if (!bfc) + return -EFAULT; + + if (len == 0) + return 0; + + LOCK_REQUIRED(bfc->bc_mutex); + + /* + * Allocate only one byte at the new desired end of the file. + * It will increase file size and create a zeroed area of + * a given size. + */ + file_size = incfs_get_end_offset(bfc->bc_file); + new_last_byte_offset = file_size + len - 1; + res = vfs_fallocate(bfc->bc_file, 0, new_last_byte_offset, 1); + if (res) + return res; + + res = vfs_fsync_range(bfc->bc_file, file_size, file_size + len, 1); + return res; +} + +static int write_to_bf(struct backing_file_context *bfc, const void *buf, + size_t count, loff_t pos, bool sync) +{ + ssize_t res = 0; + + res = incfs_kwrite(bfc->bc_file, buf, count, pos); + if (res < 0) + return res; + if (res != count) + return -EIO; + + if (sync) + return vfs_fsync_range(bfc->bc_file, pos, pos + count, 1); + + return 0; +} + +static u32 calc_md_crc(struct incfs_md_header *record) +{ + u32 result = 0; + __le32 saved_crc = record->h_record_crc; + __le64 saved_md_offset = record->h_next_md_offset; + size_t record_size = min_t(size_t, le16_to_cpu(record->h_record_size), + INCFS_MAX_METADATA_RECORD_SIZE); + + /* Zero fields which needs to be excluded from CRC calculation. */ + record->h_record_crc = 0; + record->h_next_md_offset = 0; + result = crc32(0, record, record_size); + + /* Restore excluded fields. */ + record->h_record_crc = saved_crc; + record->h_next_md_offset = saved_md_offset; + + return result; +} + +/* + * Append a given metadata record to the backing file and update a previous + * record to add the new record the the metadata list. + */ +static int append_md_to_backing_file(struct backing_file_context *bfc, + struct incfs_md_header *record) +{ + int result = 0; + loff_t record_offset; + loff_t file_pos; + __le64 new_md_offset; + size_t record_size; + + if (!bfc || !record) + return -EFAULT; + + if (bfc->bc_last_md_record_offset < 0) + return -EINVAL; + + LOCK_REQUIRED(bfc->bc_mutex); + + record_size = le16_to_cpu(record->h_record_size); + file_pos = incfs_get_end_offset(bfc->bc_file); + record->h_prev_md_offset = cpu_to_le64(bfc->bc_last_md_record_offset); + record->h_next_md_offset = 0; + record->h_record_crc = cpu_to_le32(calc_md_crc(record)); + + /* Write the metadata record to the end of the backing file */ + record_offset = file_pos; + new_md_offset = cpu_to_le64(record_offset); + result = write_to_bf(bfc, record, record_size, file_pos, true); + if (result) + return result; + + /* Update next metadata offset in a previous record or a superblock. */ + if (bfc->bc_last_md_record_offset) { + /* + * Find a place in the previous md record where new record's + * offset needs to be saved. + */ + file_pos = bfc->bc_last_md_record_offset + + offsetof(struct incfs_md_header, h_next_md_offset); + } else { + /* + * No metadata yet, file a place to update in the + * file_header. + */ + file_pos = offsetof(struct incfs_file_header, + fh_first_md_offset); + } + result = write_to_bf(bfc, &new_md_offset, sizeof(new_md_offset), + file_pos, true); + if (result) + return result; + + bfc->bc_last_md_record_offset = record_offset; + return result; +} + +/* + * Reserve 0-filled space for the blockmap body, and append + * incfs_blockmap metadata record pointing to it. + */ +int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc, + u32 block_count, loff_t *map_base_off) +{ + struct incfs_blockmap blockmap = {}; + int result = 0; + loff_t file_end = 0; + size_t map_size = block_count * sizeof(struct incfs_blockmap_entry); + + if (!bfc) + return -EFAULT; + + blockmap.m_header.h_md_entry_type = INCFS_MD_BLOCK_MAP; + blockmap.m_header.h_record_size = cpu_to_le16(sizeof(blockmap)); + blockmap.m_header.h_next_md_offset = cpu_to_le64(0); + blockmap.m_block_count = cpu_to_le32(block_count); + + LOCK_REQUIRED(bfc->bc_mutex); + + /* Reserve 0-filled space for the blockmap body in the backing file. */ + file_end = incfs_get_end_offset(bfc->bc_file); + result = append_zeros(bfc, map_size); + if (result) + return result; + + /* Write blockmap metadata record pointing to the body written above. */ + blockmap.m_base_offset = cpu_to_le64(file_end); + result = append_md_to_backing_file(bfc, &blockmap.m_header); + if (result) { + /* Error, rollback file changes */ + truncate_backing_file(bfc, file_end); + } else if (map_base_off) { + *map_base_off = file_end; + } + + return result; +} + +/* + * Write file attribute data and metadata record to the backing file. + */ +int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc, + struct mem_range value, struct incfs_file_attr *attr) +{ + struct incfs_file_attr file_attr = {}; + int result = 0; + u32 crc = 0; + loff_t value_offset = 0; + + if (!bfc) + return -EFAULT; + + if (value.len > INCFS_MAX_FILE_ATTR_SIZE) + return -ENOSPC; + + LOCK_REQUIRED(bfc->bc_mutex); + + crc = crc32(0, value.data, value.len); + value_offset = incfs_get_end_offset(bfc->bc_file); + file_attr.fa_header.h_md_entry_type = INCFS_MD_FILE_ATTR; + file_attr.fa_header.h_record_size = cpu_to_le16(sizeof(file_attr)); + file_attr.fa_header.h_next_md_offset = cpu_to_le64(0); + file_attr.fa_size = cpu_to_le16((u16)value.len); + file_attr.fa_offset = cpu_to_le64(value_offset); + file_attr.fa_crc = cpu_to_le32(crc); + + result = write_to_bf(bfc, value.data, value.len, value_offset, true); + if (result) + return result; + + result = append_md_to_backing_file(bfc, &file_attr.fa_header); + if (result) { + /* Error, rollback file changes */ + truncate_backing_file(bfc, value_offset); + } else if (attr) { + *attr = file_attr; + } + + return result; +} + +int incfs_write_signature_to_backing_file(struct backing_file_context *bfc, + u8 hash_alg, u32 tree_size, + struct mem_range root_hash, struct mem_range add_data, + struct mem_range sig) +{ + struct incfs_file_signature sg = {}; + int result = 0; + loff_t rollback_pos = 0; + loff_t tree_area_pos = 0; + size_t alignment = 0; + + if (!bfc) + return -EFAULT; + if (root_hash.len > sizeof(sg.sg_root_hash)) + return -E2BIG; + + LOCK_REQUIRED(bfc->bc_mutex); + + rollback_pos = incfs_get_end_offset(bfc->bc_file); + + sg.sg_header.h_md_entry_type = INCFS_MD_SIGNATURE; + sg.sg_header.h_record_size = cpu_to_le16(sizeof(sg)); + sg.sg_header.h_next_md_offset = cpu_to_le64(0); + sg.sg_hash_alg = hash_alg; + if (sig.data != NULL && sig.len > 0) { + loff_t pos = incfs_get_end_offset(bfc->bc_file); + + sg.sg_sig_size = cpu_to_le32(sig.len); + sg.sg_sig_offset = cpu_to_le64(pos); + + result = write_to_bf(bfc, sig.data, sig.len, pos, false); + if (result) + goto err; + } + + if (add_data.len > 0) { + loff_t pos = incfs_get_end_offset(bfc->bc_file); + + sg.sg_add_data_size = cpu_to_le32(add_data.len); + sg.sg_add_data_offset = cpu_to_le64(pos); + + result = write_to_bf(bfc, add_data.data, + add_data.len, pos, false); + if (result) + goto err; + } + + tree_area_pos = incfs_get_end_offset(bfc->bc_file); + if (hash_alg && tree_size > 0) { + if (tree_size > 5 * INCFS_DATA_FILE_BLOCK_SIZE) { + /* + * If hash tree is big enough, it makes sense to + * align in the backing file for faster access. + */ + loff_t offset = round_up(tree_area_pos, PAGE_SIZE); + + alignment = offset - tree_area_pos; + tree_area_pos = offset; + } + + /* + * If root hash is not the only hash in the tree. + * reserve 0-filled space for the tree. + */ + result = append_zeros(bfc, tree_size + alignment); + if (result) + goto err; + + sg.sg_hash_tree_size = cpu_to_le32(tree_size); + sg.sg_hash_tree_offset = cpu_to_le64(tree_area_pos); + } + memcpy(sg.sg_root_hash, root_hash.data, root_hash.len); + + /* Write a hash tree metadata record pointing to the hash tree above. */ + result = append_md_to_backing_file(bfc, &sg.sg_header); +err: + if (result) { + /* Error, rollback file changes */ + truncate_backing_file(bfc, rollback_pos); + } + return result; +} + +/* + * Write a backing file header + * It should always be called only on empty file. + * incfs_super_block.s_first_md_offset is 0 for now, but will be updated + * once first metadata record is added. + */ +int incfs_write_fh_to_backing_file(struct backing_file_context *bfc, + incfs_uuid_t *uuid, u64 file_size) +{ + struct incfs_file_header fh = {}; + loff_t file_pos = 0; + + if (!bfc) + return -EFAULT; + + fh.fh_magic = cpu_to_le64(INCFS_MAGIC_NUMBER); + fh.fh_version = cpu_to_le64(INCFS_FORMAT_CURRENT_VER); + fh.fh_header_size = cpu_to_le16(sizeof(fh)); + fh.fh_first_md_offset = cpu_to_le64(0); + fh.fh_data_block_size = cpu_to_le16(INCFS_DATA_FILE_BLOCK_SIZE); + + fh.fh_file_size = cpu_to_le64(file_size); + fh.fh_uuid = *uuid; + + LOCK_REQUIRED(bfc->bc_mutex); + + file_pos = incfs_get_end_offset(bfc->bc_file); + if (file_pos != 0) + return -EEXIST; + + return write_to_bf(bfc, &fh, sizeof(fh), file_pos, true); +} + +/* Write a given data block and update file's blockmap to point it. */ +int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc, + struct mem_range block, int block_index, + loff_t bm_base_off, u16 flags) +{ + struct incfs_blockmap_entry bm_entry = {}; + int result = 0; + loff_t data_offset = 0; + loff_t bm_entry_off = + bm_base_off + sizeof(struct incfs_blockmap_entry) * block_index; + + if (!bfc) + return -EFAULT; + + if (block.len >= (1 << 16) || block_index < 0) + return -EINVAL; + + LOCK_REQUIRED(bfc->bc_mutex); + + data_offset = incfs_get_end_offset(bfc->bc_file); + if (data_offset <= bm_entry_off) { + /* Blockmap entry is beyond the file's end. It is not normal. */ + return -EINVAL; + } + + /* Write the block data at the end of the backing file. */ + result = write_to_bf(bfc, block.data, block.len, data_offset, false); + if (result) + return result; + + /* Update the blockmap to point to the newly written data. */ + bm_entry.me_data_offset_lo = cpu_to_le32((u32)data_offset); + bm_entry.me_data_offset_hi = cpu_to_le16((u16)(data_offset >> 32)); + bm_entry.me_data_size = cpu_to_le16((u16)block.len); + bm_entry.me_flags = cpu_to_le16(flags); + + result = write_to_bf(bfc, &bm_entry, sizeof(bm_entry), + bm_entry_off, false); + return result; +} + +int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc, + struct mem_range block, + int block_index, loff_t hash_area_off) +{ + loff_t data_offset = 0; + loff_t file_end = 0; + + + if (!bfc) + return -EFAULT; + + LOCK_REQUIRED(bfc->bc_mutex); + + data_offset = hash_area_off + block_index * INCFS_DATA_FILE_BLOCK_SIZE; + file_end = incfs_get_end_offset(bfc->bc_file); + if (data_offset + block.len > file_end) { + /* Block is located beyond the file's end. It is not normal. */ + return -EINVAL; + } + + return write_to_bf(bfc, block.data, block.len, data_offset, false); +} + +/* Initialize a new image in a given backing file. */ +int incfs_make_empty_backing_file(struct backing_file_context *bfc, + incfs_uuid_t *uuid, u64 file_size) +{ + int result = 0; + + if (!bfc || !bfc->bc_file) + return -EFAULT; + + result = mutex_lock_interruptible(&bfc->bc_mutex); + if (result) + goto out; + + result = truncate_backing_file(bfc, 0); + if (result) + goto out; + + result = incfs_write_fh_to_backing_file(bfc, uuid, file_size); +out: + mutex_unlock(&bfc->bc_mutex); + return result; +} + +int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index, + loff_t bm_base_off, + struct incfs_blockmap_entry *bm_entry) +{ + return incfs_read_blockmap_entries(bfc, bm_entry, block_index, 1, + bm_base_off); +} + +int incfs_read_blockmap_entries(struct backing_file_context *bfc, + struct incfs_blockmap_entry *entries, + int start_index, int blocks_number, + loff_t bm_base_off) +{ + loff_t bm_entry_off = + bm_base_off + sizeof(struct incfs_blockmap_entry) * start_index; + const size_t bytes_to_read = sizeof(struct incfs_blockmap_entry) + * blocks_number; + int result = 0; + + if (!bfc || !entries) + return -EFAULT; + + if (start_index < 0 || bm_base_off <= 0) + return -ENODATA; + + result = incfs_kread(bfc->bc_file, entries, bytes_to_read, + bm_entry_off); + if (result < 0) + return result; + if (result < bytes_to_read) + return -EIO; + return 0; +} + + +int incfs_read_file_header(struct backing_file_context *bfc, + loff_t *first_md_off, incfs_uuid_t *uuid, + u64 *file_size) +{ + ssize_t bytes_read = 0; + struct incfs_file_header fh = {}; + + if (!bfc || !first_md_off) + return -EFAULT; + + LOCK_REQUIRED(bfc->bc_mutex); + bytes_read = incfs_kread(bfc->bc_file, &fh, sizeof(fh), 0); + if (bytes_read < 0) + return bytes_read; + + if (bytes_read < sizeof(fh)) + return -EBADMSG; + + if (le64_to_cpu(fh.fh_magic) != INCFS_MAGIC_NUMBER) + return -EILSEQ; + + if (le64_to_cpu(fh.fh_version) > INCFS_FORMAT_CURRENT_VER) + return -EILSEQ; + + if (le16_to_cpu(fh.fh_data_block_size) != INCFS_DATA_FILE_BLOCK_SIZE) + return -EILSEQ; + + if (le16_to_cpu(fh.fh_header_size) != sizeof(fh)) + return -EILSEQ; + + if (first_md_off) + *first_md_off = le64_to_cpu(fh.fh_first_md_offset); + if (uuid) + *uuid = fh.fh_uuid; + if (file_size) + *file_size = le64_to_cpu(fh.fh_file_size); + return 0; +} + +/* + * Read through metadata records from the backing file one by one + * and call provided metadata handlers. + */ +int incfs_read_next_metadata_record(struct backing_file_context *bfc, + struct metadata_handler *handler) +{ + const ssize_t max_md_size = INCFS_MAX_METADATA_RECORD_SIZE; + ssize_t bytes_read = 0; + size_t md_record_size = 0; + loff_t next_record = 0; + loff_t prev_record = 0; + int res = 0; + struct incfs_md_header *md_hdr = NULL; + + if (!bfc || !handler) + return -EFAULT; + + LOCK_REQUIRED(bfc->bc_mutex); + + if (handler->md_record_offset == 0) + return -EPERM; + + memset(&handler->md_buffer, 0, max_md_size); + bytes_read = incfs_kread(bfc->bc_file, &handler->md_buffer, + max_md_size, handler->md_record_offset); + if (bytes_read < 0) + return bytes_read; + if (bytes_read < sizeof(*md_hdr)) + return -EBADMSG; + + md_hdr = &handler->md_buffer.md_header; + next_record = le64_to_cpu(md_hdr->h_next_md_offset); + prev_record = le64_to_cpu(md_hdr->h_prev_md_offset); + md_record_size = le16_to_cpu(md_hdr->h_record_size); + + if (md_record_size > max_md_size) { + pr_warn("incfs: The record is too large. Size: %ld", + md_record_size); + return -EBADMSG; + } + + if (bytes_read < md_record_size) { + pr_warn("incfs: The record hasn't been fully read."); + return -EBADMSG; + } + + if (next_record <= handler->md_record_offset && next_record != 0) { + pr_warn("incfs: Next record (%lld) points back in file.", + next_record); + return -EBADMSG; + } + + if (prev_record != handler->md_prev_record_offset) { + pr_warn("incfs: Metadata chain has been corrupted."); + return -EBADMSG; + } + + if (le32_to_cpu(md_hdr->h_record_crc) != calc_md_crc(md_hdr)) { + pr_warn("incfs: Metadata CRC mismatch."); + return -EBADMSG; + } + + switch (md_hdr->h_md_entry_type) { + case INCFS_MD_NONE: + break; + case INCFS_MD_BLOCK_MAP: + if (handler->handle_blockmap) + res = handler->handle_blockmap( + &handler->md_buffer.blockmap, handler); + break; + case INCFS_MD_FILE_ATTR: + if (handler->handle_file_attr) + res = handler->handle_file_attr( + &handler->md_buffer.file_attr, handler); + break; + case INCFS_MD_SIGNATURE: + if (handler->handle_signature) + res = handler->handle_signature( + &handler->md_buffer.signature, handler); + break; + default: + res = -ENOTSUPP; + break; + } + + if (!res) { + if (next_record == 0) { + /* + * Zero offset for the next record means that the last + * metadata record has just been processed. + */ + bfc->bc_last_md_record_offset = + handler->md_record_offset; + } + handler->md_prev_record_offset = handler->md_record_offset; + handler->md_record_offset = next_record; + } + return res; +} + +ssize_t incfs_kread(struct file *f, void *buf, size_t size, loff_t pos) +{ + return kernel_read(f, buf, size, &pos); +} + +ssize_t incfs_kwrite(struct file *f, const void *buf, size_t size, loff_t pos) +{ + return kernel_write(f, buf, size, &pos); +} diff --git a/fs/incfs/format.h b/fs/incfs/format.h new file mode 100644 index 0000000000000000000000000000000000000000..a86881482e19110106b02033b744eb3d6877b10d --- /dev/null +++ b/fs/incfs/format.h @@ -0,0 +1,349 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2018 Google LLC + */ + +/* + * Overview + * -------- + * The backbone of the incremental-fs ondisk format is an append only linked + * list of metadata blocks. Each metadata block contains an offset of the next + * one. These blocks describe files and directories on the + * file system. They also represent actions of adding and removing file names + * (hard links). + * + * Every time incremental-fs instance is mounted, it reads through this list + * to recreate filesystem's state in memory. An offset of the first record in + * the metadata list is stored in the superblock at the beginning of the backing + * file. + * + * Most of the backing file is taken by data areas and blockmaps. + * Since data blocks can be compressed and have different sizes, + * single per-file data area can't be pre-allocated. That's why blockmaps are + * needed in order to find a location and size of each data block in + * the backing file. Each time a file is created, a corresponding block map is + * allocated to store future offsets of data blocks. + * + * Whenever a data block is given by data loader to incremental-fs: + * - A data area with the given block is appended to the end of + * the backing file. + * - A record in the blockmap for the given block index is updated to reflect + * its location, size, and compression algorithm. + + * Metadata records + * ---------------- + * incfs_blockmap - metadata record that specifies size and location + * of a blockmap area for a given file. This area + * contains an array of incfs_blockmap_entry-s. + * incfs_file_signature - metadata record that specifies where file signature + * and its hash tree can be found in the backing file. + * + * incfs_file_attr - metadata record that specifies where additional file + * attributes blob can be found. + * + * Metadata header + * --------------- + * incfs_md_header - header of a metadata record. It's always a part + * of other structures and served purpose of metadata + * bookkeeping. + * + * +-----------------------------------------------+ ^ + * | incfs_md_header | | + * | 1. type of body(BLOCKMAP, FILE_ATTR..) | | + * | 2. size of the whole record header + body | | + * | 3. CRC the whole record header + body | | + * | 4. offset of the previous md record |]------+ + * | 5. offset of the next md record (md link) |]---+ + * +-----------------------------------------------+ | + * | Metadata record body with useful data | | + * +-----------------------------------------------+ | + * +---> + * + * Other ondisk structures + * ----------------------- + * incfs_super_block - backing file header + * incfs_blockmap_entry - a record in a blockmap area that describes size + * and location of a data block. + * Data blocks dont have any particular structure, they are written to the + * backing file in a raw form as they come from a data loader. + * + * Backing file layout + * ------------------- + * + * + * +-------------------------------------------+ + * | incfs_super_block |]---+ + * +-------------------------------------------+ | + * | metadata |<---+ + * | incfs_file_signature |]---+ + * +-------------------------------------------+ | + * ......................... | + * +-------------------------------------------+ | metadata + * +------->| blockmap area | | list links + * | | [incfs_blockmap_entry] | | + * | | [incfs_blockmap_entry] | | + * | | [incfs_blockmap_entry] | | + * | +--[| [incfs_blockmap_entry] | | + * | | | [incfs_blockmap_entry] | | + * | | | [incfs_blockmap_entry] | | + * | | +-------------------------------------------+ | + * | | ......................... | + * | | +-------------------------------------------+ | + * | | | metadata |<---+ + * +----|--[| incfs_blockmap |]---+ + * | +-------------------------------------------+ | + * | ......................... | + * | +-------------------------------------------+ | + * +-->| data block | | + * +-------------------------------------------+ | + * ......................... | + * +-------------------------------------------+ | + * | metadata |<---+ + * | incfs_file_attr | + * +-------------------------------------------+ + */ +#ifndef _INCFS_FORMAT_H +#define _INCFS_FORMAT_H +#include +#include +#include + +#include "internal.h" + +#define INCFS_MAX_NAME_LEN 255 +#define INCFS_FORMAT_V1 1 +#define INCFS_FORMAT_CURRENT_VER INCFS_FORMAT_V1 + +enum incfs_metadata_type { + INCFS_MD_NONE = 0, + INCFS_MD_BLOCK_MAP = 1, + INCFS_MD_FILE_ATTR = 2, + INCFS_MD_SIGNATURE = 3 +}; + +/* Header included at the beginning of all metadata records on the disk. */ +struct incfs_md_header { + __u8 h_md_entry_type; + + /* + * Size of the metadata record. + * (e.g. inode, dir entry etc) not just this struct. + */ + __le16 h_record_size; + + /* + * CRC32 of the metadata record. + * (e.g. inode, dir entry etc) not just this struct. + */ + __le32 h_record_crc; + + /* Offset of the next metadata entry if any */ + __le64 h_next_md_offset; + + /* Offset of the previous metadata entry if any */ + __le64 h_prev_md_offset; + +} __packed; + +/* Backing file header */ +struct incfs_file_header { + /* Magic number: INCFS_MAGIC_NUMBER */ + __le64 fh_magic; + + /* Format version: INCFS_FORMAT_CURRENT_VER */ + __le64 fh_version; + + /* sizeof(incfs_file_header) */ + __le16 fh_header_size; + + /* INCFS_DATA_FILE_BLOCK_SIZE */ + __le16 fh_data_block_size; + + /* Padding, also reserved for future use. */ + __le32 fh_dummy; + + /* Offset of the first metadata record */ + __le64 fh_first_md_offset; + + /* + * Put file specific information after this point + */ + + /* Full size of the file's content */ + __le64 fh_file_size; + + /* File uuid */ + incfs_uuid_t fh_uuid; +} __packed; + +enum incfs_block_map_entry_flags { + INCFS_BLOCK_COMPRESSED_LZ4 = (1 << 0), +}; + +/* Block map entry pointing to an actual location of the data block. */ +struct incfs_blockmap_entry { + /* Offset of the actual data block. Lower 32 bits */ + __le32 me_data_offset_lo; + + /* Offset of the actual data block. Higher 16 bits */ + __le16 me_data_offset_hi; + + /* How many bytes the data actually occupies in the backing file */ + __le16 me_data_size; + + /* Block flags from incfs_block_map_entry_flags */ + __le16 me_flags; +} __packed; + +/* Metadata record for locations of file blocks. Type = INCFS_MD_BLOCK_MAP */ +struct incfs_blockmap { + struct incfs_md_header m_header; + + /* Base offset of the array of incfs_blockmap_entry */ + __le64 m_base_offset; + + /* Size of the map entry array in blocks */ + __le32 m_block_count; +} __packed; + +/* Metadata record for file attribute. Type = INCFS_MD_FILE_ATTR */ +struct incfs_file_attr { + struct incfs_md_header fa_header; + + __le64 fa_offset; + + __le16 fa_size; + + __le32 fa_crc; +} __packed; + +/* Metadata record for file attribute. Type = INCFS_MD_SIGNATURE */ +struct incfs_file_signature { + struct incfs_md_header sg_header; + + __u8 sg_hash_alg; /* Value from incfs_hash_tree_algorithm */ + + __le32 sg_hash_tree_size; /* The size of the hash tree. */ + + __le64 sg_hash_tree_offset; /* Hash tree offset in the backing file */ + + __u8 sg_root_hash[INCFS_MAX_HASH_SIZE]; + + __le32 sg_sig_size; /* The size of the pkcs7 signature. */ + + __le64 sg_sig_offset; /* pkcs7 signature's offset in the backing file */ + + __le32 sg_add_data_size; /* The size of the additional data. */ + + __le64 sg_add_data_offset; /* Additional data's offset */ +} __packed; + +/* State of the backing file. */ +struct backing_file_context { + /* Protects writes to bc_file */ + struct mutex bc_mutex; + + /* File object to read data from */ + struct file *bc_file; + + /* + * Offset of the last known metadata record in the backing file. + * 0 means there are no metadata records. + */ + loff_t bc_last_md_record_offset; +}; + + +/* Backing file locations of things required for signature validation. */ +struct ondisk_signature { + + loff_t add_data_offset; /* Additional data's offset */ + + loff_t sig_offset; /* pkcs7 signature's offset in the backing file */ + + loff_t mtree_offset; /* Backing file offset of the hash tree. */ + + u32 add_data_size; /* The size of the additional data. */ + + u32 sig_size; /* The size of the pkcs7 signature. */ + + u32 mtree_size; /* The size of the hash tree. */ +}; + +struct metadata_handler { + loff_t md_record_offset; + loff_t md_prev_record_offset; + void *context; + + union { + struct incfs_md_header md_header; + struct incfs_blockmap blockmap; + struct incfs_file_attr file_attr; + struct incfs_file_signature signature; + } md_buffer; + + int (*handle_blockmap)(struct incfs_blockmap *bm, + struct metadata_handler *handler); + int (*handle_file_attr)(struct incfs_file_attr *fa, + struct metadata_handler *handler); + int (*handle_signature)(struct incfs_file_signature *sig, + struct metadata_handler *handler); +}; +#define INCFS_MAX_METADATA_RECORD_SIZE \ + FIELD_SIZEOF(struct metadata_handler, md_buffer) + +loff_t incfs_get_end_offset(struct file *f); + +/* Backing file context management */ +struct backing_file_context *incfs_alloc_bfc(struct file *backing_file); + +void incfs_free_bfc(struct backing_file_context *bfc); + +/* Writing stuff */ +int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc, + u32 block_count, loff_t *map_base_off); + +int incfs_write_fh_to_backing_file(struct backing_file_context *bfc, + incfs_uuid_t *uuid, u64 file_size); + +int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc, + struct mem_range block, + int block_index, loff_t bm_base_off, + u16 flags); + +int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc, + struct mem_range block, + int block_index, loff_t hash_area_off); + +int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc, + struct mem_range value, struct incfs_file_attr *attr); + +int incfs_write_signature_to_backing_file(struct backing_file_context *bfc, + u8 hash_alg, u32 tree_size, + struct mem_range root_hash, struct mem_range add_data, + struct mem_range sig); + +int incfs_make_empty_backing_file(struct backing_file_context *bfc, + incfs_uuid_t *uuid, u64 file_size); + +/* Reading stuff */ +int incfs_read_file_header(struct backing_file_context *bfc, + loff_t *first_md_off, incfs_uuid_t *uuid, + u64 *file_size); + +int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index, + loff_t bm_base_off, + struct incfs_blockmap_entry *bm_entry); + +int incfs_read_blockmap_entries(struct backing_file_context *bfc, + struct incfs_blockmap_entry *entries, + int start_index, int blocks_number, + loff_t bm_base_off); + +int incfs_read_next_metadata_record(struct backing_file_context *bfc, + struct metadata_handler *handler); + +ssize_t incfs_kread(struct file *f, void *buf, size_t size, loff_t pos); +ssize_t incfs_kwrite(struct file *f, const void *buf, size_t size, loff_t pos); + +#endif /* _INCFS_FORMAT_H */ diff --git a/fs/incfs/integrity.c b/fs/incfs/integrity.c new file mode 100644 index 0000000000000000000000000000000000000000..feb212c38945721140b3147726080c14de1c6f4f --- /dev/null +++ b/fs/incfs/integrity.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ +#include +#include +#include +#include +#include + +#include "integrity.h" + +int incfs_validate_pkcs7_signature(struct mem_range pkcs7_blob, + struct mem_range root_hash, struct mem_range add_data) +{ + struct pkcs7_message *pkcs7 = NULL; + const void *data = NULL; + size_t data_len = 0; + const char *p; + int err; + + pkcs7 = pkcs7_parse_message(pkcs7_blob.data, pkcs7_blob.len); + if (IS_ERR(pkcs7)) { + pr_debug("PKCS#7 parsing error. ptr=%p size=%ld err=%ld\n", + pkcs7_blob.data, pkcs7_blob.len, -PTR_ERR(pkcs7)); + return PTR_ERR(pkcs7); + } + + err = pkcs7_get_content_data(pkcs7, &data, &data_len, NULL); + if (err || data_len == 0 || data == NULL) { + pr_debug("PKCS#7 message does not contain data\n"); + err = -EBADMSG; + goto out; + } + + if (root_hash.len == 0) { + pr_debug("Root hash is empty.\n"); + err = -EBADMSG; + goto out; + } + + if (data_len != root_hash.len + add_data.len) { + pr_debug("PKCS#7 data size doesn't match arguments.\n"); + err = -EKEYREJECTED; + goto out; + } + + p = data; + if (memcmp(p, root_hash.data, root_hash.len) != 0) { + pr_debug("Root hash mismatch.\n"); + err = -EKEYREJECTED; + goto out; + } + p += root_hash.len; + if (memcmp(p, add_data.data, add_data.len) != 0) { + pr_debug("Additional data mismatch.\n"); + err = -EKEYREJECTED; + goto out; + } + + err = pkcs7_verify(pkcs7, VERIFYING_UNSPECIFIED_SIGNATURE); + if (err) + pr_debug("PKCS#7 signature verification error: %d\n", -err); + + /* + * RSA signature verification sometimes returns unexpected error codes + * when signature doesn't match. + */ + if (err == -ERANGE || err == -EINVAL) + err = -EBADMSG; + +out: + pkcs7_free_message(pkcs7); + return err; +} + +struct incfs_hash_alg *incfs_get_hash_alg(enum incfs_hash_tree_algorithm id) +{ + static struct incfs_hash_alg sha256 = { + .name = "sha256", + .digest_size = SHA256_DIGEST_SIZE, + .id = INCFS_HASH_TREE_SHA256 + }; + struct incfs_hash_alg *result = NULL; + struct crypto_shash *shash; + + if (id == INCFS_HASH_TREE_SHA256) { + BUILD_BUG_ON(INCFS_MAX_HASH_SIZE < SHA256_DIGEST_SIZE); + result = &sha256; + } + + if (result == NULL) + return ERR_PTR(-ENOENT); + + /* pairs with cmpxchg_release() below */ + shash = smp_load_acquire(&result->shash); + if (shash) + return result; + + shash = crypto_alloc_shash(result->name, 0, 0); + if (IS_ERR(shash)) { + int err = PTR_ERR(shash); + + pr_err("Can't allocate hash alg %s, error code:%d", + result->name, err); + return ERR_PTR(err); + } + + /* pairs with smp_load_acquire() above */ + if (cmpxchg_release(&result->shash, NULL, shash) != NULL) + crypto_free_shash(shash); + + return result; +} + + +struct mtree *incfs_alloc_mtree(enum incfs_hash_tree_algorithm id, + int data_block_count, + struct mem_range root_hash) +{ + struct mtree *result = NULL; + struct incfs_hash_alg *hash_alg = NULL; + int hash_per_block; + int lvl; + int total_blocks = 0; + int blocks_in_level[INCFS_MAX_MTREE_LEVELS]; + int blocks = data_block_count; + + if (data_block_count <= 0) + return ERR_PTR(-EINVAL); + + hash_alg = incfs_get_hash_alg(id); + if (IS_ERR(hash_alg)) + return ERR_PTR(PTR_ERR(hash_alg)); + + if (root_hash.len < hash_alg->digest_size) + return ERR_PTR(-EINVAL); + + result = kzalloc(sizeof(*result), GFP_NOFS); + if (!result) + return ERR_PTR(-ENOMEM); + + result->alg = hash_alg; + hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / result->alg->digest_size; + + /* Calculating tree geometry. */ + /* First pass: calculate how many blocks in each tree level. */ + for (lvl = 0; blocks > 1; lvl++) { + if (lvl >= INCFS_MAX_MTREE_LEVELS) { + pr_err("incfs: too much data in mtree"); + goto err; + } + + blocks = (blocks + hash_per_block - 1) / hash_per_block; + blocks_in_level[lvl] = blocks; + total_blocks += blocks; + } + result->depth = lvl; + result->hash_tree_area_size = total_blocks * INCFS_DATA_FILE_BLOCK_SIZE; + if (result->hash_tree_area_size > INCFS_MAX_HASH_AREA_SIZE) + goto err; + + blocks = 0; + /* Second pass: calculate offset of each level. 0th level goes last. */ + for (lvl = 0; lvl < result->depth; lvl++) { + u32 suboffset; + + blocks += blocks_in_level[lvl]; + suboffset = (total_blocks - blocks) + * INCFS_DATA_FILE_BLOCK_SIZE; + + result->hash_level_suboffset[lvl] = suboffset; + } + + /* Root hash is stored separately from the rest of the tree. */ + memcpy(result->root_hash, root_hash.data, hash_alg->digest_size); + return result; + +err: + kfree(result); + return ERR_PTR(-E2BIG); +} + +void incfs_free_mtree(struct mtree *tree) +{ + kfree(tree); +} + +int incfs_calc_digest(struct incfs_hash_alg *alg, struct mem_range data, + struct mem_range digest) +{ + SHASH_DESC_ON_STACK(desc, alg->shash); + + if (!alg || !alg->shash || !data.data || !digest.data) + return -EFAULT; + + if (alg->digest_size > digest.len) + return -EINVAL; + + desc->tfm = alg->shash; + return crypto_shash_digest(desc, data.data, data.len, digest.data); +} + +void incfs_free_signature_info(struct signature_info *si) +{ + if (!si) + return; + kfree(si->root_hash.data); + kfree(si->additional_data.data); + kfree(si->signature.data); + kfree(si); +} + diff --git a/fs/incfs/integrity.h b/fs/incfs/integrity.h new file mode 100644 index 0000000000000000000000000000000000000000..da1c38486b2fee5a170094c52ddd7c0af4f89987 --- /dev/null +++ b/fs/incfs/integrity.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ +#ifndef _INCFS_INTEGRITY_H +#define _INCFS_INTEGRITY_H +#include +#include +#include + +#include + +#include "internal.h" + +#define INCFS_MAX_MTREE_LEVELS 8 +#define INCFS_MAX_HASH_AREA_SIZE (1280 * 1024 * 1024) + +struct incfs_hash_alg { + const char *name; + int digest_size; + enum incfs_hash_tree_algorithm id; + + struct crypto_shash *shash; +}; + +/* Merkle tree structure. */ +struct mtree { + struct incfs_hash_alg *alg; + + u8 root_hash[INCFS_MAX_HASH_SIZE]; + + /* Offset of each hash level in the hash area. */ + u32 hash_level_suboffset[INCFS_MAX_MTREE_LEVELS]; + + u32 hash_tree_area_size; + + /* Number of levels in hash_level_suboffset */ + int depth; +}; + +struct signature_info { + struct mem_range root_hash; + + struct mem_range additional_data; + + struct mem_range signature; + + enum incfs_hash_tree_algorithm hash_alg; +}; + +struct incfs_hash_alg *incfs_get_hash_alg(enum incfs_hash_tree_algorithm id); + +struct mtree *incfs_alloc_mtree(enum incfs_hash_tree_algorithm id, + int data_block_count, + struct mem_range root_hash); + +void incfs_free_mtree(struct mtree *tree); + +size_t incfs_get_mtree_depth(enum incfs_hash_tree_algorithm alg, loff_t size); + +size_t incfs_get_mtree_hash_count(enum incfs_hash_tree_algorithm alg, + loff_t size); + +int incfs_calc_digest(struct incfs_hash_alg *alg, struct mem_range data, + struct mem_range digest); + +int incfs_validate_pkcs7_signature(struct mem_range pkcs7_blob, + struct mem_range root_hash, struct mem_range add_data); + +void incfs_free_signature_info(struct signature_info *si); + +#endif /* _INCFS_INTEGRITY_H */ diff --git a/fs/incfs/internal.h b/fs/incfs/internal.h new file mode 100644 index 0000000000000000000000000000000000000000..0a85eaed41d3a8273925acd6fe7eb91c8f1a281f --- /dev/null +++ b/fs/incfs/internal.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2018 Google LLC + */ +#ifndef _INCFS_INTERNAL_H +#define _INCFS_INTERNAL_H +#include + +struct mem_range { + u8 *data; + size_t len; +}; + +static inline struct mem_range range(u8 *data, size_t len) +{ + return (struct mem_range){ .data = data, .len = len }; +} + +#define LOCK_REQUIRED(lock) WARN_ON_ONCE(!mutex_is_locked(&lock)) + +#endif /* _INCFS_INTERNAL_H */ diff --git a/fs/incfs/main.c b/fs/incfs/main.c new file mode 100644 index 0000000000000000000000000000000000000000..e65d0d895128e1b5a2be0698de3fa5fee6a3b21c --- /dev/null +++ b/fs/incfs/main.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC + */ +#include +#include +#include + +#include + +#include "vfs.h" + +#define INCFS_NODE_FEATURES "features" + +static struct file_system_type incfs_fs_type = { + .owner = THIS_MODULE, + .name = INCFS_NAME, + .mount = incfs_mount_fs, + .kill_sb = incfs_kill_sb, + .fs_flags = 0 +}; + +static struct kobject *sysfs_root, *featurefs_root; + +static ssize_t corefs_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buff) +{ + return snprintf(buff, PAGE_SIZE, "supported\n"); +} + +static struct kobj_attribute corefs_attr = __ATTR_RO(corefs); + +static struct attribute *attributes[] = { + &corefs_attr.attr, + NULL, +}; + +static const struct attribute_group attr_group = { + .attrs = attributes, +}; + +static int __init init_sysfs(void) +{ + int res = 0; + + sysfs_root = kobject_create_and_add(INCFS_NAME, fs_kobj); + if (!sysfs_root) + return -ENOMEM; + + featurefs_root = kobject_create_and_add(INCFS_NODE_FEATURES, + sysfs_root); + if (!featurefs_root) + return -ENOMEM; + + res = sysfs_create_group(featurefs_root, &attr_group); + if (res) { + kobject_put(sysfs_root); + sysfs_root = NULL; + } + return res; +} + +static void cleanup_sysfs(void) +{ + if (featurefs_root) { + sysfs_remove_group(featurefs_root, &attr_group); + kobject_put(featurefs_root); + featurefs_root = NULL; + } + + if (sysfs_root) { + kobject_put(sysfs_root); + sysfs_root = NULL; + } +} + +static int __init init_incfs_module(void) +{ + int err = 0; + + err = init_sysfs(); + if (err) + return err; + + err = register_filesystem(&incfs_fs_type); + if (err) + cleanup_sysfs(); + + return err; +} + +static void __exit cleanup_incfs_module(void) +{ + cleanup_sysfs(); + unregister_filesystem(&incfs_fs_type); +} + +module_init(init_incfs_module); +module_exit(cleanup_incfs_module); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Eugene Zemtsov "); +MODULE_DESCRIPTION("Incremental File System"); diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c new file mode 100644 index 0000000000000000000000000000000000000000..e4790189abd3c1742f0199a47579433ca24fbf92 --- /dev/null +++ b/fs/incfs/vfs.c @@ -0,0 +1,2182 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "vfs.h" +#include "data_mgmt.h" +#include "format.h" +#include "integrity.h" +#include "internal.h" + +#define INCFS_PENDING_READS_INODE 2 +#define INCFS_LOG_INODE 3 +#define INCFS_START_INO_RANGE 10 +#define READ_FILE_MODE 0444 +#define READ_EXEC_FILE_MODE 0555 +#define READ_WRITE_FILE_MODE 0666 + +/* Needed for kernel 4.14 - remove for later kernels */ +typedef unsigned int __poll_t; + +static int incfs_remount_fs(struct super_block *sb, int *flags, char *data); + +static int dentry_revalidate(struct dentry *dentry, unsigned int flags); +static void dentry_release(struct dentry *d); + +static int iterate_incfs_dir(struct file *file, struct dir_context *ctx); +static struct dentry *dir_lookup(struct inode *dir_inode, + struct dentry *dentry, unsigned int flags); +static int dir_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); +static int dir_unlink(struct inode *dir, struct dentry *dentry); +static int dir_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry); +static int dir_rmdir(struct inode *dir, struct dentry *dentry); +static int dir_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry); + +static int file_open(struct inode *inode, struct file *file); +static int file_release(struct inode *inode, struct file *file); +static ssize_t file_write(struct file *f, const char __user *buf, + size_t size, loff_t *offset); +static int read_single_page(struct file *f, struct page *page); +static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg); + +static ssize_t pending_reads_read(struct file *f, char __user *buf, size_t len, + loff_t *ppos); +static __poll_t pending_reads_poll(struct file *file, poll_table *wait); +static int pending_reads_open(struct inode *inode, struct file *file); +static int pending_reads_release(struct inode *, struct file *); + +static ssize_t log_read(struct file *f, char __user *buf, size_t len, + loff_t *ppos); +static __poll_t log_poll(struct file *file, poll_table *wait); +static int log_open(struct inode *inode, struct file *file); +static int log_release(struct inode *, struct file *); + +static struct inode *alloc_inode(struct super_block *sb); +static void free_inode(struct inode *inode); +static void evict_inode(struct inode *inode); + +static ssize_t incfs_getxattr(struct dentry *d, const char *name, + void *value, size_t size); +static ssize_t incfs_listxattr(struct dentry *d, char *list, size_t size); + +static int show_options(struct seq_file *, struct dentry *); + +static const struct super_operations incfs_super_ops = { + .statfs = simple_statfs, + .remount_fs = incfs_remount_fs, + .alloc_inode = alloc_inode, + .destroy_inode = free_inode, + .evict_inode = evict_inode, + .show_options = show_options +}; + +static int dir_rename_wrap(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +{ + return dir_rename(old_dir, old_dentry, new_dir, new_dentry); +} + +static const struct inode_operations incfs_dir_inode_ops = { + .lookup = dir_lookup, + .mkdir = dir_mkdir, + .rename = dir_rename_wrap, + .unlink = dir_unlink, + .link = dir_link, + .rmdir = dir_rmdir +}; + +static const struct file_operations incfs_dir_fops = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .iterate = iterate_incfs_dir, + .open = file_open, + .release = file_release, + .unlocked_ioctl = dispatch_ioctl, + .compat_ioctl = dispatch_ioctl +}; + +static const struct dentry_operations incfs_dentry_ops = { + .d_revalidate = dentry_revalidate, + .d_release = dentry_release +}; + +static const struct address_space_operations incfs_address_space_ops = { + .readpage = read_single_page, + /* .readpages = readpages */ +}; + +static const struct file_operations incfs_file_ops = { + .open = file_open, + .release = file_release, + .write = file_write, + .read_iter = generic_file_read_iter, + .mmap = generic_file_mmap, + .splice_read = generic_file_splice_read, + .llseek = generic_file_llseek, + .unlocked_ioctl = dispatch_ioctl, + .compat_ioctl = dispatch_ioctl +}; + +static const struct file_operations incfs_pending_read_file_ops = { + .read = pending_reads_read, + .poll = pending_reads_poll, + .open = pending_reads_open, + .release = pending_reads_release, + .llseek = noop_llseek, + .unlocked_ioctl = dispatch_ioctl, + .compat_ioctl = dispatch_ioctl +}; + +static const struct file_operations incfs_log_file_ops = { + .read = log_read, + .poll = log_poll, + .open = log_open, + .release = log_release, + .llseek = noop_llseek, + .unlocked_ioctl = dispatch_ioctl, + .compat_ioctl = dispatch_ioctl +}; + +static const struct inode_operations incfs_file_inode_ops = { + .setattr = simple_setattr, + .getattr = simple_getattr, + .listxattr = incfs_listxattr +}; + +static int incfs_handler_getxattr(const struct xattr_handler *xh, + struct dentry *d, struct inode *inode, + const char *name, void *buffer, size_t size) +{ + return incfs_getxattr(d, name, buffer, size); +} + +static const struct xattr_handler incfs_xattr_handler = { + .prefix = "", /* AKA all attributes */ + .get = incfs_handler_getxattr, +}; + +static const struct xattr_handler *incfs_xattr_ops[] = { + &incfs_xattr_handler, + NULL, +}; + +/* State of an open .pending_reads file, unique for each file descriptor. */ +struct pending_reads_state { + /* A serial number of the last pending read obtained from this file. */ + int last_pending_read_sn; +}; + +/* State of an open .log file, unique for each file descriptor. */ +struct log_file_state { + struct read_log_state state; +}; + +struct inode_search { + unsigned long ino; + + struct dentry *backing_dentry; +}; + +enum parse_parameter { + Opt_read_timeout, + Opt_readahead_pages, + Opt_no_backing_file_cache, + Opt_no_backing_file_readahead, + Opt_rlog_pages, + Opt_rlog_wakeup_cnt, + Opt_err +}; + +static const char pending_reads_file_name[] = INCFS_PENDING_READS_FILENAME; +static struct mem_range pending_reads_file_name_range = { + .data = (u8 *)pending_reads_file_name, + .len = ARRAY_SIZE(pending_reads_file_name) - 1 +}; + +static const char log_file_name[] = INCFS_LOG_FILENAME; +static struct mem_range log_file_name_range = { + .data = (u8 *)log_file_name, + .len = ARRAY_SIZE(log_file_name) - 1 +}; + +static const match_table_t option_tokens = { + { Opt_read_timeout, "read_timeout_ms=%u" }, + { Opt_readahead_pages, "readahead=%u" }, + { Opt_no_backing_file_cache, "no_bf_cache=%u" }, + { Opt_no_backing_file_readahead, "no_bf_readahead=%u" }, + { Opt_rlog_pages, "rlog_pages=%u" }, + { Opt_rlog_wakeup_cnt, "rlog_wakeup_cnt=%u" }, + { Opt_err, NULL } +}; + +static int parse_options(struct mount_options *opts, char *str) +{ + substring_t args[MAX_OPT_ARGS]; + int value; + char *position; + + if (opts == NULL) + return -EFAULT; + + opts->read_timeout_ms = 1000; /* Default: 1s */ + opts->readahead_pages = 10; + opts->read_log_pages = 2; + opts->read_log_wakeup_count = 10; + opts->no_backing_file_cache = false; + opts->no_backing_file_readahead = false; + if (str == NULL || *str == 0) + return 0; + + while ((position = strsep(&str, ",")) != NULL) { + int token; + + if (!*position) + continue; + + token = match_token(position, option_tokens, args); + + switch (token) { + case Opt_read_timeout: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->read_timeout_ms = value; + break; + case Opt_readahead_pages: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->readahead_pages = value; + break; + case Opt_no_backing_file_cache: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->no_backing_file_cache = (value != 0); + break; + case Opt_no_backing_file_readahead: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->no_backing_file_readahead = (value != 0); + break; + case Opt_rlog_pages: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->read_log_pages = value; + break; + case Opt_rlog_wakeup_cnt: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->read_log_wakeup_count = value; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static struct super_block *file_superblock(struct file *f) +{ + struct inode *inode = file_inode(f); + + return inode->i_sb; +} + +static struct mount_info *get_mount_info(struct super_block *sb) +{ + struct mount_info *result = sb->s_fs_info; + + WARN_ON(!result); + return result; +} + +/* Read file size from the attribute. Quicker than reading the header */ +static u64 read_size_attr(struct dentry *backing_dentry) +{ + __le64 attr_value; + ssize_t bytes_read; + + bytes_read = vfs_getxattr(backing_dentry, INCFS_XATTR_SIZE_NAME, + (char *)&attr_value, sizeof(attr_value)); + + if (bytes_read != sizeof(attr_value)) + return 0; + + return le64_to_cpu(attr_value); +} + +static int inode_test(struct inode *inode, void *opaque) +{ + struct inode_search *search = opaque; + struct inode_info *node = get_incfs_node(inode); + + if (!node) + return 0; + + if (search->backing_dentry) { + struct inode *backing_inode = d_inode(search->backing_dentry); + + return (node->n_backing_inode == backing_inode) && + inode->i_ino == search->ino; + } + return 1; +} + +static int inode_set(struct inode *inode, void *opaque) +{ + struct inode_search *search = opaque; + struct inode_info *node = get_incfs_node(inode); + + if (search->backing_dentry) { + /* It's a regular inode that has corresponding backing inode */ + struct dentry *backing_dentry = search->backing_dentry; + struct inode *backing_inode = d_inode(backing_dentry); + + inode_init_owner(inode, NULL, backing_inode->i_mode); + fsstack_copy_attr_all(inode, backing_inode); + if (S_ISREG(inode->i_mode)) { + u64 size = read_size_attr(backing_dentry); + + inode->i_size = size; + inode->i_blocks = get_blocks_count_for_size(size); + inode->i_mapping->a_ops = &incfs_address_space_ops; + inode->i_op = &incfs_file_inode_ops; + inode->i_fop = &incfs_file_ops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_size = 0; + inode->i_blocks = 1; + inode->i_mapping->a_ops = &incfs_address_space_ops; + inode->i_op = &incfs_dir_inode_ops; + inode->i_fop = &incfs_dir_fops; + } else { + pr_warn_once("incfs: Unexpected inode type\n"); + return -EBADF; + } + + ihold(backing_inode); + node->n_backing_inode = backing_inode; + node->n_mount_info = get_mount_info(inode->i_sb); + inode->i_ctime = backing_inode->i_ctime; + inode->i_mtime = backing_inode->i_mtime; + inode->i_atime = backing_inode->i_atime; + inode->i_ino = backing_inode->i_ino; + if (backing_inode->i_ino < INCFS_START_INO_RANGE) { + pr_warn("incfs: ino conflict with backing FS %ld\n", + backing_inode->i_ino); + } + return 0; + } else if (search->ino == INCFS_PENDING_READS_INODE) { + /* It's an inode for .pending_reads pseudo file. */ + + inode->i_ctime = (struct timespec){}; + inode->i_mtime = inode->i_ctime; + inode->i_atime = inode->i_ctime; + inode->i_size = 0; + inode->i_ino = INCFS_PENDING_READS_INODE; + inode->i_private = NULL; + + inode_init_owner(inode, NULL, S_IFREG | READ_WRITE_FILE_MODE); + + inode->i_op = &incfs_file_inode_ops; + inode->i_fop = &incfs_pending_read_file_ops; + + } else if (search->ino == INCFS_LOG_INODE) { + /* It's an inode for .log pseudo file. */ + + inode->i_ctime = (struct timespec){}; + inode->i_mtime = inode->i_ctime; + inode->i_atime = inode->i_ctime; + inode->i_size = 0; + inode->i_ino = INCFS_LOG_INODE; + inode->i_private = NULL; + + inode_init_owner(inode, NULL, S_IFREG | READ_WRITE_FILE_MODE); + + inode->i_op = &incfs_file_inode_ops; + inode->i_fop = &incfs_log_file_ops; + + } else { + /* Unknown inode requested. */ + return -EINVAL; + } + + return 0; +} + +static struct inode *fetch_regular_inode(struct super_block *sb, + struct dentry *backing_dentry) +{ + struct inode *backing_inode = d_inode(backing_dentry); + struct inode_search search = { + .ino = backing_inode->i_ino, + .backing_dentry = backing_dentry + }; + struct inode *inode = iget5_locked(sb, search.ino, inode_test, + inode_set, &search); + + if (!inode) + return ERR_PTR(-ENOMEM); + + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + + return inode; +} + +static ssize_t pending_reads_read(struct file *f, char __user *buf, size_t len, + loff_t *ppos) +{ + struct pending_reads_state *pr_state = f->private_data; + struct mount_info *mi = get_mount_info(file_superblock(f)); + struct incfs_pending_read_info *reads_buf = NULL; + size_t reads_to_collect = len / sizeof(*reads_buf); + int last_known_read_sn = READ_ONCE(pr_state->last_pending_read_sn); + int new_max_sn = last_known_read_sn; + int reads_collected = 0; + ssize_t result = 0; + int i = 0; + + if (!access_ok(VERIFY_WRITE, buf, len)) + return -EFAULT; + + if (!incfs_fresh_pending_reads_exist(mi, last_known_read_sn)) + return 0; + + reads_buf = (struct incfs_pending_read_info *)get_zeroed_page(GFP_NOFS); + if (!reads_buf) + return -ENOMEM; + + reads_to_collect = + min_t(size_t, PAGE_SIZE / sizeof(*reads_buf), reads_to_collect); + + reads_collected = incfs_collect_pending_reads( + mi, last_known_read_sn, reads_buf, reads_to_collect); + if (reads_collected < 0) { + result = reads_collected; + goto out; + } + + for (i = 0; i < reads_collected; i++) + if (reads_buf[i].serial_number > new_max_sn) + new_max_sn = reads_buf[i].serial_number; + + /* + * Just to make sure that we don't accidentally copy more data + * to reads buffer than userspace can handle. + */ + reads_collected = min_t(size_t, reads_collected, reads_to_collect); + result = reads_collected * sizeof(*reads_buf); + + /* Copy reads info to the userspace buffer */ + if (copy_to_user(buf, reads_buf, result)) { + result = -EFAULT; + goto out; + } + + WRITE_ONCE(pr_state->last_pending_read_sn, new_max_sn); + *ppos = 0; +out: + if (reads_buf) + free_page((unsigned long)reads_buf); + return result; +} + + +static __poll_t pending_reads_poll(struct file *file, poll_table *wait) +{ + struct pending_reads_state *state = file->private_data; + struct mount_info *mi = get_mount_info(file_superblock(file)); + __poll_t ret = 0; + + poll_wait(file, &mi->mi_pending_reads_notif_wq, wait); + if (incfs_fresh_pending_reads_exist(mi, + state->last_pending_read_sn)) + ret = EPOLLIN | EPOLLRDNORM; + + return ret; +} + +static int pending_reads_open(struct inode *inode, struct file *file) +{ + struct pending_reads_state *state = NULL; + + state = kzalloc(sizeof(*state), GFP_NOFS); + if (!state) + return -ENOMEM; + + file->private_data = state; + return 0; +} + +static int pending_reads_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static struct inode *fetch_pending_reads_inode(struct super_block *sb) +{ + struct inode_search search = { + .ino = INCFS_PENDING_READS_INODE + }; + struct inode *inode = iget5_locked(sb, search.ino, inode_test, + inode_set, &search); + + if (!inode) + return ERR_PTR(-ENOMEM); + + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + + return inode; +} + +static int log_open(struct inode *inode, struct file *file) +{ + struct log_file_state *log_state = NULL; + struct mount_info *mi = get_mount_info(file_superblock(file)); + + log_state = kzalloc(sizeof(*log_state), GFP_NOFS); + if (!log_state) + return -ENOMEM; + + log_state->state = incfs_get_log_state(mi); + file->private_data = log_state; + return 0; +} + +static int log_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static ssize_t log_read(struct file *f, char __user *buf, size_t len, + loff_t *ppos) +{ + struct log_file_state *log_state = f->private_data; + struct mount_info *mi = get_mount_info(file_superblock(f)); + struct incfs_pending_read_info *reads_buf = + (struct incfs_pending_read_info *)__get_free_page(GFP_NOFS); + size_t reads_to_collect = len / sizeof(*reads_buf); + size_t reads_per_page = PAGE_SIZE / sizeof(*reads_buf); + int total_reads_collected = 0; + ssize_t result = 0; + + if (!reads_buf) + return -ENOMEM; + + reads_to_collect = min_t(size_t, mi->mi_log.rl_size, reads_to_collect); + while (reads_to_collect > 0) { + struct read_log_state next_state = READ_ONCE(log_state->state); + int reads_collected = incfs_collect_logged_reads( + mi, &next_state, reads_buf, + min_t(size_t, reads_to_collect, reads_per_page)); + if (reads_collected <= 0) { + result = total_reads_collected ? + total_reads_collected * + sizeof(*reads_buf) : + reads_collected; + goto out; + } + if (copy_to_user(buf, reads_buf, + reads_collected * sizeof(*reads_buf))) { + result = total_reads_collected ? + total_reads_collected * + sizeof(*reads_buf) : + -EFAULT; + goto out; + } + + WRITE_ONCE(log_state->state, next_state); + total_reads_collected += reads_collected; + buf += reads_collected * sizeof(*reads_buf); + reads_to_collect -= reads_collected; + } + + result = total_reads_collected * sizeof(*reads_buf); + *ppos = 0; +out: + if (reads_buf) + free_page((unsigned long)reads_buf); + return result; +} + +static __poll_t log_poll(struct file *file, poll_table *wait) +{ + struct log_file_state *log_state = file->private_data; + struct mount_info *mi = get_mount_info(file_superblock(file)); + int count; + __poll_t ret = 0; + + poll_wait(file, &mi->mi_log.ml_notif_wq, wait); + count = incfs_get_uncollected_logs_count(mi, log_state->state); + if (count >= mi->mi_options.read_log_wakeup_count) + ret = EPOLLIN | EPOLLRDNORM; + + return ret; +} + +static struct inode *fetch_log_inode(struct super_block *sb) +{ + struct inode_search search = { + .ino = INCFS_LOG_INODE + }; + struct inode *inode = iget5_locked(sb, search.ino, inode_test, + inode_set, &search); + + if (!inode) + return ERR_PTR(-ENOMEM); + + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + + return inode; +} + +static int iterate_incfs_dir(struct file *file, struct dir_context *ctx) +{ + struct dir_file *dir = get_incfs_dir_file(file); + int error = 0; + struct mount_info *mi = get_mount_info(file_superblock(file)); + bool root; + + if (!dir) { + error = -EBADF; + goto out; + } + + root = dir->backing_dir->f_inode + == d_inode(mi->mi_backing_dir_path.dentry); + + if (root && ctx->pos == 0) { + if (!dir_emit(ctx, pending_reads_file_name, + ARRAY_SIZE(pending_reads_file_name) - 1, + INCFS_PENDING_READS_INODE, DT_REG)) { + error = -EINVAL; + goto out; + } + ctx->pos++; + } + + if (root && ctx->pos == 1) { + if (!dir_emit(ctx, log_file_name, + ARRAY_SIZE(log_file_name) - 1, + INCFS_LOG_INODE, DT_REG)) { + error = -EINVAL; + goto out; + } + ctx->pos++; + } + + ctx->pos -= 2; + error = iterate_dir(dir->backing_dir, ctx); + ctx->pos += 2; + file->f_pos = dir->backing_dir->f_pos; +out: + if (error) + pr_warn("incfs: %s %s %d\n", __func__, + file->f_path.dentry->d_name.name, error); + return error; +} + +static int incfs_init_dentry(struct dentry *dentry, struct path *path) +{ + struct dentry_info *d_info = NULL; + + if (!dentry || !path) + return -EFAULT; + + d_info = kzalloc(sizeof(*d_info), GFP_NOFS); + if (!d_info) + return -ENOMEM; + + d_info->backing_path = *path; + path_get(path); + + dentry->d_fsdata = d_info; + return 0; +} + +static struct dentry *incfs_lookup_dentry(struct dentry *parent, + const char *name) +{ + struct inode *inode; + struct dentry *result = NULL; + + if (!parent) + return ERR_PTR(-EFAULT); + + inode = d_inode(parent); + inode_lock_nested(inode, I_MUTEX_PARENT); + result = lookup_one_len(name, parent, strlen(name)); + inode_unlock(inode); + + if (IS_ERR(result)) + pr_warn("%s err:%ld\n", __func__, PTR_ERR(result)); + + return result; +} + +static struct dentry *open_or_create_index_dir(struct dentry *backing_dir) +{ + static const char name[] = ".index"; + struct dentry *index_dentry; + struct inode *backing_inode = d_inode(backing_dir); + int err = 0; + + index_dentry = incfs_lookup_dentry(backing_dir, name); + if (!index_dentry) { + return ERR_PTR(-EINVAL); + } else if (IS_ERR(index_dentry)) { + return index_dentry; + } else if (d_really_is_positive(index_dentry)) { + /* Index already exists. */ + return index_dentry; + } + + /* Index needs to be created. */ + inode_lock_nested(backing_inode, I_MUTEX_PARENT); + err = vfs_mkdir(backing_inode, index_dentry, 0777); + inode_unlock(backing_inode); + + if (err) + return ERR_PTR(err); + + if (!d_really_is_positive(index_dentry)) { + dput(index_dentry); + return ERR_PTR(-EINVAL); + } + + return index_dentry; +} + +static int read_single_page(struct file *f, struct page *page) +{ + loff_t offset = 0; + loff_t size = 0; + ssize_t bytes_to_read = 0; + ssize_t read_result = 0; + struct data_file *df = get_incfs_data_file(f); + int result = 0; + void *page_start = kmap(page); + int block_index; + int timeout_ms; + + if (!df) + return -EBADF; + + offset = page_offset(page); + block_index = offset / INCFS_DATA_FILE_BLOCK_SIZE; + size = df->df_size; + timeout_ms = df->df_mount_info->mi_options.read_timeout_ms; + + pr_debug("incfs: %s %s %lld\n", __func__, + f->f_path.dentry->d_name.name, offset); + + if (offset < size) { + struct mem_range tmp = { + .len = 2 * INCFS_DATA_FILE_BLOCK_SIZE + }; + + tmp.data = (u8 *)__get_free_pages(GFP_NOFS, get_order(tmp.len)); + bytes_to_read = min_t(loff_t, size - offset, PAGE_SIZE); + read_result = incfs_read_data_file_block( + range(page_start, bytes_to_read), df, block_index, + timeout_ms, tmp); + + free_pages((unsigned long)tmp.data, get_order(tmp.len)); + } else { + bytes_to_read = 0; + read_result = 0; + } + + if (read_result < 0) + result = read_result; + else if (read_result < PAGE_SIZE) + zero_user(page, read_result, PAGE_SIZE - read_result); + + if (result == 0) + SetPageUptodate(page); + else + SetPageError(page); + + flush_dcache_page(page); + kunmap(page); + unlock_page(page); + return result; +} + +static char *file_id_to_str(incfs_uuid_t id) +{ + char *result = kmalloc(1 + sizeof(id.bytes) * 2, GFP_NOFS); + char *end; + + if (!result) + return NULL; + + end = bin2hex(result, id.bytes, sizeof(id.bytes)); + *end = 0; + return result; +} + +static struct signature_info *incfs_copy_signature_info_from_user( + struct incfs_file_signature_info __user *original) +{ + struct incfs_file_signature_info usr_si; + struct signature_info *result; + int error; + + if (!original) + return NULL; + + if (!access_ok(VERIFY_READ, original, sizeof(usr_si))) + return ERR_PTR(-EFAULT); + + if (copy_from_user(&usr_si, original, sizeof(usr_si)) > 0) + return ERR_PTR(-EFAULT); + + result = kzalloc(sizeof(*result), GFP_NOFS); + if (!result) + return ERR_PTR(-ENOMEM); + + result->hash_alg = usr_si.hash_tree_alg; + + if (result->hash_alg) { + void *p = kzalloc(INCFS_MAX_HASH_SIZE, GFP_NOFS); + + if (!p) { + error = -ENOMEM; + goto err; + } + + // TODO this sets the root_hash length to MAX_HASH_SIZE not + // the actual size. Fix, then set INCFS_MAX_HASH_SIZE back + // to 64 + result->root_hash = range(p, INCFS_MAX_HASH_SIZE); + if (copy_from_user(p, u64_to_user_ptr(usr_si.root_hash), + result->root_hash.len) > 0) { + error = -EFAULT; + goto err; + } + } + + if (usr_si.additional_data_size > INCFS_MAX_FILE_ATTR_SIZE) { + error = -E2BIG; + goto err; + } + + if (usr_si.additional_data && usr_si.additional_data_size) { + void *p = kzalloc(usr_si.additional_data_size, GFP_NOFS); + + if (!p) { + error = -ENOMEM; + goto err; + } + result->additional_data = range(p, + usr_si.additional_data_size); + if (copy_from_user(p, u64_to_user_ptr(usr_si.additional_data), + result->additional_data.len) > 0) { + error = -EFAULT; + goto err; + } + } + + if (usr_si.signature_size > INCFS_MAX_SIGNATURE_SIZE) { + error = -E2BIG; + goto err; + } + + if (usr_si.signature && usr_si.signature_size) { + void *p = kzalloc(usr_si.signature_size, GFP_NOFS); + + if (!p) { + error = -ENOMEM; + goto err; + } + result->signature = range(p, usr_si.signature_size); + if (copy_from_user(p, u64_to_user_ptr(usr_si.signature), + result->signature.len) > 0) { + error = -EFAULT; + goto err; + } + } + + return result; + +err: + incfs_free_signature_info(result); + return ERR_PTR(-error); +} + +static int init_new_file(struct mount_info *mi, struct dentry *dentry, + incfs_uuid_t *uuid, u64 size, struct mem_range attr, + struct incfs_file_signature_info __user *fsi) +{ + struct path path = {}; + struct file *new_file; + int error = 0; + struct backing_file_context *bfc = NULL; + u32 block_count; + struct mem_range mem_range = {NULL}; + struct signature_info *si = NULL; + struct mtree *hash_tree = NULL; + + if (!mi || !dentry || !uuid) + return -EFAULT; + + /* Resize newly created file to its true size. */ + path = (struct path) { + .mnt = mi->mi_backing_dir_path.mnt, + .dentry = dentry + }; + new_file = dentry_open(&path, O_RDWR | O_NOATIME, mi->mi_owner); + + if (IS_ERR(new_file)) { + error = PTR_ERR(new_file); + goto out; + } + + bfc = incfs_alloc_bfc(new_file); + if (IS_ERR(bfc)) { + error = PTR_ERR(bfc); + bfc = NULL; + goto out; + } + + mutex_lock(&bfc->bc_mutex); + error = incfs_write_fh_to_backing_file(bfc, uuid, size); + if (error) + goto out; + + block_count = (u32)get_blocks_count_for_size(size); + error = incfs_write_blockmap_to_backing_file(bfc, block_count, NULL); + if (error) + goto out; + + /* This fill has data, reserve space for the block map. */ + if (block_count > 0) { + error = incfs_write_blockmap_to_backing_file( + bfc, block_count, NULL); + if (error) + goto out; + } + + if (attr.data && attr.len) { + error = incfs_write_file_attr_to_backing_file(bfc, + attr, NULL); + if (error) + goto out; + } + + if (fsi) { + si = incfs_copy_signature_info_from_user(fsi); + + if (IS_ERR(si)) { + error = PTR_ERR(si); + si = NULL; + goto out; + } + + if (si->hash_alg) { + hash_tree = incfs_alloc_mtree(si->hash_alg, block_count, + si->root_hash); + if (IS_ERR(hash_tree)) { + error = PTR_ERR(hash_tree); + hash_tree = NULL; + goto out; + } + + // TODO This code seems wrong when len is zero - we + // should error out?? + if (si->signature.len > 0) + error = incfs_validate_pkcs7_signature( + si->signature, + si->root_hash, + si->additional_data); + if (error) + goto out; + + error = incfs_write_signature_to_backing_file(bfc, + si->hash_alg, + hash_tree->hash_tree_area_size, + si->root_hash, si->additional_data, + si->signature); + + if (error) + goto out; + } + } + +out: + if (bfc) { + mutex_unlock(&bfc->bc_mutex); + incfs_free_bfc(bfc); + } + incfs_free_mtree(hash_tree); + incfs_free_signature_info(si); + kfree(mem_range.data); + + if (error) + pr_debug("incfs: %s error: %d\n", __func__, error); + return error; +} + +static int incfs_link(struct dentry *what, struct dentry *where) +{ + struct dentry *parent_dentry = dget_parent(where); + struct inode *pinode = d_inode(parent_dentry); + int error = 0; + + inode_lock_nested(pinode, I_MUTEX_PARENT); + error = vfs_link(what, pinode, where, NULL); + inode_unlock(pinode); + + dput(parent_dentry); + return error; +} + +static int incfs_unlink(struct dentry *dentry) +{ + struct dentry *parent_dentry = dget_parent(dentry); + struct inode *pinode = d_inode(parent_dentry); + int error = 0; + + inode_lock_nested(pinode, I_MUTEX_PARENT); + error = vfs_unlink(pinode, dentry, NULL); + inode_unlock(pinode); + + dput(parent_dentry); + return error; +} + +static int incfs_rmdir(struct dentry *dentry) +{ + struct dentry *parent_dentry = dget_parent(dentry); + struct inode *pinode = d_inode(parent_dentry); + int error = 0; + + inode_lock_nested(pinode, I_MUTEX_PARENT); + error = vfs_rmdir(pinode, dentry); + inode_unlock(pinode); + + dput(parent_dentry); + return error; +} + +static int dir_relative_path_resolve( + struct mount_info *mi, + const char __user *relative_path, + struct path *result_path) +{ + struct path *base_path = &mi->mi_backing_dir_path; + int dir_fd = get_unused_fd_flags(0); + struct file *dir_f = NULL; + int error = 0; + + if (dir_fd < 0) + return dir_fd; + + dir_f = dentry_open(base_path, O_RDONLY | O_NOATIME, mi->mi_owner); + + if (IS_ERR(dir_f)) { + error = PTR_ERR(dir_f); + goto out; + } + fd_install(dir_fd, dir_f); + + if (!relative_path) { + /* No relative path given, just return the base dir. */ + *result_path = *base_path; + path_get(result_path); + goto out; + } + + error = user_path_at_empty(dir_fd, relative_path, + LOOKUP_FOLLOW | LOOKUP_DIRECTORY, result_path, NULL); + +out: + // TODO sys_close should be replaced with ksys_close on later kernel + // Add to compat or some such? + sys_close(dir_fd); + if (error) + pr_debug("incfs: %s %d\n", __func__, error); + return error; +} + +static int validate_name(char *file_name) +{ + struct mem_range name = range(file_name, strlen(file_name)); + int i = 0; + + if (name.len > INCFS_MAX_NAME_LEN) + return -ENAMETOOLONG; + + if (incfs_equal_ranges(pending_reads_file_name_range, name)) + return -EINVAL; + + for (i = 0; i < name.len; i++) + if (name.data[i] == '/') + return -EINVAL; + + return 0; +} + +static long ioctl_create_file(struct mount_info *mi, + struct incfs_new_file_args __user *usr_args) +{ + struct incfs_new_file_args args; + char *file_id_str = NULL; + struct dentry *index_file_dentry = NULL; + struct dentry *named_file_dentry = NULL; + struct path parent_dir_path = {}; + struct inode *index_dir_inode = NULL; + __le64 size_attr_value = 0; + char *file_name = NULL; + char *attr_value = NULL; + int error = 0; + bool locked = false; + + if (!mi || !mi->mi_index_dir) { + error = -EFAULT; + goto out; + } + if (!access_ok(VERIFY_READ, usr_args, sizeof(args))) { + error = -EFAULT; + goto out; + } + if (copy_from_user(&args, usr_args, sizeof(args)) > 0) { + error = -EFAULT; + goto out; + } + + file_name = strndup_user(u64_to_user_ptr(args.file_name), PATH_MAX); + if (IS_ERR(file_name)) { + error = PTR_ERR(file_name); + file_name = NULL; + goto out; + } + + error = validate_name(file_name); + if (error) + goto out; + + file_id_str = file_id_to_str(args.file_id); + if (!file_id_str) { + error = -ENOMEM; + goto out; + } + + error = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (error) + goto out; + locked = true; + + /* Find a directory to put the file into. */ + error = dir_relative_path_resolve(mi, + u64_to_user_ptr(args.directory_path), + &parent_dir_path); + if (error) + goto out; + + if (parent_dir_path.dentry == mi->mi_index_dir) { + /* Can't create a file directly inside .index */ + error = -EBUSY; + goto out; + } + + /* Look up a dentry in the parent dir. It should be negative. */ + named_file_dentry = incfs_lookup_dentry(parent_dir_path.dentry, + file_name); + if (!named_file_dentry) { + error = -EFAULT; + goto out; + } + if (IS_ERR(named_file_dentry)) { + error = PTR_ERR(named_file_dentry); + named_file_dentry = NULL; + goto out; + } + if (d_really_is_positive(named_file_dentry)) { + /* File with this path already exists. */ + error = -EEXIST; + goto out; + } + /* Look up a dentry in the .index dir. It should be negative. */ + index_file_dentry = incfs_lookup_dentry(mi->mi_index_dir, file_id_str); + if (!index_file_dentry) { + error = -EFAULT; + goto out; + } + if (IS_ERR(index_file_dentry)) { + error = PTR_ERR(index_file_dentry); + index_file_dentry = NULL; + goto out; + } + if (d_really_is_positive(index_file_dentry)) { + /* File with this ID already exists in index. */ + error = -EEXIST; + goto out; + } + + /* Creating a file in the .index dir. */ + index_dir_inode = d_inode(mi->mi_index_dir); + inode_lock_nested(index_dir_inode, I_MUTEX_PARENT); + error = vfs_create(index_dir_inode, index_file_dentry, + args.mode, true); + inode_unlock(index_dir_inode); + + if (error) + goto out; + if (!d_really_is_positive(index_file_dentry)) { + error = -EINVAL; + goto out; + } + + /* Save the file's ID as an xattr for easy fetching in future. */ + error = vfs_setxattr(index_file_dentry, INCFS_XATTR_ID_NAME, + file_id_str, strlen(file_id_str), XATTR_CREATE); + if (error) { + pr_debug("incfs: vfs_setxattr err:%d\n", error); + goto delete_index_file; + } + + /* Save the file's size as an xattr for easy fetching in future. */ + size_attr_value = cpu_to_le64(args.size); + error = vfs_setxattr(index_file_dentry, INCFS_XATTR_SIZE_NAME, + (char *)&size_attr_value, sizeof(size_attr_value), + XATTR_CREATE); + if (error) { + pr_debug("incfs: vfs_setxattr err:%d\n", error); + goto delete_index_file; + } + + /* Save the file's attrubute as an xattr */ + if (args.file_attr_len && args.file_attr) { + if (args.file_attr_len > INCFS_MAX_FILE_ATTR_SIZE) { + error = -E2BIG; + goto delete_index_file; + } + + attr_value = kmalloc(args.file_attr_len, GFP_NOFS); + if (!attr_value) { + error = -ENOMEM; + goto delete_index_file; + } + + if (!access_ok(VERIFY_READ, u64_to_user_ptr(args.file_attr), + args.file_attr_len)) { + error = -EFAULT; + goto delete_index_file; + } + + if (copy_from_user(attr_value, + u64_to_user_ptr(args.file_attr), + args.file_attr_len) > 0) { + error = -EFAULT; + goto delete_index_file; + } + + error = vfs_setxattr(index_file_dentry, + INCFS_XATTR_METADATA_NAME, + attr_value, args.file_attr_len, + XATTR_CREATE); + + if (error) + goto delete_index_file; + } + + /* Initializing a newly created file. */ + error = init_new_file(mi, index_file_dentry, &args.file_id, args.size, + range(attr_value, args.file_attr_len), + (struct incfs_file_signature_info __user *) + args.signature_info); + if (error) + goto delete_index_file; + + /* Linking a file with it's real name from the requested dir. */ + error = incfs_link(index_file_dentry, named_file_dentry); + + if (!error) + goto out; + +delete_index_file: + incfs_unlink(index_file_dentry); + +out: + if (error) + pr_debug("incfs: %s err:%d\n", __func__, error); + + kfree(file_id_str); + kfree(file_name); + kfree(attr_value); + dput(named_file_dentry); + dput(index_file_dentry); + path_put(&parent_dir_path); + if (locked) + mutex_unlock(&mi->mi_dir_struct_mutex); + return error; +} + +static long ioctl_read_file_signature(struct file *f, void __user *arg) +{ + struct incfs_get_file_sig_args __user *args_usr_ptr = arg; + struct incfs_get_file_sig_args args = {}; + u8 *sig_buffer = NULL; + size_t sig_buf_size = 0; + int error = 0; + int read_result = 0; + struct data_file *df = get_incfs_data_file(f); + + if (!df) + return -EINVAL; + + if (!access_ok(VERIFY_READ, args_usr_ptr, sizeof(args))) + return -EFAULT; + if (copy_from_user(&args, args_usr_ptr, sizeof(args)) > 0) + return -EINVAL; + + if (!access_ok(VERIFY_WRITE, u64_to_user_ptr(args.file_signature), + args.file_signature_buf_size)) + return -EFAULT; + + sig_buf_size = args.file_signature_buf_size; + if (sig_buf_size > INCFS_MAX_SIGNATURE_SIZE) + return -E2BIG; + + sig_buffer = kzalloc(sig_buf_size, GFP_NOFS); + if (!sig_buffer) + return -ENOMEM; + + read_result = incfs_read_file_signature(df, + range(sig_buffer, sig_buf_size)); + + if (read_result < 0) { + error = read_result; + goto out; + } + + if (copy_to_user(u64_to_user_ptr(args.file_signature), sig_buffer, + read_result)) { + error = -EFAULT; + goto out; + } + + args.file_signature_len_out = read_result; + if (copy_to_user(args_usr_ptr, &args, sizeof(args))) + error = -EFAULT; + +out: + kfree(sig_buffer); + + return error; +} + +static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg) +{ + struct mount_info *mi = get_mount_info(file_superblock(f)); + + switch (req) { + case INCFS_IOC_CREATE_FILE: + return ioctl_create_file(mi, (void __user *)arg); + case INCFS_IOC_READ_FILE_SIGNATURE: + return ioctl_read_file_signature(f, (void __user *)arg); + default: + return -EINVAL; + } +} + +static struct dentry *dir_lookup(struct inode *dir_inode, struct dentry *dentry, + unsigned int flags) +{ + struct mount_info *mi = get_mount_info(dir_inode->i_sb); + struct dentry *dir_dentry = NULL; + struct dentry *backing_dentry = NULL; + struct path dir_backing_path = {}; + struct inode_info *dir_info = get_incfs_node(dir_inode); + struct mem_range name_range = + range((u8 *)dentry->d_name.name, dentry->d_name.len); + int err = 0; + + if (d_inode(mi->mi_backing_dir_path.dentry) == + dir_info->n_backing_inode) { + /* We do lookup in the FS root. Show pseudo files. */ + + if (incfs_equal_ranges(pending_reads_file_name_range, + name_range)) { + struct inode *inode = fetch_pending_reads_inode( + dir_inode->i_sb); + + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + + d_add(dentry, inode); + goto out; + } + + if (incfs_equal_ranges(log_file_name_range, name_range)) { + struct inode *inode = fetch_log_inode( + dir_inode->i_sb); + + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + + d_add(dentry, inode); + goto out; + } + } + + dir_dentry = dget_parent(dentry); + get_incfs_backing_path(dir_dentry, &dir_backing_path); + backing_dentry = incfs_lookup_dentry(dir_backing_path.dentry, + dentry->d_name.name); + + if (!backing_dentry || IS_ERR(backing_dentry)) { + err = IS_ERR(backing_dentry) + ? PTR_ERR(backing_dentry) + : -EFAULT; + goto out; + } else { + struct inode *inode = NULL; + struct path backing_path = { + .mnt = dir_backing_path.mnt, + .dentry = backing_dentry + }; + + err = incfs_init_dentry(dentry, &backing_path); + if (err) + goto out; + + if (!d_really_is_positive(backing_dentry)) { + /* + * No such entry found in the backing dir. + * Create a negative entry. + */ + d_add(dentry, NULL); + err = 0; + goto out; + } + + if (d_inode(backing_dentry)->i_sb != + dir_info->n_backing_inode->i_sb) { + /* + * Somehow after the path lookup we ended up in a + * different fs mount. If we keep going it's going + * to end badly. + */ + err = -EXDEV; + goto out; + } + + inode = fetch_regular_inode(dir_inode->i_sb, backing_dentry); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + + d_add(dentry, inode); + } + +out: + dput(dir_dentry); + dput(backing_dentry); + path_put(&dir_backing_path); + if (err) + pr_debug("incfs: %s %s %d\n", __func__, + dentry->d_name.name, err); + return ERR_PTR(err); +} + +static int dir_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + struct mount_info *mi = get_mount_info(dir->i_sb); + struct inode_info *dir_node = get_incfs_node(dir); + struct dentry *backing_dentry = NULL; + struct path backing_path = {}; + int err = 0; + + + if (!mi || !dir_node || !dir_node->n_backing_inode) + return -EBADF; + + err = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (err) + return err; + + get_incfs_backing_path(dentry, &backing_path); + backing_dentry = backing_path.dentry; + + if (!backing_dentry) { + err = -EBADF; + goto out; + } + + if (backing_dentry->d_parent == mi->mi_index_dir) { + /* Can't create a subdir inside .index */ + err = -EBUSY; + goto out; + } + + inode_lock_nested(dir_node->n_backing_inode, I_MUTEX_PARENT); + err = vfs_mkdir(dir_node->n_backing_inode, backing_dentry, mode); + inode_unlock(dir_node->n_backing_inode); + if (!err) { + struct inode *inode = NULL; + + if (d_really_is_negative(backing_dentry)) { + err = -EINVAL; + goto out; + } + + inode = fetch_regular_inode(dir->i_sb, backing_dentry); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + d_instantiate(dentry, inode); + } + +out: + if (d_really_is_negative(dentry)) + d_drop(dentry); + path_put(&backing_path); + mutex_unlock(&mi->mi_dir_struct_mutex); + if (err) + pr_debug("incfs: %s err:%d\n", __func__, err); + return err; +} + +/* Delete file referenced by backing_dentry and also its hardlink from .index */ +static int final_file_delete(struct mount_info *mi, + struct dentry *backing_dentry) +{ + struct dentry *index_file_dentry = NULL; + /* 2 chars per byte of file ID + 1 char for \0 */ + char file_id_str[2 * sizeof(incfs_uuid_t) + 1] = {0}; + ssize_t uuid_size = 0; + int error = 0; + + WARN_ON(!mutex_is_locked(&mi->mi_dir_struct_mutex)); + uuid_size = vfs_getxattr(backing_dentry, INCFS_XATTR_ID_NAME, + file_id_str, 2 * sizeof(incfs_uuid_t)); + if (uuid_size < 0) { + error = uuid_size; + goto out; + } + + if (uuid_size != 2 * sizeof(incfs_uuid_t)) { + error = -EBADMSG; + goto out; + } + + index_file_dentry = incfs_lookup_dentry(mi->mi_index_dir, file_id_str); + if (IS_ERR(index_file_dentry)) { + error = PTR_ERR(index_file_dentry); + goto out; + } + + error = incfs_unlink(backing_dentry); + if (error) + goto out; + + if (d_really_is_positive(index_file_dentry)) + error = incfs_unlink(index_file_dentry); +out: + if (error) + pr_debug("incfs: delete_file_from_index err:%d\n", error); + return error; +} + +static int dir_unlink(struct inode *dir, struct dentry *dentry) +{ + struct mount_info *mi = get_mount_info(dir->i_sb); + struct path backing_path = {}; + struct kstat stat; + int err = 0; + + err = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (err) + return err; + + get_incfs_backing_path(dentry, &backing_path); + if (!backing_path.dentry) { + err = -EBADF; + goto out; + } + + if (backing_path.dentry->d_parent == mi->mi_index_dir) { + /* Direct unlink from .index are not allowed. */ + err = -EBUSY; + goto out; + } + + err = vfs_getattr(&backing_path, &stat, STATX_NLINK, + AT_STATX_SYNC_AS_STAT); + if (err) + goto out; + + if (stat.nlink == 2) { + /* + * This is the last named link to this file. The only one left + * is in .index. Remove them both now. + */ + err = final_file_delete(mi, backing_path.dentry); + } else { + /* There are other links to this file. Remove just this one. */ + err = incfs_unlink(backing_path.dentry); + } + + d_drop(dentry); +out: + path_put(&backing_path); + if (err) + pr_debug("incfs: %s err:%d\n", __func__, err); + mutex_unlock(&mi->mi_dir_struct_mutex); + return err; +} + +static int dir_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry) +{ + struct mount_info *mi = get_mount_info(dir->i_sb); + struct path backing_old_path = {}; + struct path backing_new_path = {}; + int error = 0; + + error = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (error) + return error; + + get_incfs_backing_path(old_dentry, &backing_old_path); + get_incfs_backing_path(new_dentry, &backing_new_path); + + if (backing_new_path.dentry->d_parent == mi->mi_index_dir) { + /* Can't link to .index */ + error = -EBUSY; + goto out; + } + + error = incfs_link(backing_old_path.dentry, backing_new_path.dentry); + if (!error) { + struct inode *inode = NULL; + struct dentry *bdentry = backing_new_path.dentry; + + if (d_really_is_negative(bdentry)) { + error = -EINVAL; + goto out; + } + + inode = fetch_regular_inode(dir->i_sb, bdentry); + if (IS_ERR(inode)) { + error = PTR_ERR(inode); + goto out; + } + d_instantiate(new_dentry, inode); + } + +out: + path_put(&backing_old_path); + path_put(&backing_new_path); + if (error) + pr_debug("incfs: %s err:%d\n", __func__, error); + mutex_unlock(&mi->mi_dir_struct_mutex); + return error; +} + +static int dir_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct mount_info *mi = get_mount_info(dir->i_sb); + struct path backing_path = {}; + int err = 0; + + err = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (err) + return err; + + get_incfs_backing_path(dentry, &backing_path); + if (!backing_path.dentry) { + err = -EBADF; + goto out; + } + + if (backing_path.dentry == mi->mi_index_dir) { + /* Can't delete .index */ + err = -EBUSY; + goto out; + } + + err = incfs_rmdir(backing_path.dentry); + if (!err) + d_drop(dentry); +out: + path_put(&backing_path); + if (err) + pr_debug("incfs: %s err:%d\n", __func__, err); + mutex_unlock(&mi->mi_dir_struct_mutex); + return err; +} + +static int dir_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct mount_info *mi = get_mount_info(old_dir->i_sb); + struct dentry *backing_old_dentry; + struct dentry *backing_new_dentry; + struct dentry *backing_old_dir_dentry; + struct dentry *backing_new_dir_dentry; + struct inode *target_inode; + struct dentry *trap; + int error = 0; + + error = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (error) + return error; + + backing_old_dentry = get_incfs_dentry(old_dentry)->backing_path.dentry; + backing_new_dentry = get_incfs_dentry(new_dentry)->backing_path.dentry; + dget(backing_old_dentry); + dget(backing_new_dentry); + + backing_old_dir_dentry = dget_parent(backing_old_dentry); + backing_new_dir_dentry = dget_parent(backing_new_dentry); + target_inode = d_inode(new_dentry); + + if (backing_old_dir_dentry == mi->mi_index_dir) { + /* Direct moves from .index are not allowed. */ + error = -EBUSY; + goto out; + } + + trap = lock_rename(backing_old_dir_dentry, backing_new_dir_dentry); + + if (trap == backing_old_dentry) { + error = -EINVAL; + goto unlock_out; + } + if (trap == backing_new_dentry) { + error = -ENOTEMPTY; + goto unlock_out; + } + + error = vfs_rename(d_inode(backing_old_dir_dentry), backing_old_dentry, + d_inode(backing_new_dir_dentry), backing_new_dentry, + NULL, 0); + if (error) + goto unlock_out; + if (target_inode) + fsstack_copy_attr_all(target_inode, + get_incfs_node(target_inode)->n_backing_inode); + fsstack_copy_attr_all(new_dir, d_inode(backing_new_dir_dentry)); + if (new_dir != old_dir) + fsstack_copy_attr_all(old_dir, d_inode(backing_old_dir_dentry)); + +unlock_out: + unlock_rename(backing_old_dir_dentry, backing_new_dir_dentry); + +out: + dput(backing_new_dir_dentry); + dput(backing_old_dir_dentry); + dput(backing_new_dentry); + dput(backing_old_dentry); + + mutex_unlock(&mi->mi_dir_struct_mutex); + if (error) + pr_debug("incfs: %s err:%d\n", __func__, error); + return error; +} + + +static int file_open(struct inode *inode, struct file *file) +{ + struct mount_info *mi = get_mount_info(inode->i_sb); + struct file *backing_file = NULL; + struct path backing_path = {}; + int err = 0; + + get_incfs_backing_path(file->f_path.dentry, &backing_path); + backing_file = dentry_open(&backing_path, O_RDWR | O_NOATIME, + mi->mi_owner); + path_put(&backing_path); + + if (IS_ERR(backing_file)) { + err = PTR_ERR(backing_file); + backing_file = NULL; + goto out; + } + + if (S_ISREG(inode->i_mode)) + err = make_inode_ready_for_data_ops(mi, inode, backing_file); + else if (S_ISDIR(inode->i_mode)) { + struct dir_file *dir = NULL; + + dir = incfs_open_dir_file(mi, backing_file); + if (IS_ERR(dir)) + err = PTR_ERR(dir); + else + file->private_data = dir; + } else + err = -EBADF; + +out: + if (err) + pr_debug("incfs: %s name:%s err: %d\n", __func__, + file->f_path.dentry->d_name.name, err); + if (backing_file) + fput(backing_file); + return err; +} + +static int file_release(struct inode *inode, struct file *file) +{ + if (S_ISREG(inode->i_mode)) { + /* Do nothing. + * data_file is released only by inode eviction. + */ + } else if (S_ISDIR(inode->i_mode)) { + struct dir_file *dir = get_incfs_dir_file(file); + + incfs_free_dir_file(dir); + } + + return 0; +} + +static ssize_t file_write(struct file *f, const char __user *buf, + size_t size, loff_t *offset) +{ + struct data_file *df = get_incfs_data_file(f); + const ssize_t data_buf_size = 2 * INCFS_DATA_FILE_BLOCK_SIZE; + size_t block_count = size / sizeof(struct incfs_new_data_block); + struct incfs_new_data_block __user *usr_blocks = + (struct incfs_new_data_block __user *)buf; + u8 *data_buf = NULL; + ssize_t error = 0; + int i = 0; + + if (!df) + return -EBADF; + + if (!access_ok(VERIFY_READ, usr_blocks, size)) + return -EFAULT; + + data_buf = (u8 *)__get_free_pages(GFP_NOFS, get_order(data_buf_size)); + if (!data_buf) + return -ENOMEM; + + for (i = 0; i < block_count; i++) { + struct incfs_new_data_block block = {}; + + if (copy_from_user(&block, &usr_blocks[i], sizeof(block)) > 0) { + error = -EFAULT; + break; + } + + if (block.data_len > data_buf_size) { + error = -E2BIG; + break; + } + if (!access_ok(VERIFY_READ, u64_to_user_ptr(block.data), + block.data_len)) { + error = -EFAULT; + break; + } + if (copy_from_user(data_buf, u64_to_user_ptr(block.data), + block.data_len) > 0) { + error = -EFAULT; + break; + } + block.data = 0; /* To make sure nobody uses it. */ + if (block.flags & INCFS_BLOCK_FLAGS_HASH) { + error = incfs_process_new_hash_block(df, &block, + data_buf); + } else { + error = incfs_process_new_data_block(df, &block, + data_buf); + } + if (error) + break; + } + + if (data_buf) + free_pages((unsigned long)data_buf, get_order(data_buf_size)); + *offset = 0; + + /* + * Only report the error if no records were processed, otherwise + * just return how many were processed successfully. + */ + if (i == 0) + return error; + + return i * sizeof(struct incfs_new_data_block); +} + + +static int dentry_revalidate(struct dentry *d, unsigned int flags) +{ + struct path backing_path = {}; + struct inode_info *info = get_incfs_node(d_inode(d)); + struct inode *binode = (info == NULL) ? NULL : info->n_backing_inode; + struct dentry *backing_dentry = NULL; + int result = 0; + + if (flags & LOOKUP_RCU) + return -ECHILD; + + get_incfs_backing_path(d, &backing_path); + backing_dentry = backing_path.dentry; + if (!backing_dentry) + goto out; + + if (d_inode(backing_dentry) != binode) { + /* + * Backing inodes obtained via dentry and inode don't match. + * It indicates that most likely backing dir has changed + * directly bypassing Incremental FS interface. + */ + goto out; + } + + if (backing_dentry->d_flags & DCACHE_OP_REVALIDATE) { + result = backing_dentry->d_op->d_revalidate(backing_dentry, + flags); + } else + result = 1; + +out: + path_put(&backing_path); + return result; +} + +static void dentry_release(struct dentry *d) +{ + struct dentry_info *di = get_incfs_dentry(d); + + if (di) + path_put(&di->backing_path); + d->d_fsdata = NULL; +} + +static struct inode *alloc_inode(struct super_block *sb) +{ + struct inode_info *node = kzalloc(sizeof(*node), GFP_NOFS); + + /* TODO: add a slab-based cache here. */ + if (!node) + return NULL; + inode_init_once(&node->n_vfs_inode); + return &node->n_vfs_inode; +} + +static void free_inode(struct inode *inode) +{ + struct inode_info *node = get_incfs_node(inode); + + kfree(node); +} + +static void evict_inode(struct inode *inode) +{ + struct inode_info *node = get_incfs_node(inode); + + if (node) { + if (node->n_backing_inode) { + iput(node->n_backing_inode); + node->n_backing_inode = NULL; + } + if (node->n_file) { + incfs_free_data_file(node->n_file); + node->n_file = NULL; + } + } + + truncate_inode_pages(&inode->i_data, 0); + clear_inode(inode); +} + +static ssize_t incfs_getxattr(struct dentry *d, const char *name, + void *value, size_t size) +{ + struct dentry_info *di = get_incfs_dentry(d); + + if (!di || !di->backing_path.dentry) + return -ENODATA; + + return vfs_getxattr(di->backing_path.dentry, name, value, size); +} + +static ssize_t incfs_listxattr(struct dentry *d, char *list, size_t size) +{ + struct dentry_info *di = get_incfs_dentry(d); + + if (!di || !di->backing_path.dentry) + return -ENODATA; + + return vfs_listxattr(di->backing_path.dentry, list, size); +} + +struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, + const char *dev_name, void *data) +{ + struct mount_options options = {}; + struct mount_info *mi = NULL; + struct path backing_dir_path = {}; + struct dentry *index_dir; + struct super_block *src_fs_sb = NULL; + struct inode *root_inode = NULL; + struct super_block *sb = sget(type, NULL, set_anon_super, flags, NULL); + int error = 0; + + if (IS_ERR(sb)) + return ERR_CAST(sb); + + sb->s_op = &incfs_super_ops; + sb->s_d_op = &incfs_dentry_ops; + sb->s_flags |= S_NOATIME; + sb->s_magic = INCFS_MAGIC_NUMBER; + sb->s_time_gran = 1; + sb->s_blocksize = INCFS_DATA_FILE_BLOCK_SIZE; + sb->s_blocksize_bits = blksize_bits(sb->s_blocksize); + sb->s_xattr = incfs_xattr_ops; + + BUILD_BUG_ON(PAGE_SIZE != INCFS_DATA_FILE_BLOCK_SIZE); + + error = parse_options(&options, (char *)data); + if (error != 0) { + pr_err("incfs: Options parsing error. %d\n", error); + goto err; + } + + sb->s_bdi->ra_pages = options.readahead_pages; + if (!dev_name) { + pr_err("incfs: Backing dir is not set, filesystem can't be mounted.\n"); + error = -ENOENT; + goto err; + } + + error = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, + &backing_dir_path); + if (error || backing_dir_path.dentry == NULL || + !d_really_is_positive(backing_dir_path.dentry)) { + pr_err("incfs: Error accessing: %s.\n", + dev_name); + goto err; + } + src_fs_sb = backing_dir_path.dentry->d_sb; + sb->s_maxbytes = src_fs_sb->s_maxbytes; + + mi = incfs_alloc_mount_info(sb, &options, &backing_dir_path); + + if (IS_ERR_OR_NULL(mi)) { + error = PTR_ERR(mi); + pr_err("incfs: Error allocating mount info. %d\n", error); + mi = NULL; + goto err; + } + + index_dir = open_or_create_index_dir(backing_dir_path.dentry); + if (IS_ERR_OR_NULL(index_dir)) { + error = PTR_ERR(index_dir); + pr_err("incfs: Can't find or create .index dir in %s\n", + dev_name); + goto err; + } + mi->mi_index_dir = index_dir; + + sb->s_fs_info = mi; + root_inode = fetch_regular_inode(sb, backing_dir_path.dentry); + if (IS_ERR(root_inode)) { + error = PTR_ERR(root_inode); + goto err; + } + + sb->s_root = d_make_root(root_inode); + if (!sb->s_root) { + error = -ENOMEM; + goto err; + } + error = incfs_init_dentry(sb->s_root, &backing_dir_path); + if (error) + goto err; + + path_put(&backing_dir_path); + sb->s_flags |= SB_ACTIVE; + + pr_debug("infs: mount\n"); + return dget(sb->s_root); +err: + sb->s_fs_info = NULL; + path_put(&backing_dir_path); + incfs_free_mount_info(mi); + deactivate_locked_super(sb); + return ERR_PTR(error); +} + +static int incfs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + struct mount_options options; + struct mount_info *mi = get_mount_info(sb); + int err = 0; + + sync_filesystem(sb); + err = parse_options(&options, (char *)data); + if (err) + return err; + + if (mi->mi_options.read_timeout_ms != options.read_timeout_ms) { + mi->mi_options.read_timeout_ms = options.read_timeout_ms; + pr_debug("incfs: new timeout_ms=%d", options.read_timeout_ms); + } + + pr_debug("infs: remount\n"); + return 0; +} + +void incfs_kill_sb(struct super_block *sb) +{ + struct mount_info *mi = sb->s_fs_info; + + pr_debug("infs: unmount\n"); + incfs_free_mount_info(mi); + generic_shutdown_super(sb); +} + +static int show_options(struct seq_file *m, struct dentry *root) +{ + struct mount_info *mi = get_mount_info(root->d_sb); + + seq_printf(m, ",read_timeout_ms=%u", mi->mi_options.read_timeout_ms); + seq_printf(m, ",readahead=%u", mi->mi_options.readahead_pages); + if (mi->mi_options.read_log_pages != 0) { + seq_printf(m, ",rlog_pages=%u", mi->mi_options.read_log_pages); + seq_printf(m, ",rlog_wakeup_cnt=%u", + mi->mi_options.read_log_wakeup_count); + } + if (mi->mi_options.no_backing_file_cache) + seq_puts(m, ",no_bf_cache"); + if (mi->mi_options.no_backing_file_readahead) + seq_puts(m, ",no_bf_readahead"); + return 0; +} diff --git a/fs/incfs/vfs.h b/fs/incfs/vfs.h new file mode 100644 index 0000000000000000000000000000000000000000..eaa490e1907211951da09624a1f88a0bd222a6ff --- /dev/null +++ b/fs/incfs/vfs.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2018 Google LLC + */ + +#ifndef _INCFS_VFS_H +#define _INCFS_VFS_H + +void incfs_kill_sb(struct super_block *sb); +struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, + const char *dev_name, void *data); + +#endif diff --git a/fs/inode.c b/fs/inode.c index 68e6eeb72b8bbd6856997f6c3c1555493368b460..c7e140686a348f6c813e59d82714a65e56f3110a 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -656,6 +656,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty) struct inode *inode, *next; LIST_HEAD(dispose); +again: spin_lock(&sb->s_inode_list_lock); list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { spin_lock(&inode->i_lock); @@ -678,6 +679,12 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty) inode_lru_list_del(inode); spin_unlock(&inode->i_lock); list_add(&inode->i_lru, &dispose); + if (need_resched()) { + spin_unlock(&sb->s_inode_list_lock); + cond_resched(); + dispose_list(&dispose); + goto again; + } } spin_unlock(&sb->s_inode_list_lock); diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 4d973524c887990fd0ba4727362e8a70917783a4..224ef034004b7d28a5fcdcc9d1aefe100b92ff7a 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -1928,8 +1928,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, * header ? */ if (tlck->type & tlckTRUNCATE) { - /* This odd declaration suppresses a bogus gcc warning */ - pxd_t pxd = pxd; /* truncated extent of xad */ + pxd_t pxd; /* truncated extent of xad */ int twm; /* diff --git a/fs/namei.c b/fs/namei.c index ca8a9fcc552f1435ca30d6163c9fddd6b2254f45..7c876d8734ea9abfc7662e9ef61aadc755b8468a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1122,7 +1122,8 @@ static int may_linkat(struct path *link) * may_create_in_sticky - Check whether an O_CREAT open in a sticky directory * should be allowed, or not, on files that already * exist. - * @dir: the sticky parent directory + * @dir_mode: mode bits of directory + * @dir_uid: owner of directory * @inode: the inode of the file to open * * Block an O_CREAT open of a FIFO (or a regular file) when: @@ -1138,18 +1139,18 @@ static int may_linkat(struct path *link) * * Returns 0 if the open is allowed, -ve on error. */ -static int may_create_in_sticky(struct dentry * const dir, +static int may_create_in_sticky(umode_t dir_mode, kuid_t dir_uid, struct inode * const inode) { if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) || (!sysctl_protected_regular && S_ISREG(inode->i_mode)) || - likely(!(dir->d_inode->i_mode & S_ISVTX)) || - uid_eq(inode->i_uid, dir->d_inode->i_uid) || + likely(!(dir_mode & S_ISVTX)) || + uid_eq(inode->i_uid, dir_uid) || uid_eq(current_fsuid(), inode->i_uid)) return 0; - if (likely(dir->d_inode->i_mode & 0002) || - (dir->d_inode->i_mode & 0020 && + if (likely(dir_mode & 0002) || + (dir_mode & 0020 && ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) || (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) { return -EACCES; @@ -3384,6 +3385,8 @@ static int do_last(struct nameidata *nd, int *opened) { struct dentry *dir = nd->path.dentry; + kuid_t dir_uid = nd->inode->i_uid; + umode_t dir_mode = nd->inode->i_mode; int open_flag = op->open_flag; bool will_truncate = (open_flag & O_TRUNC) != 0; bool got_write = false; @@ -3519,7 +3522,7 @@ static int do_last(struct nameidata *nd, error = -EISDIR; if (d_is_dir(nd->path.dentry)) goto out; - error = may_create_in_sticky(dir, + error = may_create_in_sticky(dir_mode, dir_uid, d_backing_inode(nd->path.dentry)); if (unlikely(error)) goto out; diff --git a/fs/namespace.c b/fs/namespace.c index 2279475c6e8ade0b4d4e7fcece18811a20a7b900..68549a0d10547d3fda0b5ea5860c6280c4064b3f 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1778,6 +1778,12 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) dput_and_out: /* we mustn't call path_put() as that would clear mnt_expiry_mark */ dput(path.dentry); + if (user_request && (!retval || (flags & MNT_FORCE))) { + /* filesystem needs to handle unclosed namespaces */ + if (mnt->mnt.mnt_sb->s_op->umount_end) + mnt->mnt.mnt_sb->s_op->umount_end(mnt->mnt.mnt_sb, + flags); + } mntput_no_expire(mnt); if (!user_request) @@ -1794,11 +1800,6 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) /* flush delayed_mntput_work to put sb->s_active */ flush_delayed_mntput_wait(); } - if (!retval || (flags & MNT_FORCE)) { - /* filesystem needs to handle unclosed namespaces */ - if (mnt->mnt.mnt_sb->s_op->umount_end) - mnt->mnt.mnt_sb->s_op->umount_end(mnt->mnt.mnt_sb, flags); - } out: return retval; } diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 04d57e11577e01938ae0c3f2e6b765304bf31d51..09b3bcb86d3281703c5215a4abb2de235f250113 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -234,6 +234,8 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation spin_lock(&delegation->lock); if (delegation->inode != NULL) inode = igrab(delegation->inode); + if (!inode) + set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags); spin_unlock(&delegation->lock); return inode; } @@ -863,10 +865,11 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp) list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { list_for_each_entry_rcu(delegation, &server->delegations, super_list) { - if (test_bit(NFS_DELEGATION_RETURNING, - &delegation->flags)) - continue; - if (test_bit(NFS_DELEGATION_NEED_RECLAIM, + if (test_bit(NFS_DELEGATION_INODE_FREEING, + &delegation->flags) || + test_bit(NFS_DELEGATION_RETURNING, + &delegation->flags) || + test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0) continue; if (!nfs_sb_active(server->super)) @@ -971,10 +974,11 @@ void nfs_reap_expired_delegations(struct nfs_client *clp) list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { list_for_each_entry_rcu(delegation, &server->delegations, super_list) { - if (test_bit(NFS_DELEGATION_RETURNING, - &delegation->flags)) - continue; - if (test_bit(NFS_DELEGATION_TEST_EXPIRED, + if (test_bit(NFS_DELEGATION_INODE_FREEING, + &delegation->flags) || + test_bit(NFS_DELEGATION_RETURNING, + &delegation->flags) || + test_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags) == 0) continue; if (!nfs_sb_active(server->super)) diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index df41d16dc6ab43eff77f95f399c0f9787e30beed..510c9edcc712d5a16045002c9dceff6d38179c08 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -34,6 +34,7 @@ enum { NFS_DELEGATION_RETURNING, NFS_DELEGATION_REVOKED, NFS_DELEGATION_TEST_EXPIRED, + NFS_DELEGATION_INODE_FREEING, }; int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h index d6515f1584f3c8de762aa131a4d4a99fe8d9fdf9..d78ec99b6c4ca82f1a7acd484721ce3b78f1f66a 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.h +++ b/fs/nfs/flexfilelayout/flexfilelayout.h @@ -131,16 +131,6 @@ FF_LAYOUT_LSEG(struct pnfs_layout_segment *lseg) generic_hdr); } -static inline struct nfs4_deviceid_node * -FF_LAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg, u32 idx) -{ - if (idx >= FF_LAYOUT_LSEG(lseg)->mirror_array_cnt || - FF_LAYOUT_LSEG(lseg)->mirror_array[idx] == NULL || - FF_LAYOUT_LSEG(lseg)->mirror_array[idx]->mirror_ds == NULL) - return NULL; - return &FF_LAYOUT_LSEG(lseg)->mirror_array[idx]->mirror_ds->id_node; -} - static inline struct nfs4_ff_layout_ds * FF_LAYOUT_MIRROR_DS(struct nfs4_deviceid_node *node) { @@ -150,9 +140,25 @@ FF_LAYOUT_MIRROR_DS(struct nfs4_deviceid_node *node) static inline struct nfs4_ff_layout_mirror * FF_LAYOUT_COMP(struct pnfs_layout_segment *lseg, u32 idx) { - if (idx >= FF_LAYOUT_LSEG(lseg)->mirror_array_cnt) - return NULL; - return FF_LAYOUT_LSEG(lseg)->mirror_array[idx]; + struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); + + if (idx < fls->mirror_array_cnt) + return fls->mirror_array[idx]; + return NULL; +} + +static inline struct nfs4_deviceid_node * +FF_LAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg, u32 idx) +{ + struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, idx); + + if (mirror != NULL) { + struct nfs4_ff_layout_ds *mirror_ds = mirror->mirror_ds; + + if (!IS_ERR_OR_NULL(mirror_ds)) + return &mirror_ds->id_node; + } + return NULL; } static inline u32 diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f1526f65cc580c20c4cb6d3a04a03ace06ed7e36..3dd403943b07fd3e30f836c73b2cb19ffcbd8c58 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5797,8 +5797,10 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) d_data = (struct nfs4_delegreturndata *)data; - if (!d_data->lr.roc && nfs4_wait_on_layoutreturn(d_data->inode, task)) + if (!d_data->lr.roc && nfs4_wait_on_layoutreturn(d_data->inode, task)) { + nfs4_sequence_done(task, &d_data->res.seq_res); return; + } nfs4_setup_sequence(d_data->res.server->nfs_client, &d_data->args.seq_args, diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index ec04cce31814bc5bedee01825326b28ad875273d..83abf3dd73511352d8c27ba4dd9ba8ff530b7343 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -725,22 +725,35 @@ static int pnfs_layout_bulk_destroy_byserver_locked(struct nfs_client *clp, struct nfs_server *server, struct list_head *layout_list) + __must_hold(&clp->cl_lock) + __must_hold(RCU) { struct pnfs_layout_hdr *lo, *next; struct inode *inode; list_for_each_entry_safe(lo, next, &server->layouts, plh_layouts) { - if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) + if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) || + test_bit(NFS_LAYOUT_INODE_FREEING, &lo->plh_flags) || + !list_empty(&lo->plh_bulk_destroy)) continue; + /* If the sb is being destroyed, just bail */ + if (!nfs_sb_active(server->super)) + break; inode = igrab(lo->plh_inode); - if (inode == NULL) - continue; - list_del_init(&lo->plh_layouts); - if (pnfs_layout_add_bulk_destroy_list(inode, layout_list)) - continue; - rcu_read_unlock(); - spin_unlock(&clp->cl_lock); - iput(inode); + if (inode != NULL) { + list_del_init(&lo->plh_layouts); + if (pnfs_layout_add_bulk_destroy_list(inode, + layout_list)) + continue; + rcu_read_unlock(); + spin_unlock(&clp->cl_lock); + iput(inode); + } else { + rcu_read_unlock(); + spin_unlock(&clp->cl_lock); + set_bit(NFS_LAYOUT_INODE_FREEING, &lo->plh_flags); + } + nfs_sb_deactive(server->super); spin_lock(&clp->cl_lock); rcu_read_lock(); return -EAGAIN; @@ -778,7 +791,7 @@ pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list, /* Free all lsegs that are attached to commit buckets */ nfs_commit_inode(inode, 0); pnfs_put_layout_hdr(lo); - iput(inode); + nfs_iput_and_deactive(inode); } return ret; } diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 87f144f14d1e0c0c6c3232cc54c6e6b4167d5c24..965d657086c8bbb866a0fddb09bb8223f5b9ee0e 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -99,6 +99,7 @@ enum { NFS_LAYOUT_RETURN_REQUESTED, /* Return this layout ASAP */ NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */ NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */ + NFS_LAYOUT_INODE_FREEING, /* The inode is being freed */ }; enum layoutdriver_policy_flags { diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f464f8d9060c0461ce5eaf208c3702b03da83c10..470b761839a51d7a435d7b5f87e78144ad4fab2f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1925,7 +1925,7 @@ static int nfs_parse_devname(const char *dev_name, /* kill possible hostname list: not supported */ comma = strchr(dev_name, ','); if (comma != NULL && comma < end) - *comma = 0; + len = comma - dev_name; } if (len > maxnamlen) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 01b9d9341b541a3988e277c97d75a2044ce6ca43..ed3f5afc4ff7f2e12f3621bf3b4cdb962f958c27 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -643,7 +643,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, return ret; out_launder: nfs_write_error_remove_page(req); - return ret; + return 0; } static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 506da82ff3f14915e6afc75af79570aeb85d981f..a308f7a7e57704787c9fe816aae5440b7ea37289 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -90,6 +90,7 @@ void fsnotify_unmount_inodes(struct super_block *sb) iput_inode = inode; + cond_resched(); spin_lock(&sb->s_inode_list_lock); } spin_unlock(&sb->s_inode_list_lock); diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 2459ae9d2234f6dc19914facacbf7092750d6cc0..39bb80fb2934484e233e06cabecd4b31d0021858 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -1080,6 +1080,14 @@ int ocfs2_journal_load(struct ocfs2_journal *journal, int local, int replayed) ocfs2_clear_journal_error(osb->sb, journal->j_journal, osb->slot_num); + if (replayed) { + jbd2_journal_lock_updates(journal->j_journal); + status = jbd2_journal_flush(journal->j_journal); + jbd2_journal_unlock_updates(journal->j_journal); + if (status < 0) + mlog_errno(status); + } + status = ocfs2_journal_toggle_dirty(osb, 1, replayed); if (status < 0) { mlog_errno(status); diff --git a/fs/proc/base.c b/fs/proc/base.c index 693d67501ea74644bde8607180e2b7640eb5f029..b37ec658c63ae686b4bb401e25edd2e075d69a2a 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3054,6 +3054,9 @@ static ssize_t proc_sched_task_boost_period_write(struct file *file, unsigned int sched_boost_period; int err; + if (!task) + return -ESRCH; + memset(buffer, 0, sizeof(buffer)); if (count > sizeof(buffer) - 1) count = sizeof(buffer) - 1; diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 3fdbdd29702bc26f6d1d2160d41ca2e466f21406..30f5da8f4affafd0ccbee08ecd65103ee7cf14c1 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -976,6 +976,7 @@ static int add_dquot_ref(struct super_block *sb, int type) * later. */ old_inode = inode; + cond_resched(); spin_lock(&sb->s_inode_list_lock); } spin_unlock(&sb->s_inode_list_lock); diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index cc0b22c72e83dab044b3882061adadd4259df8c6..5208d85dd30c55f711b7892601541e401c931ad3 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -629,6 +629,7 @@ static void reiserfs_put_super(struct super_block *s) reiserfs_write_unlock(s); mutex_destroy(&REISERFS_SB(s)->lock); destroy_workqueue(REISERFS_SB(s)->commit_wq); + kfree(REISERFS_SB(s)->s_jdev); kfree(s->s_fs_info); s->s_fs_info = NULL; } @@ -2243,6 +2244,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) kfree(qf_names[j]); } #endif + kfree(sbi->s_jdev); kfree(sbi); s->s_fs_info = NULL; diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 29a0c0969e912571a9ea8b28db5878884c1f14c9..28f6daf371d3df22f7e97c2b777715ad4cd76545 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -319,8 +319,12 @@ static int reiserfs_for_each_xattr(struct inode *inode, out_dir: dput(dir); out: - /* -ENODATA isn't an error */ - if (err == -ENODATA) + /* + * -ENODATA: this object doesn't have any xattrs + * -EOPNOTSUPP: this file system doesn't have xattrs enabled on disk. + * Neither are errors + */ + if (err == -ENODATA || err == -EOPNOTSUPP) err = 0; return err; } diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c index a65108594a070dcade75db6d55869049b875b247..21bc6d2d23cab4ae9c699d3d9e08f3bf1fb77049 100644 --- a/fs/xfs/xfs_quotaops.c +++ b/fs/xfs/xfs_quotaops.c @@ -214,6 +214,9 @@ xfs_fs_rm_xquota( if (XFS_IS_QUOTA_ON(mp)) return -EINVAL; + if (uflags & ~(FS_USER_QUOTA | FS_GROUP_QUOTA | FS_PROJ_QUOTA)) + return -EINVAL; + if (uflags & FS_USER_QUOTA) flags |= XFS_DQ_USER; if (uflags & FS_GROUP_QUOTA) diff --git a/gen_headers_arm.bp b/gen_headers_arm.bp index 3328f0946807e4ae0bffafe4638d5f6c38ed5614..d56ace0fe65abce18a735bf0ce8200d9b316ac41 100644 --- a/gen_headers_arm.bp +++ b/gen_headers_arm.bp @@ -146,6 +146,7 @@ gen_headers_out_arm = [ "linux/bcache.h", "linux/bcm933xx_hcs.h", "linux/bfs_fs.h", + "linux/bgcom_interface.h", "linux/binfmts.h", "linux/blkpg.h", "linux/blktrace_api.h", @@ -296,6 +297,7 @@ gen_headers_out_arm = [ "linux/in.h", "linux/in6.h", "linux/in_route.h", + "linux/incrementalfs.h", "linux/inet_diag.h", "linux/inotify.h", "linux/input-event-codes.h", @@ -610,6 +612,7 @@ gen_headers_out_arm = [ "linux/virtio_mmio.h", "linux/virtio_net.h", "linux/virtio_pci.h", + "linux/virtio_pmem.h", "linux/virtio_ring.h", "linux/virtio_rng.h", "linux/virtio_scsi.h", diff --git a/gen_headers_arm64.bp b/gen_headers_arm64.bp index 59e3ed2c3c507ccebac43b47b6800822c7eac24c..c2beed537f2fd535c2d0bac3c7b88b473d6b10c3 100644 --- a/gen_headers_arm64.bp +++ b/gen_headers_arm64.bp @@ -142,6 +142,7 @@ gen_headers_out_arm64 = [ "linux/bcache.h", "linux/bcm933xx_hcs.h", "linux/bfs_fs.h", + "linux/bgcom_interface.h", "linux/binfmts.h", "linux/blkpg.h", "linux/blktrace_api.h", @@ -292,6 +293,7 @@ gen_headers_out_arm64 = [ "linux/in.h", "linux/in6.h", "linux/in_route.h", + "linux/incrementalfs.h", "linux/inet_diag.h", "linux/inotify.h", "linux/input-event-codes.h", @@ -605,6 +607,7 @@ gen_headers_out_arm64 = [ "linux/virtio_mmio.h", "linux/virtio_net.h", "linux/virtio_pci.h", + "linux/virtio_pmem.h", "linux/virtio_ring.h", "linux/virtio_rng.h", "linux/virtio_scsi.h", diff --git a/include/dt-bindings/clock/qcom,cpu-sdm.h b/include/dt-bindings/clock/qcom,cpu-sdm.h new file mode 100644 index 0000000000000000000000000000000000000000..a9c8b7f6500679c542a80deb0495df0432b6729a --- /dev/null +++ b/include/dt-bindings/clock/qcom,cpu-sdm.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020, 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. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_CPU_SDM_H +#define _DT_BINDINGS_CLK_QCOM_CPU_SDM_H + +#define APCS_CPU_PLL 0 +#define APCS_MUX_C1_CLK 1 +#define APCS_MUX_CCI_CLK 2 + +#endif diff --git a/include/dt-bindings/clock/qcom,gcc-sdm429w.h b/include/dt-bindings/clock/qcom,gcc-sdm429w.h index 5aaf5e814279a92e4f4043191b9c595a58b064e8..6df9141c80c3bad9cbaf8e90f6e3b039a5b6eacd 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm429w.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm429w.h @@ -23,182 +23,183 @@ #define GPLL4_OUT_MAIN 5 #define GPLL0_AO_OUT_MAIN 6 #define GPLL0_SLEEP_CLK_SRC 7 -#define GPLL6_OUT_MAIN 8 -#define GPLL6_OUT_AUX 9 -#define APSS_AHB_CLK_SRC 10 -#define BLSP1_QUP1_I2C_APPS_CLK_SRC 11 -#define BLSP1_QUP1_SPI_APPS_CLK_SRC 12 -#define BLSP1_QUP2_I2C_APPS_CLK_SRC 13 -#define BLSP1_QUP2_SPI_APPS_CLK_SRC 14 -#define BLSP1_QUP3_I2C_APPS_CLK_SRC 15 -#define BLSP1_QUP3_SPI_APPS_CLK_SRC 16 -#define BLSP1_QUP4_I2C_APPS_CLK_SRC 17 -#define BLSP1_QUP4_SPI_APPS_CLK_SRC 18 -#define BLSP1_UART1_APPS_CLK_SRC 19 -#define BLSP1_UART2_APPS_CLK_SRC 20 -#define BLSP2_QUP1_I2C_APPS_CLK_SRC 21 -#define BLSP2_QUP1_SPI_APPS_CLK_SRC 22 -#define BLSP2_QUP2_I2C_APPS_CLK_SRC 23 -#define BLSP2_QUP2_SPI_APPS_CLK_SRC 24 -#define BLSP2_QUP3_I2C_APPS_CLK_SRC 25 -#define BLSP2_QUP3_SPI_APPS_CLK_SRC 26 -#define BLSP2_QUP4_I2C_APPS_CLK_SRC 27 -#define BLSP2_QUP4_SPI_APPS_CLK_SRC 28 -#define BLSP2_UART1_APPS_CLK_SRC 29 -#define BLSP2_UART2_APPS_CLK_SRC 30 -#define BYTE0_CLK_SRC 31 -#define BYTE1_CLK_SRC 32 -#define CAMSS_TOP_AHB_CLK_SRC 33 -#define CCI_CLK_SRC 34 -#define CPP_CLK_SRC 35 -#define CRYPTO_CLK_SRC 36 -#define CSI0_CLK_SRC 37 -#define CSI0PHYTIMER_CLK_SRC 38 -#define CSI1_CLK_SRC 39 -#define CSI1PHYTIMER_CLK_SRC 40 -#define CSI2_CLK_SRC 41 -#define ESC0_CLK_SRC 42 -#define ESC1_CLK_SRC 43 -#define GCC_BIMC_GFX_CLK 44 -#define GCC_BIMC_GPU_CLK 45 -#define GCC_BLSP1_AHB_CLK 46 -#define GCC_BLSP1_QUP1_I2C_APPS_CLK 47 -#define GCC_BLSP1_QUP1_SPI_APPS_CLK 48 -#define GCC_BLSP1_QUP2_I2C_APPS_CLK 49 -#define GCC_BLSP1_QUP2_SPI_APPS_CLK 50 -#define GCC_BLSP1_QUP3_I2C_APPS_CLK 51 -#define GCC_BLSP1_QUP3_SPI_APPS_CLK 52 -#define GCC_BLSP1_QUP4_I2C_APPS_CLK 53 -#define GCC_BLSP1_QUP4_SPI_APPS_CLK 54 -#define GCC_BLSP1_UART1_APPS_CLK 55 -#define GCC_BLSP1_UART2_APPS_CLK 56 -#define GCC_BLSP2_QUP1_I2C_APPS_CLK 57 -#define GCC_BLSP2_QUP1_SPI_APPS_CLK 58 -#define GCC_BLSP2_QUP2_I2C_APPS_CLK 59 -#define GCC_BLSP2_QUP2_SPI_APPS_CLK 60 -#define GCC_BLSP2_QUP3_I2C_APPS_CLK 61 -#define GCC_BLSP2_QUP3_SPI_APPS_CLK 62 -#define GCC_BLSP2_QUP4_I2C_APPS_CLK 63 -#define GCC_BLSP2_QUP4_SPI_APPS_CLK 64 -#define GCC_BLSP2_UART1_APPS_CLK 65 -#define GCC_BLSP2_UART2_APPS_CLK 66 -#define GCC_BLSP2_AHB_CLK 67 -#define GCC_BOOT_ROM_AHB_CLK 68 -#define GCC_CAMSS_AHB_CLK 69 -#define GCC_CAMSS_CCI_AHB_CLK 70 -#define GCC_CAMSS_CCI_CLK 71 -#define GCC_CAMSS_CPP_AHB_CLK 72 -#define GCC_CAMSS_CPP_AXI_CLK 73 -#define GCC_CAMSS_CPP_CLK 74 -#define GCC_CAMSS_CSI0_AHB_CLK 75 -#define GCC_CAMSS_CSI0_CLK 76 -#define GCC_CAMSS_CSI0PHY_CLK 77 -#define GCC_CAMSS_CSI0PIX_CLK 78 -#define GCC_CAMSS_CSI0RDI_CLK 79 -#define GCC_CAMSS_CSI1_AHB_CLK 80 -#define GCC_CAMSS_CSI1_CLK 81 -#define GCC_CAMSS_CSI1PHY_CLK 82 -#define GCC_CAMSS_CSI1PIX_CLK 83 -#define GCC_CAMSS_CSI1RDI_CLK 84 -#define GCC_CAMSS_CSI2_AHB_CLK 85 -#define GCC_CAMSS_CSI2_CLK 86 -#define GCC_CAMSS_CSI2PHY_CLK 87 -#define GCC_CAMSS_CSI2PIX_CLK 88 -#define GCC_CAMSS_CSI2RDI_CLK 89 -#define GCC_CAMSS_CSI_VFE0_CLK 90 -#define GCC_CAMSS_GP0_CLK_SRC 91 -#define GCC_CAMSS_GP1_CLK_SRC 92 -#define GCC_CAMSS_CSI_VFE1_CLK 93 -#define GCC_CAMSS_CSI0PHYTIMER_CLK 94 -#define GCC_CAMSS_CSI1PHYTIMER_CLK 95 -#define GCC_CAMSS_GP0_CLK 96 -#define GCC_CAMSS_GP1_CLK 97 -#define GCC_CAMSS_ISPIF_AHB_CLK 98 -#define GCC_CAMSS_JPEG0_CLK 99 -#define GCC_CAMSS_JPEG_AHB_CLK 100 -#define GCC_CAMSS_JPEG_AXI_CLK 101 -#define GCC_CAMSS_MCLK0_CLK 102 -#define GCC_CAMSS_MCLK1_CLK 103 -#define GCC_CAMSS_MCLK2_CLK 104 -#define GCC_CAMSS_MICRO_AHB_CLK 105 -#define GCC_CAMSS_TOP_AHB_CLK 106 -#define GCC_CAMSS_VFE0_CLK 107 -#define GCC_CAMSS_VFE1_AHB_CLK 108 -#define GCC_CAMSS_VFE1_AXI_CLK 109 -#define GCC_CAMSS_VFE1_CLK 110 -#define GCC_CAMSS_VFE_AHB_CLK 111 -#define GCC_CAMSS_VFE_AXI_CLK 112 -#define GCC_CRYPTO_AHB_CLK 113 -#define GCC_CRYPTO_AXI_CLK 114 -#define GCC_CRYPTO_CLK 115 -#define GCC_DCC_CLK 116 -#define GCC_GP1_CLK 117 -#define GCC_GP2_CLK 118 -#define GCC_GP3_CLK 119 -#define GCC_MDSS_AHB_CLK 120 -#define GCC_MDSS_AXI_CLK 121 -#define GCC_MDSS_BYTE0_CLK 122 -#define GCC_MDSS_BYTE1_CLK 123 -#define GCC_MDSS_ESC0_CLK 124 -#define GCC_MDSS_ESC1_CLK 125 -#define GCC_MDSS_MDP_CLK 126 -#define GCC_MDSS_PCLK0_CLK 127 -#define GCC_MDSS_PCLK1_CLK 128 -#define GCC_MDSS_VSYNC_CLK 129 -#define GCC_MSS_CFG_AHB_CLK 130 -#define GCC_MSS_Q6_BIMC_AXI_CLK 131 -#define GCC_OXILI_AHB_CLK 132 -#define GCC_OXILI_AON_CLK 133 -#define GCC_OXILI_GFX3D_CLK 134 -#define GCC_OXILI_TIMER_CLK 135 -#define GCC_PDM2_CLK 136 -#define GCC_PDM_AHB_CLK 137 -#define GCC_PRNG_AHB_CLK 138 -#define GCC_SDCC1_AHB_CLK 139 -#define GCC_SDCC1_APPS_CLK 140 -#define GCC_SDCC1_ICE_CORE_CLK 141 -#define GCC_SDCC2_AHB_CLK 142 -#define GCC_SDCC2_APPS_CLK 143 -#define GCC_USB2A_PHY_SLEEP_CLK 144 -#define GCC_USB_HS_AHB_CLK 145 -#define GCC_USB_HS_PHY_CFG_AHB_CLK 146 -#define GCC_USB_HS_SYSTEM_CLK 147 -#define GCC_VENUS0_AHB_CLK 148 -#define GCC_VENUS0_AXI_CLK 149 -#define GCC_VENUS0_CORE0_VCODEC0_CLK 150 -#define GCC_VENUS0_VCODEC0_CLK 151 -#define GCC_XO_CLK_SRC 152 -#define GFX3D_CLK_SRC 153 -#define GP1_CLK_SRC 154 -#define GP2_CLK_SRC 155 -#define GP3_CLK_SRC 156 -#define JPEG0_CLK_SRC 157 -#define MCLK0_CLK_SRC 158 -#define MCLK1_CLK_SRC 159 -#define MCLK2_CLK_SRC 160 -#define MDP_CLK_SRC 161 -#define MDSS_MDP_VOTE_CLK 162 -#define MDSS_ROTATOR_VOTE_CLK 163 -#define PCLK0_CLK_SRC 164 -#define PCLK1_CLK_SRC 165 -#define PDM2_CLK_SRC 166 -#define SDCC1_APPS_CLK_SRC 167 -#define SDCC1_ICE_CORE_CLK_SRC 168 -#define SDCC2_APPS_CLK_SRC 169 -#define USB_HS_SYSTEM_CLK_SRC 170 -#define VCODEC0_CLK_SRC 171 -#define VFE0_CLK_SRC 172 -#define VFE1_CLK_SRC 173 -#define VSYNC_CLK_SRC 174 -#define GCC_APSS_TCU_CLK 175 -#define GCC_CPP_TBU_CLK 176 -#define GCC_JPEG_TBU_CLK 177 -#define GCC_MDP_TBU_CLK 178 -#define GCC_SMMU_CFG_CLK 179 -#define GCC_VENUS_TBU_CLK 180 -#define GCC_VFE_TBU_CLK 181 -#define GCC_VFE1_TBU_CLK 182 -#define GCC_QDSS_DAP_CLK 183 +#define GPLL6 8 +#define GPLL6_OUT_MAIN 9 +#define GPLL6_OUT_AUX 10 +#define APSS_AHB_CLK_SRC 11 +#define BLSP1_QUP1_I2C_APPS_CLK_SRC 12 +#define BLSP1_QUP1_SPI_APPS_CLK_SRC 13 +#define BLSP1_QUP2_I2C_APPS_CLK_SRC 14 +#define BLSP1_QUP2_SPI_APPS_CLK_SRC 15 +#define BLSP1_QUP3_I2C_APPS_CLK_SRC 16 +#define BLSP1_QUP3_SPI_APPS_CLK_SRC 17 +#define BLSP1_QUP4_I2C_APPS_CLK_SRC 18 +#define BLSP1_QUP4_SPI_APPS_CLK_SRC 19 +#define BLSP1_UART1_APPS_CLK_SRC 20 +#define BLSP1_UART2_APPS_CLK_SRC 21 +#define BLSP2_QUP1_I2C_APPS_CLK_SRC 22 +#define BLSP2_QUP1_SPI_APPS_CLK_SRC 23 +#define BLSP2_QUP2_I2C_APPS_CLK_SRC 24 +#define BLSP2_QUP2_SPI_APPS_CLK_SRC 25 +#define BLSP2_QUP3_I2C_APPS_CLK_SRC 26 +#define BLSP2_QUP3_SPI_APPS_CLK_SRC 27 +#define BLSP2_QUP4_I2C_APPS_CLK_SRC 28 +#define BLSP2_QUP4_SPI_APPS_CLK_SRC 29 +#define BLSP2_UART1_APPS_CLK_SRC 30 +#define BLSP2_UART2_APPS_CLK_SRC 31 +#define BYTE0_CLK_SRC 32 +#define BYTE1_CLK_SRC 33 +#define CAMSS_TOP_AHB_CLK_SRC 34 +#define CCI_CLK_SRC 35 +#define CPP_CLK_SRC 36 +#define CRYPTO_CLK_SRC 37 +#define CSI0_CLK_SRC 38 +#define CSI0PHYTIMER_CLK_SRC 39 +#define CSI1_CLK_SRC 40 +#define CSI1PHYTIMER_CLK_SRC 41 +#define CSI2_CLK_SRC 42 +#define ESC0_CLK_SRC 43 +#define ESC1_CLK_SRC 44 +#define GCC_BIMC_GFX_CLK 45 +#define GCC_BIMC_GPU_CLK 46 +#define GCC_BLSP1_AHB_CLK 47 +#define GCC_BLSP1_QUP1_I2C_APPS_CLK 48 +#define GCC_BLSP1_QUP1_SPI_APPS_CLK 49 +#define GCC_BLSP1_QUP2_I2C_APPS_CLK 50 +#define GCC_BLSP1_QUP2_SPI_APPS_CLK 51 +#define GCC_BLSP1_QUP3_I2C_APPS_CLK 52 +#define GCC_BLSP1_QUP3_SPI_APPS_CLK 53 +#define GCC_BLSP1_QUP4_I2C_APPS_CLK 54 +#define GCC_BLSP1_QUP4_SPI_APPS_CLK 55 +#define GCC_BLSP1_UART1_APPS_CLK 56 +#define GCC_BLSP1_UART2_APPS_CLK 57 +#define GCC_BLSP2_QUP1_I2C_APPS_CLK 58 +#define GCC_BLSP2_QUP1_SPI_APPS_CLK 59 +#define GCC_BLSP2_QUP2_I2C_APPS_CLK 60 +#define GCC_BLSP2_QUP2_SPI_APPS_CLK 61 +#define GCC_BLSP2_QUP3_I2C_APPS_CLK 62 +#define GCC_BLSP2_QUP3_SPI_APPS_CLK 63 +#define GCC_BLSP2_QUP4_I2C_APPS_CLK 64 +#define GCC_BLSP2_QUP4_SPI_APPS_CLK 65 +#define GCC_BLSP2_UART1_APPS_CLK 66 +#define GCC_BLSP2_UART2_APPS_CLK 67 +#define GCC_BLSP2_AHB_CLK 68 +#define GCC_BOOT_ROM_AHB_CLK 69 +#define GCC_CAMSS_AHB_CLK 70 +#define GCC_CAMSS_CCI_AHB_CLK 71 +#define GCC_CAMSS_CCI_CLK 72 +#define GCC_CAMSS_CPP_AHB_CLK 73 +#define GCC_CAMSS_CPP_AXI_CLK 74 +#define GCC_CAMSS_CPP_CLK 75 +#define GCC_CAMSS_CSI0_AHB_CLK 76 +#define GCC_CAMSS_CSI0_CLK 77 +#define GCC_CAMSS_CSI0PHY_CLK 78 +#define GCC_CAMSS_CSI0PIX_CLK 79 +#define GCC_CAMSS_CSI0RDI_CLK 80 +#define GCC_CAMSS_CSI1_AHB_CLK 81 +#define GCC_CAMSS_CSI1_CLK 82 +#define GCC_CAMSS_CSI1PHY_CLK 83 +#define GCC_CAMSS_CSI1PIX_CLK 84 +#define GCC_CAMSS_CSI1RDI_CLK 85 +#define GCC_CAMSS_CSI2_AHB_CLK 86 +#define GCC_CAMSS_CSI2_CLK 87 +#define GCC_CAMSS_CSI2PHY_CLK 88 +#define GCC_CAMSS_CSI2PIX_CLK 89 +#define GCC_CAMSS_CSI2RDI_CLK 90 +#define GCC_CAMSS_CSI_VFE0_CLK 91 +#define GCC_CAMSS_GP0_CLK_SRC 92 +#define GCC_CAMSS_GP1_CLK_SRC 93 +#define GCC_CAMSS_CSI_VFE1_CLK 94 +#define GCC_CAMSS_CSI0PHYTIMER_CLK 95 +#define GCC_CAMSS_CSI1PHYTIMER_CLK 96 +#define GCC_CAMSS_GP0_CLK 97 +#define GCC_CAMSS_GP1_CLK 98 +#define GCC_CAMSS_ISPIF_AHB_CLK 99 +#define GCC_CAMSS_JPEG0_CLK 100 +#define GCC_CAMSS_JPEG_AHB_CLK 101 +#define GCC_CAMSS_JPEG_AXI_CLK 102 +#define GCC_CAMSS_MCLK0_CLK 103 +#define GCC_CAMSS_MCLK1_CLK 104 +#define GCC_CAMSS_MCLK2_CLK 105 +#define GCC_CAMSS_MICRO_AHB_CLK 106 +#define GCC_CAMSS_TOP_AHB_CLK 107 +#define GCC_CAMSS_VFE0_CLK 108 +#define GCC_CAMSS_VFE1_AHB_CLK 109 +#define GCC_CAMSS_VFE1_AXI_CLK 110 +#define GCC_CAMSS_VFE1_CLK 111 +#define GCC_CAMSS_VFE_AHB_CLK 112 +#define GCC_CAMSS_VFE_AXI_CLK 113 +#define GCC_CRYPTO_AHB_CLK 114 +#define GCC_CRYPTO_AXI_CLK 115 +#define GCC_CRYPTO_CLK 116 +#define GCC_DCC_CLK 117 +#define GCC_GP1_CLK 118 +#define GCC_GP2_CLK 119 +#define GCC_GP3_CLK 120 +#define GCC_MDSS_AHB_CLK 121 +#define GCC_MDSS_AXI_CLK 122 +#define GCC_MDSS_BYTE0_CLK 123 +#define GCC_MDSS_BYTE1_CLK 124 +#define GCC_MDSS_ESC0_CLK 125 +#define GCC_MDSS_ESC1_CLK 126 +#define GCC_MDSS_MDP_CLK 127 +#define GCC_MDSS_PCLK0_CLK 128 +#define GCC_MDSS_PCLK1_CLK 129 +#define GCC_MDSS_VSYNC_CLK 130 +#define GCC_MSS_CFG_AHB_CLK 131 +#define GCC_MSS_Q6_BIMC_AXI_CLK 132 +#define GCC_OXILI_AHB_CLK 133 +#define GCC_OXILI_AON_CLK 134 +#define GCC_OXILI_GFX3D_CLK 135 +#define GCC_OXILI_TIMER_CLK 136 +#define GCC_PDM2_CLK 137 +#define GCC_PDM_AHB_CLK 138 +#define GCC_PRNG_AHB_CLK 139 +#define GCC_SDCC1_AHB_CLK 140 +#define GCC_SDCC1_APPS_CLK 141 +#define GCC_SDCC1_ICE_CORE_CLK 142 +#define GCC_SDCC2_AHB_CLK 143 +#define GCC_SDCC2_APPS_CLK 144 +#define GCC_USB2A_PHY_SLEEP_CLK 145 +#define GCC_USB_HS_AHB_CLK 146 +#define GCC_USB_HS_PHY_CFG_AHB_CLK 147 +#define GCC_USB_HS_SYSTEM_CLK 148 +#define GCC_VENUS0_AHB_CLK 149 +#define GCC_VENUS0_AXI_CLK 150 +#define GCC_VENUS0_CORE0_VCODEC0_CLK 151 +#define GCC_VENUS0_VCODEC0_CLK 152 +#define GCC_XO_CLK_SRC 153 +#define GFX3D_CLK_SRC 154 +#define GP1_CLK_SRC 155 +#define GP2_CLK_SRC 156 +#define GP3_CLK_SRC 157 +#define JPEG0_CLK_SRC 158 +#define MCLK0_CLK_SRC 159 +#define MCLK1_CLK_SRC 160 +#define MCLK2_CLK_SRC 161 +#define MDP_CLK_SRC 162 +#define MDSS_MDP_VOTE_CLK 163 +#define MDSS_ROTATOR_VOTE_CLK 164 +#define PCLK0_CLK_SRC 165 +#define PCLK1_CLK_SRC 166 +#define PDM2_CLK_SRC 167 +#define SDCC1_APPS_CLK_SRC 168 +#define SDCC1_ICE_CORE_CLK_SRC 169 +#define SDCC2_APPS_CLK_SRC 170 +#define USB_HS_SYSTEM_CLK_SRC 171 +#define VCODEC0_CLK_SRC 172 +#define VFE0_CLK_SRC 173 +#define VFE1_CLK_SRC 174 +#define VSYNC_CLK_SRC 175 +#define GCC_APSS_TCU_CLK 176 +#define GCC_CPP_TBU_CLK 177 +#define GCC_JPEG_TBU_CLK 178 +#define GCC_MDP_TBU_CLK 179 +#define GCC_SMMU_CFG_CLK 180 +#define GCC_VENUS_TBU_CLK 181 +#define GCC_VFE_TBU_CLK 182 +#define GCC_VFE1_TBU_CLK 183 +#define GCC_QDSS_DAP_CLK 184 /* GCC resets */ #define GCC_CAMSS_MICRO_BCR 0 diff --git a/include/dt-bindings/reset/amlogic,meson8b-reset.h b/include/dt-bindings/reset/amlogic,meson8b-reset.h index 614aff2c7affe914bf12cb841656f1eb1342aa6e..a03e86fe2c5709b1c1e70253b115a5ee2f2bfb26 100644 --- a/include/dt-bindings/reset/amlogic,meson8b-reset.h +++ b/include/dt-bindings/reset/amlogic,meson8b-reset.h @@ -95,9 +95,9 @@ #define RESET_VD_RMEM 64 #define RESET_AUDIN 65 #define RESET_DBLK 66 -#define RESET_PIC_DC 66 -#define RESET_PSC 66 -#define RESET_NAND 66 +#define RESET_PIC_DC 67 +#define RESET_PSC 68 +#define RESET_NAND 69 #define RESET_GE2D 70 #define RESET_PARSER_REG 71 #define RESET_PARSER_FETCH 72 diff --git a/include/dt-bindings/sound/qcom,gpr.h b/include/dt-bindings/sound/qcom,gpr.h new file mode 100644 index 0000000000000000000000000000000000000000..1ab6d2c99a1d779eced030d01fc87cfd2f19be19 --- /dev/null +++ b/include/dt-bindings/sound/qcom,gpr.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2020, 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. + */ + +#ifndef __DT_BINDINGS_QCOM_GPR_H +#define __DT_BINDINGS_QCOM_GPR_H + +/* Domain IDs */ +#define GPR_DOMAIN_SIM 0x1 +#define GPR_DOMAIN_PC 0x2 +#define GPR_DOMAIN_MODEM 0x3 +#define GPR_DOMAIN_ADSP 0x4 +#define GPR_DOMAIN_APPS 0x5 +#define GPR_DOMAIN_MAX 0x6 + +/* ADSP service IDs */ +#define GPR_SVC_ADSP_CORE 0x3 +#define GPR_SVC_AFE 0x4 +#define GPR_SVC_VSM 0x5 +#define GPR_SVC_VPM 0x6 +#define GPR_SVC_ASM 0x7 +#define GPR_SVC_ADM 0x8 +#define GPR_SVC_ADSP_MVM 0x09 +#define GPR_SVC_ADSP_CVS 0x0A +#define GPR_SVC_ADSP_CVP 0x0B +#define GPR_SVC_USM 0x0C +#define GPR_SVC_LSM 0x0D +#define GPR_SVC_VIDC 0x16 +#define GPR_SVC_MAX 0x17 + +#endif /* __DT_BINDINGS_QCOM_GPR_H */ diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index aec255fb62aad1b01d6de8f9dc1967bf0f84b841..10a4dd02221d5d51b1fbdd7b0d013918a989912b 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -86,6 +86,14 @@ * contain all bit positions from 0 to 'bits' - 1. */ +/* + * Allocation and deallocation of bitmap. + * Provided in lib/bitmap.c to avoid circular dependency. + */ +extern unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags); +extern unsigned long *bitmap_zalloc(unsigned int nbits, gfp_t flags); +extern void bitmap_free(const unsigned long *bitmap); + /* * lib/bitmap.c provides these functions: */ diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2d228d9e6a617cf0592ca57828fa1a3d26ea745e..1673d238b60f3242c12bf026074c92943b241757 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -347,6 +347,7 @@ struct queue_limits { unsigned int max_sectors; unsigned int max_segment_size; unsigned int physical_block_size; + unsigned int logical_block_size; unsigned int alignment_offset; unsigned int io_min; unsigned int io_opt; @@ -357,7 +358,6 @@ struct queue_limits { unsigned int discard_granularity; unsigned int discard_alignment; - unsigned short logical_block_size; unsigned short max_segments; unsigned short max_integrity_segments; unsigned short max_discard_segments; @@ -1190,7 +1190,7 @@ extern void blk_queue_max_write_same_sectors(struct request_queue *q, unsigned int max_write_same_sectors); extern void blk_queue_max_write_zeroes_sectors(struct request_queue *q, unsigned int max_write_same_sectors); -extern void blk_queue_logical_block_size(struct request_queue *, unsigned short); +extern void blk_queue_logical_block_size(struct request_queue *, unsigned int); extern void blk_queue_physical_block_size(struct request_queue *, unsigned int); extern void blk_queue_alignment_offset(struct request_queue *q, unsigned int alignment); @@ -1448,7 +1448,7 @@ static inline unsigned int queue_max_segment_size(struct request_queue *q) return q->limits.max_segment_size; } -static inline unsigned short queue_logical_block_size(struct request_queue *q) +static inline unsigned queue_logical_block_size(struct request_queue *q) { int retval = 512; @@ -1458,7 +1458,7 @@ static inline unsigned short queue_logical_block_size(struct request_queue *q) return retval; } -static inline unsigned short bdev_logical_block_size(struct block_device *bdev) +static inline unsigned int bdev_logical_block_size(struct block_device *bdev) { return queue_logical_block_size(bdev_get_queue(bdev)); } diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index c0c0b992210e99ebced5cafc803cac1823e4c267..995903c7055be3dab9334153eccdeb2a10b9ae2f 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -18,6 +18,7 @@ #include #include #include +#include #include /* @@ -90,6 +91,36 @@ struct can_priv { #define get_can_dlc(i) (min_t(__u8, (i), CAN_MAX_DLC)) #define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC)) +/* Check for outgoing skbs that have not been created by the CAN subsystem */ +static inline bool can_skb_headroom_valid(struct net_device *dev, + struct sk_buff *skb) +{ + /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */ + if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv))) + return false; + + /* af_packet does not apply CAN skb specific settings */ + if (skb->ip_summed == CHECKSUM_NONE) { + /* init headroom */ + can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; + + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* preform proper loopback on capable devices */ + if (dev->flags & IFF_ECHO) + skb->pkt_type = PACKET_LOOPBACK; + else + skb->pkt_type = PACKET_HOST; + + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + } + + return true; +} + /* Drop a given socketbuffer if it does not contain a valid CAN frame. */ static inline bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb) @@ -107,6 +138,9 @@ static inline bool can_dropped_invalid_skb(struct net_device *dev, } else goto inval_skb; + if (!can_skb_headroom_valid(dev, skb)) + goto inval_skb; + return false; inval_skb: diff --git a/include/linux/device.h b/include/linux/device.h index eb0923007e92f60ce3ac60e8e3a8362e09486488..b52773b0598de15bdbedbdea3bdaa21c498a767a 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -684,7 +684,8 @@ extern unsigned long devm_get_free_pages(struct device *dev, gfp_t gfp_mask, unsigned int order); extern void devm_free_pages(struct device *dev, unsigned long addr); -void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res); +void __iomem *devm_ioremap_resource(struct device *dev, + const struct resource *res); /* allows to add/remove a custom action to devres stack */ int devm_add_action(struct device *dev, void (*action)(void *), void *data); diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index a3d4da1cb14da09320cb9ae740026cc6533a8876..76647fd57a0e6410c11b8dceb8de9fe0fe2faa09 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -433,6 +433,8 @@ struct dma_buf { } cb_excl, cb_shared; struct list_head refs; + atomic_t dent_count; + }; /** diff --git a/include/linux/filter.h b/include/linux/filter.h index 5a5786240006e89b0006428e6810cb8f6353cc54..f33f80ee9dc6fa13218cfdff8428ca1a57d02715 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -536,7 +536,7 @@ static inline void bpf_jit_set_header_magic(struct bpf_binary_header *hdr) } #endif -#define BPF_PROG_RUN(filter, ctx) (*(filter)->bpf_func)(ctx, (filter)->insnsi) +#define BPF_PROG_RUN(filter, ctx) bpf_call_func(filter, ctx) #define BPF_SKB_CB_LEN QDISC_CB_PRIV_LEN diff --git a/include/linux/fs.h b/include/linux/fs.h index a9556d1115ef6502a462e9ce30a5404749ba1e10..9948a8fdde3f3d56486171a90b35467e5bd2c707 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3357,6 +3357,7 @@ int proc_nr_dentry(struct ctl_table *table, int write, int proc_nr_inodes(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); int __init get_filesystem_list(char *buf); +int get_filesystem_list_runtime(char *buf); #define __FMODE_EXEC ((__force int) FMODE_EXEC) #define __FMODE_NONOTIFY ((__force int) FMODE_NONOTIFY) diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 28136ff5b4dd08e8c17cf7d0e8aaf094ecfdd293..e65ce4237f52a43cf9b9115a166adc694f77c981 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -20,8 +20,6 @@ #define FS_CRYPTO_BLOCK_SIZE 16 -struct fscrypt_ctx; - /* iv sector for security/pfe/pfk_fscrypt.c and f2fs */ #define PG_DUN(i, p) \ (((((u64)(i)->i_ino) & 0xffffffff) << 32) | ((p)->index & 0xffffffff)) @@ -68,18 +66,9 @@ struct fscrypt_operations { bool (*empty_dir)(struct inode *); unsigned int max_namelen; bool (*is_encrypted)(struct inode *); -}; - -/* Decryption work */ -struct fscrypt_ctx { - union { - struct { - struct bio *bio; - struct work_struct work; - }; - struct list_head free_list; /* Free list */ - }; - u8 flags; /* Flags */ + bool (*has_stable_inodes)(struct super_block *sb); + void (*get_ino_and_lblk_bits)(struct super_block *sb, + int *ino_bits_ret, int *lblk_bits_ret); }; static inline bool fscrypt_has_encryption_key(const struct inode *inode) @@ -108,8 +97,6 @@ static inline void fscrypt_handle_d_move(struct dentry *dentry) /* crypto.c */ extern void fscrypt_enqueue_decrypt_work(struct work_struct *); -extern struct fscrypt_ctx *fscrypt_get_ctx(gfp_t); -extern void fscrypt_release_ctx(struct fscrypt_ctx *); extern struct page *fscrypt_encrypt_pagecache_blocks(struct page *page, unsigned int len, @@ -252,8 +239,6 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname, /* bio.c */ extern void fscrypt_decrypt_bio(struct bio *); -extern void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, - struct bio *bio); extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); @@ -298,16 +283,6 @@ static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work) { } -static inline struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags) -{ - return ERR_PTR(-EOPNOTSUPP); -} - -static inline void fscrypt_release_ctx(struct fscrypt_ctx *ctx) -{ - return; -} - static inline struct page *fscrypt_encrypt_pagecache_blocks(struct page *page, unsigned int len, unsigned int offs, @@ -499,11 +474,6 @@ static inline void fscrypt_decrypt_bio(struct bio *bio) { } -static inline void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, - struct bio *bio) -{ -} - static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, sector_t pblk, unsigned int len) { diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 548fd535fd02399634bace0607471d07b973d8dc..d433f5e292c9fb9ff3175120000cc8dd4e4f4f84 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -28,6 +28,14 @@ static inline struct ethhdr *eth_hdr(const struct sk_buff *skb) return (struct ethhdr *)skb_mac_header(skb); } +/* Prefer this version in TX path, instead of + * skb_reset_mac_header() + eth_hdr() + */ +static inline struct ethhdr *skb_eth_hdr(const struct sk_buff *skb) +{ + return (struct ethhdr *)skb->data; +} + static inline struct ethhdr *inner_eth_hdr(const struct sk_buff *skb) { return (struct ethhdr *)skb_inner_mac_header(skb); diff --git a/include/linux/init.h b/include/linux/init.h index f00665ba66fc530a45161f396e1f41e91b88aab5..a55e03e9703be2910d31961fb26294d54909a1ab 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -133,7 +133,10 @@ extern unsigned int reset_devices; /* used by init/main.c */ void setup_arch(char **); void prepare_namespace(void); -void __init launch_early_services(void); +void launch_early_services(void); +#ifdef CONFIG_EARLY_SERVICES +int get_early_services_status(void); +#endif void __init load_default_modules(void); int __init init_rootfs(void); diff --git a/include/linux/ipa_qdss.h b/include/linux/ipa_qdss.h new file mode 100644 index 0000000000000000000000000000000000000000..eca9cecfb4b72124a926fd9509b806167021b1af --- /dev/null +++ b/include/linux/ipa_qdss.h @@ -0,0 +1,107 @@ +/* Copyright (c) 2020, 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. + */ + +#ifndef _IPA_QDSS_H_ +#define _IPA_QDSS_H_ + +#include + +/** + * enum ipa_qdss_notify - these are the only return items + * @IPA_QDSS_SUCCESS: will be returned as it is for both conn + * and disconn + * @IPA_QDSS_PIPE_CONN_FAILURE: will be returned as negative value + * @IPA_QDSS_PIPE_DISCONN_FAILURE: will be returned as negative value + */ +enum ipa_qdss_notify { + IPA_QDSS_SUCCESS, + IPA_QDSS_PIPE_CONN_FAILURE, + IPA_QDSS_PIPE_DISCONN_FAILURE, +}; + +/** + * struct ipa_qdss_conn_in_params - QDSS -> IPA TX configuration + * @data_fifo_base_addr: Base address of the data FIFO used by BAM + * @data_fifo_size: Size of the data FIFO + * @desc_fifo_base_addr: Base address of the descriptor FIFO by BAM + * @desc_fifo_size: Should be configured to 1 by QDSS + * @bam_p_evt_dest_addr: equivalent to event_ring_doorbell_pa + * physical address of the doorbell that IPA uC + * will update the headpointer of the event ring. + * QDSS should send BAM_P_EVNT_REG address in this var + * Configured with the GSI Doorbell Address. + * GSI sends Update RP by doing a write to this address + * @bam_p_evt_threshold: Threshold level of how many bytes consumed + * @override_eot: if override EOT==1, it doesn't check the EOT bit in + * the descriptor + */ +struct ipa_qdss_conn_in_params { + phys_addr_t data_fifo_base_addr; + u32 data_fifo_size; + phys_addr_t desc_fifo_base_addr; + u32 desc_fifo_size; + phys_addr_t bam_p_evt_dest_addr; + u32 bam_p_evt_threshold; + u32 override_eot; +}; + +/** + * struct ipa_qdss_conn_out_params - information provided + * to QDSS driver + * @rx_db_pa: physical address of IPA doorbell for RX (QDSS->IPA transactions) + * QDSS to take this address and assign it to BAM_P_EVENT_DEST_ADDR + */ +struct ipa_qdss_conn_out_params { + phys_addr_t ipa_rx_db_pa; +}; + +#if defined CONFIG_IPA3 + +/** + * ipa_qdss_conn_pipes - Client should call this + * function to connect QDSS -> IPA pipe + * + * @in: [in] input parameters from client + * @out: [out] output params to client + * + * Note: Should not be called from atomic context + * + * @Return 0 on success, negative on failure + */ +int ipa_qdss_conn_pipes(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out); + +/** + * ipa_qdss_disconn_pipes() - Client should call this + * function to disconnect pipes + * + * Note: Should not be called from atomic context + * + * Returns: 0 on success, negative on failure + */ +int ipa_qdss_disconn_pipes(void); + +#else /* CONFIG_IPA3 */ + +static inline int ipa_qdss_conn_pipes(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out) +{ + return -IPA_QDSS_PIPE_CONN_FAILURE; +} + +static inline int ipa_qdss_disconn_pipes(void) +{ + return -IPA_QDSS_PIPE_DISCONN_FAILURE; +} + +#endif /* CONFIG_IPA3 */ +#endif /* _IPA_QDSS_H_ */ diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 3aa1f35ee9f975fe27b3eed5e68a8dc1d2ee87e8..b8eb16489cbc2af9e34cf21cbaaaaa238b3ca281 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -152,7 +152,7 @@ #define GICR_PROPBASER_nCnB GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, nCnB) #define GICR_PROPBASER_nC GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, nC) #define GICR_PROPBASER_RaWt GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWt) -#define GICR_PROPBASER_RaWb GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWt) +#define GICR_PROPBASER_RaWb GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWb) #define GICR_PROPBASER_WaWt GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, WaWt) #define GICR_PROPBASER_WaWb GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, WaWb) #define GICR_PROPBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWaWt) @@ -179,7 +179,7 @@ #define GICR_PENDBASER_nCnB GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, nCnB) #define GICR_PENDBASER_nC GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, nC) #define GICR_PENDBASER_RaWt GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWt) -#define GICR_PENDBASER_RaWb GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWt) +#define GICR_PENDBASER_RaWb GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWb) #define GICR_PENDBASER_WaWt GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, WaWt) #define GICR_PENDBASER_WaWb GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, WaWb) #define GICR_PENDBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWaWt) @@ -238,7 +238,7 @@ #define GICR_VPROPBASER_nCnB GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, nCnB) #define GICR_VPROPBASER_nC GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, nC) #define GICR_VPROPBASER_RaWt GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWt) -#define GICR_VPROPBASER_RaWb GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWt) +#define GICR_VPROPBASER_RaWb GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWb) #define GICR_VPROPBASER_WaWt GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, WaWt) #define GICR_VPROPBASER_WaWb GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, WaWb) #define GICR_VPROPBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWaWt) @@ -264,7 +264,7 @@ #define GICR_VPENDBASER_nCnB GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, nCnB) #define GICR_VPENDBASER_nC GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, nC) #define GICR_VPENDBASER_RaWt GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWt) -#define GICR_VPENDBASER_RaWb GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWt) +#define GICR_VPENDBASER_RaWb GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWb) #define GICR_VPENDBASER_WaWt GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, WaWt) #define GICR_VPENDBASER_WaWb GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, WaWb) #define GICR_VPENDBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWaWt) @@ -337,7 +337,7 @@ #define GITS_CBASER_nCnB GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, nCnB) #define GITS_CBASER_nC GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, nC) #define GITS_CBASER_RaWt GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWt) -#define GITS_CBASER_RaWb GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWt) +#define GITS_CBASER_RaWb GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWb) #define GITS_CBASER_WaWt GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, WaWt) #define GITS_CBASER_WaWb GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, WaWb) #define GITS_CBASER_RaWaWt GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWaWt) @@ -361,7 +361,7 @@ #define GITS_BASER_nCnB GIC_BASER_CACHEABILITY(GITS_BASER, INNER, nCnB) #define GITS_BASER_nC GIC_BASER_CACHEABILITY(GITS_BASER, INNER, nC) #define GITS_BASER_RaWt GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWt) -#define GITS_BASER_RaWb GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWt) +#define GITS_BASER_RaWb GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWb) #define GITS_BASER_WaWt GIC_BASER_CACHEABILITY(GITS_BASER, INNER, WaWt) #define GITS_BASER_WaWb GIC_BASER_CACHEABILITY(GITS_BASER, INNER, WaWb) #define GITS_BASER_RaWaWt GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWaWt) diff --git a/include/linux/kcov.h b/include/linux/kcov.h index f5d8ce4f4f8667d8fd1002f058c8b56f250d480a..a10e84707d820b54739f7dde0064c9334ac6c6e5 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -8,23 +8,64 @@ struct task_struct; #ifdef CONFIG_KCOV -void kcov_task_init(struct task_struct *t); -void kcov_task_exit(struct task_struct *t); - enum kcov_mode { /* Coverage collection is not enabled yet. */ KCOV_MODE_DISABLED = 0, + /* KCOV was initialized, but tracing mode hasn't been chosen yet. */ + KCOV_MODE_INIT = 1, /* * Tracing coverage collection mode. * Covered PCs are collected in a per-task buffer. */ - KCOV_MODE_TRACE = 1, + KCOV_MODE_TRACE_PC = 2, + /* Collecting comparison operands mode. */ + KCOV_MODE_TRACE_CMP = 3, }; +#define KCOV_IN_CTXSW (1 << 30) + +void kcov_task_init(struct task_struct *t); +void kcov_task_exit(struct task_struct *t); + +#define kcov_prepare_switch(t) \ +do { \ + (t)->kcov_mode |= KCOV_IN_CTXSW; \ +} while (0) + +#define kcov_finish_switch(t) \ +do { \ + (t)->kcov_mode &= ~KCOV_IN_CTXSW; \ +} while (0) + +/* See Documentation/dev-tools/kcov.rst for usage details. */ +void kcov_remote_start(u64 handle); +void kcov_remote_stop(void); +u64 kcov_common_handle(void); + +static inline void kcov_remote_start_common(u64 id) +{ + kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_COMMON, id)); +} + +static inline void kcov_remote_start_usb(u64 id) +{ + kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_USB, id)); +} + #else static inline void kcov_task_init(struct task_struct *t) {} static inline void kcov_task_exit(struct task_struct *t) {} +static inline void kcov_prepare_switch(struct task_struct *t) {} +static inline void kcov_finish_switch(struct task_struct *t) {} +static inline void kcov_remote_start(u64 handle) {} +static inline void kcov_remote_stop(void) {} +static inline u64 kcov_common_handle(void) +{ + return 0; +} +static inline void kcov_remote_start_common(u64 id) {} +static inline void kcov_remote_start_usb(u64 id) {} #endif /* CONFIG_KCOV */ #endif /* _LINUX_KCOV_H */ diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 3eaad2fbf284ea81688316a6a623f062adeadb4c..84284e3353ed03ceaf3f64f6a3637fb11fc7d9dd 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -18,6 +18,7 @@ #include #include #include +#include enum { /* when a dimm supports both PMEM and BLK access a label is required */ @@ -36,6 +37,9 @@ enum { /* region flag indicating to direct-map persistent memory by default */ ND_REGION_PAGEMAP = 0, + /* Platform provides asynchronous flush mechanism */ + ND_REGION_ASYNC = 3, + /* mark newly adjusted resources as requiring a label update */ DPA_RESOURCE_ADJUSTED = 1 << 0, }; @@ -53,12 +57,14 @@ typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc); +struct device_node; struct nvdimm_bus_descriptor { const struct attribute_group **attr_groups; unsigned long bus_dsm_mask; unsigned long cmd_mask; struct module *module; char *provider_name; + struct device_node *of_node; ndctl_fn ndctl; int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc); int (*clear_to_send)(struct nvdimm_bus_descriptor *nd_desc, @@ -90,6 +96,7 @@ struct nd_mapping_desc { int position; }; +struct nd_region; struct nd_region_desc { struct resource *res; struct nd_mapping_desc *mapping; @@ -100,6 +107,8 @@ struct nd_region_desc { int num_lanes; int numa_node; unsigned long flags; + struct device_node *of_node; + int (*flush)(struct nd_region *nd_region, struct bio *bio); }; struct device; @@ -171,7 +180,8 @@ unsigned long nd_blk_memremap_flags(struct nd_blk_region *ndbr); unsigned int nd_region_acquire_lane(struct nd_region *nd_region); void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane); u64 nd_fletcher64(void *addr, size_t len, bool le); -void nvdimm_flush(struct nd_region *nd_region); +int nvdimm_flush(struct nd_region *nd_region, struct bio *bio); +int generic_nvdimm_flush(struct nd_region *nd_region); int nvdimm_has_flush(struct nd_region *nd_region); int nvdimm_has_cache(struct nd_region *nd_region); diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index d1431c1bfed3308053f87fbb86fee8400497c7ea..f40789bd5c153654ff358140592147dc11b171c0 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1729,6 +1729,14 @@ union security_list_options { int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux); void (*bpf_prog_free_security)(struct bpf_prog_aux *aux); #endif /* CONFIG_BPF_SYSCALL */ +#ifdef CONFIG_PERF_EVENTS + int (*perf_event_open)(struct perf_event_attr *attr, int type); + int (*perf_event_alloc)(struct perf_event *event); + void (*perf_event_free)(struct perf_event *event); + int (*perf_event_read)(struct perf_event *event); + int (*perf_event_write)(struct perf_event *event); + +#endif }; struct security_hook_heads { @@ -1958,6 +1966,13 @@ struct security_hook_heads { struct list_head bpf_prog_alloc_security; struct list_head bpf_prog_free_security; #endif /* CONFIG_BPF_SYSCALL */ +#ifdef CONFIG_PERF_EVENTS + struct list_head perf_event_open; + struct list_head perf_event_alloc; + struct list_head perf_event_free; + struct list_head perf_event_read; + struct list_head perf_event_write; +#endif } __randomize_layout; /* diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 5460fc206d7e2fe615f21adab5a5fd342e532cd5..9c422c96b7183e6c2b506886d0ab6c18b724ccb9 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -610,6 +610,30 @@ void mhi_device_get(struct mhi_device *mhi_dev, int vote); */ int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote); +/** + * mhi_device_get_sync_atomic - Asserts device_wait and moves device to M0 + * @mhi_dev: Device associated with the channels + * @timeout_us: timeout, in micro-seconds + * + * The device_wake is asserted to keep device in M0 or bring it to M0. + * If device is not in M0 state, then this function will wait for device to + * move to M0, until @timeout_us elapses. + * However, if device's M1 state-change event races with this function + * then there is a possiblity of device moving from M0 to M2 and back + * to M0. That can't be avoided as host must transition device from M1 to M2 + * as per the spec. + * Clients can ignore that transition after this function returns as the device + * is expected to immediately move from M2 to M0 as wake is asserted and + * wouldn't enter low power state. + * + * Returns: + * 0 if operation was successful (however, M0 -> M2 -> M0 is possible later) as + * mentioned above. + * -ETIMEDOUT is device faled to move to M0 before @timeout_us elapsed + * -EIO if the MHI state is one of the ERROR states. + */ +int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev, int timeout_us); + /** * mhi_device_put - re-enable low power modes * @mhi_dev: Device associated with the channels diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 1d793d86d55fa1ba444fd64cc417cdd9071ecaf8..6ffa181598e61c5a2d4bb511c12143167214dea9 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -8671,8 +8671,6 @@ struct mlx5_ifc_query_lag_out_bits { u8 syndrome[0x20]; - u8 reserved_at_40[0x40]; - struct mlx5_ifc_lagc_bits ctx; }; diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 0a7abe8a407ff223bfdbd18890a0b20bac9f4aee..68bbbd9edc08e6b9b319899d90fbf68a164bd305 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -67,6 +67,8 @@ #define SDIO_VENDOR_ID_TI 0x0097 #define SDIO_DEVICE_ID_TI_WL1271 0x4076 +#define SDIO_VENDOR_ID_TI_WL1251 0x104c +#define SDIO_DEVICE_ID_TI_WL1251 0x9066 #define SDIO_VENDOR_ID_STE 0x0020 #define SDIO_DEVICE_ID_STE_CW1200 0x2280 diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 7490f2592f3a0b7413f2feed89bbd12503c78e7d..129ceb61cfca80b4cc16e934e6845b13268be87f 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -452,6 +452,18 @@ struct spi_device_id { kernel_ulong_t driver_data; /* Data private to the driver */ }; +/* gpr */ +#define GPR_NAME_SIZE 32 +#define GPR_MODULE_PREFIX "gpr:" + +struct gpr_device_id { + char name[GPR_NAME_SIZE]; + __u32 domain_id; + __u32 svc_id; + __u32 svc_version; + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + #define SPMI_NAME_SIZE 32 #define SPMI_MODULE_PREFIX "spmi:" diff --git a/include/linux/msm-sps.h b/include/linux/msm-sps.h index 719f79d502525377c349c5ce7b1fc5525f08f5db..138537d923fd04cddff9886010cdd649c603cf2e 100644 --- a/include/linux/msm-sps.h +++ b/include/linux/msm-sps.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, 2020, 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 @@ -211,6 +211,8 @@ enum sps_option { SPS_O_NO_EP_SYNC = 0x40000000, /* Allow partial polling duing IRQ mode */ SPS_O_HYBRID = 0x80000000, + /* Allow dummy BAM connection */ + SPS_O_DUMMY_PEER = 0x00000400, }; /** @@ -490,7 +492,7 @@ struct sps_bam_props { * */ struct sps_mem_buffer { - void *base; + void __iomem *base; phys_addr_t phys_base; unsigned long iova; u32 size; diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index de179ee36d1364f24025d18ec94b4ae30807ab7e..520a53033484208eb7793e61c8d63a2bc58149c6 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -234,6 +234,8 @@ enum gsi_chan_prot { GSI_CHAN_PROT_MHIP = 0x7, GSI_CHAN_PROT_AQC = 0x8, GSI_CHAN_PROT_11AD = 0x9, + GSI_CHAN_PROT_MHIC = 0xA, + GSI_CHAN_PROT_QDSS = 0xB, }; enum gsi_chan_dir { @@ -917,6 +919,32 @@ struct __packed gsi_wdi3_channel_scratch { uint32_t reserved2 : 16; }; +/** + * gsi_qdss_channel_scratch - QDSS SW config area of + * channel scratch + * + * @bam_p_evt_dest_addr: equivalent to event_ring_doorbell_pa + * physical address of the doorbell that IPA uC + * will update the headpointer of the event ring. + * QDSS should send BAM_P_EVNT_REG address in this var + * Configured with the GSI Doorbell Address. + * GSI sends Update RP by doing a write to this address + * @data_fifo_base_addr: Base address of the data FIFO used by BAM + * @data_fifo_size: Size of the data FIFO + * @bam_p_evt_threshold: Threshold level of how many bytes consumed + * @override_eot: if override EOT==1, it doesn't check the EOT bit in + * the descriptor + */ +struct __packed gsi_qdss_channel_scratch { + uint32_t bam_p_evt_dest_addr; + uint32_t data_fifo_base_addr; + uint32_t data_fifo_size : 16; + uint32_t bam_p_evt_threshold : 16; + uint32_t reserved1 : 2; + uint32_t override_eot : 1; + uint32_t reserved2 : 29; +}; + /** * gsi_wdi3_channel_scratch2 - WDI3 protocol SW config area of * channel scratch2 @@ -969,6 +997,7 @@ union __packed gsi_channel_scratch { struct __packed gsi_wdi3_channel_scratch wdi3; struct __packed gsi_mhip_channel_scratch mhip; struct __packed gsi_wdi2_channel_scratch_new wdi2_new; + struct __packed gsi_qdss_channel_scratch qdss; struct __packed { uint32_t word1; uint32_t word2; @@ -1727,7 +1756,6 @@ int gsi_halt_channel_ee(unsigned int chan_idx, unsigned int ee, int *code); void gsi_wdi3_write_evt_ring_db(unsigned long chan_hdl, uint32_t db_addr_low, uint32_t db_addr_high); - /** * gsi_wdi3_dump_register - dump wdi3 related gsi registers * diff --git a/include/linux/ndctl.h b/include/linux/ndctl.h new file mode 100644 index 0000000000000000000000000000000000000000..cd5a293ce3aef7c71145b3d8cb6dc1fca7f9c2a5 --- /dev/null +++ b/include/linux/ndctl.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014-2016, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + */ +#ifndef _LINUX_NDCTL_H +#define _LINUX_NDCTL_H + +#include + +enum { + ND_MIN_NAMESPACE_SIZE = PAGE_SIZE, +}; + +#endif /* _LINUX_NDCTL_H */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b6ad6697aaa18d22ccb55cd0934b6d1ca80832f7..a62f40f633a81e7f9f7e756ce7f3cb56ab84621d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3351,6 +3351,7 @@ int dev_set_alias(struct net_device *, const char *, size_t); int dev_change_net_namespace(struct net_device *, struct net *, const char *); int __dev_set_mtu(struct net_device *, int); int dev_set_mtu(struct net_device *, int); +int dev_validate_mtu(struct net_device *dev, int mtu); void dev_set_group(struct net_device *, int); int dev_set_mac_address(struct net_device *, struct sockaddr *); int dev_change_carrier(struct net_device *, bool new_carrier); diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index 91a533bd3eb19d1447b122e07b8e2f347403480a..b7246b7e0bf4932620e44530407910b50670bd48 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -445,13 +445,6 @@ ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr) sizeof(*addr)); } -/* Calculate the bytes required to store the inclusive range of a-b */ -static inline int -bitmap_bytes(u32 a, u32 b) -{ - return 4 * ((((b - a + 8) / 8) + 3) / 4); -} - #include #include #include diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 729adf5becc1443a87ca56dd6a27f82c46287a7f..621342fbb3b4f53204a323ce884f7910197c78a4 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -54,6 +54,7 @@ struct perf_guest_info_callbacks { #include #include #include +#include #include struct perf_callchain_entry { @@ -722,6 +723,9 @@ struct perf_event { int cgrp_defer_enabled; #endif +#ifdef CONFIG_SECURITY + void *security; +#endif struct list_head sb_list; /* @@ -1195,24 +1199,46 @@ extern int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write, int perf_event_max_stack_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); +/* Access to perf_event_open(2) syscall. */ +#define PERF_SECURITY_OPEN 0 + +/* Finer grained perf_event_open(2) access control. */ +#define PERF_SECURITY_CPU 1 +#define PERF_SECURITY_KERNEL 2 +#define PERF_SECURITY_TRACEPOINT 3 + static inline bool perf_paranoid_any(void) { return sysctl_perf_event_paranoid > 2; } -static inline bool perf_paranoid_tracepoint_raw(void) +static inline int perf_is_paranoid(void) { return sysctl_perf_event_paranoid > -1; } -static inline bool perf_paranoid_cpu(void) +static inline int perf_allow_kernel(struct perf_event_attr *attr) { - return sysctl_perf_event_paranoid > 0; + if (sysctl_perf_event_paranoid > 1 && !capable(CAP_SYS_ADMIN)) + return -EACCES; + + return security_perf_event_open(attr, PERF_SECURITY_KERNEL); } -static inline bool perf_paranoid_kernel(void) +static inline int perf_allow_cpu(struct perf_event_attr *attr) { - return sysctl_perf_event_paranoid > 1; + if (sysctl_perf_event_paranoid > 0 && !capable(CAP_SYS_ADMIN)) + return -EACCES; + + return security_perf_event_open(attr, PERF_SECURITY_CPU); +} + +static inline int perf_allow_tracepoint(struct perf_event_attr *attr) +{ + if (sysctl_perf_event_paranoid > -1 && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + return security_perf_event_open(attr, PERF_SECURITY_TRACEPOINT); } extern void perf_event_init(void); diff --git a/include/linux/platform_data/dma-imx-sdma.h b/include/linux/platform_data/dma-imx-sdma.h index 6eaa53cef0bd228b8a0d7bb2b3938ff04c548f95..30e676b36b247a595c39e98d7c59bdaa7e6eb233 100644 --- a/include/linux/platform_data/dma-imx-sdma.h +++ b/include/linux/platform_data/dma-imx-sdma.h @@ -51,7 +51,10 @@ struct sdma_script_start_addrs { /* End of v2 array */ s32 zcanfd_2_mcu_addr; s32 zqspi_2_mcu_addr; + s32 mcu_2_ecspi_addr; /* End of v3 array */ + s32 mcu_2_zqspi_addr; + /* End of v4 array */ }; /** diff --git a/include/linux/poll.h b/include/linux/poll.h index d384f12abdd59d58b425eaf8cf945e14c0f1cf83..c7acd7c097471cc58dd563c8a6b2b79c0b20a40a 100644 --- a/include/linux/poll.h +++ b/include/linux/poll.h @@ -15,7 +15,11 @@ extern struct ctl_table epoll_table[]; /* for sysctl */ /* ~832 bytes of stack space used max in sys_select/sys_poll before allocating additional memory. */ +#ifdef __clang__ +#define MAX_STACK_ALLOC 768 +#else #define MAX_STACK_ALLOC 832 +#endif #define FRONTEND_STACK_ALLOC 256 #define SELECT_STACK_ALLOC FRONTEND_STACK_ALLOC #define POLL_STACK_ALLOC FRONTEND_STACK_ALLOC diff --git a/include/linux/qcom_eth_smmu.h b/include/linux/qcom_eth_smmu.h new file mode 100644 index 0000000000000000000000000000000000000000..53f0a83c648a1f3c73a740fca7e0c09fde1cf36f --- /dev/null +++ b/include/linux/qcom_eth_smmu.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2020 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. + */ + +#ifndef _QCOM_ETH_SMMU_H_ +#define _QCOM_ETH_SMMU_H_ + +#include + + +int qcom_smmu_register(struct pci_driver *pdrv); +void qcom_smmu_unregister(struct pci_driver *pdrv); + + +#endif // _QCOM_ETH_SMMU_H_ + diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 260c4aa1d9761aed1e52f92537ce984ecd1d0740..3f6b8b9ef49da3258c53e0eae4660b150fe5bc25 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -43,8 +43,6 @@ enum ab8505_regulator_id { AB8505_LDO_ANAMIC2, AB8505_LDO_AUX8, AB8505_LDO_ANA, - AB8505_SYSCLKREQ_2, - AB8505_SYSCLKREQ_4, AB8505_NUM_REGULATORS, }; diff --git a/include/linux/sched.h b/include/linux/sched.h index ae9a5c28245866447d57f15e1296d9dd6c36cf4a..0a6475eaa1c831a6bcc7e534bd8aeb133b485f71 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1300,8 +1300,10 @@ struct task_struct { #endif /* CONFIG_TRACING */ #ifdef CONFIG_KCOV + /* See kernel/kcov.c for more details. */ + /* Coverage collection mode enabled for this task (0 if disabled): */ - enum kcov_mode kcov_mode; + unsigned int kcov_mode; /* Size of the kcov_area: */ unsigned int kcov_size; @@ -1311,6 +1313,12 @@ struct task_struct { /* KCOV descriptor wired with this task or NULL: */ struct kcov *kcov; + + /* KCOV common handle for remote coverage collection: */ + u64 kcov_handle; + + /* KCOV sequence number: */ + int kcov_sequence; #endif #ifdef CONFIG_MEMCG diff --git a/include/linux/security.h b/include/linux/security.h index 0cd947e5fb00edc4f6ef7facfe83f56b1df064e9..ecd3b0dd9c120d6c3cc5ffd0bb5cc6db6368f1f2 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1811,5 +1811,42 @@ static inline void free_secdata(void *secdata) { } #endif /* CONFIG_SECURITY */ -#endif /* ! __LINUX_SECURITY_H */ +#ifdef CONFIG_PERF_EVENTS +struct perf_event_attr; +struct perf_event; + +#ifdef CONFIG_SECURITY +extern int security_perf_event_open(struct perf_event_attr *attr, int type); +extern int security_perf_event_alloc(struct perf_event *event); +extern void security_perf_event_free(struct perf_event *event); +extern int security_perf_event_read(struct perf_event *event); +extern int security_perf_event_write(struct perf_event *event); +#else +static inline int security_perf_event_open(struct perf_event_attr *attr, + int type) +{ + return 0; +} + +static inline int security_perf_event_alloc(struct perf_event *event) +{ + return 0; +} + +static inline void security_perf_event_free(struct perf_event *event) +{ +} + +static inline int security_perf_event_read(struct perf_event *event) +{ + return 0; +} +static inline int security_perf_event_write(struct perf_event *event) +{ + return 0; +} +#endif /* CONFIG_SECURITY */ +#endif /* CONFIG_PERF_EVENTS */ + +#endif /* ! __LINUX_SECURITY_H */ diff --git a/include/linux/signal.h b/include/linux/signal.h index 843bd62b1eadf03962ada053a0ab991e6fcc81b1..c4e3eb89a6229c105e98f5f32129593bde61daf0 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -268,6 +268,9 @@ extern void signal_setup_done(int failed, struct ksignal *ksig, int stepping); extern void exit_signals(struct task_struct *tsk); extern void kernel_sigaction(int, __sighandler_t); +#define SIG_KTHREAD ((__force __sighandler_t)2) +#define SIG_KTHREAD_KERNEL ((__force __sighandler_t)3) + static inline void allow_signal(int sig) { /* @@ -275,7 +278,17 @@ static inline void allow_signal(int sig) * know it'll be handled, so that they don't get converted to * SIGKILL or just silently dropped. */ - kernel_sigaction(sig, (__force __sighandler_t)2); + kernel_sigaction(sig, SIG_KTHREAD); +} + +static inline void allow_kernel_signal(int sig) +{ + /* + * Kernel threads handle their own signals. Let the signal code + * know signals sent by the kernel will be handled, so that they + * don't get silently dropped. + */ + kernel_sigaction(sig, SIG_KTHREAD_KERNEL); } static inline void disallow_signal(int sig) diff --git a/include/linux/spi/qcom-spi.h b/include/linux/spi/qcom-spi.h index 099ad965fc8bec8ffb80662cd4b05dd3ae421d9d..137fc66be6e88db26749dae98db7da8f84350730 100644 --- a/include/linux/spi/qcom-spi.h +++ b/include/linux/spi/qcom-spi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, 2020 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 @@ -34,7 +34,10 @@ * @bam_producer_pipe_index BAM producer pipe * @rt_priority true if RT thread * @use_pinctrl true if pinctrl library is used - * @is_shared true when qup is shared between ee's + * @is_shared true when qup is shared between ee's and client driver is not + in control of spi pm_runtime_get_sync/put_sync. + * @shared_ee true when qup is shared between ee's and client driver is in + control of spi pm_runtime_get_sync/put_sync. */ struct msm_spi_platform_data { u32 max_clock_speed; @@ -53,4 +56,5 @@ struct msm_spi_platform_data { bool rt_priority; bool use_pinctrl; bool is_shared; + bool shared_ee; }; diff --git a/include/linux/stat.h b/include/linux/stat.h index 22484e44544d56c8e069b90861f4ce7699c4db66..07295841fccd0c1decb1c75e1d07f9052dba6fb5 100644 --- a/include/linux/stat.h +++ b/include/linux/stat.h @@ -33,7 +33,8 @@ struct kstat { STATX_ATTR_IMMUTABLE | \ STATX_ATTR_APPEND | \ STATX_ATTR_NODUMP | \ - STATX_ATTR_ENCRYPTED \ + STATX_ATTR_ENCRYPTED | \ + STATX_ATTR_VERITY \ )/* Attrs corresponding to FS_*_FL flags */ u64 ino; dev_t dev; diff --git a/include/linux/usb/irda.h b/include/linux/usb/irda.h index 396d2b043e6476fe98c578eff331a36aa4d8ba61..556a801efce30163fca9588a6f6a2d4d9d17d8fe 100644 --- a/include/linux/usb/irda.h +++ b/include/linux/usb/irda.h @@ -119,11 +119,22 @@ struct usb_irda_cs_descriptor { * 6 - 115200 bps * 7 - 576000 bps * 8 - 1.152 Mbps - * 9 - 5 mbps + * 9 - 4 Mbps * 10..15 - Reserved */ #define USB_IRDA_STATUS_LINK_SPEED 0x0f +#define USB_IRDA_LS_NO_CHANGE 0 +#define USB_IRDA_LS_2400 1 +#define USB_IRDA_LS_9600 2 +#define USB_IRDA_LS_19200 3 +#define USB_IRDA_LS_38400 4 +#define USB_IRDA_LS_57600 5 +#define USB_IRDA_LS_115200 6 +#define USB_IRDA_LS_576000 7 +#define USB_IRDA_LS_1152000 8 +#define USB_IRDA_LS_4000000 9 + /* The following is a 4-bit value used only for * outbound header: * diff --git a/include/linux/usb/usb_bridge.h b/include/linux/usb/usb_bridge.h index a48c180d236ba19f5ac7ffa48a8d9f5d8f559e59..af25b51071a81d1d7ae1d88fab1c78cb2083cc1e 100644 --- a/include/linux/usb/usb_bridge.h +++ b/include/linux/usb/usb_bridge.h @@ -23,6 +23,7 @@ enum bridge_id { USB_BRIDGE_QDSS, USB_BRIDGE_DPL, USB_BRIDGE_EDL, + USB_BRIDGE_DIAG, MAX_BRIDGE_DEVICES, }; @@ -37,6 +38,8 @@ static int bridge_name_to_id(const char *name) return USB_BRIDGE_DPL; if (!strncasecmp(name, "edl", MAX_INST_NAME_LEN)) return USB_BRIDGE_EDL; + if (!strncasecmp(name, "diag", MAX_INST_NAME_LEN)) + return USB_BRIDGE_DIAG; fail: return -EINVAL; @@ -51,6 +54,8 @@ static int bridge_id_to_protocol(enum bridge_id id) return 0x80; case USB_BRIDGE_EDL: return 0x10; + case USB_BRIDGE_DIAG: + return 0x30; default: return -EINVAL; } diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 0decda7587b9d045a2690d5294252c06cdaa46d7..4d814a42e0e2e17862b7e96961a450e6f5e3d11f 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -100,11 +100,24 @@ enum wcnss_log_type { #define PRONTO_PMU_OFFSET 0x1004 #define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP BIT(5) +enum wcnss_driver_state { + WCNSS_SMD_OPEN, + WCNSS_SMD_CLOSE, +}; + +struct wcnss_driver_ops { + char *name; + void *priv_data; + int (*driver_state)(void *priv, enum wcnss_driver_state state); +}; + struct device *wcnss_wlan_get_device(void); void wcnss_get_monotonic_boottime(struct timespec *ts); struct resource *wcnss_wlan_get_memory_map(struct device *dev); int wcnss_wlan_get_dxe_tx_irq(struct device *dev); int wcnss_wlan_get_dxe_rx_irq(struct device *dev); +int wcnss_register_driver(struct wcnss_driver_ops *ops, void *priv); +int wcnss_unregister_driver(struct wcnss_driver_ops *ops); void wcnss_wlan_register_pm_ops(struct device *dev, const struct dev_pm_ops *pm_ops); void wcnss_wlan_unregister_pm_ops(struct device *dev, @@ -169,6 +182,8 @@ int wcnss_get_wlan_unsafe_channel( u16 *ch_count); struct rpmsg_endpoint *wcnss_open_channel(const char *name, rpmsg_rx_cb_t cb, void *priv); +void wcnss_close_channel(struct rpmsg_endpoint *channel); +int wcnss_smd_tx(struct rpmsg_endpoint *channel, void *data, int len); #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev) #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data)) /* WLAN driver uses these names */ diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h index 79a566d7defd00353651c8a06fc0d3a3d62a8615..180a05e91497936611c2b340a755fc6e9491207d 100644 --- a/include/media/davinci/vpbe.h +++ b/include/media/davinci/vpbe.h @@ -92,7 +92,7 @@ struct vpbe_config { struct encoder_config_info *ext_encoders; /* amplifier information goes here */ struct amp_config_info *amp; - int num_outputs; + unsigned int num_outputs; /* Order is venc outputs followed by LCD and then external encoders */ struct vpbe_output *outputs; }; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e34336870fa7212ca894cbd2ddcf207eabd241fd..9f46a00215a8814eb4d506df3c3f0df6774a9c91 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2981,6 +2981,9 @@ struct cfg80211_update_owe_info { * * @start_radar_detection: Start radar detection in the driver. * + * @end_cac: End running CAC, probably because a related CAC + * was finished on another phy. + * * @update_ft_ies: Provide updated Fast BSS Transition information to the * driver. If the SME is in the driver/firmware, this information can be * used in building Authentication and Reassociation Request frames. @@ -3296,6 +3299,8 @@ struct cfg80211_ops { struct net_device *dev, struct cfg80211_chan_def *chandef, u32 cac_time_ms); + void (*end_cac)(struct wiphy *wiphy, + struct net_device *dev); int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_update_ft_ies_params *ftie); int (*crit_proto_start)(struct wiphy *wiphy, @@ -4655,6 +4660,17 @@ static inline const u8 *cfg80211_find_ext_ie(u8 ext_eid, const u8 *ies, int len) const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type, const u8 *ies, int len); +/** + * cfg80211_send_layer2_update - send layer 2 update frame + * + * @dev: network device + * @addr: STA MAC address + * + * Wireless drivers can use this function to update forwarding tables in bridge + * devices upon STA association. + */ +void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr); + /** * DOC: Regulatory enforcement infrastructure * diff --git a/include/net/cnss2.h b/include/net/cnss2.h index 0c47377c55865f3d37f8d3607d87f7fcb61c92e3..5ad24a14657046ba1bdb630c5787ee2f58007a40 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -225,6 +225,7 @@ extern int cnss_wlan_pm_control(struct device *dev, bool vote); extern int cnss_auto_suspend(struct device *dev); extern int cnss_auto_resume(struct device *dev); extern int cnss_pci_is_drv_connected(struct device *dev); +extern int cnss_pci_force_wake_request_sync(struct device *dev, int timeout); extern int cnss_pci_force_wake_request(struct device *dev); extern int cnss_pci_is_device_awake(struct device *dev); extern int cnss_pci_force_wake_release(struct device *dev); diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 5ac169a735f4bdfab76d76f2036488bcf5e0347a..c25b2e75732b3cbf39a6897453e581f540d56aa7 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -34,12 +34,6 @@ struct genl_info; * do additional, common, filtering and return an error * @post_doit: called after an operation's doit callback, it may * undo operations done by pre_doit, for example release locks - * @mcast_bind: a socket bound to the given multicast group (which - * is given as the offset into the groups array) - * @mcast_unbind: a socket was unbound from the given multicast group. - * Note that unbind() will not be called symmetrically if the - * generic netlink family is removed while there are still open - * sockets. * @attrbuf: buffer to store parsed attributes (private) * @mcgrps: multicast groups used by this family * @n_mcgrps: number of multicast groups @@ -62,8 +56,6 @@ struct genl_family { void (*post_doit)(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info); - int (*mcast_bind)(struct net *net, int group); - void (*mcast_unbind)(struct net *net, int group); struct nlattr ** attrbuf; /* private */ const struct genl_ops * ops; const struct genl_multicast_group *mcgrps; diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 23e22054aa60d653a4b4db62cbea13d30adfd945..04aa2c7d35c4e42f2af383430d46f4717bd66290 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -181,7 +181,7 @@ void reqsk_fastopen_remove(struct sock *sk, struct request_sock *req, static inline bool reqsk_queue_empty(const struct request_sock_queue *queue) { - return queue->rskq_accept_head == NULL; + return READ_ONCE(queue->rskq_accept_head) == NULL; } static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue *queue, @@ -193,7 +193,7 @@ static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue req = queue->rskq_accept_head; if (req) { sk_acceptq_removed(parent); - queue->rskq_accept_head = req->dl_next; + WRITE_ONCE(queue->rskq_accept_head, req->dl_next); if (queue->rskq_accept_head == NULL) queue->rskq_accept_tail = NULL; } diff --git a/include/net/tcp.h b/include/net/tcp.h index dad1beef9325fac15701921a3ed0d26744d86ee6..99be79730770c02ddedcc68bcfcb299ab3670ad0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -298,7 +298,7 @@ static inline bool tcp_under_memory_pressure(const struct sock *sk) mem_cgroup_under_socket_pressure(sk->sk_memcg)) return true; - return tcp_memory_pressure; + return READ_ONCE(tcp_memory_pressure); } /* * The next routines deal with comparing 32 bit unsigned ints diff --git a/include/soc/qcom/profiler.h b/include/soc/qcom/profiler.h new file mode 100644 index 0000000000000000000000000000000000000000..7d336aeccf505056b6bed272c2195946f79529b3 --- /dev/null +++ b/include/soc/qcom/profiler.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017, 2020 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. + */ + +#ifndef __PROFILER_H_ +#define __PROFILER_H_ + + +struct profiler_bw_cntrs_req { + uint32_t llcc_total; + uint32_t llcc_rd; + uint32_t llcc_wr; + uint32_t cabo_total; + uint32_t cabo_rd; + uint32_t cabo_wr; + uint32_t cmd; +}; + +struct compat_profiler_bw_cntrs_req { + compat_uint_t llcc_total; + compat_uint_t llcc_rd; + compat_uint_t llcc_wr; + compat_uint_t cabo_total; + compat_uint_t cabo_rd; + compat_uint_t cabo_wr; + compat_uint_t cmd; +}; + +/* Error types */ +enum tz_bw_svc_err { + E_BW_SUCCESS = 0, /* Operation successful */ + E_BW_FAILURE = 1, /* Operation failed due to unknown err */ + E_BW_NULL_PARAM = 2, /* Null Parameter */ + E_BW_INVALID_ARG = 3, /* Arg is not recognized */ + E_BW_BAD_ADDRESS = 4, /* Ptr arg is bad address */ + E_BW_INVALID_ARG_LEN = 5, /* Arg length is wrong */ + E_BW_NOT_SUPPORTED = 6, /* Operation not supported */ + E_BW_NOT_PERMITTED = 7, /* Operation not permitted on platform */ + E_BW_TIME_LOCKED = 8, /* Operation not permitted right now */ + E_BW_RESERVED = 0x7FFFFFFF +}; + +#define TZ_BW_SVC_VERSION (1) +#define PROFILER_IOC_MAGIC 0x98 + +#define PROFILER_IOCTL_GET_BW_INFO \ + _IOWR(PROFILER_IOC_MAGIC, 1, struct profiler_bw_cntrs_req) + +#define COMPAT_PROFILER_IOCTL_GET_BW_INFO \ + _IOWR(PROFILER_IOC_MAGIC, 1, struct compat_profiler_bw_cntrs_req) + +/* Command types */ +enum tz_bw_svc_cmd { + TZ_BW_SVC_START_ID = 0x00000001, + TZ_BW_SVC_GET_ID = 0x00000002, + TZ_BW_SVC_STOP_ID = 0x00000003, + TZ_BW_SVC_LAST_ID = 0x7FFFFFFF +}; +/* Start Request */ +struct tz_bw_svc_start_req { + enum tz_bw_svc_cmd cmd_id; + uint32_t version; +} __packed; + +/* Get Request */ +struct tz_bw_svc_get_req { + enum tz_bw_svc_cmd cmd_id; + uint64_t buf_ptr; + uint32_t buf_size; +} __packed; + +/* Stop Request */ +struct tz_bw_svc_stop_req { + enum tz_bw_svc_cmd cmd_id; +} __packed; + +struct tz_bw_svc_resp { + enum tz_bw_svc_cmd cmd_id; + enum tz_bw_svc_err status; +} __packed; + +union tz_bw_svc_req { + struct tz_bw_svc_start_req *start_req; + struct tz_bw_svc_get_req *get_req; + struct tz_bw_svc_stop_req *stop_req; +} __packed; + +struct tz_bw_svc_buf { + union tz_bw_svc_req bwreq; + struct tz_bw_svc_resp bwresp; + uint32_t req_size; +} __packed; + + +#define TZ_SVC_INFO 6 /* Misc. information services */ +#define TZ_SVC_BW_PROF_ID 0x07 + +#endif /* __PROFILER_H_ */ diff --git a/include/soc/qcom/qmi_rmnet.h b/include/soc/qcom/qmi_rmnet.h index dbfdca1006deb1d48b91e53eb29e112f263038b2..2e5a8e70a712779d871102797706db031dcde319 100644 --- a/include/soc/qcom/qmi_rmnet.h +++ b/include/soc/qcom/qmi_rmnet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, 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 @@ -52,7 +52,8 @@ qmi_rmnet_all_flows_enabled(struct net_device *dev) #endif #ifdef CONFIG_QCOM_QMI_DFC -void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id); +void *qmi_rmnet_qos_init(struct net_device *real_dev, + struct net_device *vnd_dev, u8 mux_id); void qmi_rmnet_qos_exit_pre(void *qos); void qmi_rmnet_qos_exit_post(void); void qmi_rmnet_burst_fc_check(struct net_device *dev, @@ -60,7 +61,8 @@ void qmi_rmnet_burst_fc_check(struct net_device *dev, int qmi_rmnet_get_queue(struct net_device *dev, struct sk_buff *skb); #else static inline void * -qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) +qmi_rmnet_qos_init(struct net_device *real_dev, + struct net_device *vnd_dev, u8 mux_id) { return NULL; } diff --git a/include/soc/qcom/sb_notification.h b/include/soc/qcom/sb_notification.h new file mode 100644 index 0000000000000000000000000000000000000000..20bbe73344192ac6a866eef68750fe4f1c0a6716 --- /dev/null +++ b/include/soc/qcom/sb_notification.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020, 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. + * + */ + +#ifndef _SB_NOTIFICATION_H +#define _SB_NOTIFICATION_H + +/* Indicates a system wake up event */ +#define EVT_WAKE_UP 0x01 + +#ifdef CONFIG_QTI_NOTIFY_SIDEBAND +/** + * sb_register_evt_listener - registers a notifier callback + * @nb: pointer to the notifier block for the callback events + */ +int sb_register_evt_listener(struct notifier_block *nb); + +/** + * sb_unregister_evt_listener - un-registers a notifier callback + * registered previously. + * @nb: pointer to the notifier block for the callback events + */ +int sb_unregister_evt_listener(struct notifier_block *nb); + +/** + * sb_notifier_call_chain - send events to all registered listeners + * as received from publishers. + * @nb: pointer to the notifier block for the callback events + */ +int sb_notifier_call_chain(unsigned long val, void *v); + +#else +static inline int sb_register_evt_listener(struct notifier_block *nb) +{ + return -EINVAL; +} +static inline int sb_unregister_evt_listener(struct notifier_block *nb) +{ + return -EINVAL; +} +static inline int sb_notifier_call_chain(unsigned long val, void *v) +{ + return -EINVAL; +} +#endif /* !CONFIG_QTI_NOTIFY_SIDEBAND */ + +#endif /* _SB_NOTIFICATION_H */ diff --git a/include/soc/qcom/scm.h b/include/soc/qcom/scm.h index a4e59f7e643e22316a656525e9cad4d9eb5da867..e36ef468bfd905900646082a377e77a9a00a4f1b 100644 --- a/include/soc/qcom/scm.h +++ b/include/soc/qcom/scm.h @@ -32,6 +32,7 @@ #define SCM_SVC_RTIC 0x19 #define SCM_SVC_TSENS 0x1E #define SCM_SVC_TZSCHEDULER 0xFC +#define SCM_SVC_BW 0xFD #define SCM_FUSE_READ 0x7 #define SCM_CMD_HDCP 0x01 diff --git a/include/trace/events/dfc.h b/include/trace/events/dfc.h index cd53ba83e897286083956694a58ffcae6b42ed32..e94e7438396ef802c516b067d50477a7ec9ebcfd 100644 --- a/include/trace/events/dfc.h +++ b/include/trace/events/dfc.h @@ -291,6 +291,28 @@ TRACE_EVENT(dfc_adjust_grant, __entry->rx_bytes, __entry->inflight, __entry->a_grant) ); +TRACE_EVENT(dfc_watchdog, + + TP_PROTO(u8 mux_id, u8 bearer_id, u8 event), + + TP_ARGS(mux_id, bearer_id, event), + + TP_STRUCT__entry( + __field(u8, mux_id) + __field(u8, bearer_id) + __field(u8, event) + ), + + TP_fast_assign( + __entry->mux_id = mux_id; + __entry->bearer_id = bearer_id; + __entry->event = event; + ), + + TP_printk("mid=%u bid=%u event=%u", + __entry->mux_id, __entry->bearer_id, __entry->event) +); + #endif /* _TRACE_DFC_H */ /* This part must be outside protection */ diff --git a/include/trace/events/xen.h b/include/trace/events/xen.h index 2ec9064a2bb7373ef4f138cfc22404bd06538c0b..e5150fc67e91d9b3ed145c1dd44a72f99c462172 100644 --- a/include/trace/events/xen.h +++ b/include/trace/events/xen.h @@ -66,7 +66,11 @@ TRACE_EVENT(xen_mc_callback, TP_PROTO(xen_mc_callback_fn_t fn, void *data), TP_ARGS(fn, data), TP_STRUCT__entry( - __field(xen_mc_callback_fn_t, fn) + /* + * Use field_struct to avoid is_signed_type() + * comparison of a function pointer. + */ + __field_struct(xen_mc_callback_fn_t, fn) __field(void *, data) ), TP_fast_assign( diff --git a/include/uapi/linux/bgcom_interface.h b/include/uapi/linux/bgcom_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..76632a9ef2ee6408729cd60a156067a7ab2336e7 --- /dev/null +++ b/include/uapi/linux/bgcom_interface.h @@ -0,0 +1,84 @@ +#ifndef LINUX_BG_CHAR_H + +#include + +#define LINUX_BG_CHAR_H +#define BGCOM_REG_READ 0 +#define BGCOM_AHB_READ 1 +#define BGCOM_AHB_WRITE 2 +#define BGCOM_SET_SPI_FREE 3 +#define BGCOM_SET_SPI_BUSY 4 +#define BGCOM_REG_WRITE 5 +#define BGCOM_SOFT_RESET 6 +#define BGCOM_MODEM_DOWN2_BG 7 +#define BGCOM_TWM_EXIT 8 +#define BGCOM_BG_APP_RUNNING 9 +#define BGCOM_ADSP_DOWN2_BG 10 +#define BGCOM_BG_WEAR_LOAD 11 +#define BGCOM_BG_WEAR_TWM_LOAD 12 +#define BGCOM_BG_WEAR_UNLOAD 13 +#define EXCHANGE_CODE 'V' + +struct bg_ui_data { + __u64 __user write; + __u64 __user result; + __u32 bg_address; + __u32 cmd; + __u32 num_of_words; +}; + +enum bg_event_type { + BG_BEFORE_POWER_DOWN = 1, + BG_AFTER_POWER_DOWN, + BG_BEFORE_POWER_UP, + BG_AFTER_POWER_UP, + MODEM_BEFORE_POWER_DOWN, + MODEM_AFTER_POWER_UP, + ADSP_BEFORE_POWER_DOWN, + ADSP_AFTER_POWER_UP, + TWM_BG_AFTER_POWER_UP, +}; + +#define REG_READ \ + _IOWR(EXCHANGE_CODE, BGCOM_REG_READ, \ + struct bg_ui_data) +#define AHB_READ \ + _IOWR(EXCHANGE_CODE, BGCOM_AHB_READ, \ + struct bg_ui_data) +#define AHB_WRITE \ + _IOW(EXCHANGE_CODE, BGCOM_AHB_WRITE, \ + struct bg_ui_data) +#define SET_SPI_FREE \ + _IOR(EXCHANGE_CODE, BGCOM_SET_SPI_FREE, \ + struct bg_ui_data) +#define SET_SPI_BUSY \ + _IOR(EXCHANGE_CODE, BGCOM_SET_SPI_BUSY, \ + struct bg_ui_data) +#define REG_WRITE \ + _IOWR(EXCHANGE_CODE, BGCOM_REG_WRITE, \ + struct bg_ui_data) +#define BG_SOFT_RESET \ + _IOWR(EXCHANGE_CODE, BGCOM_SOFT_RESET, \ + struct bg_ui_data) +#define BG_TWM_EXIT \ + _IOWR(EXCHANGE_CODE, BGCOM_TWM_EXIT, \ + struct bg_ui_data) +#define BG_APP_RUNNING \ + _IOWR(EXCHANGE_CODE, BGCOM_BG_APP_RUNNING, \ + struct bg_ui_data) +#define BG_MODEM_DOWN2_BG_DONE \ + _IOWR(EXCHANGE_CODE, BGCOM_MODEM_DOWN2_BG, \ + struct bg_ui_data) +#define BG_WEAR_LOAD \ + _IOWR(EXCHANGE_CODE, BGCOM_BG_WEAR_LOAD, \ + struct bg_ui_data) +#define BG_WEAR_TWM_LOAD \ + _IOWR(EXCHANGE_CODE, BGCOM_BG_WEAR_TWM_LOAD, \ + struct bg_ui_data) +#define BG_WEAR_UNLOAD \ + _IOWR(EXCHANGE_CODE, BGCOM_BG_WEAR_UNLOAD, \ + struct bg_ui_data) +#define BG_ADSP_DOWN2_BG_DONE \ + _IOWR(EXCHANGE_CODE, BGCOM_ADSP_DOWN2_BG, \ + struct bg_ui_data) +#endif diff --git a/include/uapi/linux/fscrypt.h b/include/uapi/linux/fscrypt.h index 705f129b01d169d68cb0001c1af85797afb8936b..393b5ae4e7d4c67a9872067121da1fb04442d670 100644 --- a/include/uapi/linux/fscrypt.h +++ b/include/uapi/linux/fscrypt.h @@ -17,7 +17,8 @@ #define FSCRYPT_POLICY_FLAGS_PAD_32 0x03 #define FSCRYPT_POLICY_FLAGS_PAD_MASK 0x03 #define FSCRYPT_POLICY_FLAG_DIRECT_KEY 0x04 -#define FSCRYPT_POLICY_FLAGS_VALID 0x07 +#define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 0x08 +#define FSCRYPT_POLICY_FLAGS_VALID 0x0F /* Encryption algorithms */ #define FSCRYPT_MODE_AES_256_XTS 1 diff --git a/include/uapi/linux/incrementalfs.h b/include/uapi/linux/incrementalfs.h new file mode 100644 index 0000000000000000000000000000000000000000..8a06e2e48fc4f5e809fa86b98a892f7ba9c9b0fd --- /dev/null +++ b/include/uapi/linux/incrementalfs.h @@ -0,0 +1,244 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Userspace interface for Incremental FS. + * + * Incremental FS is special-purpose Linux virtual file system that allows + * execution of a program while its binary and resource files are still being + * lazily downloaded over the network, USB etc. + * + * Copyright 2019 Google LLC + */ +#ifndef _UAPI_LINUX_INCREMENTALFS_H +#define _UAPI_LINUX_INCREMENTALFS_H + +#include +#include +#include +#include + +/* ===== constants ===== */ +#define INCFS_NAME "incremental-fs" +#define INCFS_MAGIC_NUMBER (0x5346434e49ul) +#define INCFS_DATA_FILE_BLOCK_SIZE 4096 +#define INCFS_HEADER_VER 1 + +// TODO: This value is assumed in incfs_copy_signature_info_from_user to be the +// actual signature length. Set back to 64 when fixed. +#define INCFS_MAX_HASH_SIZE 32 +#define INCFS_MAX_FILE_ATTR_SIZE 512 + +#define INCFS_PENDING_READS_FILENAME ".pending_reads" +#define INCFS_LOG_FILENAME ".log" +#define INCFS_XATTR_ID_NAME (XATTR_USER_PREFIX "incfs.id") +#define INCFS_XATTR_SIZE_NAME (XATTR_USER_PREFIX "incfs.size") +#define INCFS_XATTR_METADATA_NAME (XATTR_USER_PREFIX "incfs.metadata") + +#define INCFS_MAX_SIGNATURE_SIZE 8096 + +#define INCFS_IOCTL_BASE_CODE 'g' + +/* ===== ioctl requests on the command dir ===== */ + +/* Create a new file */ +#define INCFS_IOC_CREATE_FILE \ + _IOWR(INCFS_IOCTL_BASE_CODE, 30, struct incfs_new_file_args) + +/* Read file signature */ +#define INCFS_IOC_READ_FILE_SIGNATURE \ + _IOWR(INCFS_IOCTL_BASE_CODE, 31, struct incfs_get_file_sig_args) + +enum incfs_compression_alg { + COMPRESSION_NONE = 0, + COMPRESSION_LZ4 = 1 +}; + +enum incfs_block_flags { + INCFS_BLOCK_FLAGS_NONE = 0, + INCFS_BLOCK_FLAGS_HASH = 1, +}; + +typedef struct { + __u8 bytes[16]; +} incfs_uuid_t __attribute__((aligned (8))); + +/* + * Description of a pending read. A pending read - a read call by + * a userspace program for which the filesystem currently doesn't have data. + */ +struct incfs_pending_read_info { + /* Id of a file that is being read from. */ + incfs_uuid_t file_id; + + /* A number of microseconds since system boot to the read. */ + __aligned_u64 timestamp_us; + + /* Index of a file block that is being read. */ + __u32 block_index; + + /* A serial number of this pending read. */ + __u32 serial_number; +}; + +/* + * A struct to be written into a control file to load a data or hash + * block to a data file. + */ +struct incfs_new_data_block { + /* Index of a data block. */ + __u32 block_index; + + /* Length of data */ + __u32 data_len; + + /* + * A pointer to an actual data for the block. + * + * Equivalent to: __u8 *data; + */ + __aligned_u64 data; + + /* + * Compression algorithm used to compress the data block. + * Values from enum incfs_compression_alg. + */ + __u8 compression; + + /* Values from enum incfs_block_flags */ + __u8 flags; + + __u16 reserved1; + + __u32 reserved2; + + __aligned_u64 reserved3; +}; + +enum incfs_hash_tree_algorithm { + INCFS_HASH_TREE_NONE = 0, + INCFS_HASH_TREE_SHA256 = 1 +}; + +struct incfs_file_signature_info { + /* + * A pointer to file's root hash (if determined != 0) + * Actual hash size determined by hash_tree_alg. + * Size of the buffer should be at least INCFS_MAX_HASH_SIZE + * + * Equivalent to: u8 *root_hash; + */ + __aligned_u64 root_hash; + + /* + * A pointer to additional data that was attached to the root hash + * before signing. + * + * Equivalent to: u8 *additional_data; + */ + __aligned_u64 additional_data; + + /* Size of additional data. */ + __u32 additional_data_size; + + __u32 reserved1; + + /* + * A pointer to pkcs7 signature DER blob. + * + * Equivalent to: u8 *signature; + */ + __aligned_u64 signature; + + + /* Size of pkcs7 signature DER blob */ + __u32 signature_size; + + __u32 reserved2; + + /* Value from incfs_hash_tree_algorithm */ + __u8 hash_tree_alg; +}; + +/* + * Create a new file or directory. + */ +struct incfs_new_file_args { + /* Id of a file to create. */ + incfs_uuid_t file_id; + + /* + * Total size of the new file. Ignored if S_ISDIR(mode). + */ + __aligned_u64 size; + + /* + * File mode. Permissions and dir flag. + */ + __u16 mode; + + __u16 reserved1; + + __u32 reserved2; + + /* + * A pointer to a null-terminated relative path to the file's parent + * dir. + * Max length: PATH_MAX + * + * Equivalent to: char *directory_path; + */ + __aligned_u64 directory_path; + + /* + * A pointer to a null-terminated file's name. + * Max length: PATH_MAX + * + * Equivalent to: char *file_name; + */ + __aligned_u64 file_name; + + /* + * A pointer to a file attribute to be set on creation. + * + * Equivalent to: u8 *file_attr; + */ + __aligned_u64 file_attr; + + /* + * Length of the data buffer specfied by file_attr. + * Max value: INCFS_MAX_FILE_ATTR_SIZE + */ + __u32 file_attr_len; + + __u32 reserved4; + + /* struct incfs_file_signature_info *signature_info; */ + __aligned_u64 signature_info; + + __aligned_u64 reserved5; + + __aligned_u64 reserved6; +}; + +/* + * Request a digital signature blob for a given file. + * Argument for INCFS_IOC_READ_FILE_SIGNATURE ioctl + */ +struct incfs_get_file_sig_args { + /* + * A pointer to the data buffer to save an signature blob to. + * + * Equivalent to: u8 *file_signature; + */ + __aligned_u64 file_signature; + + /* Size of the buffer at file_signature. */ + __u32 file_signature_buf_size; + + /* + * Number of bytes save file_signature buffer. + * It is set after ioctl done. + */ + __u32 file_signature_len_out; +}; + +#endif /* _UAPI_LINUX_INCREMENTALFS_H */ diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index 33eabbb8ada11e5376364c5f3db99f90a97ddb10..1d0350e44ae34c57ae029de544a51c47d9fb0b95 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -4,8 +4,60 @@ #include +/* + * Argument for KCOV_REMOTE_ENABLE ioctl, see Documentation/dev-tools/kcov.rst + * and the comment before kcov_remote_start() for usage details. + */ +struct kcov_remote_arg { + __u32 trace_mode; /* KCOV_TRACE_PC or KCOV_TRACE_CMP */ + __u32 area_size; /* Length of coverage buffer in words */ + __u32 num_handles; /* Size of handles array */ + __aligned_u64 common_handle; + __aligned_u64 handles[0]; +}; + +#define KCOV_REMOTE_MAX_HANDLES 0x100 + #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) #define KCOV_ENABLE _IO('c', 100) #define KCOV_DISABLE _IO('c', 101) +#define KCOV_REMOTE_ENABLE _IOW('c', 102, struct kcov_remote_arg) + +enum { + /* + * Tracing coverage collection mode. + * Covered PCs are collected in a per-task buffer. + * In new KCOV version the mode is chosen by calling + * ioctl(fd, KCOV_ENABLE, mode). In older versions the mode argument + * was supposed to be 0 in such a call. So, for reasons of backward + * compatibility, we have chosen the value KCOV_TRACE_PC to be 0. + */ + KCOV_TRACE_PC = 0, + /* Collecting comparison operands mode. */ + KCOV_TRACE_CMP = 1, +}; + +/* + * The format for the types of collected comparisons. + * + * Bit 0 shows whether one of the arguments is a compile-time constant. + * Bits 1 & 2 contain log2 of the argument size, up to 8 bytes. + */ +#define KCOV_CMP_CONST (1 << 0) +#define KCOV_CMP_SIZE(n) ((n) << 1) +#define KCOV_CMP_MASK KCOV_CMP_SIZE(3) + +#define KCOV_SUBSYSTEM_COMMON (0x00ull << 56) +#define KCOV_SUBSYSTEM_USB (0x01ull << 56) + +#define KCOV_SUBSYSTEM_MASK (0xffull << 56) +#define KCOV_INSTANCE_MASK (0xffffffffull) + +static inline __u64 kcov_remote_handle(__u64 subsys, __u64 inst) +{ + if (subsys & ~KCOV_SUBSYSTEM_MASK || inst & ~KCOV_INSTANCE_MASK) + return 0; + return subsys | inst; +} #endif /* _LINUX_KCOV_IOCTLS_H */ diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index eb8594bd0435079d674894f14b997a0fc4b611c8..497526feb0caa7145dd8eccd8ac74d57e89cf504 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -415,7 +415,7 @@ enum ipa_client_type { IPA_CLIENT_MHI_LOW_LAT_PROD = 108, IPA_CLIENT_MHI_LOW_LAT_CONS = 109, - /* RESERVERD PROD = 110, */ + IPA_CLIENT_QDSS_PROD = 110, IPA_CLIENT_MHI_QDSS_CONS = 111, }; @@ -441,6 +441,7 @@ enum ipa_client_type { #define IPA_CLIENT_MHI_PRIME_RMNET_CONS IPA_CLIENT_MHI_PRIME_RMNET_CONS #define IPA_CLIENT_MHI_PRIME_DPL_PROD IPA_CLIENT_MHI_PRIME_DPL_PROD #define IPA_CLIENT_MHI_QDSS_CONS IPA_CLIENT_MHI_QDSS_CONS +#define IPA_CLIENT_QDSS_PROD IPA_CLIENT_QDSS_PROD #define IPA_CLIENT_IS_APPS_CONS(client) \ ((client) == IPA_CLIENT_APPS_LAN_CONS || \ diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h index 145f242c7c9095dfe5752c717ef308ae820d799c..0303ad623ab498e8e4c3dc6cd45836901f1fe139 100644 --- a/include/uapi/linux/ndctl.h +++ b/include/uapi/linux/ndctl.h @@ -256,10 +256,6 @@ enum nd_driver_flags { ND_DRIVER_DAX_PMEM = 1 << ND_DEVICE_DAX_PMEM, }; -enum { - ND_MIN_NAMESPACE_SIZE = 0x00400000, -}; - enum ars_masks { ARS_STATUS_MASK = 0x0000FFFF, ARS_EXT_STATUS_SHIFT = 16, diff --git a/include/uapi/linux/netfilter/xt_sctp.h b/include/uapi/linux/netfilter/xt_sctp.h index 4bc6d1a087816a67a560ccf333af3a8bab1cbfc5..b4d804a9fccb2d36e242149177f8c522cff12c60 100644 --- a/include/uapi/linux/netfilter/xt_sctp.h +++ b/include/uapi/linux/netfilter/xt_sctp.h @@ -41,19 +41,19 @@ struct xt_sctp_info { #define SCTP_CHUNKMAP_SET(chunkmap, type) \ do { \ (chunkmap)[type / bytes(__u32)] |= \ - 1 << (type % bytes(__u32)); \ + 1u << (type % bytes(__u32)); \ } while (0) #define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \ do { \ (chunkmap)[type / bytes(__u32)] &= \ - ~(1 << (type % bytes(__u32))); \ + ~(1u << (type % bytes(__u32))); \ } while (0) #define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \ ({ \ ((chunkmap)[type / bytes (__u32)] & \ - (1 << (type % bytes (__u32)))) ? 1: 0; \ + (1u << (type % bytes (__u32)))) ? 1: 0; \ }) #define SCTP_CHUNKMAP_RESET(chunkmap) \ diff --git a/include/uapi/linux/stat.h b/include/uapi/linux/stat.h index 7b35e98d3c58b1df9f4315e3f76a2564c25a106b..ad80a5c885d598231ccf207ac48d2d908eaf1b85 100644 --- a/include/uapi/linux/stat.h +++ b/include/uapi/linux/stat.h @@ -167,8 +167,8 @@ struct statx { #define STATX_ATTR_APPEND 0x00000020 /* [I] File is append-only */ #define STATX_ATTR_NODUMP 0x00000040 /* [I] File is not to be dumped */ #define STATX_ATTR_ENCRYPTED 0x00000800 /* [I] File requires key to decrypt in fs */ - #define STATX_ATTR_AUTOMOUNT 0x00001000 /* Dir: Automount trigger */ +#define STATX_ATTR_VERITY 0x00100000 /* [I] Verity protected file */ #endif /* _UAPI_LINUX_STAT_H */ diff --git a/include/uapi/linux/taskstats.h b/include/uapi/linux/taskstats.h index 125b5a9488a765b522e91f49d706cfe0799086d3..ac1e1881ac89b2976681e3f863d1bba32f8bda63 100644 --- a/include/uapi/linux/taskstats.h +++ b/include/uapi/linux/taskstats.h @@ -35,7 +35,7 @@ #define TASKSTATS_VERSION 9 -#define TASKSTATS2_VERSION 1 +#define TASKSTATS2_VERSION 2 #define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN * in linux/sched.h */ @@ -181,6 +181,20 @@ struct taskstats2 { __u64 shmem_rss; /* KB */ __u64 unreclaimable; /* KB */ /* version 1 ends here */ + + /* version 2 begins here */ + __u64 utime; /* User CPU time [usec] */ + __u64 stime; /* System CPU time [usec] */ + __u64 cutime; /* Cumulative User CPU time [usec] */ + __u64 cstime; /* Cumulative System CPU time [usec] */ + + __u32 uid __attribute__((aligned(8))); + /* User ID */ + __u32 ppid; /* Parent process ID */ + char name[TS_COMM_LEN]; /* Command name */ + char state[TS_COMM_LEN]; /* Process state */ + /* version 2 ends here*/ + }; /* diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index 781958456edb3b9dbc0967a2fff62f09990253f5..635a83616794605581949e77624f216a3212e295 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -43,6 +43,7 @@ #define VIRTIO_ID_INPUT 18 /* virtio input */ #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */ +#define VIRTIO_ID_PMEM 27 /* virtio pmem */ #define VIRTIO_ID_CLOCK 30 /* virtio clock */ #define VIRTIO_ID_REGULATOR 31 /* virtio regulator */ diff --git a/include/uapi/linux/virtio_pmem.h b/include/uapi/linux/virtio_pmem.h new file mode 100644 index 0000000000000000000000000000000000000000..efcd72f2d20d5f41aadd7c8a58ebbe55f454e2f5 --- /dev/null +++ b/include/uapi/linux/virtio_pmem.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Definitions for virtio-pmem devices. + * + * Copyright (C) 2019 Red Hat, Inc. + * + * Author(s): Pankaj Gupta + */ + +#ifndef _UAPI_LINUX_VIRTIO_PMEM_H +#define _UAPI_LINUX_VIRTIO_PMEM_H + +#include +#include +#include + +struct virtio_pmem_config { + __u64 start; + __u64 size; +}; + +#define VIRTIO_PMEM_REQ_TYPE_FLUSH 0 + +struct virtio_pmem_resp { + /* Host return status corresponding to flush request */ + __u32 ret; +}; + +struct virtio_pmem_req { + /* command type */ + __u32 type; +}; + +#endif diff --git a/init/do_mounts.c b/init/do_mounts.c index fa23cf487f4e57cd9de89bb68c7a5c7e83879079..f1645f4ece5ecd2eadde1da745f73f0a24395ab2 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -43,10 +43,11 @@ static char * __initdata root_device_name; static char __initdata saved_root_name[64]; static int root_wait; #ifdef CONFIG_EARLY_SERVICES -static char saved_modem_name[64] __initdata; -static char saved_early_userspace[64] __initdata; +static char saved_modem_name[64]; +static char saved_early_userspace[64]; static char init_prog[128] = "/early_services/init_early"; static char *init_prog_argv[2] = { init_prog, NULL }; +static int es_status; /*1= es mount is success 0= es failed to run*/ #define EARLY_SERVICES_MOUNT_POINT "/early_services" #endif dev_t ROOT_DEV; @@ -383,6 +384,26 @@ static void __init get_fs_names(char *page) *s = '\0'; } +#ifdef CONFIG_EARLY_SERVICES +static void get_fs_names_runtime(char *page) +{ + char *s = page; + int len = get_filesystem_list_runtime(page); + char *p, *next; + + page[len] = '\0'; + + for (p = page-1; p; p = next) { + next = strnchr(++p, len, '\n'); + if (*p++ != '\t') + continue; + while ((*s++ = *p++) != '\n') + ; + s[-1] = '\0'; + } + *s = '\0'; +} +#endif static int __init do_mount_root(char *name, char *fs, int flags, void *data) { struct super_block *s; @@ -410,7 +431,7 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data) return 0; } #ifdef CONFIG_EARLY_SERVICES -static int __init do_mount_part(char *name, char *fs, int flags, +static int do_mount_part(char *name, char *fs, int flags, void *data, char *mnt_point) { int err; @@ -590,14 +611,24 @@ void __init mount_root(void) } #ifdef CONFIG_EARLY_SERVICES -static int __init mount_partition(char *part_name, char *mnt_point) +int get_early_services_status(void) +{ + return es_status; +} + +static int mount_partition(char *part_name, char *mnt_point) { struct page *page = alloc_page(GFP_KERNEL); char *fs_names = page_address(page); char *p; int err = -EPERM; - get_fs_names(fs_names); + if (!part_name[0]) { + pr_err("Unknown partition\n"); + return -ENOENT; + } + + get_fs_names_runtime(fs_names); for (p = fs_names; *p; p += strlen(p)+1) { err = do_mount_part(part_name, p, root_mountflags, NULL, mnt_point); @@ -608,12 +639,11 @@ static int __init mount_partition(char *part_name, char *mnt_point) case -EINVAL: continue; } - printk_all_partitions(); return err; } return err; } -void __init launch_early_services(void) +void launch_early_services(void) { int rc = 0; @@ -622,14 +652,15 @@ void __init launch_early_services(void) if (!rc) { place_marker("Early Services Partition ready"); rc = call_usermodehelper(init_prog, init_prog_argv, NULL, 0); - if (!rc) + if (!rc) { + es_status = 1; pr_info("early_init launched\n"); - else + } else pr_err("early_init failed\n"); } } #else -void __init launch_early_services(void) { } +void launch_early_services(void) { } #endif /* * Prepare the namespace - decide what/where to mount, load ramdisks, etc. diff --git a/init/main.c b/init/main.c index aed0801c319734344996cbf9c44620c0de6c4ec6..22f1c5b9e8e589fb6df27ff90388f76c49db917b 100644 --- a/init/main.c +++ b/init/main.c @@ -96,6 +96,8 @@ #include #include +#include "do_mounts.h" + static int kernel_init(void *); extern void init_IRQ(void); @@ -1019,7 +1021,9 @@ static inline void mark_readonly(void) static int __ref kernel_init(void *unused) { int ret; - +#ifdef CONFIG_EARLY_SERVICES + int status = get_early_services_status(); +#endif kernel_init_freeable(); /* need to finish all async __init code before freeing the memory */ async_synchronize_full(); @@ -1032,6 +1036,14 @@ static int __ref kernel_init(void *unused) rcu_end_inkernel_boot(); place_marker("M - DRIVER Kernel Boot Done"); +#ifdef CONFIG_EARLY_SERVICES + if (status) { + struct kstat stat; + /* Wait for early services SE policy load completion signal */ + while (vfs_stat("/dev/sedone", &stat) != 0) + ; + } +#endif if (ramdisk_execute_command) { ret = run_init_process(ramdisk_execute_command); if (!ret) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a4875ff0bab197f8e71aa0b0d3fdea141e55c5a6..615a2e44d2a095d85ae39d582a4647927d8eb7f1 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1251,6 +1251,30 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, return check_generic_ptr_alignment(reg, pointer_desc, off, size, strict); } +static int check_ctx_reg(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg, int regno) +{ + /* Access to ctx or passing it to a helper is only allowed in + * its original, unmodified form. + */ + + if (reg->off) { + verbose("dereference of modified ctx ptr R%d off=%d disallowed\n", + regno, reg->off); + return -EACCES; + } + + if (!tnum_is_const(reg->var_off) || reg->var_off.value) { + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); + verbose("variable ctx access var_off=%s disallowed\n", tn_buf); + return -EACCES; + } + + return 0; +} + /* truncate register to smaller size (in bytes) * must be called with size < BPF_REG_SIZE */ @@ -1320,22 +1344,10 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn verbose("R%d leaks addr into ctx\n", value_regno); return -EACCES; } - /* ctx accesses must be at a fixed offset, so that we can - * determine what type of data were returned. - */ - if (reg->off) { - verbose("dereference of modified ctx ptr R%d off=%d+%d, ctx+const is allowed, ctx+const+const is not\n", - regno, reg->off, off - reg->off); - return -EACCES; - } - if (!tnum_is_const(reg->var_off) || reg->var_off.value) { - char tn_buf[48]; + err = check_ctx_reg(env, reg, regno); + if (err < 0) + return err; - tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); - verbose("variable ctx access var_off=%s off=%d size=%d", - tn_buf, off, size); - return -EACCES; - } err = check_ctx_access(env, insn_idx, off, size, t, ®_type); if (!err && t == BPF_READ && value_regno >= 0) { /* ctx access returns either a scalar, or a @@ -1573,6 +1585,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, expected_type = PTR_TO_CTX; if (type != expected_type) goto err_type; + err = check_ctx_reg(env, reg, regno); + if (err < 0) + return err; } else if (arg_type == ARG_PTR_TO_MEM || arg_type == ARG_PTR_TO_UNINIT_MEM) { expected_type = PTR_TO_STACK; @@ -3442,6 +3457,7 @@ static bool may_access_skb(enum bpf_prog_type type) static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) { struct bpf_reg_state *regs = cur_regs(env); + static const int ctx_reg = BPF_REG_6; u8 mode = BPF_MODE(insn->code); int i, err; @@ -3458,11 +3474,11 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) } /* check whether implicit source operand (register R6) is readable */ - err = check_reg_arg(env, BPF_REG_6, SRC_OP); + err = check_reg_arg(env, ctx_reg, SRC_OP); if (err) return err; - if (regs[BPF_REG_6].type != PTR_TO_CTX) { + if (regs[ctx_reg].type != PTR_TO_CTX) { verbose("at the time of BPF_LD_ABS|IND R6 != pointer to skb\n"); return -EINVAL; } @@ -3474,6 +3490,10 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) return err; } + err = check_ctx_reg(env, ®s[ctx_reg], ctx_reg); + if (err < 0) + return err; + /* reset caller saved regs to unreadable */ for (i = 0; i < CALLER_SAVED_REGS; i++) { mark_reg_not_init(regs, caller_saved[i]); diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 4d7a961615ff61f3864ed250f80b1a42f9325095..ea287f53c3a3da70843df836b95ff22083faffb0 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -2888,8 +2888,6 @@ static int cgroup_apply_control_enable(struct cgroup *cgrp) for_each_subsys(ss, ssid) { struct cgroup_subsys_state *css = cgroup_css(dsct, ss); - WARN_ON_ONCE(css && percpu_ref_is_dying(&css->refcnt)); - if (!(cgroup_ss_mask(dsct) & (1 << ss->id))) continue; @@ -2899,6 +2897,8 @@ static int cgroup_apply_control_enable(struct cgroup *cgrp) return PTR_ERR(css); } + WARN_ON_ONCE(percpu_ref_is_dying(&css->refcnt)); + if (css_visible(css)) { ret = css_populate_dir(css); if (ret) @@ -2934,11 +2934,11 @@ static void cgroup_apply_control_disable(struct cgroup *cgrp) for_each_subsys(ss, ssid) { struct cgroup_subsys_state *css = cgroup_css(dsct, ss); - WARN_ON_ONCE(css && percpu_ref_is_dying(&css->refcnt)); - if (!css) continue; + WARN_ON_ONCE(percpu_ref_is_dying(&css->refcnt)); + if (css->parent && !(cgroup_ss_mask(dsct) & (1 << ss->id))) { kill_css(css); @@ -3225,7 +3225,8 @@ static ssize_t cgroup_type_write(struct kernfs_open_file *of, char *buf, if (strcmp(strstrip(buf), "threaded")) return -EINVAL; - cgrp = cgroup_kn_lock_live(of->kn, false); + /* drain dying csses before we re-apply (threaded) subtree control */ + cgrp = cgroup_kn_lock_live(of->kn, true); if (!cgrp) return -ENOENT; diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 3083df2a783e9f4d551a5239f20ed2dae1b2e6da..90bd7895dc85b60f8883c05c9b425c6cc8a9b338 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -2629,7 +2629,7 @@ static int kdb_per_cpu(int argc, const char **argv) diag = kdbgetularg(argv[3], &whichcpu); if (diag) return diag; - if (!cpu_online(whichcpu)) { + if (whichcpu >= nr_cpu_ids || !cpu_online(whichcpu)) { kdb_printf("cpu %ld is not online\n", whichcpu); return KDB_BADCPUNUM; } diff --git a/kernel/events/core.c b/kernel/events/core.c index 8c54a1a521965dae8cd2bd3491ca3a9ebdfbe68b..52cd55918417775082776d474febf12988a7895f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4029,9 +4029,11 @@ find_get_context(struct pmu *pmu, struct task_struct *task, if (!task) { /* Must be root to operate on a CPU event: */ - if (!is_kernel_event(event) && perf_paranoid_cpu() && - !capable(CAP_SYS_ADMIN)) - return ERR_PTR(-EACCES); + if (!is_kernel_event(event)) { + err = perf_allow_cpu(&event->attr); + if (err) + return ERR_PTR(err); + } cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); ctx = &cpuctx->ctx; @@ -4363,6 +4365,8 @@ static void _free_event(struct perf_event *event) unaccount_event(event); + security_perf_event_free(event); + if (event->rb) { /* * Can happen when we close an event with re-directed output. @@ -4823,6 +4827,10 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) spin_unlock(&dormant_event_list_lock); #endif + ret = security_perf_event_read(event); + if (ret) + return ret; + ctx = perf_event_ctx_lock(event); ret = __perf_read(event, buf, count); perf_event_ctx_unlock(event, ctx); @@ -4956,6 +4964,9 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg) if (perf_event_check_period(event, value)) return -EINVAL; + if (!event->attr.freq && (value & (1ULL << 63))) + return -EINVAL; + event_function_call(event, __perf_event_period, &value); return 0; @@ -5068,6 +5079,11 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct perf_event_context *ctx; long ret; + /* Treat ioctl like writes as it is likely a mutating operation. */ + ret = security_perf_event_write(event); + if (ret) + return ret; + ctx = perf_event_ctx_lock(event); ret = _perf_ioctl(event, cmd, arg); perf_event_ctx_unlock(event, ctx); @@ -5529,6 +5545,10 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; + ret = security_perf_event_read(event); + if (ret) + return ret; + vma_size = vma->vm_end - vma->vm_start; if (vma->vm_pgoff == 0) { @@ -5642,7 +5662,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) lock_limit >>= PAGE_SHIFT; locked = vma->vm_mm->pinned_vm + extra; - if ((locked > lock_limit) && perf_paranoid_tracepoint_raw() && + if ((locked > lock_limit) && perf_is_paranoid() && !capable(CAP_IPC_LOCK)) { ret = -EPERM; goto unlock; @@ -10004,11 +10024,20 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, } } + err = security_perf_event_alloc(event); + if (err) + goto err_callchain_buffer; + /* symmetric to unaccount_event() in _free_event() */ account_event(event); return event; +err_callchain_buffer: + if (!event->parent) { + if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) + put_callchain_buffers(); + } err_addr_filters: kfree(event->addr_filter_ranges); @@ -10126,9 +10155,11 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, attr->branch_sample_type = mask; } /* privileged levels capture (kernel, hv): check permissions */ - if ((mask & PERF_SAMPLE_BRANCH_PERM_PLM) - && perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + if (mask & PERF_SAMPLE_BRANCH_PERM_PLM) { + ret = perf_allow_kernel(attr); + if (ret) + return ret; + } } if (attr->sample_type & PERF_SAMPLE_REGS_USER) { @@ -10366,13 +10397,19 @@ SYSCALL_DEFINE5(perf_event_open, if (perf_paranoid_any() && !capable(CAP_SYS_ADMIN)) return -EACCES; + /* Do we allow access to perf_event_open(2) ? */ + err = security_perf_event_open(&attr, PERF_SECURITY_OPEN); + if (err) + return err; + err = perf_copy_attr(attr_uptr, &attr); if (err) return err; if (!attr.exclude_kernel) { - if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + err = perf_allow_kernel(&attr); + if (err) + return err; } if (attr.namespaces) { @@ -10389,9 +10426,11 @@ SYSCALL_DEFINE5(perf_event_open, } /* Only privileged users can get physical addresses */ - if ((attr.sample_type & PERF_SAMPLE_PHYS_ADDR) && - perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + if ((attr.sample_type & PERF_SAMPLE_PHYS_ADDR)) { + err = perf_allow_kernel(&attr); + if (err) + return err; + } if (!attr.sample_max_stack) attr.sample_max_stack = sysctl_perf_event_max_stack; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index ac4644e92b499949b1a11652ddde3e3bccba8072..0f0e7975a3093486e3e9c2e45e9ece05f052c33d 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -147,6 +147,7 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, switch (fwid->type) { case IRQCHIP_FWNODE_NAMED: case IRQCHIP_FWNODE_NAMED_ID: + domain->fwnode = fwnode; domain->name = kstrdup(fwid->name, GFP_KERNEL); if (!domain->name) { kfree(domain); diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 06432e1a792ae6cff11aa25446b54b6632c357cb..4ad367a05274091989353a3e8796189b2ebea82b 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -314,6 +314,12 @@ static inline void cleanup_symbol_name(char *s) { char *res; +#ifdef CONFIG_THINLTO + /* Filter out hashes from static functions */ + res = strrchr(s, '$'); + if (res) + *res = '\0'; +#endif res = strrchr(s, '.'); if (res && !strcmp(res, ".cfi")) *res = '\0'; diff --git a/kernel/kcov.c b/kernel/kcov.c index f1e060b04ef626188361c924979803f7e937b627..2f0048ef4b64f8f92c1ace0c0cda8ae6cb82ecd9 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -20,34 +21,157 @@ #include #include #include +#include +#include #include +#define kcov_debug(fmt, ...) pr_debug("%s: " fmt, __func__, ##__VA_ARGS__) + +/* Number of 64-bit words written per one comparison: */ +#define KCOV_WORDS_PER_CMP 4 + /* * kcov descriptor (one per opened debugfs file). * State transitions of the descriptor: * - initial state after open() * - then there must be a single ioctl(KCOV_INIT_TRACE) call * - then, mmap() call (several calls are allowed but not useful) - * - then, repeated enable/disable for a task (only one task a time allowed) + * - then, ioctl(KCOV_ENABLE, arg), where arg is + * KCOV_TRACE_PC - to trace only the PCs + * or + * KCOV_TRACE_CMP - to trace only the comparison operands + * - then, ioctl(KCOV_DISABLE) to disable the task. + * Enabling/disabling ioctls can be repeated (only one task a time allowed). */ struct kcov { /* * Reference counter. We keep one for: * - opened file descriptor * - task with enabled coverage (we can't unwire it from another task) + * - each code section for remote coverage collection */ - atomic_t refcount; + refcount_t refcount; /* The lock protects mode, size, area and t. */ spinlock_t lock; enum kcov_mode mode; - /* Size of arena (in long's for KCOV_MODE_TRACE). */ - unsigned size; + /* Size of arena (in long's). */ + unsigned int size; /* Coverage buffer shared with user space. */ void *area; /* Task for which we collect coverage, or NULL. */ struct task_struct *t; + /* Collecting coverage from remote (background) threads. */ + bool remote; + /* Size of remote area (in long's). */ + unsigned int remote_size; + /* + * Sequence is incremented each time kcov is reenabled, used by + * kcov_remote_stop(), see the comment there. + */ + int sequence; +}; + +struct kcov_remote_area { + struct list_head list; + unsigned int size; +}; + +struct kcov_remote { + u64 handle; + struct kcov *kcov; + struct hlist_node hnode; }; +static DEFINE_SPINLOCK(kcov_remote_lock); +static DEFINE_HASHTABLE(kcov_remote_map, 4); +static struct list_head kcov_remote_areas = LIST_HEAD_INIT(kcov_remote_areas); + +/* Must be called with kcov_remote_lock locked. */ +static struct kcov_remote *kcov_remote_find(u64 handle) +{ + struct kcov_remote *remote; + + hash_for_each_possible(kcov_remote_map, remote, hnode, handle) { + if (remote->handle == handle) + return remote; + } + return NULL; +} + +static struct kcov_remote *kcov_remote_add(struct kcov *kcov, u64 handle) +{ + struct kcov_remote *remote; + + if (kcov_remote_find(handle)) + return ERR_PTR(-EEXIST); + remote = kmalloc(sizeof(*remote), GFP_ATOMIC); + if (!remote) + return ERR_PTR(-ENOMEM); + remote->handle = handle; + remote->kcov = kcov; + hash_add(kcov_remote_map, &remote->hnode, handle); + return remote; +} + +/* Must be called with kcov_remote_lock locked. */ +static struct kcov_remote_area *kcov_remote_area_get(unsigned int size) +{ + struct kcov_remote_area *area; + struct list_head *pos; + + kcov_debug("size = %u\n", size); + list_for_each(pos, &kcov_remote_areas) { + area = list_entry(pos, struct kcov_remote_area, list); + if (area->size == size) { + list_del(&area->list); + kcov_debug("rv = %px\n", area); + return area; + } + } + kcov_debug("rv = NULL\n"); + return NULL; +} + +/* Must be called with kcov_remote_lock locked. */ +static void kcov_remote_area_put(struct kcov_remote_area *area, + unsigned int size) +{ + kcov_debug("area = %px, size = %u\n", area, size); + INIT_LIST_HEAD(&area->list); + area->size = size; + list_add(&area->list, &kcov_remote_areas); +} + +static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t) +{ + unsigned int mode; + + /* + * We are interested in code coverage as a function of a syscall inputs, + * so we ignore code executed in interrupts. + */ + if (!in_task()) + return false; + mode = READ_ONCE(t->kcov_mode); + /* + * There is some code that runs in interrupts but for which + * in_interrupt() returns false (e.g. preempt_schedule_irq()). + * READ_ONCE()/barrier() effectively provides load-acquire wrt + * interrupts, there are paired barrier()/WRITE_ONCE() in + * kcov_start(). + */ + barrier(); + return mode == needed_mode; +} + +static notrace unsigned long canonicalize_ip(unsigned long ip) +{ +#ifdef CONFIG_RANDOMIZE_BASE + ip -= kaslr_offset(); +#endif + return ip; +} + /* * Entry point from instrumented code. * This is called once per basic-block/edge. @@ -55,64 +179,223 @@ struct kcov { void notrace __sanitizer_cov_trace_pc(void) { struct task_struct *t; - enum kcov_mode mode; + unsigned long *area; + unsigned long ip = canonicalize_ip(_RET_IP_); + unsigned long pos; + + t = current; + if (!check_kcov_mode(KCOV_MODE_TRACE_PC, t)) + return; + + area = t->kcov_area; + /* The first 64-bit word is the number of subsequent PCs. */ + pos = READ_ONCE(area[0]) + 1; + if (likely(pos < t->kcov_size)) { + area[pos] = ip; + WRITE_ONCE(area[0], pos); + } +} +EXPORT_SYMBOL(__sanitizer_cov_trace_pc); + +#ifdef CONFIG_KCOV_ENABLE_COMPARISONS +static void notrace write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip) +{ + struct task_struct *t; + u64 *area; + u64 count, start_index, end_pos, max_pos; t = current; + if (!check_kcov_mode(KCOV_MODE_TRACE_CMP, t)) + return; + + ip = canonicalize_ip(ip); + /* - * We are interested in code coverage as a function of a syscall inputs, - * so we ignore code executed in interrupts. + * We write all comparison arguments and types as u64. + * The buffer was allocated for t->kcov_size unsigned longs. */ - if (!t || !in_task()) - return; - mode = READ_ONCE(t->kcov_mode); - if (mode == KCOV_MODE_TRACE) { - unsigned long *area; - unsigned long pos; - unsigned long ip = _RET_IP_; + area = (u64 *)t->kcov_area; + max_pos = t->kcov_size * sizeof(unsigned long); -#ifdef CONFIG_RANDOMIZE_BASE - ip -= kaslr_offset(); -#endif + count = READ_ONCE(area[0]); - /* - * There is some code that runs in interrupts but for which - * in_interrupt() returns false (e.g. preempt_schedule_irq()). - * READ_ONCE()/barrier() effectively provides load-acquire wrt - * interrupts, there are paired barrier()/WRITE_ONCE() in - * kcov_ioctl_locked(). - */ - barrier(); - area = t->kcov_area; - /* The first word is number of subsequent PCs. */ - pos = READ_ONCE(area[0]) + 1; - if (likely(pos < t->kcov_size)) { - area[pos] = ip; - WRITE_ONCE(area[0], pos); - } + /* Every record is KCOV_WORDS_PER_CMP 64-bit words. */ + start_index = 1 + count * KCOV_WORDS_PER_CMP; + end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64); + if (likely(end_pos <= max_pos)) { + area[start_index] = type; + area[start_index + 1] = arg1; + area[start_index + 2] = arg2; + area[start_index + 3] = ip; + WRITE_ONCE(area[0], count + 1); } } -EXPORT_SYMBOL(__sanitizer_cov_trace_pc); -static void kcov_get(struct kcov *kcov) +void notrace __sanitizer_cov_trace_cmp1(u8 arg1, u8 arg2) { - atomic_inc(&kcov->refcount); + write_comp_data(KCOV_CMP_SIZE(0), arg1, arg2, _RET_IP_); } +EXPORT_SYMBOL(__sanitizer_cov_trace_cmp1); -static void kcov_put(struct kcov *kcov) +void notrace __sanitizer_cov_trace_cmp2(u16 arg1, u16 arg2) { - if (atomic_dec_and_test(&kcov->refcount)) { - vfree(kcov->area); - kfree(kcov); + write_comp_data(KCOV_CMP_SIZE(1), arg1, arg2, _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_cmp2); + +void notrace __sanitizer_cov_trace_cmp4(u32 arg1, u32 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(2), arg1, arg2, _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_cmp4); + +void notrace __sanitizer_cov_trace_cmp8(u64 arg1, u64 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(3), arg1, arg2, _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_cmp8); + +void notrace __sanitizer_cov_trace_const_cmp1(u8 arg1, u8 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(0) | KCOV_CMP_CONST, arg1, arg2, + _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp1); + +void notrace __sanitizer_cov_trace_const_cmp2(u16 arg1, u16 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(1) | KCOV_CMP_CONST, arg1, arg2, + _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp2); + +void notrace __sanitizer_cov_trace_const_cmp4(u32 arg1, u32 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(2) | KCOV_CMP_CONST, arg1, arg2, + _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp4); + +void notrace __sanitizer_cov_trace_const_cmp8(u64 arg1, u64 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(3) | KCOV_CMP_CONST, arg1, arg2, + _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp8); + +void notrace __sanitizer_cov_trace_switch(u64 val, u64 *cases) +{ + u64 i; + u64 count = cases[0]; + u64 size = cases[1]; + u64 type = KCOV_CMP_CONST; + + switch (size) { + case 8: + type |= KCOV_CMP_SIZE(0); + break; + case 16: + type |= KCOV_CMP_SIZE(1); + break; + case 32: + type |= KCOV_CMP_SIZE(2); + break; + case 64: + type |= KCOV_CMP_SIZE(3); + break; + default: + return; } + for (i = 0; i < count; i++) + write_comp_data(type, cases[i + 2], val, _RET_IP_); } +EXPORT_SYMBOL(__sanitizer_cov_trace_switch); +#endif /* ifdef CONFIG_KCOV_ENABLE_COMPARISONS */ -void kcov_task_init(struct task_struct *t) +static void kcov_start(struct task_struct *t, unsigned int size, + void *area, enum kcov_mode mode, int sequence) +{ + kcov_debug("t = %px, size = %u, area = %px\n", t, size, area); + /* Cache in task struct for performance. */ + t->kcov_size = size; + t->kcov_area = area; + /* See comment in check_kcov_mode(). */ + barrier(); + WRITE_ONCE(t->kcov_mode, mode); + t->kcov_sequence = sequence; +} + +static void kcov_stop(struct task_struct *t) { WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED); barrier(); t->kcov_size = 0; t->kcov_area = NULL; +} + +static void kcov_task_reset(struct task_struct *t) +{ + kcov_stop(t); t->kcov = NULL; + t->kcov_sequence = 0; + t->kcov_handle = 0; +} + +void kcov_task_init(struct task_struct *t) +{ + kcov_task_reset(t); + t->kcov_handle = current->kcov_handle; +} + +static void kcov_reset(struct kcov *kcov) +{ + kcov->t = NULL; + kcov->mode = KCOV_MODE_INIT; + kcov->remote = false; + kcov->remote_size = 0; + kcov->sequence++; +} + +static void kcov_remote_reset(struct kcov *kcov) +{ + int bkt; + struct kcov_remote *remote; + struct hlist_node *tmp; + + spin_lock(&kcov_remote_lock); + hash_for_each_safe(kcov_remote_map, bkt, tmp, remote, hnode) { + if (remote->kcov != kcov) + continue; + kcov_debug("removing handle %llx\n", remote->handle); + hash_del(&remote->hnode); + kfree(remote); + } + /* Do reset before unlock to prevent races with kcov_remote_start(). */ + kcov_reset(kcov); + spin_unlock(&kcov_remote_lock); +} + +static void kcov_disable(struct task_struct *t, struct kcov *kcov) +{ + kcov_task_reset(t); + if (kcov->remote) + kcov_remote_reset(kcov); + else + kcov_reset(kcov); +} + +static void kcov_get(struct kcov *kcov) +{ + refcount_inc(&kcov->refcount); +} + +static void kcov_put(struct kcov *kcov) +{ + if (refcount_dec_and_test(&kcov->refcount)) { + kcov_remote_reset(kcov); + vfree(kcov->area); + kfree(kcov); + } } void kcov_task_exit(struct task_struct *t) @@ -122,14 +405,36 @@ void kcov_task_exit(struct task_struct *t) kcov = t->kcov; if (kcov == NULL) return; + spin_lock(&kcov->lock); + kcov_debug("t = %px, kcov->t = %px\n", t, kcov->t); + /* + * For KCOV_ENABLE devices we want to make sure that t->kcov->t == t, + * which comes down to: + * WARN_ON(!kcov->remote && kcov->t != t); + * + * For KCOV_REMOTE_ENABLE devices, the exiting task is either: + * 2. A remote task between kcov_remote_start() and kcov_remote_stop(). + * In this case we should print a warning right away, since a task + * shouldn't be exiting when it's in a kcov coverage collection + * section. Here t points to the task that is collecting remote + * coverage, and t->kcov->t points to the thread that created the + * kcov device. Which means that to detect this case we need to + * check that t != t->kcov->t, and this gives us the following: + * WARN_ON(kcov->remote && kcov->t != t); + * + * 2. The task that created kcov exiting without calling KCOV_DISABLE, + * and then again we can make sure that t->kcov->t == t: + * WARN_ON(kcov->remote && kcov->t != t); + * + * By combining all three checks into one we get: + */ if (WARN_ON(kcov->t != t)) { spin_unlock(&kcov->lock); return; } /* Just to not leave dangling references behind. */ - kcov_task_init(t); - kcov->t = NULL; + kcov_disable(t, kcov); spin_unlock(&kcov->lock); kcov_put(kcov); } @@ -148,7 +453,7 @@ static int kcov_mmap(struct file *filep, struct vm_area_struct *vma) spin_lock(&kcov->lock); size = kcov->size * sizeof(unsigned long); - if (kcov->mode == KCOV_MODE_DISABLED || vma->vm_pgoff != 0 || + if (kcov->mode != KCOV_MODE_INIT || vma->vm_pgoff != 0 || vma->vm_end - vma->vm_start != size) { res = -EINVAL; goto exit; @@ -177,7 +482,9 @@ static int kcov_open(struct inode *inode, struct file *filep) kcov = kzalloc(sizeof(*kcov), GFP_KERNEL); if (!kcov) return -ENOMEM; - atomic_set(&kcov->refcount, 1); + kcov->mode = KCOV_MODE_DISABLED; + kcov->sequence = 1; + refcount_set(&kcov->refcount, 1); spin_lock_init(&kcov->lock); filep->private_data = kcov; return nonseekable_open(inode, filep); @@ -189,14 +496,64 @@ static int kcov_close(struct inode *inode, struct file *filep) return 0; } +static int kcov_get_mode(unsigned long arg) +{ + if (arg == KCOV_TRACE_PC) + return KCOV_MODE_TRACE_PC; + else if (arg == KCOV_TRACE_CMP) +#ifdef CONFIG_KCOV_ENABLE_COMPARISONS + return KCOV_MODE_TRACE_CMP; +#else + return -ENOTSUPP; +#endif + else + return -EINVAL; +} + +/* + * Fault in a lazily-faulted vmalloc area before it can be used by + * __santizer_cov_trace_pc(), to avoid recursion issues if any code on the + * vmalloc fault handling path is instrumented. + */ +static void kcov_fault_in_area(struct kcov *kcov) +{ + unsigned long stride = PAGE_SIZE / sizeof(unsigned long); + unsigned long *area = kcov->area; + unsigned long offset; + + for (offset = 0; offset < kcov->size; offset += stride) + READ_ONCE(area[offset]); +} + +static inline bool kcov_check_handle(u64 handle, bool common_valid, + bool uncommon_valid, bool zero_valid) +{ + if (handle & ~(KCOV_SUBSYSTEM_MASK | KCOV_INSTANCE_MASK)) + return false; + switch (handle & KCOV_SUBSYSTEM_MASK) { + case KCOV_SUBSYSTEM_COMMON: + return (handle & KCOV_INSTANCE_MASK) ? + common_valid : zero_valid; + case KCOV_SUBSYSTEM_USB: + return uncommon_valid; + default: + return false; + } + return false; +} + static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, unsigned long arg) { struct task_struct *t; unsigned long size, unused; + int mode, i; + struct kcov_remote_arg *remote_arg; + struct kcov_remote *remote; switch (cmd) { case KCOV_INIT_TRACE: + kcov_debug("KCOV_INIT_TRACE\n"); /* * Enable kcov in trace mode and setup buffer size. * Must happen before anything else. @@ -212,9 +569,10 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, if (size < 2 || size > INT_MAX / sizeof(unsigned long)) return -EINVAL; kcov->size = size; - kcov->mode = KCOV_MODE_TRACE; + kcov->mode = KCOV_MODE_INIT; return 0; case KCOV_ENABLE: + kcov_debug("KCOV_ENABLE\n"); /* * Enable coverage for the current task. * At this point user must have been enabled trace mode, @@ -222,25 +580,25 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, * at task exit or voluntary by KCOV_DISABLE. After that it can * be enabled for another task. */ - unused = arg; - if (unused != 0 || kcov->mode == KCOV_MODE_DISABLED || - kcov->area == NULL) + if (kcov->mode != KCOV_MODE_INIT || !kcov->area) return -EINVAL; t = current; if (kcov->t != NULL || t->kcov != NULL) return -EBUSY; - /* Cache in task struct for performance. */ - t->kcov_size = kcov->size; - t->kcov_area = kcov->area; - /* See comment in __sanitizer_cov_trace_pc(). */ - barrier(); - WRITE_ONCE(t->kcov_mode, kcov->mode); + mode = kcov_get_mode(arg); + if (mode < 0) + return mode; + kcov_fault_in_area(kcov); + kcov->mode = mode; + kcov_start(t, kcov->size, kcov->area, kcov->mode, + kcov->sequence); t->kcov = kcov; kcov->t = t; - /* This is put either in kcov_task_exit() or in KCOV_DISABLE. */ + /* Put either in kcov_task_exit() or in KCOV_DISABLE. */ kcov_get(kcov); return 0; case KCOV_DISABLE: + kcov_debug("KCOV_DISABLE\n"); /* Disable coverage for the current task. */ unused = arg; if (unused != 0 || current->kcov != kcov) @@ -248,10 +606,65 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, t = current; if (WARN_ON(kcov->t != t)) return -EINVAL; - kcov_task_init(t); - kcov->t = NULL; + kcov_disable(t, kcov); kcov_put(kcov); return 0; + case KCOV_REMOTE_ENABLE: + kcov_debug("KCOV_REMOTE_ENABLE\n"); + if (kcov->mode != KCOV_MODE_INIT || !kcov->area) + return -EINVAL; + t = current; + if (kcov->t != NULL || t->kcov != NULL) + return -EBUSY; + remote_arg = (struct kcov_remote_arg *)arg; + mode = kcov_get_mode(remote_arg->trace_mode); + if (mode < 0) + return mode; + if (remote_arg->area_size > LONG_MAX / sizeof(unsigned long)) + return -EINVAL; + kcov->mode = mode; + t->kcov = kcov; + kcov->t = t; + kcov->remote = true; + kcov->remote_size = remote_arg->area_size; + spin_lock(&kcov_remote_lock); + for (i = 0; i < remote_arg->num_handles; i++) { + kcov_debug("handle %llx\n", remote_arg->handles[i]); + if (!kcov_check_handle(remote_arg->handles[i], + false, true, false)) { + spin_unlock(&kcov_remote_lock); + kcov_disable(t, kcov); + return -EINVAL; + } + remote = kcov_remote_add(kcov, remote_arg->handles[i]); + if (IS_ERR(remote)) { + spin_unlock(&kcov_remote_lock); + kcov_disable(t, kcov); + return PTR_ERR(remote); + } + } + if (remote_arg->common_handle) { + kcov_debug("common handle %llx\n", + remote_arg->common_handle); + if (!kcov_check_handle(remote_arg->common_handle, + true, false, false)) { + spin_unlock(&kcov_remote_lock); + kcov_disable(t, kcov); + return -EINVAL; + } + remote = kcov_remote_add(kcov, + remote_arg->common_handle); + if (IS_ERR(remote)) { + spin_unlock(&kcov_remote_lock); + kcov_disable(t, kcov); + return PTR_ERR(remote); + } + t->kcov_handle = remote_arg->common_handle; + } + spin_unlock(&kcov_remote_lock); + /* Put either in kcov_task_exit() or in KCOV_DISABLE. */ + kcov_get(kcov); + return 0; default: return -ENOTTY; } @@ -261,11 +674,35 @@ static long kcov_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { struct kcov *kcov; int res; + struct kcov_remote_arg *remote_arg = NULL; + unsigned int remote_num_handles; + unsigned long remote_arg_size; + + if (cmd == KCOV_REMOTE_ENABLE) { + if (get_user(remote_num_handles, (unsigned __user *)(arg + + offsetof(struct kcov_remote_arg, num_handles)))) + return -EFAULT; + if (remote_num_handles > KCOV_REMOTE_MAX_HANDLES) + return -EINVAL; + remote_arg_size = sizeof(*remote_arg) + + sizeof(remote_arg->handles[0]) * remote_num_handles; + remote_arg = memdup_user((void __user *)arg, remote_arg_size); + if (IS_ERR(remote_arg)) + return PTR_ERR(remote_arg); + if (remote_arg->num_handles != remote_num_handles) { + kfree(remote_arg); + return -EINVAL; + } + arg = (unsigned long)remote_arg; + } kcov = filep->private_data; spin_lock(&kcov->lock); res = kcov_ioctl_locked(kcov, cmd, arg); spin_unlock(&kcov->lock); + + kfree(remote_arg); + return res; } @@ -277,6 +714,207 @@ static const struct file_operations kcov_fops = { .release = kcov_close, }; +/* + * kcov_remote_start() and kcov_remote_stop() can be used to annotate a section + * of code in a kernel background thread to allow kcov to be used to collect + * coverage from that part of code. + * + * The handle argument of kcov_remote_start() identifies a code section that is + * used for coverage collection. A userspace process passes this handle to + * KCOV_REMOTE_ENABLE ioctl to make the used kcov device start collecting + * coverage for the code section identified by this handle. + * + * The usage of these annotations in the kernel code is different depending on + * the type of the kernel thread whose code is being annotated. + * + * For global kernel threads that are spawned in a limited number of instances + * (e.g. one USB hub_event() worker thread is spawned per USB HCD), each + * instance must be assigned a unique 4-byte instance id. The instance id is + * then combined with a 1-byte subsystem id to get a handle via + * kcov_remote_handle(subsystem_id, instance_id). + * + * For local kernel threads that are spawned from system calls handler when a + * user interacts with some kernel interface (e.g. vhost workers), a handle is + * passed from a userspace process as the common_handle field of the + * kcov_remote_arg struct (note, that the user must generate a handle by using + * kcov_remote_handle() with KCOV_SUBSYSTEM_COMMON as the subsystem id and an + * arbitrary 4-byte non-zero number as the instance id). This common handle + * then gets saved into the task_struct of the process that issued the + * KCOV_REMOTE_ENABLE ioctl. When this proccess issues system calls that spawn + * kernel threads, the common handle must be retrived via kcov_common_handle() + * and passed to the spawned threads via custom annotations. Those kernel + * threads must in turn be annotated with kcov_remote_start(common_handle) and + * kcov_remote_stop(). All of the threads that are spawned by the same process + * obtain the same handle, hence the name "common". + * + * See Documentation/dev-tools/kcov.rst for more details. + * + * Internally, this function looks up the kcov device associated with the + * provided handle, allocates an area for coverage collection, and saves the + * pointers to kcov and area into the current task_struct to allow coverage to + * be collected via __sanitizer_cov_trace_pc() + * In turns kcov_remote_stop() clears those pointers from task_struct to stop + * collecting coverage and copies all collected coverage into the kcov area. + */ +void kcov_remote_start(u64 handle) +{ + struct kcov_remote *remote; + void *area; + struct task_struct *t; + unsigned int size; + enum kcov_mode mode; + int sequence; + + if (WARN_ON(!kcov_check_handle(handle, true, true, true))) + return; + if (WARN_ON(!in_task())) + return; + t = current; + /* + * Check that kcov_remote_start is not called twice + * nor called by user tasks (with enabled kcov). + */ + if (WARN_ON(t->kcov)) + return; + + kcov_debug("handle = %llx\n", handle); + + spin_lock(&kcov_remote_lock); + remote = kcov_remote_find(handle); + if (!remote) { + kcov_debug("no remote found"); + spin_unlock(&kcov_remote_lock); + return; + } + /* Put in kcov_remote_stop(). */ + kcov_get(remote->kcov); + t->kcov = remote->kcov; + /* + * Read kcov fields before unlock to prevent races with + * KCOV_DISABLE / kcov_remote_reset(). + */ + size = remote->kcov->remote_size; + mode = remote->kcov->mode; + sequence = remote->kcov->sequence; + area = kcov_remote_area_get(size); + spin_unlock(&kcov_remote_lock); + + if (!area) { + area = vmalloc(size * sizeof(unsigned long)); + if (!area) { + t->kcov = NULL; + kcov_put(remote->kcov); + return; + } + } + /* Reset coverage size. */ + *(u64 *)area = 0; + + kcov_debug("area = %px, size = %u", area, size); + + kcov_start(t, size, area, mode, sequence); + +} +EXPORT_SYMBOL(kcov_remote_start); + +static void kcov_move_area(enum kcov_mode mode, void *dst_area, + unsigned int dst_area_size, void *src_area) +{ + u64 word_size = sizeof(unsigned long); + u64 count_size, entry_size_log; + u64 dst_len, src_len; + void *dst_entries, *src_entries; + u64 dst_occupied, dst_free, bytes_to_move, entries_moved; + + kcov_debug("%px %u <= %px %lu\n", + dst_area, dst_area_size, src_area, *(unsigned long *)src_area); + + switch (mode) { + case KCOV_MODE_TRACE_PC: + dst_len = READ_ONCE(*(unsigned long *)dst_area); + src_len = *(unsigned long *)src_area; + count_size = sizeof(unsigned long); + entry_size_log = __ilog2_u64(sizeof(unsigned long)); + break; + case KCOV_MODE_TRACE_CMP: + dst_len = READ_ONCE(*(u64 *)dst_area); + src_len = *(u64 *)src_area; + count_size = sizeof(u64); + BUILD_BUG_ON(!is_power_of_2(KCOV_WORDS_PER_CMP)); + entry_size_log = __ilog2_u64(sizeof(u64) * KCOV_WORDS_PER_CMP); + break; + default: + WARN_ON(1); + return; + } + + /* As arm can't divide u64 integers use log of entry size. */ + if (dst_len > ((dst_area_size * word_size - count_size) >> + entry_size_log)) + return; + dst_occupied = count_size + (dst_len << entry_size_log); + dst_free = dst_area_size * word_size - dst_occupied; + bytes_to_move = min(dst_free, src_len << entry_size_log); + dst_entries = dst_area + dst_occupied; + src_entries = src_area + count_size; + memcpy(dst_entries, src_entries, bytes_to_move); + entries_moved = bytes_to_move >> entry_size_log; + + switch (mode) { + case KCOV_MODE_TRACE_PC: + WRITE_ONCE(*(unsigned long *)dst_area, dst_len + entries_moved); + break; + case KCOV_MODE_TRACE_CMP: + WRITE_ONCE(*(u64 *)dst_area, dst_len + entries_moved); + break; + default: + break; + } +} + +/* See the comment before kcov_remote_start() for usage details. */ +void kcov_remote_stop(void) +{ + struct task_struct *t = current; + struct kcov *kcov = t->kcov; + void *area = t->kcov_area; + unsigned int size = t->kcov_size; + int sequence = t->kcov_sequence; + + if (!kcov) { + kcov_debug("no kcov found\n"); + return; + } + + kcov_stop(t); + t->kcov = NULL; + + spin_lock(&kcov->lock); + /* + * KCOV_DISABLE could have been called between kcov_remote_start() + * and kcov_remote_stop(), hence the check. + */ + kcov_debug("move if: %d == %d && %d\n", + sequence, kcov->sequence, (int)kcov->remote); + if (sequence == kcov->sequence && kcov->remote) + kcov_move_area(kcov->mode, kcov->area, kcov->size, area); + spin_unlock(&kcov->lock); + + spin_lock(&kcov_remote_lock); + kcov_remote_area_put(area, size); + spin_unlock(&kcov_remote_lock); + + kcov_put(kcov); +} +EXPORT_SYMBOL(kcov_remote_stop); + +/* See the comment before kcov_remote_start() for usage details. */ +u64 kcov_common_handle(void) +{ + return current->kcov_handle; +} +EXPORT_SYMBOL(kcov_common_handle); + static int __init kcov_init(void) { /* @@ -284,10 +922,8 @@ static int __init kcov_init(void) * there is no need to protect it against removal races. The * use of debugfs_create_file_unsafe() is actually safe here. */ - if (!debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops)) { - pr_err("failed to create kcov in debugfs\n"); - return -ENOMEM; - } + debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops); + return 0; } diff --git a/kernel/locking/spinlock_debug.c b/kernel/locking/spinlock_debug.c index c18dadd02af4d38e100323f46854648559b1de66..8ab57cce761ad26fef3464efa35066b238d376d9 100644 --- a/kernel/locking/spinlock_debug.c +++ b/kernel/locking/spinlock_debug.c @@ -53,19 +53,19 @@ EXPORT_SYMBOL(__rwlock_init); static void spin_dump(raw_spinlock_t *lock, const char *msg) { - struct task_struct *owner = NULL; + struct task_struct *owner = READ_ONCE(lock->owner); - if (lock->owner && lock->owner != SPINLOCK_OWNER_INIT) - owner = lock->owner; + if (owner == SPINLOCK_OWNER_INIT) + owner = NULL; printk(KERN_EMERG "BUG: spinlock %s on CPU#%d, %s/%d\n", msg, raw_smp_processor_id(), current->comm, task_pid_nr(current)); printk(KERN_EMERG " lock: %pS, .magic: %08x, .owner: %s/%d, " ".owner_cpu: %d\n", - lock, lock->magic, + lock, READ_ONCE(lock->magic), owner ? owner->comm : "", owner ? task_pid_nr(owner) : -1, - lock->owner_cpu); + READ_ONCE(lock->owner_cpu)); #ifdef CONFIG_DEBUG_SPINLOCK_BITE_ON_BUG msm_trigger_wdog_bite(); #elif defined(CONFIG_DEBUG_SPINLOCK_PANIC_ON_BUG) @@ -87,16 +87,16 @@ static void spin_bug(raw_spinlock_t *lock, const char *msg) static inline void debug_spin_lock_before(raw_spinlock_t *lock) { - SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic"); - SPIN_BUG_ON(lock->owner == current, lock, "recursion"); - SPIN_BUG_ON(lock->owner_cpu == raw_smp_processor_id(), + SPIN_BUG_ON(READ_ONCE(lock->magic) != SPINLOCK_MAGIC, lock, "bad magic"); + SPIN_BUG_ON(READ_ONCE(lock->owner) == current, lock, "recursion"); + SPIN_BUG_ON(READ_ONCE(lock->owner_cpu) == raw_smp_processor_id(), lock, "cpu recursion"); } static inline void debug_spin_lock_after(raw_spinlock_t *lock) { - lock->owner_cpu = raw_smp_processor_id(); - lock->owner = current; + WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id()); + WRITE_ONCE(lock->owner, current); } static inline void debug_spin_unlock(raw_spinlock_t *lock) @@ -106,8 +106,8 @@ static inline void debug_spin_unlock(raw_spinlock_t *lock) SPIN_BUG_ON(lock->owner != current, lock, "wrong owner"); SPIN_BUG_ON(lock->owner_cpu != raw_smp_processor_id(), lock, "wrong CPU"); - lock->owner = SPINLOCK_OWNER_INIT; - lock->owner_cpu = -1; + WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT); + WRITE_ONCE(lock->owner_cpu, -1); } /* @@ -195,8 +195,8 @@ static inline void debug_write_lock_before(rwlock_t *lock) static inline void debug_write_lock_after(rwlock_t *lock) { - lock->owner_cpu = raw_smp_processor_id(); - lock->owner = current; + WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id()); + WRITE_ONCE(lock->owner, current); } static inline void debug_write_unlock(rwlock_t *lock) @@ -205,8 +205,8 @@ static inline void debug_write_unlock(rwlock_t *lock) RWLOCK_BUG_ON(lock->owner != current, lock, "wrong owner"); RWLOCK_BUG_ON(lock->owner_cpu != raw_smp_processor_id(), lock, "wrong CPU"); - lock->owner = SPINLOCK_OWNER_INIT; - lock->owner_cpu = -1; + WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT); + WRITE_ONCE(lock->owner_cpu, -1); } void do_raw_write_lock(rwlock_t *lock) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 09fb3f58a838ef39d558fd2a1c777979857eceaa..43a283041296d34fa5034201c66974794528c628 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -258,12 +258,17 @@ static int ptrace_check_attach(struct task_struct *child, bool ignore_state) return ret; } -static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) +static bool ptrace_has_cap(const struct cred *cred, struct user_namespace *ns, + unsigned int mode) { + int ret; + if (mode & PTRACE_MODE_NOAUDIT) - return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE); + ret = security_capable(cred, ns, CAP_SYS_PTRACE); else - return has_ns_capability(current, ns, CAP_SYS_PTRACE); + ret = security_capable(cred, ns, CAP_SYS_PTRACE); + + return ret == 0; } /* Returns 0 on success, -errno on denial. */ @@ -315,7 +320,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) gid_eq(caller_gid, tcred->sgid) && gid_eq(caller_gid, tcred->gid)) goto ok; - if (ptrace_has_cap(tcred->user_ns, mode)) + if (ptrace_has_cap(cred, tcred->user_ns, mode)) goto ok; rcu_read_unlock(); return -EPERM; @@ -334,7 +339,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) mm = task->mm; if (mm && ((get_dumpable(mm) != SUID_DUMP_USER) && - !ptrace_has_cap(mm->user_ns, mode))) + !ptrace_has_cap(cred, mm->user_ns, mode))) return -EPERM; return security_ptrace_access_check(task, mode); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index c6029fc13ea10c7d4e40d0e3c0e916b3073bc8c5..d125602d43cb3a9617c3382458d12fe2de7fbef9 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -2720,6 +2721,7 @@ static inline void prepare_task_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next) { + kcov_prepare_switch(prev); sched_info_switch(rq, prev, next); perf_event_task_sched_out(prev, next); fire_sched_out_preempt_notifiers(prev, next); @@ -2797,6 +2799,7 @@ static struct rq *finish_task_switch(struct task_struct *prev) smp_mb__after_unlock_lock(); finish_lock_switch(rq, prev); finish_arch_post_lock_switch(); + kcov_finish_switch(current); fire_sched_in_preempt_notifiers(current); if (mm) diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c index da18b81348aff0f18ea54160bf75baba2da7828e..8966f8b9fd03148b5488e4f93a2e6834d111ad4d 100644 --- a/kernel/sched/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, 2020, 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 @@ -819,7 +819,7 @@ static u64 core_ctl_check_timestamp; int core_ctl_set_boost(bool boost) { unsigned int index = 0; - struct cluster_data *cluster; + struct cluster_data *cluster = NULL; unsigned long flags; int ret = 0; bool boost_state_changed = false; @@ -850,7 +850,8 @@ int core_ctl_set_boost(bool boost) apply_need(cluster); } - trace_core_ctl_set_boost(cluster->boost, ret); + if (cluster) + trace_core_ctl_set_boost(cluster->boost, ret); return ret; } diff --git a/kernel/signal.c b/kernel/signal.c index e6e3428936e3242a45cb7b0670e6caeebdaea5c9..84b028ece696c03a9c977eac152a7b506461a0e2 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -89,6 +89,11 @@ static int sig_task_ignored(struct task_struct *t, int sig, bool force) handler == SIG_DFL && !(force && sig_kernel_only(sig))) return 1; + /* Only allow kernel generated signals to this kthread */ + if (unlikely((t->flags & PF_KTHREAD) && + (handler == SIG_KTHREAD_KERNEL) && !force)) + return true; + return sig_handler_ignored(handler, sig); } diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 30750014c33bdc8c72dcce879f3cb728c4e54eb1..14460de10a19667ea73ccceeb1af8ea73c79fe0d 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -654,6 +654,13 @@ static int taskstats2_cmd_attr_pid(struct genl_info *info) size_t size; u32 pid; int rc; + u64 utime, stime; + const struct cred *tcred; +#ifdef CONFIG_CPUSETS + struct cgroup_subsys_state *css; +#endif //CONFIG_CPUSETS + unsigned long flags; + struct signal_struct *sig; size = nla_total_size_64bit(sizeof(struct taskstats2)); @@ -695,6 +702,37 @@ static int taskstats2_cmd_attr_pid(struct genl_info *info) #undef K task_unlock(p); } + + /* version 2 fields begin here */ + task_cputime(tsk, &utime, &stime); + stats->utime = div_u64(utime, NSEC_PER_USEC); + stats->stime = div_u64(stime, NSEC_PER_USEC); + + if (lock_task_sighand(tsk, &flags)) { + sig = tsk->signal; + stats->cutime = sig->cutime; + stats->cstime = sig->cstime; + unlock_task_sighand(tsk, &flags); + } + + rcu_read_lock(); + tcred = __task_cred(tsk); + stats->uid = from_kuid_munged(current_user_ns(), tcred->uid); + stats->ppid = pid_alive(tsk) ? + task_tgid_nr_ns(rcu_dereference(tsk->real_parent), + task_active_pid_ns(current)) : 0; + rcu_read_unlock(); + + strlcpy(stats->name, tsk->comm, sizeof(stats->name)); + +#ifdef CONFIG_CPUSETS + css = task_get_css(tsk, cpuset_cgrp_id); + cgroup_path_ns(css->cgroup, stats->state, sizeof(stats->state), + current->nsproxy->cgroup_ns); + css_put(css); +#endif //CONFIG_CPUSETS + /* version 2 fields end here */ + put_task_struct(tsk); return send_reply(rep_skb, info); diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 8c5e1e3ba79874febbc4f27835785e725ae07b8e..d8a2ae86ebd329cb720944c217da0049be9f49b2 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -66,8 +66,9 @@ static void tick_do_update_jiffies64(ktime_t now) /* * Do a quick check without holding jiffies_lock: + * The READ_ONCE() pairs with two updates done later in this function. */ - delta = ktime_sub(now, last_jiffies_update); + delta = ktime_sub(now, READ_ONCE(last_jiffies_update)); if (delta < tick_period) return; @@ -78,8 +79,9 @@ static void tick_do_update_jiffies64(ktime_t now) if (delta >= tick_period) { delta = ktime_sub(delta, tick_period); - last_jiffies_update = ktime_add(last_jiffies_update, - tick_period); + /* Pairs with the lockless read in this function. */ + WRITE_ONCE(last_jiffies_update, + ktime_add(last_jiffies_update, tick_period)); /* Slow path for long timeouts */ if (unlikely(delta >= tick_period)) { @@ -87,8 +89,10 @@ static void tick_do_update_jiffies64(ktime_t now) ticks = ktime_divns(delta, incr); - last_jiffies_update = ktime_add_ns(last_jiffies_update, - incr * ticks); + /* Pairs with the lockless read in this function. */ + WRITE_ONCE(last_jiffies_update, + ktime_add_ns(last_jiffies_update, + incr * ticks)); } do_timer(++ticks); diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 78e167ef4d78c907e3e9efd39472bf23acd691fb..a44d91bca770b52e68d8dfbb643c22ccc3eb4c6f 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -7,6 +7,7 @@ #include #include +#include #include "trace.h" static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS]; @@ -24,8 +25,10 @@ static int total_ref_count; static int perf_trace_event_perm(struct trace_event_call *tp_event, struct perf_event *p_event) { + int ret; + if (tp_event->perf_perm) { - int ret = tp_event->perf_perm(tp_event, p_event); + ret = tp_event->perf_perm(tp_event, p_event); if (ret) return ret; } @@ -44,8 +47,9 @@ static int perf_trace_event_perm(struct trace_event_call *tp_event, /* The ftrace function trace is allowed only for root. */ if (ftrace_event_is_function(tp_event)) { - if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) - return -EPERM; + ret = perf_allow_tracepoint(&p_event->attr); + if (ret) + return ret; if (!is_sampling_event(p_event)) return 0; @@ -80,8 +84,9 @@ static int perf_trace_event_perm(struct trace_event_call *tp_event, * ...otherwise raw tracepoint data can be a severe data leak, * only allow root to have these. */ - if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) - return -EPERM; + ret = perf_allow_tracepoint(&p_event->attr); + if (ret) + return ret; return 0; } diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c index 0fa9dadf3f4f2fc907c325d398278f0dba4cc0e0..a5a4b5663163005c16ff2129462c64bf4fbc5fc7 100644 --- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c @@ -640,7 +640,7 @@ static void start_wakeup_tracer(struct trace_array *tr) if (ret) { pr_info("wakeup trace: Couldn't activate tracepoint" " probe to kernel_sched_migrate_task\n"); - return; + goto fail_deprobe_sched_switch; } wakeup_reset(tr); @@ -658,6 +658,8 @@ static void start_wakeup_tracer(struct trace_array *tr) printk(KERN_ERR "failed to start wakeup tracer\n"); return; +fail_deprobe_sched_switch: + unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL); fail_deprobe_wake_new: unregister_trace_sched_wakeup_new(probe_wakeup, NULL); fail_deprobe: diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 719a52a4064a0f6472ab7e662d00c47b6dd5993d..6f9091f874a9a79768213fb70fcd3664ce6cf772 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -196,6 +196,11 @@ check_stack(unsigned long ip, unsigned long *stack) local_irq_restore(flags); } +/* Some archs may not define MCOUNT_INSN_SIZE */ +#ifndef MCOUNT_INSN_SIZE +# define MCOUNT_INSN_SIZE 0 +#endif + static void stack_trace_call(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *pt_regs) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2a0c0b284cd7a6bcf81ea4c536416b4affa06b76..5edeeae34343adde501c4b9bd07910d0ef0a16bc 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -766,16 +766,21 @@ endmenu # "Memory Debugging" config ARCH_HAS_KCOV bool help - KCOV does not have any arch-specific code, but currently it is enabled - only for x86_64. KCOV requires testing on other archs, and most likely - disabling of instrumentation for some early boot code. + An architecture should select this when it can successfully + build and run with CONFIG_KCOV. This typically requires + disabling instrumentation for some early boot code. + +# Upstream uses $(cc-option, -fsanitize-coverage=trace-pc), which requires +# cc-option support. Here we instead check CC in scripts/Makefile.kcov. +config CC_HAS_SANCOV_TRACE_PC + def_bool ARCH_HAS_KCOV config KCOV bool "Code coverage for fuzzing" depends on ARCH_HAS_KCOV + depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS select DEBUG_FS - select GCC_PLUGINS if !COMPILE_TEST - select GCC_PLUGIN_SANCOV if !COMPILE_TEST + select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC help KCOV exposes kernel code coverage information in a form suitable for coverage-guided fuzzing (randomized testing). @@ -786,10 +791,21 @@ config KCOV For more details, see Documentation/dev-tools/kcov.rst. +# Upstream uses $(cc-option, -fsanitize-coverage=trace-cmp), which requires +# cc-option support. Here we instead check CC in scripts/Makefile.kcov. +config KCOV_ENABLE_COMPARISONS + bool "Enable comparison operands collection by KCOV" + depends on KCOV + help + KCOV also exposes operands of every comparison in the instrumented + code along with operand sizes and PCs of the comparison instructions. + These operands can be used by fuzzing engines to improve the quality + of fuzzing coverage. + config KCOV_INSTRUMENT_ALL bool "Instrument all code by default" depends on KCOV - default y if KCOV + default y help If you are doing generic system call fuzzing (like e.g. syzkaller), then you will want to instrument the whole kernel and you should diff --git a/lib/bitmap.c b/lib/bitmap.c index 2a9373ef4054c4d9c0a397a2167976b80317a299..fbe38a83acb32f50d95f27d09a6d395f99a9c29a 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -1212,3 +1213,22 @@ void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int n } EXPORT_SYMBOL(bitmap_copy_le); #endif + +unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags) +{ + return kmalloc_array(BITS_TO_LONGS(nbits), sizeof(unsigned long), + flags); +} +EXPORT_SYMBOL(bitmap_alloc); + +unsigned long *bitmap_zalloc(unsigned int nbits, gfp_t flags) +{ + return bitmap_alloc(nbits, flags | __GFP_ZERO); +} +EXPORT_SYMBOL(bitmap_zalloc); + +void bitmap_free(const unsigned long *bitmap) +{ + kfree(bitmap); +} +EXPORT_SYMBOL(bitmap_free); diff --git a/lib/devres.c b/lib/devres.c index 5f2aedd58bc5032eb18e882fbb2e539f0feed550..40a8b12a8b6b9237f34a63d90f4566a2b24fd154 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -132,7 +132,8 @@ EXPORT_SYMBOL(devm_iounmap); * if (IS_ERR(base)) * return PTR_ERR(base); */ -void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res) +void __iomem *devm_ioremap_resource(struct device *dev, + const struct resource *res) { resource_size_t size; const char *name; diff --git a/lib/kfifo.c b/lib/kfifo.c index 90ba1eb1df06e5283a2dad9132b53346f5106812..a94227c5555109bfcfc14ab9a750cd0761680470 100644 --- a/lib/kfifo.c +++ b/lib/kfifo.c @@ -82,7 +82,8 @@ int __kfifo_init(struct __kfifo *fifo, void *buffer, { size /= esize; - size = roundup_pow_of_two(size); + if (!is_power_of_2(size)) + size = rounddown_pow_of_two(size); fifo->in = 0; fifo->out = 0; diff --git a/lib/test_meminit.c b/lib/test_meminit.c index 9729f271d15041ac1930eb85922b81ba094a574f..e4f706a404b3a1f45b3443b4f8de0fbdd15107f8 100644 --- a/lib/test_meminit.c +++ b/lib/test_meminit.c @@ -183,6 +183,9 @@ static bool __init check_buf(void *buf, int size, bool want_ctor, return fail; } +#define BULK_SIZE 100 +static void *bulk_array[BULK_SIZE]; + /* * Test kmem_cache with given parameters: * want_ctor - use a constructor; @@ -203,9 +206,24 @@ static int __init do_kmem_cache_size(size_t size, bool want_ctor, want_rcu ? SLAB_TYPESAFE_BY_RCU : 0, want_ctor ? test_ctor : NULL); for (iter = 0; iter < 10; iter++) { + /* Do a test of bulk allocations */ + if (!want_rcu && !want_ctor) { + int ret; + + ret = kmem_cache_alloc_bulk(c, alloc_mask, BULK_SIZE, bulk_array); + if (!ret) { + fail = true; + } else { + int i; + for (i = 0; i < ret; i++) + fail |= check_buf(bulk_array[i], size, want_ctor, want_rcu, want_zero); + kmem_cache_free_bulk(c, ret, bulk_array); + } + } + buf = kmem_cache_alloc(c, alloc_mask); /* Check that buf is zeroed, if it must be. */ - fail = check_buf(buf, size, want_ctor, want_rcu, want_zero); + fail |= check_buf(buf, size, want_ctor, want_rcu, want_zero); fill_with_garbage_skip(buf, size, want_ctor ? CTOR_BYTES : 0); if (!want_rcu) { @@ -297,6 +315,32 @@ static int __init do_kmem_cache_rcu_persistent(int size, int *total_failures) return 1; } +static int __init do_kmem_cache_size_bulk(int size, int *total_failures) +{ + struct kmem_cache *c; + int i, iter, maxiter = 1024; + int num, bytes; + bool fail = false; + void *objects[10]; + + c = kmem_cache_create("test_cache", size, size, 0, NULL); + for (iter = 0; (iter < maxiter) && !fail; iter++) { + num = kmem_cache_alloc_bulk(c, GFP_KERNEL, ARRAY_SIZE(objects), + objects); + for (i = 0; i < num; i++) { + bytes = count_nonzero_bytes(objects[i], size); + if (bytes) + fail = true; + fill_with_garbage(objects[i], size); + } + + if (num) + kmem_cache_free_bulk(c, num, objects); + } + *total_failures += fail; + return 1; +} + /* * Test kmem_cache allocation by creating caches of different sizes, with and * without constructors, with and without SLAB_TYPESAFE_BY_RCU. @@ -318,6 +362,7 @@ static int __init test_kmemcache(int *total_failures) num_tests += do_kmem_cache_size(size, ctor, rcu, zero, &failures); } + num_tests += do_kmem_cache_size_bulk(size, &failures); } REPORT_FAILURES_IN_FN(); *total_failures += failures; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 82b92ca6ff4010f22aa2437545e7aaba1acbdfff..5c089f2d2d4c74f4226ebb81e6d01b66e6bc30d8 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -502,13 +502,13 @@ void prep_transhuge_page(struct page *page) set_compound_page_dtor(page, TRANSHUGE_PAGE_DTOR); } -unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long len, +static unsigned long __thp_get_unmapped_area(struct file *filp, + unsigned long addr, unsigned long len, loff_t off, unsigned long flags, unsigned long size) { - unsigned long addr; loff_t off_end = off + len; loff_t off_align = round_up(off, size); - unsigned long len_pad; + unsigned long len_pad, ret; if (off_end <= off_align || (off_end - off_align) < size) return 0; @@ -517,30 +517,40 @@ unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long len, if (len_pad < len || (off + len_pad) < off) return 0; - addr = current->mm->get_unmapped_area(filp, 0, len_pad, + ret = current->mm->get_unmapped_area(filp, addr, len_pad, off >> PAGE_SHIFT, flags); - if (IS_ERR_VALUE(addr)) + + /* + * The failure might be due to length padding. The caller will retry + * without the padding. + */ + if (IS_ERR_VALUE(ret)) return 0; - addr += (off - addr) & (size - 1); - return addr; + /* + * Do not try to align to THP boundary if allocation at the address + * hint succeeds. + */ + if (ret == addr) + return addr; + + ret += (off - ret) & (size - 1); + return ret; } unsigned long thp_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { + unsigned long ret; loff_t off = (loff_t)pgoff << PAGE_SHIFT; - if (addr) - goto out; if (!IS_DAX(filp->f_mapping->host) || !IS_ENABLED(CONFIG_FS_DAX_PMD)) goto out; - addr = __thp_get_unmapped_area(filp, len, off, flags, PMD_SIZE); - if (addr) - return addr; - - out: + ret = __thp_get_unmapped_area(filp, addr, len, off, flags, PMD_SIZE); + if (ret) + return ret; +out: return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags); } EXPORT_SYMBOL_GPL(thp_get_unmapped_area); diff --git a/mm/memblock.c b/mm/memblock.c index deaf4c018e1eb3a874f0afa4be348171cc485206..dc202c7702c8e8671432d8a6a8eebc758259d2e6 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1833,12 +1833,14 @@ static bool __init memblock_in_no_hotplug_area(phys_addr_t addr) static int __init early_dyn_memhotplug(char *p) { - int idx = 0; + unsigned long idx = 0; + unsigned long old_cnt; phys_addr_t addr, rgn_end; struct memblock_region *rgn; int blk = 0; while (idx < memblock.memory.cnt) { + old_cnt = memblock.memory.cnt; rgn = &memblock.memory.regions[idx++]; addr = ALIGN(rgn->base, MIN_MEMORY_BLOCK_SIZE); rgn_end = rgn->base + rgn->size; @@ -1849,6 +1851,8 @@ static int __init early_dyn_memhotplug(char *p) } addr += MIN_MEMORY_BLOCK_SIZE; } + if (old_cnt != memblock.memory.cnt) + idx--; } return 0; } diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 123b88dc3091600fd27d8c6ef9c615352159ddeb..6bc6c2f833a4a30819bc65796f6478380051c27c 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2745,6 +2745,9 @@ int mpol_parse_str(char *str, struct mempolicy **mpol) char *flags = strchr(str, '='); int err = 1; + if (flags) + *flags++ = '\0'; /* terminate mode string */ + if (nodelist) { /* NUL-terminate mode or flags string */ *nodelist++ = '\0'; @@ -2755,9 +2758,6 @@ int mpol_parse_str(char *str, struct mempolicy **mpol) } else nodes_clear(nodes); - if (flags) - *flags++ = '\0'; /* terminate mode string */ - for (mode = 0; mode < MPOL_MAX; mode++) { if (!strcmp(str, policy_modes[mode])) { break; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 7f316826aee56f8aabf37fb56871ab20c3e591a9..5b405e9a2b896f0e9008f9f2b61d12b7a597cb14 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -201,11 +201,11 @@ static void wb_min_max_ratio(struct bdi_writeback *wb, if (this_bw < tot_bw) { if (min) { min *= this_bw; - do_div(min, tot_bw); + min = div64_ul(min, tot_bw); } if (max < 100) { max *= this_bw; - do_div(max, tot_bw); + max = div64_ul(max, tot_bw); } } diff --git a/mm/page_io.c b/mm/page_io.c index beb65104018701437e760782188596a3fdcf20f3..ff224c477906a69c2ead5e67e02d694875a6034b 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -356,10 +357,19 @@ int swap_readpage(struct page *page, bool synchronous) struct swap_info_struct *sis = page_swap_info(page); blk_qc_t qc; struct gendisk *disk; + unsigned long pflags; VM_BUG_ON_PAGE(!PageSwapCache(page) && !synchronous, page); VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_PAGE(PageUptodate(page), page); + + /* + * Count submission time as memory stall. When the device is congested, + * or the submitting cgroup IO-throttled, submission can be a + * significant part of overall IO time. + */ + psi_memstall_enter(&pflags); + if (frontswap_load(page) == 0) { SetPageUptodate(page); unlock_page(page); @@ -373,7 +383,7 @@ int swap_readpage(struct page *page, bool synchronous) ret = mapping->a_ops->readpage(swap_file, page); if (!ret) count_vm_event(PSWPIN); - return ret; + goto out; } ret = bdev_read_page(sis->bdev, swap_page_sector(page), page); @@ -384,7 +394,7 @@ int swap_readpage(struct page *page, bool synchronous) } count_vm_event(PSWPIN); - return 0; + goto out; } ret = 0; @@ -417,6 +427,7 @@ int swap_readpage(struct page *page, bool synchronous) bio_put(bio); out: + psi_memstall_leave(&pflags); return ret; } diff --git a/mm/shmem.c b/mm/shmem.c index 72243fd63e10288bbae9a4b4841668ca64162c7d..393a674b92bf8965dab63e6848fe84a61c76a577 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2055,9 +2055,10 @@ unsigned long shmem_get_unmapped_area(struct file *file, /* * Our priority is to support MAP_SHARED mapped hugely; * and support MAP_PRIVATE mapped hugely too, until it is COWed. - * But if caller specified an address hint, respect that as before. + * But if caller specified an address hint and we allocated area there + * successfully, respect that as before. */ - if (uaddr) + if (uaddr == addr) return addr; if (shmem_huge != SHMEM_HUGE_FORCE) { @@ -2091,7 +2092,7 @@ unsigned long shmem_get_unmapped_area(struct file *file, if (inflated_len < len) return addr; - inflated_addr = get_area(NULL, 0, inflated_len, 0, flags); + inflated_addr = get_area(NULL, uaddr, inflated_len, 0, flags); if (IS_ERR_VALUE(inflated_addr)) return addr; if (inflated_addr & ~PAGE_MASK) diff --git a/mm/slub.c b/mm/slub.c index 6b6ea3fbe1eee440ec548c9ea83e82d969436839..5dcbbea0d57ab85056dd4ff2b19622fba8bd30f1 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1428,12 +1428,15 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, void *old_tail = *tail ? *tail : *head; int rsize; - if (slab_want_init_on_free(s)) { - void *p = NULL; + /* Head and tail of the reconstructed freelist */ + *head = NULL; + *tail = NULL; - do { - object = next; - next = get_freepointer(s, object); + do { + object = next; + next = get_freepointer(s, object); + + if (slab_want_init_on_free(s)) { /* * Clear the object and the metadata, but don't touch * the redzone. @@ -1443,29 +1446,8 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, : 0; memset((char *)object + s->inuse, 0, s->size - s->inuse - rsize); - set_freepointer(s, object, p); - p = object; - } while (object != old_tail); - } - -/* - * Compiler cannot detect this function can be removed if slab_free_hook() - * evaluates to nothing. Thus, catch all relevant config debug options here. - */ -#if defined(CONFIG_LOCKDEP) || \ - defined(CONFIG_DEBUG_KMEMLEAK) || \ - defined(CONFIG_DEBUG_OBJECTS_FREE) || \ - defined(CONFIG_KASAN) - - next = *head; - - /* Head and tail of the reconstructed freelist */ - *head = NULL; - *tail = NULL; - do { - object = next; - next = get_freepointer(s, object); + } /* If object's reuse doesn't have to be delayed */ if (!slab_free_hook(s, object)) { /* Move object to the new freelist */ @@ -1480,9 +1462,6 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, *tail = NULL; return *head != NULL; -#else - return true; -#endif } static void *setup_object(struct kmem_cache *s, struct page *page, @@ -2727,6 +2706,17 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, return p; } +/* + * If the object has been wiped upon free, make sure it's fully initialized by + * zeroing out freelist pointer. + */ +static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s, + void *obj) +{ + if (unlikely(slab_want_init_on_free(s)) && obj) + memset((void *)((char *)obj + s->offset), 0, sizeof(void *)); +} + /* * Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc) * have the fastpath folded into their functions. So no function call @@ -2815,12 +2805,8 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, prefetch_freepointer(s, next_object); stat(s, ALLOC_FASTPATH); } - /* - * If the object has been wiped upon free, make sure it's fully - * initialized by zeroing out freelist pointer. - */ - if (unlikely(slab_want_init_on_free(s)) && object) - memset(object + s->offset, 0, sizeof(void *)); + + maybe_wipe_obj_freeptr(s, object); if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) memset(object, 0, s->object_size); @@ -3235,10 +3221,13 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, goto error; c = this_cpu_ptr(s->cpu_slab); + maybe_wipe_obj_freeptr(s, p[i]); + continue; /* goto for-loop */ } c->freelist = get_freepointer(s, object); p[i] = object; + maybe_wipe_obj_freeptr(s, p[i]); } c->tid = next_tid(c->tid); local_irq_enable(); diff --git a/mm/swapfile.c b/mm/swapfile.c index aaf933538ae4830ae1f2e275d468b4add5b22146..2ba909118887fe016f9671c89a9fad29e3aa151f 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2926,10 +2926,6 @@ static int claim_swapfile(struct swap_info_struct *p, struct inode *inode) p->bdev = inode->i_sb->s_bdev; } - inode_lock(inode); - if (IS_SWAPFILE(inode)) - return -EBUSY; - return 0; } @@ -3183,36 +3179,40 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) mapping = swap_file->f_mapping; inode = mapping->host; - /* If S_ISREG(inode->i_mode) will do inode_lock(inode); */ error = claim_swapfile(p, inode); if (unlikely(error)) goto bad_swap; + inode_lock(inode); + if (IS_SWAPFILE(inode)) { + error = -EBUSY; + goto bad_swap_unlock_inode; + } /* * Read the swap header. */ if (!mapping->a_ops->readpage) { error = -EINVAL; - goto bad_swap; + goto bad_swap_unlock_inode; } page = read_mapping_page(mapping, 0, swap_file); if (IS_ERR(page)) { error = PTR_ERR(page); - goto bad_swap; + goto bad_swap_unlock_inode; } swap_header = kmap(page); maxpages = read_swap_header(p, swap_header, inode); if (unlikely(!maxpages)) { error = -EINVAL; - goto bad_swap; + goto bad_swap_unlock_inode; } /* OK, set up the swap map and apply the bad block list */ swap_map = vzalloc(maxpages); if (!swap_map) { error = -ENOMEM; - goto bad_swap; + goto bad_swap_unlock_inode; } if (bdi_cap_stable_pages_required(inode_to_bdi(inode))) @@ -3238,7 +3238,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) GFP_KERNEL); if (!cluster_info) { error = -ENOMEM; - goto bad_swap; + goto bad_swap_unlock_inode; } for (ci = 0; ci < nr_cluster; ci++) @@ -3247,7 +3247,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) p->percpu_cluster = alloc_percpu(struct percpu_cluster); if (!p->percpu_cluster) { error = -ENOMEM; - goto bad_swap; + goto bad_swap_unlock_inode; } for_each_possible_cpu(cpu) { struct percpu_cluster *cluster; @@ -3259,13 +3259,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = swap_cgroup_swapon(p->type, maxpages); if (error) - goto bad_swap; + goto bad_swap_unlock_inode; nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map, cluster_info, maxpages, &span); if (unlikely(nr_extents < 0)) { error = nr_extents; - goto bad_swap; + goto bad_swap_unlock_inode; } /* frontswap enabled? set up bit-per-page map for frontswap */ if (IS_ENABLED(CONFIG_FRONTSWAP)) @@ -3304,7 +3304,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = init_swap_address_space(p->type, maxpages); if (error) - goto bad_swap; + goto bad_swap_unlock_inode; /* * Flush any pending IO and dirty mappings before we start using this @@ -3314,7 +3314,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = inode_drain_writes(inode); if (error) { inode->i_flags &= ~S_SWAPFILE; - goto bad_swap; + goto bad_swap_unlock_inode; } mutex_lock(&swapon_mutex); @@ -3341,6 +3341,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = 0; goto out; +bad_swap_unlock_inode: + inode_unlock(inode); bad_swap: free_percpu(p->percpu_cluster); p->percpu_cluster = NULL; @@ -3348,6 +3350,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) set_blocksize(p->bdev, p->old_block_size); blkdev_put(p->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); } + inode = NULL; destroy_swap_extents(p); swap_cgroup_swapoff(p->type); spin_lock(&swap_lock); @@ -3357,13 +3360,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) vfree(swap_map); kvfree(cluster_info); kvfree(frontswap_map); - if (swap_file) { - if (inode) { - inode_unlock(inode); - inode = NULL; - } + if (swap_file) filp_close(swap_file, NULL); - } out: if (page && !IS_ERR(page)) { kunmap(page); diff --git a/net/6lowpan/nhc.c b/net/6lowpan/nhc.c index 4fa2fdda174d0139e669bd282ab4362aea41f512..9e56fb98f33cf0682991774293f77749a272478c 100644 --- a/net/6lowpan/nhc.c +++ b/net/6lowpan/nhc.c @@ -18,7 +18,7 @@ #include "nhc.h" static struct rb_root rb_root = RB_ROOT; -static struct lowpan_nhc *lowpan_nexthdr_nhcs[NEXTHDR_MAX]; +static struct lowpan_nhc *lowpan_nexthdr_nhcs[NEXTHDR_MAX + 1]; static DEFINE_SPINLOCK(lowpan_nhc_lock); static int lowpan_nhc_insert(struct lowpan_nhc *nhc) diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 0e7afdf86127d051297f907c928cf7395dbf0549..235bed825e3acdac6f760842db7b7e6731b8326d 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -110,6 +110,7 @@ int vlan_check_real_dev(struct net_device *real_dev, void vlan_setup(struct net_device *dev); int register_vlan_dev(struct net_device *dev); void unregister_vlan_dev(struct net_device *dev, struct list_head *head); +void vlan_dev_uninit(struct net_device *dev); bool vlan_dev_inherit_address(struct net_device *dev, struct net_device *real_dev); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index ac4c93c999b089a8e3751c2d1ed1bf3033d75ab2..ed3717dc2d2011543d0e468a46368659a8bd64ae 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -610,7 +610,8 @@ static int vlan_dev_init(struct net_device *dev) return 0; } -static void vlan_dev_uninit(struct net_device *dev) +/* Note: this function might be called multiple times for the same device. */ +void vlan_dev_uninit(struct net_device *dev) { struct vlan_priority_tci_mapping *pm; struct vlan_dev_priv *vlan = vlan_dev_priv(dev); diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 5e831de3103e2f7092c7fa15534def403bc62fb4..fdf39dd5e75529d8b6d694e79a3fd98de657d709 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -95,11 +95,13 @@ static int vlan_changelink(struct net_device *dev, struct nlattr *tb[], struct ifla_vlan_flags *flags; struct ifla_vlan_qos_mapping *m; struct nlattr *attr; - int rem; + int rem, err; if (data[IFLA_VLAN_FLAGS]) { flags = nla_data(data[IFLA_VLAN_FLAGS]); - vlan_dev_change_flags(dev, flags->flags, flags->mask); + err = vlan_dev_change_flags(dev, flags->flags, flags->mask); + if (err) + return err; } if (data[IFLA_VLAN_INGRESS_QOS]) { nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) { @@ -110,7 +112,9 @@ static int vlan_changelink(struct net_device *dev, struct nlattr *tb[], if (data[IFLA_VLAN_EGRESS_QOS]) { nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) { m = nla_data(attr); - vlan_dev_set_egress_priority(dev, m->from, m->to); + err = vlan_dev_set_egress_priority(dev, m->from, m->to); + if (err) + return err; } } return 0; @@ -157,10 +161,11 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev, return -EINVAL; err = vlan_changelink(dev, tb, data, extack); - if (err < 0) - return err; - - return register_vlan_dev(dev); + if (!err) + err = register_vlan_dev(dev); + if (err) + vlan_dev_uninit(dev); + return err; } static inline size_t vlan_qos_map_size(unsigned int n) diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 8d1d0fdb157e748eef3997c97f9de63ed53f949b..1519cbf70150b363d93aebd6e3a2d21f4da963c7 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -243,6 +243,7 @@ static u32 batadv_hash_dat(const void *data, u32 size) u32 hash = 0; const struct batadv_dat_entry *dat = data; const unsigned char *key; + __be16 vid; u32 i; key = (const unsigned char *)&dat->ip; @@ -252,7 +253,8 @@ static u32 batadv_hash_dat(const void *data, u32 size) hash ^= (hash >> 6); } - key = (const unsigned char *)&dat->vid; + vid = htons(dat->vid); + key = (__force const unsigned char *)&vid; for (i = 0; i < sizeof(dat->vid); i++) { hash += key[i]; hash += (hash << 10); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 4a05235929b954cf3fc80b1b5a21d0210a5c472f..93093d7c3824001ea388961b4151d5f2f161c414 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -826,6 +826,8 @@ static int hci_sock_release(struct socket *sock) if (!sk) return 0; + lock_sock(sk); + switch (hci_pi(sk)->channel) { case HCI_CHANNEL_MONITOR: atomic_dec(&monitor_promisc); @@ -873,6 +875,7 @@ static int hci_sock_release(struct socket *sock) skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_write_queue); + release_sock(sk); sock_put(sk); return 0; } diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 35a670ec90775a9a753a5b171ee9fcd21f2c8d59..a1834ad7422ceb101a475b545cf2804627d1be4c 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -2164,7 +2164,9 @@ static int compat_copy_entries(unsigned char *data, unsigned int size_user, if (ret < 0) return ret; - WARN_ON(size_remaining); + if (size_remaining) + return -EINVAL; + return state->buf_kern_offset; } diff --git a/net/core/dev.c b/net/core/dev.c index 77e0d46d2fba5dc84d75658dde27a3001b953e8e..9c533ee7fcf44b89a745f8bbe19802bf956397bd 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6960,18 +6960,9 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) if (new_mtu == dev->mtu) return 0; - /* MTU must be positive, and in range */ - if (new_mtu < 0 || new_mtu < dev->min_mtu) { - net_err_ratelimited("%s: Invalid MTU %d requested, hw min %d\n", - dev->name, new_mtu, dev->min_mtu); - return -EINVAL; - } - - if (dev->max_mtu > 0 && new_mtu > dev->max_mtu) { - net_err_ratelimited("%s: Invalid MTU %d requested, hw max %d\n", - dev->name, new_mtu, dev->max_mtu); - return -EINVAL; - } + err = dev_validate_mtu(dev, new_mtu); + if (err) + return err; if (!netif_device_present(dev)) return -ENODEV; @@ -7743,8 +7734,10 @@ int register_netdevice(struct net_device *dev) goto err_uninit; ret = netdev_register_kobject(dev); - if (ret) + if (ret) { + dev->reg_state = NETREG_UNREGISTERED; goto err_uninit; + } dev->reg_state = NETREG_REGISTERED; __netdev_update_features(dev); @@ -7843,6 +7836,23 @@ int init_dummy_netdev(struct net_device *dev) EXPORT_SYMBOL_GPL(init_dummy_netdev); +int dev_validate_mtu(struct net_device *dev, int new_mtu) +{ + /* MTU must be positive, and in range */ + if (new_mtu < 0 || new_mtu < dev->min_mtu) { + net_err_ratelimited("%s: Invalid MTU %d requested, hw min %d\n", + dev->name, new_mtu, dev->min_mtu); + return -EINVAL; + } + + if (dev->max_mtu > 0 && new_mtu > dev->max_mtu) { + net_err_ratelimited("%s: Invalid MTU %d requested, hw max %d\n", + dev->name, new_mtu, dev->max_mtu); + return -EINVAL; + } + return 0; +} + /** * register_netdev - register a network device * @dev: device to register diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 99e04b6806723b6e8dfdffc0ca39d3c8aa9b4f25..b234ff5e5a862e39d71a58970a71bda281dc380b 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -2346,10 +2346,10 @@ static int ethtool_set_tunable(struct net_device *dev, void __user *useraddr) return ret; } -static noinline_for_stack -int ethtool_get_per_queue_coalesce(struct net_device *dev, - void __user *useraddr, - struct ethtool_per_queue_op *per_queue_opt) +static noinline_for_stack int +ethtool_get_per_queue_coalesce(struct net_device *dev, + void __user *useraddr, + struct ethtool_per_queue_op *per_queue_opt) { u32 bit; int ret; @@ -2379,10 +2379,10 @@ int ethtool_get_per_queue_coalesce(struct net_device *dev, return 0; } -static noinline_for_stack -int ethtool_set_per_queue_coalesce(struct net_device *dev, - void __user *useraddr, - struct ethtool_per_queue_op *per_queue_opt) +static noinline_for_stack int +ethtool_set_per_queue_coalesce(struct net_device *dev, + void __user *useraddr, + struct ethtool_per_queue_op *per_queue_opt) { u32 bit; int i, ret = 0; @@ -2439,7 +2439,7 @@ int ethtool_set_per_queue_coalesce(struct net_device *dev, return ret; } -static int ethtool_set_per_queue(struct net_device *dev, +static int noinline_for_stack ethtool_set_per_queue(struct net_device *dev, void __user *useraddr, u32 sub_cmd) { struct ethtool_per_queue_op per_queue_opt; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 1fa68e023cafff38dd1d044fb7c706fb4c624024..7b150e6de1ad68fe3cb8a920c9d5261c41dd4c06 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1898,8 +1898,8 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, goto nla_put_failure; { unsigned long now = jiffies; - unsigned int flush_delta = now - tbl->last_flush; - unsigned int rand_delta = now - tbl->last_rand; + long flush_delta = now - tbl->last_flush; + long rand_delta = now - tbl->last_rand; struct neigh_hash_table *nht; struct ndt_config ndc = { .ndtc_key_len = tbl->key_len, diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index dee57c5ff738ef310f0c8b6ea43c177cdbe6c2cd..baf771d2d088f7e7d2c4c24276a8d46fa734de69 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -911,25 +911,30 @@ static int rx_queue_add_kobject(struct net_device *dev, int index) struct kobject *kobj = &queue->kobj; int error = 0; + /* Kobject_put later will trigger rx_queue_release call which + * decreases dev refcount: Take that reference here + */ + dev_hold(queue->dev); + kobj->kset = dev->queues_kset; error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, "rx-%u", index); if (error) - return error; - - dev_hold(queue->dev); + goto err; if (dev->sysfs_rx_queue_group) { error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); - if (error) { - kobject_put(kobj); - return error; - } + if (error) + goto err; } kobject_uevent(kobj, KOBJ_ADD); return error; + +err: + kobject_put(kobj); + return error; } #endif /* CONFIG_SYSFS */ @@ -1322,25 +1327,29 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index) struct kobject *kobj = &queue->kobj; int error = 0; + /* Kobject_put later will trigger netdev_queue_release call + * which decreases dev refcount: Take that reference here + */ + dev_hold(queue->dev); + kobj->kset = dev->queues_kset; error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, "tx-%u", index); if (error) - return error; - - dev_hold(queue->dev); + goto err; #ifdef CONFIG_BQL error = sysfs_create_group(kobj, &dql_group); - if (error) { - kobject_put(kobj); - return error; - } + if (error) + goto err; #endif kobject_uevent(kobj, KOBJ_ADD); - return 0; + +err: + kobject_put(kobj); + return error; } #endif /* CONFIG_SYSFS */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b598e9909fece456f6cec277a8724924b5dc7f39..7c479c1ffd77ff1bc2827ef659f6f29e0183ee64 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2466,8 +2466,17 @@ struct net_device *rtnl_create_link(struct net *net, dev->rtnl_link_ops = ops; dev->rtnl_link_state = RTNL_LINK_INITIALIZING; - if (tb[IFLA_MTU]) - dev->mtu = nla_get_u32(tb[IFLA_MTU]); + if (tb[IFLA_MTU]) { + u32 mtu = nla_get_u32(tb[IFLA_MTU]); + int err; + + err = dev_validate_mtu(dev, mtu); + if (err) { + free_netdev(dev); + return ERR_PTR(err); + } + dev->mtu = mtu; + } if (tb[IFLA_ADDRESS]) { memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), nla_len(tb[IFLA_ADDRESS])); diff --git a/net/core/sock.c b/net/core/sock.c index aaba11d7da5e704f182d408e0cc08e7fa532e68e..4e934404aeaf0edf7df2c3d79cdc05540f5c70b9 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2165,8 +2165,8 @@ static void sk_leave_memory_pressure(struct sock *sk) } else { unsigned long *memory_pressure = sk->sk_prot->memory_pressure; - if (memory_pressure && *memory_pressure) - *memory_pressure = 0; + if (memory_pressure && READ_ONCE(*memory_pressure)) + WRITE_ONCE(*memory_pressure, 0); } } diff --git a/net/core/utils.c b/net/core/utils.c index 93066bd0305ab73dbee756125e2cb77b7f46aa44..b1823e76b877253583b99327b32311287212b3fd 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -419,6 +419,23 @@ void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, } EXPORT_SYMBOL(inet_proto_csum_replace4); +/** + * inet_proto_csum_replace16 - update layer 4 header checksum field + * @sum: Layer 4 header checksum field + * @skb: sk_buff for the packet + * @from: old IPv6 address + * @to: new IPv6 address + * @pseudohdr: True if layer 4 header checksum includes pseudoheader + * + * Update layer 4 header as per the update in IPv6 src/dst address. + * + * There is no need to update skb->csum in this function, because update in two + * fields a.) IPv6 src/dst address and b.) L4 header checksum cancels each other + * for skb->csum calculation. Whereas inet_proto_csum_replace4 function needs to + * update skb->csum, because update in 3 fields a.) IPv4 src/dst address, + * b.) IPv4 Header checksum and c.) L4 header checksum results in same diff as + * L4 Header checksum for skb->csum calculation. + */ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, const __be32 *from, const __be32 *to, bool pseudohdr) @@ -430,9 +447,6 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, if (skb->ip_summed != CHECKSUM_PARTIAL) { *sum = csum_fold(csum_partial(diff, sizeof(diff), ~csum_unfold(*sum))); - if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) - skb->csum = ~csum_partial(diff, sizeof(diff), - ~skb->csum); } else if (pseudohdr) *sum = ~csum_fold(csum_partial(diff, sizeof(diff), csum_unfold(*sum))); diff --git a/net/dccp/feat.c b/net/dccp/feat.c index f227f002c73d382fecd98c8857ce4c9139cb7a8a..db87d9f5801983913e66549e5d5911ead10f3ac1 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -738,7 +738,12 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local, if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len)) return -ENOMEM; - return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval); + if (dccp_feat_push_change(fn, feat, is_local, mandatory, &fval)) { + kfree(fval.sp.vec); + return -ENOMEM; + } + + return 0; } /** diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c index b8c05f1cf47db8b81c3c02b53ae882884593a804..af3a12a36d882645ba929d4a28ee066e0d12df03 100644 --- a/net/dsa/tag_qca.c +++ b/net/dsa/tag_qca.c @@ -41,9 +41,6 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev) struct dsa_slave_priv *p = netdev_priv(dev); u16 *phdr, hdr; - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - if (skb_cow_head(skb, 0) < 0) return NULL; diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index cfe20f15f6180efc9daab80208872076a0d54376..c962c406d7b147025c89e6dc91205603c32f687b 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -281,6 +281,8 @@ static void send_hsr_supervision_frame(struct hsr_port *master, skb->dev->dev_addr, skb->len) <= 0) goto out; skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); if (hsrVer > 0) { hsr_tag = skb_put(skb, sizeof(struct hsr_tag)); diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c index ec7a5da561290ac92c234338d306fb300e46e62c..e873a6a007f2a51ed7e3da4cc1abebfa4c98c104 100644 --- a/net/ieee802154/6lowpan/reassembly.c +++ b/net/ieee802154/6lowpan/reassembly.c @@ -634,7 +634,7 @@ int __init lowpan_net_frag_init(void) void lowpan_net_frag_exit(void) { - inet_frags_fini(&lowpan_frags); lowpan_frags_sysctl_unregister(); unregister_pernet_subsys(&lowpan_frags_ops); + inet_frags_fini(&lowpan_frags); } diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 6833894a8e1b6d39196b5f8b02363ba79599385c..45b00b76c430dffaa27c248606bfbf8902c43d4a 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -943,7 +943,7 @@ struct sock *inet_csk_reqsk_queue_add(struct sock *sk, req->sk = child; req->dl_next = NULL; if (queue->rskq_accept_head == NULL) - queue->rskq_accept_head = req; + WRITE_ONCE(queue->rskq_accept_head, req); else queue->rskq_accept_tail->dl_next = req; queue->rskq_accept_tail = req; diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index f1784162acc22832ac69c20d20de8ab8f72a1543..404dc765f2bf82186ea81783d4829f15856619e0 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -1202,10 +1202,8 @@ int ip_tunnel_init(struct net_device *dev) iph->version = 4; iph->ihl = 5; - if (tunnel->collect_md) { - dev->features |= NETIF_F_NETNS_LOCAL; + if (tunnel->collect_md) netif_keep_dst(dev); - } return 0; } EXPORT_SYMBOL_GPL(ip_tunnel_init); diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 08c15dd42d935fd95190d5469bf7e805769fb8e3..59384ffe89f730acf5cd32dfc1202af79be70d19 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -208,8 +208,17 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev, int mtu; if (!dst) { - dev->stats.tx_carrier_errors++; - goto tx_error_icmp; + struct rtable *rt; + + fl->u.ip4.flowi4_oif = dev->ifindex; + fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC; + rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4); + if (IS_ERR(rt)) { + dev->stats.tx_carrier_errors++; + goto tx_error_icmp; + } + dst = &rt->dst; + skb_dst_set(skb, dst); } dst_hold(dst); diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 356ae7da4f1634e42e2c0b57c08d9d5770bb36d1..6dd727e0a72f6fdbb96da1508ba09d5c3b03ddf7 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -394,10 +394,11 @@ next: ; return 1; } -static inline int check_target(struct arpt_entry *e, const char *name) +static int check_target(struct arpt_entry *e, struct net *net, const char *name) { struct xt_entry_target *t = arpt_get_target(e); struct xt_tgchk_param par = { + .net = net, .table = name, .entryinfo = e, .target = t->u.kernel.target, @@ -409,8 +410,9 @@ static inline int check_target(struct arpt_entry *e, const char *name) return xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false); } -static inline int -find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, +static int +find_check_entry(struct arpt_entry *e, struct net *net, const char *name, + unsigned int size, struct xt_percpu_counter_alloc_state *alloc_state) { struct xt_entry_target *t; @@ -429,7 +431,7 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, } t->u.kernel.target = target; - ret = check_target(e, name); + ret = check_target(e, net, name); if (ret) goto err; return 0; @@ -504,12 +506,13 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, return 0; } -static inline void cleanup_entry(struct arpt_entry *e) +static void cleanup_entry(struct arpt_entry *e, struct net *net) { struct xt_tgdtor_param par; struct xt_entry_target *t; t = arpt_get_target(e); + par.net = net; par.target = t->u.kernel.target; par.targinfo = t->data; par.family = NFPROTO_ARP; @@ -522,7 +525,9 @@ static inline void cleanup_entry(struct arpt_entry *e) /* Checks and translates the user-supplied table segment (held in * newinfo). */ -static int translate_table(struct xt_table_info *newinfo, void *entry0, +static int translate_table(struct net *net, + struct xt_table_info *newinfo, + void *entry0, const struct arpt_replace *repl) { struct xt_percpu_counter_alloc_state alloc_state = { 0 }; @@ -586,7 +591,7 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, /* Finally, each sanity check must pass */ i = 0; xt_entry_foreach(iter, entry0, newinfo->size) { - ret = find_check_entry(iter, repl->name, repl->size, + ret = find_check_entry(iter, net, repl->name, repl->size, &alloc_state); if (ret != 0) break; @@ -597,7 +602,7 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, xt_entry_foreach(iter, entry0, newinfo->size) { if (i-- == 0) break; - cleanup_entry(iter); + cleanup_entry(iter, net); } return ret; } @@ -922,7 +927,7 @@ static int __do_replace(struct net *net, const char *name, /* Decrease module usage counts and free resource */ loc_cpu_old_entry = oldinfo->entries; xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) - cleanup_entry(iter); + cleanup_entry(iter, net); xt_free_table_info(oldinfo); if (copy_to_user(counters_ptr, counters, @@ -974,7 +979,7 @@ static int do_replace(struct net *net, const void __user *user, goto free_newinfo; } - ret = translate_table(newinfo, loc_cpu_entry, &tmp); + ret = translate_table(net, newinfo, loc_cpu_entry, &tmp); if (ret != 0) goto free_newinfo; @@ -986,7 +991,7 @@ static int do_replace(struct net *net, const void __user *user, free_newinfo_untrans: xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) - cleanup_entry(iter); + cleanup_entry(iter, net); free_newinfo: xt_free_table_info(newinfo); return ret; @@ -1149,7 +1154,8 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, } } -static int translate_compat_table(struct xt_table_info **pinfo, +static int translate_compat_table(struct net *net, + struct xt_table_info **pinfo, void **pentry0, const struct compat_arpt_replace *compatr) { @@ -1217,7 +1223,7 @@ static int translate_compat_table(struct xt_table_info **pinfo, repl.num_counters = 0; repl.counters = NULL; repl.size = newinfo->size; - ret = translate_table(newinfo, entry1, &repl); + ret = translate_table(net, newinfo, entry1, &repl); if (ret) goto free_newinfo; @@ -1270,7 +1276,7 @@ static int compat_do_replace(struct net *net, void __user *user, goto free_newinfo; } - ret = translate_compat_table(&newinfo, &loc_cpu_entry, &tmp); + ret = translate_compat_table(net, &newinfo, &loc_cpu_entry, &tmp); if (ret != 0) goto free_newinfo; @@ -1282,7 +1288,7 @@ static int compat_do_replace(struct net *net, void __user *user, free_newinfo_untrans: xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) - cleanup_entry(iter); + cleanup_entry(iter, net); free_newinfo: xt_free_table_info(newinfo); return ret; @@ -1509,7 +1515,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len return ret; } -static void __arpt_unregister_table(struct xt_table *table) +static void __arpt_unregister_table(struct net *net, struct xt_table *table) { struct xt_table_info *private; void *loc_cpu_entry; @@ -1521,7 +1527,7 @@ static void __arpt_unregister_table(struct xt_table *table) /* Decrease module usage counts and free resources */ loc_cpu_entry = private->entries; xt_entry_foreach(iter, loc_cpu_entry, private->size) - cleanup_entry(iter); + cleanup_entry(iter, net); if (private->number > private->initial_entries) module_put(table_owner); xt_free_table_info(private); @@ -1546,7 +1552,7 @@ int arpt_register_table(struct net *net, loc_cpu_entry = newinfo->entries; memcpy(loc_cpu_entry, repl->entries, repl->size); - ret = translate_table(newinfo, loc_cpu_entry, repl); + ret = translate_table(net, newinfo, loc_cpu_entry, repl); if (ret != 0) goto out_free; @@ -1561,7 +1567,7 @@ int arpt_register_table(struct net *net, ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); if (ret != 0) { - __arpt_unregister_table(new_table); + __arpt_unregister_table(net, new_table); *res = NULL; } @@ -1576,7 +1582,7 @@ void arpt_unregister_table(struct net *net, struct xt_table *table, const struct nf_hook_ops *ops) { nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); - __arpt_unregister_table(table); + __arpt_unregister_table(net, table); } /* The built-in targets: standard (NULL) and error. */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index aa8e52c515ce0d0c9f008b07af6215a51075814f..254e3c79b09d8c88d84c1db6a33df95f44d63957 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -334,7 +334,7 @@ void tcp_enter_memory_pressure(struct sock *sk) { unsigned long val; - if (tcp_memory_pressure) + if (READ_ONCE(tcp_memory_pressure)) return; val = jiffies; @@ -349,7 +349,7 @@ void tcp_leave_memory_pressure(struct sock *sk) { unsigned long val; - if (!tcp_memory_pressure) + if (!READ_ONCE(tcp_memory_pressure)) return; val = xchg(&tcp_memory_pressure, 0); if (val) diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index 06f247ca9197e3e34728ef688be74d26b465edc7..434ad1e7244703b1f1535e32f09c01c60c7005d4 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -678,8 +678,7 @@ static void bbr_update_bw(struct sock *sk, const struct rate_sample *rs) * bandwidth sample. Delivered is in packets and interval_us in uS and * ratio will be <<1 for most connections. So delivered is first scaled. */ - bw = (u64)rs->delivered * BW_UNIT; - do_div(bw, rs->interval_us); + bw = div64_long((u64)rs->delivered * BW_UNIT, rs->interval_us); /* If this sample is application-limited, it is likely to have a very * low delivered count that represents application behavior rather than diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6988df06b0946267555c2b12f96c84eda70a6a81..12c8bc5f96f8cd06c0808847a65eebaffe4853ca 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -933,9 +933,10 @@ static void tcp_update_reordering(struct sock *sk, const int metric, /* This must be called before lost_out is incremented */ static void tcp_verify_retransmit_hint(struct tcp_sock *tp, struct sk_buff *skb) { - if (!tp->retransmit_skb_hint || - before(TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(tp->retransmit_skb_hint)->seq)) + if ((!tp->retransmit_skb_hint && tp->retrans_out >= tp->lost_out) || + (tp->retransmit_skb_hint && + before(TCP_SKB_CB(skb)->seq, + TCP_SKB_CB(tp->retransmit_skb_hint)->seq))) tp->retransmit_skb_hint = skb; } @@ -1751,8 +1752,11 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, } /* Ignore very old stuff early */ - if (!after(sp[used_sacks].end_seq, prior_snd_una)) + if (!after(sp[used_sacks].end_seq, prior_snd_una)) { + if (i == 0) + first_sack_index = -1; continue; + } used_sacks++; } diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 5bc2788e6ba462c20113109b9017559ff216c96f..c2644405bab192432ce3a8b24fb7f509f62a6e7a 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1878,10 +1878,8 @@ static int ip6_tnl_dev_init(struct net_device *dev) if (err) return err; ip6_tnl_link_config(t); - if (t->parms.collect_md) { - dev->features |= NETIF_F_NETNS_LOCAL; + if (t->parms.collect_md) netif_keep_dst(dev); - } return 0; } diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 557fe3880a3f37082309ffd7fddba61ed95a6919..396a0f61f5f88a4aa2ee3b30c1e69ab6b9642e4e 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -453,8 +453,17 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) int err = -1; int mtu; - if (!dst) - goto tx_err_link_failure; + if (!dst) { + fl->u.ip6.flowi6_oif = dev->ifindex; + fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC; + dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6); + if (dst->error) { + dst_release(dst); + dst = NULL; + goto tx_err_link_failure; + } + skb_dst_set(skb, dst); + } dst_hold(dst); dst = xfrm_lookup(t->net, dst, fl, NULL, 0); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index fe797b29ca89d802058735eb51fa2769e2976597..6dea6e92e686342a50c2fdb651923853463fb0d6 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -593,8 +593,8 @@ int __init ipv6_frag_init(void) void ipv6_frag_exit(void) { - inet_frags_fini(&ip6_frags); ip6_frags_sysctl_unregister(); unregister_pernet_subsys(&ip6_frags_ops); inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT); + inet_frags_fini(&ip6_frags); } diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c index 825b8e01f94762c483f20e41218cdd26e83b4d50..9a01f72d907fb7a85d7989c8a3069f3811a7ab2c 100644 --- a/net/ipv6/seg6_local.c +++ b/net/ipv6/seg6_local.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef CONFIG_IPV6_SEG6_HMAC #include #endif @@ -126,7 +127,8 @@ static bool decap_and_validate(struct sk_buff *skb, int proto) skb_reset_network_header(skb); skb_reset_transport_header(skb); - skb->encapsulation = 0; + if (iptunnel_pull_offloads(skb)) + return false; return true; } diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index ca98276c270970464e0e95101c84797b3f1cfd87..7a9cbc9502d9c52035e63a85c06a641d61f3a762 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -2446,6 +2446,13 @@ static int afiucv_iucv_init(void) return err; } +static void afiucv_iucv_exit(void) +{ + device_unregister(af_iucv_dev); + driver_unregister(&af_iucv_driver); + pr_iucv->iucv_unregister(&af_iucv_handler, 0); +} + static int __init afiucv_init(void) { int err; @@ -2479,11 +2486,18 @@ static int __init afiucv_init(void) err = afiucv_iucv_init(); if (err) goto out_sock; - } else - register_netdevice_notifier(&afiucv_netdev_notifier); + } + + err = register_netdevice_notifier(&afiucv_netdev_notifier); + if (err) + goto out_notifier; + dev_add_pack(&iucv_packet_type); return 0; +out_notifier: + if (pr_iucv) + afiucv_iucv_exit(); out_sock: sock_unregister(PF_IUCV); out_proto: @@ -2497,12 +2511,11 @@ static int __init afiucv_init(void) static void __exit afiucv_exit(void) { if (pr_iucv) { - device_unregister(af_iucv_dev); - driver_unregister(&af_iucv_driver); - pr_iucv->iucv_unregister(&af_iucv_handler, 0); + afiucv_iucv_exit(); symbol_put(iucv_if); - } else - unregister_netdevice_notifier(&afiucv_netdev_notifier); + } + + unregister_netdevice_notifier(&afiucv_netdev_notifier); dev_remove_pack(&iucv_packet_type); sock_unregister(PF_IUCV); proto_unregister(&iucv_proto); diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 12b7752b31935bba5e5b08a9c195ddfab6442bcf..6fe90ec21300197ed341a327c34f7f749b5e7e14 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1884,7 +1884,8 @@ static __net_exit void l2tp_exit_net(struct net *net) } rcu_read_unlock_bh(); - flush_workqueue(l2tp_wq); + if (l2tp_wq) + flush_workqueue(l2tp_wq); rcu_barrier(); } diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 2e472d5c3ea41493eb064a36474de20586eb9d03..d552e88197133345a35943ce6aa74e8bc993a0a6 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -113,22 +113,26 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr) * * Send data via reliable llc2 connection. * Returns 0 upon success, non-zero if action did not succeed. + * + * This function always consumes a reference to the skb. */ static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock) { struct llc_sock* llc = llc_sk(sk); - int rc = 0; if (unlikely(llc_data_accept_state(llc->state) || llc->remote_busy_flag || llc->p_flag)) { long timeout = sock_sndtimeo(sk, noblock); + int rc; rc = llc_ui_wait_for_busy_core(sk, timeout); + if (rc) { + kfree_skb(skb); + return rc; + } } - if (unlikely(!rc)) - rc = llc_build_and_send_pkt(sk, skb); - return rc; + return llc_build_and_send_pkt(sk, skb); } static void llc_ui_sk_init(struct socket *sock, struct sock *sk) @@ -900,7 +904,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) DECLARE_SOCKADDR(struct sockaddr_llc *, addr, msg->msg_name); int flags = msg->msg_flags; int noblock = flags & MSG_DONTWAIT; - struct sk_buff *skb; + struct sk_buff *skb = NULL; size_t size = 0; int rc = -EINVAL, copied = 0, hdrlen; @@ -909,10 +913,10 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) lock_sock(sk); if (addr) { if (msg->msg_namelen < sizeof(*addr)) - goto release; + goto out; } else { if (llc_ui_addr_null(&llc->addr)) - goto release; + goto out; addr = &llc->addr; } /* must bind connection to sap if user hasn't done it. */ @@ -920,7 +924,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) /* bind to sap with null dev, exclusive. */ rc = llc_ui_autobind(sock, addr); if (rc) - goto release; + goto out; } hdrlen = llc->dev->hard_header_len + llc_ui_header_len(sk, addr); size = hdrlen + len; @@ -929,12 +933,12 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) copied = size - hdrlen; rc = -EINVAL; if (copied < 0) - goto release; + goto out; release_sock(sk); skb = sock_alloc_send_skb(sk, size, noblock, &rc); lock_sock(sk); if (!skb) - goto release; + goto out; skb->dev = llc->dev; skb->protocol = llc_proto_type(addr->sllc_arphrd); skb_reserve(skb, hdrlen); @@ -944,29 +948,31 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) if (sk->sk_type == SOCK_DGRAM || addr->sllc_ua) { llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_mac, addr->sllc_sap); + skb = NULL; goto out; } if (addr->sllc_test) { llc_build_and_send_test_pkt(llc->sap, skb, addr->sllc_mac, addr->sllc_sap); + skb = NULL; goto out; } if (addr->sllc_xid) { llc_build_and_send_xid_pkt(llc->sap, skb, addr->sllc_mac, addr->sllc_sap); + skb = NULL; goto out; } rc = -ENOPROTOOPT; if (!(sk->sk_type == SOCK_STREAM && !addr->sllc_ua)) goto out; rc = llc_ui_send_data(sk, skb, noblock); + skb = NULL; out: - if (rc) { - kfree_skb(skb); -release: + kfree_skb(skb); + if (rc) dprintk("%s: failed sending from %02X to %02X: %d\n", __func__, llc->laddr.lsap, llc->daddr.lsap, rc); - } release_sock(sk); return rc ? : copied; } diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 444c13e752a0822b517a18353f05be65a60303dc..7fbc682aff0434319d4db34a83ed68d342ac8dca 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -55,6 +55,8 @@ int sysctl_llc2_busy_timeout = LLC2_BUSY_TIME * HZ; * (executing it's actions and changing state), upper layer will be * indicated or confirmed, if needed. Returns 0 for success, 1 for * failure. The socket lock has to be held before calling this function. + * + * This function always consumes a reference to the skb. */ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) { @@ -62,12 +64,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) struct llc_sock *llc = llc_sk(skb->sk); struct llc_conn_state_ev *ev = llc_conn_ev(skb); - /* - * We have to hold the skb, because llc_conn_service will kfree it in - * the sending path and we need to look at the skb->cb, where we encode - * llc_conn_state_ev. - */ - skb_get(skb); ev->ind_prim = ev->cfm_prim = 0; /* * Send event to state machine @@ -75,21 +71,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) rc = llc_conn_service(skb->sk, skb); if (unlikely(rc != 0)) { printk(KERN_ERR "%s: llc_conn_service failed\n", __func__); - goto out_kfree_skb; - } - - if (unlikely(!ev->ind_prim && !ev->cfm_prim)) { - /* indicate or confirm not required */ - if (!skb->next) - goto out_kfree_skb; goto out_skb_put; } - if (unlikely(ev->ind_prim && ev->cfm_prim)) /* Paranoia */ - skb_get(skb); - switch (ev->ind_prim) { case LLC_DATA_PRIM: + skb_get(skb); llc_save_primitive(sk, skb, LLC_DATA_PRIM); if (unlikely(sock_queue_rcv_skb(sk, skb))) { /* @@ -106,6 +93,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) * skb->sk pointing to the newly created struct sock in * llc_conn_handler. -acme */ + skb_get(skb); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_state_change(sk); break; @@ -121,7 +109,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) sk->sk_state_change(sk); } } - kfree_skb(skb); sock_put(sk); break; case LLC_RESET_PRIM: @@ -130,14 +117,11 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) * RESET is not being notified to upper layers for now */ printk(KERN_INFO "%s: received a reset ind!\n", __func__); - kfree_skb(skb); break; default: - if (ev->ind_prim) { + if (ev->ind_prim) printk(KERN_INFO "%s: received unknown %d prim!\n", __func__, ev->ind_prim); - kfree_skb(skb); - } /* No indication */ break; } @@ -179,15 +163,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) printk(KERN_INFO "%s: received a reset conf!\n", __func__); break; default: - if (ev->cfm_prim) { + if (ev->cfm_prim) printk(KERN_INFO "%s: received unknown %d prim!\n", __func__, ev->cfm_prim); - break; - } - goto out_skb_put; /* No confirmation */ + /* No confirmation */ + break; } -out_kfree_skb: - kfree_skb(skb); out_skb_put: kfree_skb(skb); return rc; diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c index 6daf391b3e847db42396caf9fbbfe7dca6440006..fc4d2bd8816f5aa95642b67d47e9cee3d77268e9 100644 --- a/net/llc/llc_if.c +++ b/net/llc/llc_if.c @@ -38,6 +38,8 @@ * closed and -EBUSY when sending data is not permitted in this state or * LLC has send an I pdu with p bit set to 1 and is waiting for it's * response. + * + * This function always consumes a reference to the skb. */ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb) { @@ -46,20 +48,22 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb) struct llc_sock *llc = llc_sk(sk); if (unlikely(llc->state == LLC_CONN_STATE_ADM)) - goto out; + goto out_free; rc = -EBUSY; if (unlikely(llc_data_accept_state(llc->state) || /* data_conn_refuse */ llc->p_flag)) { llc->failed_data_req = 1; - goto out; + goto out_free; } ev = llc_conn_ev(skb); ev->type = LLC_CONN_EV_TYPE_PRIM; ev->prim = LLC_DATA_PRIM; ev->prim_type = LLC_PRIM_TYPE_REQ; skb->dev = llc->dev; - rc = llc_conn_state_process(sk, skb); -out: + return llc_conn_state_process(sk, skb); + +out_free: + kfree_skb(skb); return rc; } diff --git a/net/llc/llc_station.c b/net/llc/llc_station.c index 204a8351efffc86f566e51b27f173c8bdee6c4cb..c29170e767a8ca3964c8958cc99db5893302b4f1 100644 --- a/net/llc/llc_station.c +++ b/net/llc/llc_station.c @@ -32,7 +32,7 @@ static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb) return LLC_PDU_IS_CMD(pdu) && /* command PDU */ LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID && - !pdu->dsap ? 0 : 1; /* NULL DSAP value */ + !pdu->dsap; /* NULL DSAP value */ } static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb) @@ -42,7 +42,7 @@ static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb) return LLC_PDU_IS_CMD(pdu) && /* command PDU */ LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST && - !pdu->dsap ? 0 : 1; /* NULL DSAP */ + !pdu->dsap; /* NULL DSAP */ } static int llc_station_ac_send_xid_r(struct sk_buff *skb) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8168c667d91d92390576576a4125c8679c2db8a5..b1484b8316e878fde9f0a46b3f52d218f464b17e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1089,50 +1089,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) return 0; } -/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ -struct iapp_layer2_update { - u8 da[ETH_ALEN]; /* broadcast */ - u8 sa[ETH_ALEN]; /* STA addr */ - __be16 len; /* 6 */ - u8 dsap; /* 0 */ - u8 ssap; /* 0 */ - u8 control; - u8 xid_info[3]; -} __packed; - -static void ieee80211_send_layer2_update(struct sta_info *sta) -{ - struct iapp_layer2_update *msg; - struct sk_buff *skb; - - /* Send Level 2 Update Frame to update forwarding tables in layer 2 - * bridge devices */ - - skb = dev_alloc_skb(sizeof(*msg)); - if (!skb) - return; - msg = skb_put(skb, sizeof(*msg)); - - /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) - * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ - - eth_broadcast_addr(msg->da); - memcpy(msg->sa, sta->sta.addr, ETH_ALEN); - msg->len = htons(6); - msg->dsap = 0; - msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ - msg->control = 0xaf; /* XID response lsb.1111F101. - * F=0 (no poll command; unsolicited frame) */ - msg->xid_info[0] = 0x81; /* XID format identifier */ - msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ - msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ - - skb->dev = sta->sdata->dev; - skb->protocol = eth_type_trans(skb, sta->sdata->dev); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx_ni(skb); -} - static int sta_apply_auth_flags(struct ieee80211_local *local, struct sta_info *sta, u32 mask, u32 set) @@ -1442,7 +1398,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, struct sta_info *sta; struct ieee80211_sub_if_data *sdata; int err; - int layer2_update; if (params->vlan) { sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); @@ -1486,18 +1441,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, test_sta_flag(sta, WLAN_STA_ASSOC)) rate_control_rate_init(sta); - layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || - sdata->vif.type == NL80211_IFTYPE_AP; - err = sta_info_insert_rcu(sta); if (err) { rcu_read_unlock(); return err; } - if (layer2_update) - ieee80211_send_layer2_update(sta); - rcu_read_unlock(); return 0; @@ -1595,10 +1544,11 @@ static int ieee80211_change_station(struct wiphy *wiphy, sta->sdata = vlansdata; ieee80211_check_fast_xmit(sta); - if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) + if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { ieee80211_vif_inc_num_mcast(sta->sdata); - - ieee80211_send_layer2_update(sta); + cfg80211_send_layer2_update(sta->sdata->dev, + sta->sta.addr); + } } err = sta_apply_parameters(local, sta, params); @@ -2850,6 +2800,28 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, return err; } +static void ieee80211_end_cac(struct wiphy *wiphy, + struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + + mutex_lock(&local->mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + /* it might be waiting for the local->mtx, but then + * by the time it gets it, sdata->wdev.cac_started + * will no longer be true + */ + cancel_delayed_work(&sdata->dfs_cac_timer_work); + + if (sdata->wdev.cac_started) { + ieee80211_vif_release_channel(sdata); + sdata->wdev.cac_started = false; + } + } + mutex_unlock(&local->mtx); +} + static struct cfg80211_beacon_data * cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) { @@ -3780,6 +3752,7 @@ const struct cfg80211_ops mac80211_config_ops = { #endif .get_channel = ieee80211_cfg_get_channel, .start_radar_detection = ieee80211_start_radar_detection, + .end_cac = ieee80211_end_cac, .channel_switch = ieee80211_channel_switch, .set_qos_map = ieee80211_set_qos_map, .set_ap_chanwidth = ieee80211_set_ap_chanwidth, diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index fab0764c315fe7f65350dfe2adfce6d2ef46e391..994dde6e5f9d91df43624915d85d143b8b623de1 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -326,6 +326,9 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, unsigned long fail_avg = ewma_mesh_fail_avg_read(&sta->mesh->fail_avg); + if (sta->mesh->plink_state != NL80211_PLINK_ESTAB) + return MAX_METRIC; + /* Try to get rate based on HW/SW RC algorithm. * Rate is returned in units of Kbps, correct this * to comply with airtime calculation units diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index e57811e4b91f652fee66fc275cbe32d26fd5b79f..7ba4272642c9f24e85d77768df371e668371de9b 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -529,7 +529,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) /* (re)Initialize group rate indexes */ for(j = 0; j < MAX_THR_RATES; j++) - tmp_group_tp_rate[j] = group; + tmp_group_tp_rate[j] = MCS_GROUP_RATES * group; for (i = 0; i < MCS_GROUP_RATES; i++) { if (!(mi->supported[group] & BIT(i))) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4a6b3c7b35e3795844ec1520f59fa8a7f082f00d..31000622376dfe72f2a2ad73342d4d9337f04f84 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3227,9 +3227,18 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): /* process for all: mesh, mlme, ibss */ break; + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + if (is_multicast_ether_addr(mgmt->da) && + !is_broadcast_ether_addr(mgmt->da)) + return RX_DROP_MONITOR; + + /* process only for station/IBSS */ + if (sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_ADHOC) + return RX_DROP_MONITOR; + break; case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): - case cpu_to_le16(IEEE80211_STYPE_DEAUTH): case cpu_to_le16(IEEE80211_STYPE_DISASSOC): if (is_multicast_ether_addr(mgmt->da) && !is_broadcast_ether_addr(mgmt->da)) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1a86974b02e39bb47c6482e4f429afc6058c33d5..627dc642f894ee188c0bd14e6cd9746fa9aaa714 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1899,6 +1899,10 @@ int sta_info_move_state(struct sta_info *sta, ieee80211_check_fast_xmit(sta); ieee80211_check_fast_rx(sta); } + if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN || + sta->sdata->vif.type == NL80211_IFTYPE_AP) + cfg80211_send_layer2_update(sta->sdata->dev, + sta->sta.addr); break; default: break; diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index b3622823bad23b9a34a58b09fea1dd3e067bbcf2..ebd66e8f46b3f81b017719a99066c14e3f1fdebe 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -266,9 +266,21 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, if ((keyid >> 6) != key->conf.keyidx) return TKIP_DECRYPT_INVALID_KEYIDX; - if (rx_ctx->ctx.state != TKIP_STATE_NOT_INIT && - (iv32 < rx_ctx->iv32 || - (iv32 == rx_ctx->iv32 && iv16 <= rx_ctx->iv16))) + /* Reject replays if the received TSC is smaller than or equal to the + * last received value in a valid message, but with an exception for + * the case where a new key has been set and no valid frame using that + * key has yet received and the local RSC was initialized to 0. This + * exception allows the very first frame sent by the transmitter to be + * accepted even if that transmitter were to use TSC 0 (IEEE 802.11 + * described TSC to be initialized to 1 whenever a new key is taken into + * use). + */ + if (iv32 < rx_ctx->iv32 || + (iv32 == rx_ctx->iv32 && + (iv16 < rx_ctx->iv16 || + (iv16 == rx_ctx->iv16 && + (rx_ctx->iv32 || rx_ctx->iv16 || + rx_ctx->ctx.state != TKIP_STATE_NOT_INIT))))) return TKIP_DECRYPT_REPLAY; if (only_iv) { diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c index 6e558a419f60337a28426db411d88c7fed60213a..6c01166f972b90460f1b167fe21879da5f9be722 100644 --- a/net/mpls/mpls_iptunnel.c +++ b/net/mpls/mpls_iptunnel.c @@ -28,7 +28,7 @@ #include "internal.h" static const struct nla_policy mpls_iptunnel_policy[MPLS_IPTUNNEL_MAX + 1] = { - [MPLS_IPTUNNEL_DST] = { .type = NLA_U32 }, + [MPLS_IPTUNNEL_DST] = { .len = sizeof(u32) }, [MPLS_IPTUNNEL_TTL] = { .type = NLA_U8 }, }; diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h index 8ad2b52a0b328249688656c1fa80a7135b932c02..3c0e345367a57bced27a7f1cad66ecf5806d2d99 100644 --- a/net/netfilter/ipset/ip_set_bitmap_gen.h +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h @@ -64,9 +64,9 @@ mtype_destroy(struct ip_set *set) if (SET_WITH_TIMEOUT(set)) del_timer_sync(&map->gc); - ip_set_free(map->members); if (set->dsize && set->extensions & IPSET_EXT_DESTROY) mtype_ext_cleanup(set); + ip_set_free(map->members); ip_set_free(map); set->data = NULL; @@ -79,7 +79,7 @@ mtype_flush(struct ip_set *set) if (set->extensions & IPSET_EXT_DESTROY) mtype_ext_cleanup(set); - memset(map->members, 0, map->memsize); + bitmap_zero(map->members, map->elements); set->elements = 0; set->ext_size = 0; } diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index 4783efff0bde6b7c70707c8153563669308d995a..a4c104a4977fd9fd129dfe0553f98328f09ac189 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c @@ -40,7 +40,7 @@ MODULE_ALIAS("ip_set_bitmap:ip"); /* Type structure */ struct bitmap_ip { - void *members; /* the set members */ + unsigned long *members; /* the set members */ u32 first_ip; /* host byte order, included in range */ u32 last_ip; /* host byte order, included in range */ u32 elements; /* number of max elements in the set */ @@ -222,7 +222,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, u32 first_ip, u32 last_ip, u32 elements, u32 hosts, u8 netmask) { - map->members = ip_set_alloc(map->memsize); + map->members = bitmap_zalloc(elements, GFP_KERNEL | __GFP_NOWARN); if (!map->members) return false; map->first_ip = first_ip; @@ -315,7 +315,7 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[], if (!map) return -ENOMEM; - map->memsize = bitmap_bytes(0, elements - 1); + map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long); set->variant = &bitmap_ip; if (!init_map_ip(set, map, first_ip, last_ip, elements, hosts, netmask)) { diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 9a065f672d3a56f33a22e38937780ab59d318c13..8e58e7e349819c4f1bf71a5b0af1f6a6b93fea07 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c @@ -46,7 +46,7 @@ enum { /* Type structure */ struct bitmap_ipmac { - void *members; /* the set members */ + unsigned long *members; /* the set members */ u32 first_ip; /* host byte order, included in range */ u32 last_ip; /* host byte order, included in range */ u32 elements; /* number of max elements in the set */ @@ -299,7 +299,7 @@ static bool init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, u32 first_ip, u32 last_ip, u32 elements) { - map->members = ip_set_alloc(map->memsize); + map->members = bitmap_zalloc(elements, GFP_KERNEL | __GFP_NOWARN); if (!map->members) return false; map->first_ip = first_ip; @@ -363,7 +363,7 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[], if (!map) return -ENOMEM; - map->memsize = bitmap_bytes(0, elements - 1); + map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long); set->variant = &bitmap_ipmac; if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { kfree(map); diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index 7f0c733358a428225e15afe611aad1edcd52812a..6771b362a123ae8a66fad97b3188f75fe159fafb 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c @@ -34,7 +34,7 @@ MODULE_ALIAS("ip_set_bitmap:port"); /* Type structure */ struct bitmap_port { - void *members; /* the set members */ + unsigned long *members; /* the set members */ u16 first_port; /* host byte order, included in range */ u16 last_port; /* host byte order, included in range */ u32 elements; /* number of max elements in the set */ @@ -207,7 +207,7 @@ static bool init_map_port(struct ip_set *set, struct bitmap_port *map, u16 first_port, u16 last_port) { - map->members = ip_set_alloc(map->memsize); + map->members = bitmap_zalloc(map->elements, GFP_KERNEL | __GFP_NOWARN); if (!map->members) return false; map->first_port = first_port; @@ -250,7 +250,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[], return -ENOMEM; map->elements = elements; - map->memsize = bitmap_bytes(0, map->elements); + map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long); set->variant = &bitmap_port; if (!init_map_port(set, map, first_port, last_port)) { kfree(map); diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 94d74ec61f42cc81a7610405a8ea2518631a50da..c2b21c9c12295f90c425be644c0275fcc90ca484 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1639,6 +1639,7 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb, struct ip_set *set; struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {}; int ret = 0; + u32 lineno; if (unlikely(protocol_failed(attr) || !attr[IPSET_ATTR_SETNAME] || @@ -1655,7 +1656,7 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb, return -IPSET_ERR_PROTOCOL; rcu_read_lock_bh(); - ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0, 0); + ret = set->variant->uadt(set, tb, IPSET_TEST, &lineno, 0, 0); rcu_read_unlock_bh(); /* Userspace can't trigger element to be re-added */ if (ret == -EAGAIN) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 08b31b1a14d6ea5dfa6a58f1267dc658bea1467e..829b89701522b5e676496ddeac172bfd3355bdc5 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -3437,6 +3437,9 @@ static void __net_exit ctnetlink_net_exit_batch(struct list_head *net_exit_list) list_for_each_entry(net, net_exit_list, exit_list) ctnetlink_net_exit(net); + + /* wait for other cpus until they are done with ctnl_notifiers */ + synchronize_rcu(); } static struct pernet_operations ctnetlink_net_ops = { diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 7ef126489d4ed1e4fc6087111f94e2cf3544df2b..91490446ebb42ea9d70d91dd0a5ec1c9b8e02d81 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -3917,14 +3917,20 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, if (nla[NFTA_SET_ELEM_DATA] == NULL && !(flags & NFT_SET_ELEM_INTERVAL_END)) return -EINVAL; - if (nla[NFTA_SET_ELEM_DATA] != NULL && - flags & NFT_SET_ELEM_INTERVAL_END) - return -EINVAL; } else { if (nla[NFTA_SET_ELEM_DATA] != NULL) return -EINVAL; } + if ((flags & NFT_SET_ELEM_INTERVAL_END) && + (nla[NFTA_SET_ELEM_DATA] || + nla[NFTA_SET_ELEM_OBJREF] || + nla[NFTA_SET_ELEM_TIMEOUT] || + nla[NFTA_SET_ELEM_EXPIRATION] || + nla[NFTA_SET_ELEM_USERDATA] || + nla[NFTA_SET_ELEM_EXPR])) + return -EINVAL; + timeout = 0; if (nla[NFTA_SET_ELEM_TIMEOUT] != NULL) { if (!(set->flags & NFT_SET_TIMEOUT)) diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c index 33aa2ac3a62ef6cf7b9879e81eafae3a95ec329d..73f8f99b1193bef9698f38b23d939538cbee8b3b 100644 --- a/net/netfilter/nft_set_hash.c +++ b/net/netfilter/nft_set_hash.c @@ -442,6 +442,23 @@ static bool nft_hash_lookup_fast(const struct net *net, return false; } +static u32 nft_jhash(const struct nft_set *set, const struct nft_hash *priv, + const struct nft_set_ext *ext) +{ + const struct nft_data *key = nft_set_ext_key(ext); + u32 hash, k1; + + if (set->klen == 4) { + k1 = *(u32 *)key; + hash = jhash_1word(k1, priv->seed); + } else { + hash = jhash(key, set->klen, priv->seed); + } + hash = reciprocal_scale(hash, priv->buckets); + + return hash; +} + static int nft_hash_insert(const struct net *net, const struct nft_set *set, const struct nft_set_elem *elem, struct nft_set_ext **ext) @@ -451,8 +468,7 @@ static int nft_hash_insert(const struct net *net, const struct nft_set *set, u8 genmask = nft_genmask_next(net); u32 hash; - hash = jhash(nft_set_ext_key(&this->ext), set->klen, priv->seed); - hash = reciprocal_scale(hash, priv->buckets); + hash = nft_jhash(set, priv, &this->ext); hlist_for_each_entry(he, &priv->table[hash], node) { if (!memcmp(nft_set_ext_key(&this->ext), nft_set_ext_key(&he->ext), set->klen) && @@ -491,8 +507,7 @@ static void *nft_hash_deactivate(const struct net *net, u8 genmask = nft_genmask_next(net); u32 hash; - hash = jhash(nft_set_ext_key(&this->ext), set->klen, priv->seed); - hash = reciprocal_scale(hash, priv->buckets); + hash = nft_jhash(set, priv, &this->ext); hlist_for_each_entry(he, &priv->table[hash], node) { if (!memcmp(nft_set_ext_key(&this->ext), &elem->key.val, set->klen) || diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index dd3d13799cb634e8889ae2e3a0a088711cfea1a4..7bc631bfb101e43e3ec722a962f8b3feac81ed9f 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -959,60 +959,11 @@ static struct genl_family genl_ctrl __ro_after_init = { .netnsok = true, }; -static int genl_bind(struct net *net, int group) -{ - struct genl_family *f; - int err = 0; - unsigned int id; - - down_read(&cb_lock); - - idr_for_each_entry(&genl_fam_idr, f, id) { - if (group >= f->mcgrp_offset && - group < f->mcgrp_offset + f->n_mcgrps) { - int fam_grp = group - f->mcgrp_offset; - - if (!f->netnsok && net != &init_net) - err = -ENOENT; - else if (f->mcast_bind) - err = f->mcast_bind(net, fam_grp); - else - err = 0; - break; - } - } - up_read(&cb_lock); - - return err; -} - -static void genl_unbind(struct net *net, int group) -{ - struct genl_family *f; - unsigned int id; - - down_read(&cb_lock); - - idr_for_each_entry(&genl_fam_idr, f, id) { - if (group >= f->mcgrp_offset && - group < f->mcgrp_offset + f->n_mcgrps) { - int fam_grp = group - f->mcgrp_offset; - - if (f->mcast_unbind) - f->mcast_unbind(net, fam_grp); - break; - } - } - up_read(&cb_lock); -} - static int __net_init genl_pernet_init(struct net *net) { struct netlink_kernel_cfg cfg = { .input = genl_rcv, .flags = NL_CFG_F_NONROOT_RECV, - .bind = genl_bind, - .unbind = genl_unbind, }; /* we'll bump the group number right afterwards */ diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 5aa11d1b38657ba2f839e6028f643095e9d38edd..69a50fad81dcb95aee22742822365105259b5e3d 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1337,15 +1337,21 @@ static void packet_sock_destruct(struct sock *sk) static bool fanout_flow_is_huge(struct packet_sock *po, struct sk_buff *skb) { - u32 rxhash; + u32 *history = po->rollover->history; + u32 victim, rxhash; int i, count = 0; rxhash = skb_get_hash(skb); for (i = 0; i < ROLLOVER_HLEN; i++) - if (po->rollover->history[i] == rxhash) + if (READ_ONCE(history[i]) == rxhash) count++; - po->rollover->history[prandom_u32() % ROLLOVER_HLEN] = rxhash; + victim = prandom_u32() % ROLLOVER_HLEN; + + /* Avoid dirtying the cache line if possible */ + if (READ_ONCE(history[victim]) != rxhash) + WRITE_ONCE(history[victim], rxhash); + return count > (ROLLOVER_HLEN >> 1); } @@ -3407,20 +3413,29 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, sock_recv_ts_and_drops(msg, sk, skb); if (msg->msg_name) { + int copy_len; + /* If the address length field is there to be filled * in, we fill it in now. */ if (sock->type == SOCK_PACKET) { __sockaddr_check_size(sizeof(struct sockaddr_pkt)); msg->msg_namelen = sizeof(struct sockaddr_pkt); + copy_len = msg->msg_namelen; } else { struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr); + copy_len = msg->msg_namelen; + if (msg->msg_namelen < sizeof(struct sockaddr_ll)) { + memset(msg->msg_name + + offsetof(struct sockaddr_ll, sll_addr), + 0, sizeof(sll->sll_addr)); + msg->msg_namelen = sizeof(struct sockaddr_ll); + } } - memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, - msg->msg_namelen); + memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, copy_len); } if (pkt_sk(sk)->auxdata) { diff --git a/net/rds/ib_stats.c b/net/rds/ib_stats.c index 9252ad126335971fa202e5aee6e2babb55d969e0..ac46d8961b61a199032fbed88337558a713a1845 100644 --- a/net/rds/ib_stats.c +++ b/net/rds/ib_stats.c @@ -42,7 +42,7 @@ DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_ib_statistics, rds_ib_stats); static const char *const rds_ib_stat_names[] = { "ib_connect_raced", "ib_listen_closed_stale", - "s_ib_evt_handler_call", + "ib_evt_handler_call", "ib_tasklet_call", "ib_tx_cq_event", "ib_tx_ring_full", diff --git a/net/rds/stats.c b/net/rds/stats.c index 73be187d389ed044c886d22e4960905283d9de87..6bbab4d74c4fecfe3a3b94851c87406d6d887b17 100644 --- a/net/rds/stats.c +++ b/net/rds/stats.c @@ -76,6 +76,8 @@ static const char *const rds_stat_names[] = { "cong_update_received", "cong_send_error", "cong_send_blocked", + "recv_bytes_added_to_sock", + "recv_bytes_freed_fromsock", }; void rds_stats_info_copy(struct rds_info_iterator *iter, diff --git a/net/rfkill/core.c b/net/rfkill/core.c index b22c51b911c8f6620352d53cd91ca7a122da26a7..fdca887aa7314a132fa037a75a4683c987991dc9 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -993,10 +993,13 @@ static void rfkill_sync_work(struct work_struct *work) int __must_check rfkill_register(struct rfkill *rfkill) { static unsigned long rfkill_no; - struct device *dev = &rfkill->dev; + struct device *dev; int error; - BUG_ON(!rfkill); + if (!rfkill) + return -EINVAL; + + dev = &rfkill->dev; mutex_lock(&rfkill_global_mutex); diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 5b67cb5d47f0e7579dcb032dc3c68809e23de477..edddbacf33bc8682125eceebc5e1ebf748a227ba 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -404,6 +404,9 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb, } break; #endif + + default: + BUG(); } up_write(&conn->params.local->defrag_sem); diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 529bb064c4a4d27f891df1443e60e1eeef39f1f0..dcfaa4f9c7c5b8dfb31b046fa92f0c7f0b668fe4 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -371,7 +371,11 @@ static int __init mirred_init_module(void) return err; pr_info("Mirror/redirect action on\n"); - return tcf_register_action(&act_mirred_ops, &mirred_net_ops); + err = tcf_register_action(&act_mirred_ops, &mirred_net_ops); + if (err) + unregister_netdevice_notifier(&mirred_device_notifier); + + return err; } static void __exit mirred_cleanup_module(void) diff --git a/net/sched/ematch.c b/net/sched/ematch.c index 03b677bc07005c7f864077edad6f22ca9dadbfdd..a48dca26f17873b30d26d513507452b85d2df872 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -242,6 +242,9 @@ static int tcf_em_validate(struct tcf_proto *tp, goto errout; if (em->ops->change) { + err = -EINVAL; + if (em_hdr->flags & TCF_EM_SIMPLE) + goto errout; err = em->ops->change(net, data, data_len, em); if (err < 0) goto errout; @@ -267,12 +270,12 @@ static int tcf_em_validate(struct tcf_proto *tp, } em->data = (unsigned long) v; } + em->datalen = data_len; } } em->matchid = em_hdr->matchid; em->flags = em_hdr->flags; - em->datalen = data_len; em->net = net; err = 0; diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index f50eb87cfe7996ef03d6ffd8b6869ac9fcec969e..7a944f508cae82d07669db3a0219aff7fc424d40 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -734,7 +734,7 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt) if (tb[TCA_FQ_QUANTUM]) { u32 quantum = nla_get_u32(tb[TCA_FQ_QUANTUM]); - if (quantum > 0) + if (quantum > 0 && quantum <= (1 << 20)) q->quantum = quantum; else err = -EINVAL; diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 6266121a03f9ac5c1266b5e978c39c1fe9065022..328b043edf074c3224539a10cc4cba896b416b4c 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -431,8 +431,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct netem_skb_cb *cb; struct sk_buff *skb2; struct sk_buff *segs = NULL; - unsigned int len = 0, last_len, prev_len = qdisc_pkt_len(skb); - int nb = 0; + unsigned int prev_len = qdisc_pkt_len(skb); int count = 1; int rc = NET_XMIT_SUCCESS; int rc_drop = NET_XMIT_DROP; @@ -489,6 +488,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, segs = netem_segment(skb, sch, to_free); if (!segs) return rc_drop; + qdisc_skb_cb(segs)->pkt_len = segs->len; } else { segs = skb; } @@ -504,6 +504,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) { qdisc_drop(skb, sch, to_free); + skb = NULL; goto finish_segs; } @@ -579,6 +580,12 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, finish_segs: if (segs) { + unsigned int len, last_len; + int nb; + + len = skb ? skb->len : 0; + nb = skb ? 1 : 0; + while (segs) { skb2 = segs->next; segs->next = NULL; @@ -594,9 +601,10 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, } segs = skb2; } - sch->q.qlen += nb; - if (nb > 1) - qdisc_tree_reduce_backlog(sch, 1 - nb, prev_len - len); + /* Parent qdiscs accounted for 1 skb of size @prev_len */ + qdisc_tree_reduce_backlog(sch, -(nb - 1), -(len - prev_len)); + } else if (!skb) { + return NET_XMIT_DROP; } return NET_XMIT_SUCCESS; } diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index cc997ace64d4d3ee0b133b284e11194da813645a..a8fc70a3c48ce8acc8d6b6e12ae2780998a3af8c 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -265,8 +265,14 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct prio_sched_data *q = qdisc_priv(sch); unsigned long band = arg - 1; - if (new == NULL) - new = &noop_qdisc; + if (!new) { + new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, + TC_H_MAKE(sch->handle, arg)); + if (!new) + new = &noop_qdisc; + else + qdisc_hash_add(new, true); + } *old = qdisc_replace(sch, new, &q->queues[band]); return 0; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index bf0c61adb09c1e42a1772e58daf0c15456e99261..482bb0a5d4d3058df2d5c24378d8ed415ba72391 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1359,8 +1359,10 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, /* Generate an INIT ACK chunk. */ new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC, 0); - if (!new_obj) - goto nomem; + if (!new_obj) { + error = -ENOMEM; + break; + } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); @@ -1382,7 +1384,8 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, if (!new_obj) { if (cmd->obj.chunk) sctp_chunk_free(cmd->obj.chunk); - goto nomem; + error = -ENOMEM; + break; } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); @@ -1429,8 +1432,10 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, /* Generate a SHUTDOWN chunk. */ new_obj = sctp_make_shutdown(asoc, chunk); - if (!new_obj) - goto nomem; + if (!new_obj) { + error = -ENOMEM; + break; + } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); break; @@ -1760,11 +1765,17 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, break; } - if (error) + if (error) { + cmd = sctp_next_cmd(commands); + while (cmd) { + if (cmd->verb == SCTP_CMD_REPLY) + sctp_chunk_free(cmd->obj.chunk); + cmd = sctp_next_cmd(commands); + } break; + } } -out: /* If this is in response to a received chunk, wait until * we are done with the packet to open the queue so that we don't * send multiple packets in response to a single request. @@ -1779,8 +1790,5 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, sp->data_ready_signalled = 0; return error; -nomem: - error = -ENOMEM; - goto out; } diff --git a/net/socket.c b/net/socket.c index 454033ef6c3ac0d7f0e5e87b15e3e08072215b70..1e415a5fc352c9ad684f8eac3026553c494a1cbc 100644 --- a/net/socket.c +++ b/net/socket.c @@ -3292,6 +3292,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCSARP: case SIOCGARP: case SIOCDARP: + case SIOCOUTQNSD: case SIOCATMARK: return sock_do_ioctl(net, sock, cmd, arg); } diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 2aaf46599126e55eee01e819f06cf0ff1b61d858..c5e991d14888a4c818d383dd4bc3f360146b6c30 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -264,6 +264,7 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) ia->ri_device->name, sap, rpc_get_port(sap)); #endif + init_completion(&ia->ri_remove_done); set_bit(RPCRDMA_IAF_REMOVING, &ia->ri_flags); ep->rep_connected = -ENODEV; xprt_force_disconnect(&xprt->rx_xprt); @@ -319,7 +320,6 @@ rpcrdma_create_id(struct rpcrdma_xprt *xprt, int rc; init_completion(&ia->ri_done); - init_completion(&ia->ri_remove_done); id = rdma_create_id(&init_net, rpcrdma_conn_upcall, xprt, RDMA_PS_TCP, IB_QPT_RC); diff --git a/net/tipc/link.c b/net/tipc/link.c index da749916faac4932d878d3afe6ec7e56eb206d07..82e4e0e152d1608c3133f5a74bafd5fdfed179e4 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -811,18 +811,31 @@ static int link_schedule_user(struct tipc_link *l, struct tipc_msg *hdr) */ void link_prepare_wakeup(struct tipc_link *l) { + struct sk_buff_head *wakeupq = &l->wakeupq; + struct sk_buff_head *inputq = l->inputq; struct sk_buff *skb, *tmp; - int imp, i = 0; + struct sk_buff_head tmpq; + int avail[5] = {0,}; + int imp = 0; + + __skb_queue_head_init(&tmpq); - skb_queue_walk_safe(&l->wakeupq, skb, tmp) { + for (; imp <= TIPC_SYSTEM_IMPORTANCE; imp++) + avail[imp] = l->backlog[imp].limit - l->backlog[imp].len; + + skb_queue_walk_safe(wakeupq, skb, tmp) { imp = TIPC_SKB_CB(skb)->chain_imp; - if (l->backlog[imp].len < l->backlog[imp].limit) { - skb_unlink(skb, &l->wakeupq); - skb_queue_tail(l->inputq, skb); - } else if (i++ > 10) { - break; - } + if (avail[imp] <= 0) + continue; + avail[imp]--; + __skb_unlink(skb, wakeupq); + __skb_queue_tail(&tmpq, skb); } + + spin_lock_bh(&inputq->lock); + skb_queue_splice_tail(&tmpq, inputq); + spin_unlock_bh(&inputq->lock); + } void tipc_link_reset(struct tipc_link *l) diff --git a/net/tipc/node.c b/net/tipc/node.c index 42e9bdcc4bb6eee93b73b64d789d82dce71a09a7..82f8f69f4d6b0d7a1e644f85b116e2b74686015d 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -688,10 +688,10 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id, static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete) { struct tipc_link_entry *le = &n->links[bearer_id]; + struct tipc_media_addr *maddr = NULL; struct tipc_link *l = le->link; - struct tipc_media_addr *maddr; - struct sk_buff_head xmitq; int old_bearer_id = bearer_id; + struct sk_buff_head xmitq; if (!l) return; @@ -713,7 +713,8 @@ static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete) tipc_node_write_unlock(n); if (delete) tipc_mon_remove_peer(n->net, n->addr, old_bearer_id); - tipc_bearer_xmit(n->net, bearer_id, &xmitq, maddr); + if (!skb_queue_empty(&xmitq)) + tipc_bearer_xmit(n->net, bearer_id, &xmitq, maddr); tipc_sk_rcv(n->net, &le->inputq); } diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 21929ba196eb781de91b7f641d15766dcd22d1f8..d9ec6335c7dcf6e1aa6eda5b21c92247c3b6d288 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -487,7 +487,7 @@ static void __tipc_shutdown(struct socket *sock, int error) struct sock *sk = sock->sk; struct tipc_sock *tsk = tipc_sk(sk); struct net *net = sock_net(sk); - long timeout = CONN_TIMEOUT_DEFAULT; + long timeout = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT); u32 dnode = tsk_peer_node(tsk); struct sk_buff *skb; diff --git a/net/tipc/sysctl.c b/net/tipc/sysctl.c index 1a779b1e85100b501c1f0cde29cbfaa0d98fb4eb..40f6d82083d7bbcc3968b0091811519103fba497 100644 --- a/net/tipc/sysctl.c +++ b/net/tipc/sysctl.c @@ -37,6 +37,8 @@ #include +static int zero; +static int one = 1; static struct ctl_table_header *tipc_ctl_hdr; static struct ctl_table tipc_table[] = { @@ -45,14 +47,16 @@ static struct ctl_table tipc_table[] = { .data = &sysctl_tipc_rmem, .maxlen = sizeof(sysctl_tipc_rmem), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &one, }, { .procname = "named_timeout", .data = &sysctl_tipc_named_timeout, .maxlen = sizeof(sysctl_tipc_named_timeout), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, }, {} }; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 99f581a61cfac1434cad0312604245bfbae46852..091e93798eacc92b40c44d4b4a27ac7dc055c1da 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -644,6 +644,9 @@ static unsigned int unix_poll(struct file *, struct socket *, poll_table *); static unsigned int unix_dgram_poll(struct file *, struct socket *, poll_table *); static int unix_ioctl(struct socket *, unsigned int, unsigned long); +#ifdef CONFIG_COMPAT +static int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +#endif static int unix_shutdown(struct socket *, int); static int unix_stream_sendmsg(struct socket *, struct msghdr *, size_t); static int unix_stream_recvmsg(struct socket *, struct msghdr *, size_t, int); @@ -685,6 +688,9 @@ static const struct proto_ops unix_stream_ops = { .getname = unix_getname, .poll = unix_poll, .ioctl = unix_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = unix_compat_ioctl, +#endif .listen = unix_listen, .shutdown = unix_shutdown, .setsockopt = sock_no_setsockopt, @@ -708,6 +714,9 @@ static const struct proto_ops unix_dgram_ops = { .getname = unix_getname, .poll = unix_dgram_poll, .ioctl = unix_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = unix_compat_ioctl, +#endif .listen = sock_no_listen, .shutdown = unix_shutdown, .setsockopt = sock_no_setsockopt, @@ -730,6 +739,9 @@ static const struct proto_ops unix_seqpacket_ops = { .getname = unix_getname, .poll = unix_dgram_poll, .ioctl = unix_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = unix_compat_ioctl, +#endif .listen = unix_listen, .shutdown = unix_shutdown, .setsockopt = sock_no_setsockopt, @@ -2650,6 +2662,13 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return err; } +#ifdef CONFIG_COMPAT +static int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + return unix_ioctl(sock, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 33c5c5be319c3cdd55f353b57d4709d43082b27a..4ac59a65bd162556c5b17fcf30251a1bbb800a37 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -550,6 +550,10 @@ static inline int rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed) { int ret; + + if (!rdev->ops->set_wiphy_params) + return -EOPNOTSUPP; + trace_rdev_set_wiphy_params(&rdev->wiphy, changed); ret = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); trace_rdev_return_int(&rdev->wiphy, ret); @@ -1152,6 +1156,16 @@ rdev_start_radar_detection(struct cfg80211_registered_device *rdev, return ret; } +static inline void +rdev_end_cac(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + trace_rdev_end_cac(&rdev->wiphy, dev); + if (rdev->ops->end_cac) + rdev->ops->end_cac(&rdev->wiphy, dev); + trace_rdev_return_void(&rdev->wiphy); +} + static inline int rdev_set_mcast_rate(struct cfg80211_registered_device *rdev, struct net_device *dev, diff --git a/net/wireless/reg.c b/net/wireless/reg.c index dec93d90909ed9192c7b8b27bd80a24fe53139eb..8692ef603e76f8a79c06407438cd66b00ea55f94 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1725,14 +1725,15 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) static void handle_channel_custom(struct wiphy *wiphy, struct ieee80211_channel *chan, - const struct ieee80211_regdomain *regd) + const struct ieee80211_regdomain *regd, + u32 min_bw) { u32 bw_flags = 0; const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL; u32 bw; - for (bw = MHZ_TO_KHZ(20); bw >= MHZ_TO_KHZ(5); bw = bw / 2) { + for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) { reg_rule = freq_reg_info_regd(MHZ_TO_KHZ(chan->center_freq), regd, bw); if (!IS_ERR(reg_rule)) @@ -1788,8 +1789,14 @@ static void handle_band_custom(struct wiphy *wiphy, if (!sband) return; + /* + * We currently assume that you always want at least 20 MHz, + * otherwise channel 12 might get enabled if this rule is + * compatible to US, which permits 2402 - 2472 MHz. + */ for (i = 0; i < sband->n_channels; i++) - handle_channel_custom(wiphy, &sband->channels[i], regd); + handle_channel_custom(wiphy, &sband->channels[i], regd, + MHZ_TO_KHZ(20)); } /* Used by drivers prior to wiphy registration */ @@ -3310,6 +3317,25 @@ bool regulatory_pre_cac_allowed(struct wiphy *wiphy) return pre_cac_allowed; } +static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev) +{ + struct wireless_dev *wdev; + /* If we finished CAC or received radar, we should end any + * CAC running on the same channels. + * the check !cfg80211_chandef_dfs_usable contain 2 options: + * either all channels are available - those the CAC_FINISHED + * event has effected another wdev state, or there is a channel + * in unavailable state in wdev chandef - those the RADAR_DETECTED + * event has effected another wdev state. + * In both cases we should end the CAC on the wdev. + */ + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { + if (wdev->cac_started && + !cfg80211_chandef_dfs_usable(&rdev->wiphy, &wdev->chandef)) + rdev_end_cac(rdev, wdev->netdev); + } +} + void regulatory_propagate_dfs_state(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, enum nl80211_dfs_state dfs_state, @@ -3336,8 +3362,10 @@ void regulatory_propagate_dfs_state(struct wiphy *wiphy, cfg80211_set_dfs_state(&rdev->wiphy, chandef, dfs_state); if (event == NL80211_RADAR_DETECTED || - event == NL80211_RADAR_CAC_FINISHED) + event == NL80211_RADAR_CAC_FINISHED) { cfg80211_sched_dfs_chan_update(rdev); + cfg80211_check_and_end_cac(rdev); + } nl80211_radar_notify(rdev, chandef, event, NULL, GFP_KERNEL); } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index a9fa6d3c4cfc4a5b073c5373aae631235e16ac39..f4940870d83da685d90b2cb0390986f19e8c8eb5 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -624,6 +624,11 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa, TP_ARGS(wiphy, netdev) ); +DEFINE_EVENT(wiphy_netdev_evt, rdev_end_cac, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev) +); + DECLARE_EVENT_CLASS(station_add_change, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *mac, struct station_parameters *params), diff --git a/net/wireless/util.c b/net/wireless/util.c index d74c2bcda79184e19b00316b2a3e221e21df9940..81b9585ef16c2b010b4cd479aa02411efc57693e 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -659,7 +659,7 @@ __frame_add_frag(struct sk_buff *skb, struct page *page, struct skb_shared_info *sh = skb_shinfo(skb); int page_offset; - page_ref_inc(page); + get_page(page); page_offset = ptr - page_address(page); skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size); } @@ -1931,3 +1931,48 @@ bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb) return false; } EXPORT_SYMBOL(cfg80211_is_gratuitous_arp_unsolicited_na); + +/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ +struct iapp_layer2_update { + u8 da[ETH_ALEN]; /* broadcast */ + u8 sa[ETH_ALEN]; /* STA addr */ + __be16 len; /* 6 */ + u8 dsap; /* 0 */ + u8 ssap; /* 0 */ + u8 control; + u8 xid_info[3]; +} __packed; + +void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr) +{ + struct iapp_layer2_update *msg; + struct sk_buff *skb; + + /* Send Level 2 Update Frame to update forwarding tables in layer 2 + * bridge devices */ + + skb = dev_alloc_skb(sizeof(*msg)); + if (!skb) + return; + msg = skb_put(skb, sizeof(*msg)); + + /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) + * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ + + eth_broadcast_addr(msg->da); + ether_addr_copy(msg->sa, addr); + msg->len = htons(6); + msg->dsap = 0; + msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ + msg->control = 0xaf; /* XID response lsb.1111F101. + * F=0 (no poll command; unsolicited frame) */ + msg->xid_info[0] = 0x81; /* XID format identifier */ + msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ + msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx_ni(skb); +} +EXPORT_SYMBOL(cfg80211_send_layer2_update); diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index 6cdb054484d66d40e4523965457a619bd1c9154f..5236a3c2c0ccf337843fe7e61665dea711d8a77a 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -659,7 +659,8 @@ struct iw_statistics *get_wireless_stats(struct net_device *dev) return NULL; } -static int iw_handler_get_iwstats(struct net_device * dev, +/* noinline to avoid a bogus warning with -O3 */ +static noinline int iw_handler_get_iwstats(struct net_device * dev, struct iw_request_info * info, union iwreq_data * wrqu, char * extra) diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index a156b6dc3a72441cda4c19bd940abfc9c9e2f028..f4fa33b84cde75a56357e9def784737389d24a1d 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -764,6 +764,10 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, if (sk->sk_state == TCP_ESTABLISHED) goto out; + rc = -EALREADY; /* Do nothing if call is already in progress */ + if (sk->sk_state == TCP_SYN_SENT) + goto out; + sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; @@ -810,7 +814,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, /* Now the loop */ rc = -EINPROGRESS; if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) - goto out_put_neigh; + goto out; rc = x25_wait_for_connection_establishment(sk); if (rc) diff --git a/samples/bpf/syscall_tp_kern.c b/samples/bpf/syscall_tp_kern.c index 9149c524d279313c8cf8d2805224e7b7e02966c3..8833aacb9c8c89d3e738509fc2e971c44157f945 100644 --- a/samples/bpf/syscall_tp_kern.c +++ b/samples/bpf/syscall_tp_kern.c @@ -50,13 +50,27 @@ static __always_inline void count(void *map) SEC("tracepoint/syscalls/sys_enter_open") int trace_enter_open(struct syscalls_enter_open_args *ctx) { - count((void *)&enter_open_map); + count(&enter_open_map); + return 0; +} + +SEC("tracepoint/syscalls/sys_enter_openat") +int trace_enter_open_at(struct syscalls_enter_open_args *ctx) +{ + count(&enter_open_map); return 0; } SEC("tracepoint/syscalls/sys_exit_open") int trace_enter_exit(struct syscalls_exit_open_args *ctx) { - count((void *)&exit_open_map); + count(&exit_open_map); + return 0; +} + +SEC("tracepoint/syscalls/sys_exit_openat") +int trace_enter_exit_at(struct syscalls_exit_open_args *ctx) +{ + count(&exit_open_map); return 0; } diff --git a/samples/bpf/trace_event_user.c b/samples/bpf/trace_event_user.c index c7d525e5696ec01d569074199cf633fec53b646a..8c744587466264625ca813860588dc42459decc8 100644 --- a/samples/bpf/trace_event_user.c +++ b/samples/bpf/trace_event_user.c @@ -34,9 +34,9 @@ static void print_ksym(__u64 addr) return; sym = ksym_search(addr); printf("%s;", sym->name); - if (!strcmp(sym->name, "sys_read")) + if (!strstr(sym->name, "sys_read")) sys_read_seen = true; - else if (!strcmp(sym->name, "sys_write")) + else if (!strstr(sym->name, "sys_write")) sys_write_seen = true; } diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index b2a95af7df189509c5827bfe7af1d69918d5cfda..708c8f6a57173ad3cf9f00f5bfd1c92fc177efa3 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -14,16 +14,12 @@ ifdef CONFIG_GCC_PLUGINS endif ifdef CONFIG_GCC_PLUGIN_SANCOV - ifeq ($(CFLAGS_KCOV),) # It is needed because of the gcc-plugin.sh and gcc version checks. gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so - ifneq ($(PLUGINCC),) - CFLAGS_KCOV := $(SANCOV_PLUGIN) - else + ifeq ($(PLUGINCC),) $(warning warning: cannot use CONFIG_KCOV: -fsanitize-coverage=trace-pc is not supported by compiler) endif - endif endif gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so @@ -38,7 +34,7 @@ ifdef CONFIG_GCC_PLUGINS GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR - export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN + export DISABLE_LATENT_ENTROPY_PLUGIN ifneq ($(PLUGINCC),) # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication. diff --git a/scripts/Makefile.kcov b/scripts/Makefile.kcov new file mode 100644 index 0000000000000000000000000000000000000000..945724d226e84ddd0396944d6f8012600d86b1b4 --- /dev/null +++ b/scripts/Makefile.kcov @@ -0,0 +1,25 @@ +ifdef CONFIG_KCOV + +ifeq ($(call cc-option, -fsanitize-coverage=trace-pc -Werror),) + ifneq ($(CONFIG_COMPILE_TEST),y) + $(error Cannot use CONFIG_KCOV: \ + -fsanitize-coverage=trace-pc is not supported by compiler) + endif +endif + +ifdef CONFIG_KCOV_ENABLE_COMPARISONS + ifeq ($(call cc-option, -fsanitize-coverage=trace-cmp -Werror),) + ifneq ($(CONFIG_COMPILE_TEST),y) + $(error Cannot use CONFIG_KCOV_ENABLE_COMPARISONS: \ + -fsanitize-coverage=trace-cmp is not supported by compiler) + endif + endif +endif + +kcov-flags-$(CONFIG_CC_HAS_SANCOV_TRACE_PC) += -fsanitize-coverage=trace-pc +kcov-flags-$(CONFIG_KCOV_ENABLE_COMPARISONS) += -fsanitize-coverage=trace-cmp +kcov-flags-$(CONFIG_GCC_PLUGIN_SANCOV) += -fplugin=$(objtree)/scripts/gcc-plugins/sancov_plugin.so + +export CFLAGS_KCOV := $(kcov-flags-y) + +endif diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile index e2ff425f4c7ea6958beddb3571ed9ac72a3b9ea8..ea465799ced590a3f9653500642b71d81a6d353e 100644 --- a/scripts/gcc-plugins/Makefile +++ b/scripts/gcc-plugins/Makefile @@ -13,10 +13,6 @@ else export HOST_EXTRACXXFLAGS endif -ifneq ($(CFLAGS_KCOV), $(SANCOV_PLUGIN)) - GCC_PLUGIN := $(filter-out $(SANCOV_PLUGIN), $(GCC_PLUGIN)) -endif - export HOSTLIBS $(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index ed29bad1f03a3cf33097332fc67940b15154b2b4..96420b6209631dbfda8d94d2d270634d2bf319da 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -201,6 +201,13 @@ static int expr_eq(struct expr *e1, struct expr *e2) { int res, old_count; + /* + * A NULL expr is taken to be yes, but there's also a different way to + * represent yes. expr_is_yes() checks for either representation. + */ + if (!e1 || !e2) + return expr_is_yes(e1) && expr_is_yes(e2); + if (e1->type != e2->type) return 0; switch (e1->type) { diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 69a769904da74d304ff4c11acedbc1be210a9b6d..d4e674f6ffaf0d4059eb87f29b338180ff5ebe73 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -53,6 +53,10 @@ #define R_AARCH64_ABS64 257 #endif +#define R_ARM_PC24 1 +#define R_ARM_THM_CALL 10 +#define R_ARM_CALL 28 + static int fd_map; /* File descriptor for file being modified. */ static int mmap_failed; /* Boolean flag. */ static char gpfx; /* prefix for global symbol name (sometimes '_') */ @@ -429,6 +433,18 @@ is_mcounted_section_name(char const *const txtname) #define RECORD_MCOUNT_64 #include "recordmcount.h" +static int arm_is_fake_mcount(Elf32_Rel const *rp) +{ + switch (ELF32_R_TYPE(w(rp->r_info))) { + case R_ARM_THM_CALL: + case R_ARM_CALL: + case R_ARM_PC24: + return 0; + } + + return 1; +} + /* 64-bit EM_MIPS has weird ELF64_Rela.r_info. * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40] @@ -530,6 +546,7 @@ do_file(char const *const fname) altmcount = "__gnu_mcount_nc"; make_nop = make_nop_arm; rel_type_nop = R_ARM_NONE; + is_fake_mcount32 = arm_is_fake_mcount; break; case EM_AARCH64: reltype = R_AARCH64_ABS64; diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 6ae07e9aaa172dac7cd8820af0b9817afdf73f8a..812cdec9dd3be795990b56e0d0c9afa98d2dd1f1 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -191,6 +191,8 @@ static inline struct aa_label *begin_current_label_crit_section(void) { struct aa_label *label = aa_current_raw_label(); + might_sleep(); + if (label_is_stale(label)) { label = aa_get_newest_label(label); if (aa_replace_current_label(label) == 0) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 17893fde44873ade4c28a62b7a3729e73d7c161d..c58df3375390d1fa04f3c6b6991ac014eff85026 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -108,12 +108,12 @@ static int apparmor_ptrace_access_check(struct task_struct *child, struct aa_label *tracer, *tracee; int error; - tracer = begin_current_label_crit_section(); + tracer = __begin_current_label_crit_section(); tracee = aa_get_task_label(child); error = aa_may_ptrace(tracer, tracee, mode == PTRACE_MODE_READ ? AA_PTRACE_READ : AA_PTRACE_TRACE); aa_put_label(tracee); - end_current_label_crit_section(tracer); + __end_current_label_crit_section(tracer); return error; } diff --git a/security/keys/key.c b/security/keys/key.c index 87172f99f73e06962803ebd84aae5b5d263d0520..17244f5f54c6987cafdb656b62a65d54e15dbb68 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -297,6 +297,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, key->gid = gid; key->perm = perm; key->restrict_link = restrict_link; + key->last_used_at = ktime_get_real_seconds(); if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) key->flags |= 1 << KEY_FLAG_IN_QUOTA; diff --git a/security/security.c b/security/security.c index be7cbdc49f0122f4302e7582651abec9203c3f53..2655987c96381748b3c6ac4af6980fb4149234ff 100644 --- a/security/security.c +++ b/security/security.c @@ -1753,3 +1753,30 @@ void security_bpf_prog_free(struct bpf_prog_aux *aux) call_void_hook(bpf_prog_free_security, aux); } #endif /* CONFIG_BPF_SYSCALL */ + +#ifdef CONFIG_PERF_EVENTS +int security_perf_event_open(struct perf_event_attr *attr, int type) +{ + return call_int_hook(perf_event_open, 0, attr, type); +} + +int security_perf_event_alloc(struct perf_event *event) +{ + return call_int_hook(perf_event_alloc, 0, event); +} + +void security_perf_event_free(struct perf_event *event) +{ + call_void_hook(perf_event_free, event); +} + +int security_perf_event_read(struct perf_event *event) +{ + return call_int_hook(perf_event_read, 0, event); +} + +int security_perf_event_write(struct perf_event *event) +{ + return call_int_hook(perf_event_write, 0, event); +} +#endif /* CONFIG_PERF_EVENTS */ diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3a79403cdd327577c108c5aea8441600650e5950..84f89ab1f2b594cbb84a29dcc8acc1df3754cefb 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -870,6 +870,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, !strcmp(sb->s_type->name, "tracefs") || !strcmp(sb->s_type->name, "sysfs") || !strcmp(sb->s_type->name, "pstore") || + !strcmp(sb->s_type->name, "binder") || !strcmp(sb->s_type->name, "cgroup") || !strcmp(sb->s_type->name, "cgroup2")) sbsec->flags |= SE_SBGENFS; @@ -6620,6 +6621,68 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) } #endif + +#ifdef CONFIG_PERF_EVENTS +static int selinux_perf_event_open(struct perf_event_attr *attr, int type) +{ + u32 requested, sid = current_sid(); + + if (type == PERF_SECURITY_OPEN) + requested = PERF_EVENT__OPEN; + else if (type == PERF_SECURITY_CPU) + requested = PERF_EVENT__CPU; + else if (type == PERF_SECURITY_KERNEL) + requested = PERF_EVENT__KERNEL; + else if (type == PERF_SECURITY_TRACEPOINT) + requested = PERF_EVENT__TRACEPOINT; + else + return -EINVAL; + + return avc_has_perm(&selinux_state, sid, sid, SECCLASS_PERF_EVENT, + requested, NULL); +} + +static int selinux_perf_event_alloc(struct perf_event *event) +{ + struct perf_event_security_struct *perfsec; + + perfsec = kzalloc(sizeof(*perfsec), GFP_KERNEL); + if (!perfsec) + return -ENOMEM; + + perfsec->sid = current_sid(); + event->security = perfsec; + + return 0; +} + +static void selinux_perf_event_free(struct perf_event *event) +{ + struct perf_event_security_struct *perfsec = event->security; + + event->security = NULL; + kfree(perfsec); +} + +static int selinux_perf_event_read(struct perf_event *event) +{ + struct perf_event_security_struct *perfsec = event->security; + u32 sid = current_sid(); + + return avc_has_perm(&selinux_state, sid, perfsec->sid, + SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL); +} + +static int selinux_perf_event_write(struct perf_event *event) +{ + struct perf_event_security_struct *perfsec = event->security; + u32 sid = current_sid(); + + return avc_has_perm(&selinux_state, sid, perfsec->sid, + SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL); +} +#endif + static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), @@ -6849,6 +6912,14 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free), #endif + +#ifdef CONFIG_PERF_EVENTS + LSM_HOOK_INIT(perf_event_open, selinux_perf_event_open), + LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc), + LSM_HOOK_INIT(perf_event_free, selinux_perf_event_free), + LSM_HOOK_INIT(perf_event_read, selinux_perf_event_read), + LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write), +#endif }; static __init int selinux_init(void) diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 702bdaf07252dd63482316136797b510542c38ff..34631690b5f966b28b3d7dd855ffe478ae37273e 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -241,6 +241,8 @@ struct security_class_mapping secclass_map[] = { { "manage_subnet", NULL } }, { "bpf", {"map_create", "map_read", "map_write", "prog_load", "prog_run"} }, + { "perf_event", + {"open", "cpu", "kernel", "tracepoint", "read", "write"} }, { NULL } }; diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index f10918e73f4fde78b524fc005f057cac6154a863..2ac6edc1d1317a462663d2115339a8cf2e54d732 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -154,7 +154,11 @@ struct pkey_security_struct { }; struct bpf_security_struct { - u32 sid; /*SID of bpf obj creater*/ + u32 sid; /* SID of bpf obj creator */ +}; + +struct perf_event_security_struct { + u32 sid; /* SID of perf_event obj creator */ }; #endif /* _SELINUX_OBJSEC_H_ */ diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index d2d96ca082b71a204f3f18e7fa207e929564e4da..6224fd3bbf7ccf516ae4c417c806f56904c37169 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -74,8 +74,10 @@ static int onyx_read_register(struct onyx *onyx, u8 reg, u8 *value) return 0; } v = i2c_smbus_read_byte_data(onyx->i2c, reg); - if (v < 0) + if (v < 0) { + *value = 0; return -1; + } *value = (u8)v; onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value; return 0; diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index b80985fbc334cc6598d7ca2953d1ce79edb9f68b..0e1feb597586fbcab9278b4ed53367a294071c7d 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -479,15 +479,19 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry, q = queueptr(idx); if (q == NULL) continue; - if ((tmr = q->timer) == NULL || - (ti = tmr->timeri) == NULL) { - queuefree(q); - continue; - } + mutex_lock(&q->timer_mutex); + tmr = q->timer; + if (!tmr) + goto unlock; + ti = tmr->timeri; + if (!ti) + goto unlock; snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name); resolution = snd_timer_resolution(ti) * tmr->ticks; snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000); snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base); +unlock: + mutex_unlock(&q->timer_mutex); queuefree(q); } } diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 8a9dd4767b1ecb65c4ab4e801c29e1ff9f188b9e..63cc10604afc7c70db2ad58ce5ec2300c3b0ad95 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -176,11 +176,10 @@ struct azx { #define azx_bus(chip) (&(chip)->bus.core) #define bus_to_azx(_bus) container_of(_bus, struct azx, bus.core) -#ifdef CONFIG_X86 -#define azx_snoop(chip) ((chip)->snoop) -#else -#define azx_snoop(chip) true -#endif +static inline bool azx_snoop(struct azx *chip) +{ + return !IS_ENABLED(CONFIG_X86) || chip->snoop; +} /* * macros for easy use diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 41e3c77d5fb767fb48194f6ac7a9c39838cbfc48..5a7afbeb612d59037e5fe320d1b84122f2ba13c3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -378,6 +378,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0672: alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */ break; + case 0x10ec0222: case 0x10ec0623: alc_update_coef_idx(codec, 0x19, 1<<13, 0); break; @@ -396,6 +397,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) break; case 0x10ec0899: case 0x10ec0900: + case 0x10ec0b00: case 0x10ec1168: case 0x10ec1220: alc_update_coef_idx(codec, 0x7, 1<<1, 0); @@ -2389,6 +2391,7 @@ static int patch_alc882(struct hda_codec *codec) case 0x10ec0882: case 0x10ec0885: case 0x10ec0900: + case 0x10ec0b00: case 0x10ec1220: break; default: @@ -8398,6 +8401,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662), HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882), HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882), HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882), HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882), {} /* terminator */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c367d11079bc90feec2ad0fa748d7ffc3035faba..a16215781573298304231caf03d689d29aab7884 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -217,6 +217,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM9705 if SND_SOC_AC97_BUS select SND_SOC_WM9712 if SND_SOC_AC97_BUS select SND_SOC_WM9713 if SND_SOC_AC97_BUS + select SND_SOC_TFA98XX if I2C help Normally ASoC codec drivers are only built if a machine driver which uses them is also built since they are only usable with a machine @@ -1177,4 +1178,10 @@ config SND_SOC_TPA6130A2 tristate "Texas Instruments TPA6130A2 headphone amplifier" depends on I2C +config SND_SOC_TFA98XX + tristate "NXP Semiconductors TFA98XX amplifier" + depends on I2C + help + Enables support for NXP98xx Smart PA. + endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 05018b7ca72bdd7219cd64ba91525df7fc1c6e2f..787655b8e2cdc74d788fce6be96b8341267d31ce 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -237,6 +237,11 @@ snd-soc-max98504-objs := max98504.o snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-tas2552-objs := tas2552.o +snd-soc-tfa98xx-objs := tfa98xx.o +snd-soc-tfa98xx-objs += tfa_container.o +snd-soc-tfa98xx-objs += tfa_dsp.o +snd-soc-tfa98xx-objs += tfa_init.o + obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o @@ -474,3 +479,4 @@ obj-$(CONFIG_SND_SOC_DIO2125) += snd-soc-dio2125.o obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o +obj-$(CONFIG_SND_SOC_TFA98XX) += snd-soc-tfa98xx.o diff --git a/sound/soc/codecs/config.h b/sound/soc/codecs/config.h new file mode 100644 index 0000000000000000000000000000000000000000..85b0aebe17d1a723c800b6f6ca91daf0d66534a8 --- /dev/null +++ b/sound/soc/codecs/config.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +/* + * Linux kernel specific definitions used by code shared with + * Linux/Windows user space. + */ + +#ifndef __CONFIG_LINUX_KERNEL_INC__ +#define __CONFIG_LINUX_KERNEL_INC__ + +#include +#include +#include +#include +#include + +#define _ASSERT(e) +#ifndef PRINT_ASSERT +#define PRINT_ASSERT(e) {\ + (if ((e))\ + printk(KERN_ERR "PrintAssert:%s (%s:%d) error code:%d\n",\ + __FUNCTION__, __FILE__, __LINE__, e)) \ + } +#endif +#if defined(CONFIG_TRACING) && defined(DEBUG) + #define tfa98xx_trace_printk(...) trace_printk(__VA_ARGS__) +#else + #define tfa98xx_trace_printk(...) +#endif + +#endif /* __CONFIG_LINUX_KERNEL_INC__ */ + diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 0a749c79ef579bdd6bcf9688d6a24f784cfdc6db..1d38e53dc95c88d1c225249aec50ad989457655d 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -380,6 +380,7 @@ static struct i2c_driver cs4349_i2c_driver = { .driver = { .name = "cs4349", .of_match_table = cs4349_of_match, + .pm = &cs4349_runtime_pm, }, .id_table = cs4349_i2c_id, .probe = cs4349_i2c_probe, diff --git a/sound/soc/codecs/dbgprint.h b/sound/soc/codecs/dbgprint.h new file mode 100644 index 0000000000000000000000000000000000000000..bcd3bda64523886a9bbf496cdc64dbc69bffa1b5 --- /dev/null +++ b/sound/soc/codecs/dbgprint.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _DBGPRINT_H +# define _DBGPRINT_H + +/* Debugging macro's. */ +# ifndef DEBUG +# define DEBUG +# endif + +# ifndef ASSERT +//#define ASSERT +# endif + //TODO wwwim +# ifndef _ASSERT + #define _ASSERT(e) +# endif + +# ifndef PREFIX +# define PREFIX "tfa98xx: " +# define DRIVER_NAME "tfa98xx" +# endif + +#ifdef __KERNEL__ + +# ifdef DEBUG +# define _DEBUG(level, fmt, va...) do {\ + if (unlikely(debug >= (level))) \ + printk(KERN_INFO PREFIX "%s:%d: "fmt,\ + __func__, __LINE__, ##va); \ + } while (0); + +# else +# define _DEBUG(level, fmt, va...) do {} while (0) +# endif + +# define MSG(fmt, va...) printk(KERN_INFO PREFIX "%s:%d: "fmt,\ + __func__, __LINE__, ##va) +# define _ERRORMSG(fmt, va...) printk(KERN_ERR PREFIX "ERROR %s:%d: "fmt,\ + __func__, __LINE__, ##va) + + +# define DEBUG0(x...) MSG(x) +# define DEBUG1(x...) _DEBUG(1, x) +# define DEBUG2(x...) _DEBUG(2, x) +# define DEBUG3(x...) _DEBUG(3, x) +# define ERRORMSG(x...) _ERRORMSG(x) +# define PRINT(x...) printk(x) +# define PRINT_ERROR(x...) printk(KERN_INFO PREFIX " **ERROR** " x) +# define PRINT_ASSERT(e) if (e) printk(KERN_ERR\ + "PrintAssert:%s (%s:%d) error code:%d\n",\ + __FUNCTION__, __FILE__, __LINE__, e) + +# define PRINT_ENTRY DEBUG2("+[%s]\n", __func__) +# define PRINT_EXIT DEBUG2("-[%s]\n", __func__) + +# ifdef ASSERT +# define assert(cond, action) do {\ + if (unlikely(!(cond))) { + DEBUG0("Assert:\ + %s\n", #cond); action; } } \ + while (0) +# else +# define assert(cond, action) do { } while (0) +# endif + +#else /* __KERNEL__ */ +#if defined(WIN32) || defined(_X64) +#include +/* user mode */ +# ifdef DEBUG +# define _DEBUGMSG(level, fmt, ...) printf(PREFIX "%s:%d: "fmt,\ + __FUNCTION__, __LINE__, __VA_ARGS__) +# else +# define _DEBUGMSG(level, fmt, ...) do {} while (0) +# endif + +# define _ERRORMSG(fmt, ...) printf(PREFIX "%s:%s:%d: "fmt, __FILE__,\ + __FUNCTION__, __LINE__, __VA_ARGS__) + +# define DEBUG0(...) MSG(__VA_ARGS__) +# define DEBUG1(...) _DEBUGMSG(1, __VA_ARGS__) +# define DEBUG2(...) _DEBUGMSG(2, __VA_ARGS__) +# define DEBUG3(...) _DEBUGMSG(3, __VA_ARGS__) +# define ERRORMSG(fmt, ...) _ERRORMSG(fmt, __VA_ARGS__) +# define PRINT(...) printf(__VA_ARGS__) +/* +# define PRINT(...) { FILE *stream; \ + if((stream = freopen("nxp_tfa.txt", "ab+", stdout)) == NULL) exit(-1);\ + printf(__VA_ARGS__); \ + freopen( "CON", "ab+", stdout ); \ + } +*/ +# define PRINT_ERROR(...) fprintf(stderr, __VA_ARGS__) +# define PRINT_FILE(file, ...) fprintf(file, __VA_ARGS__) +# define PRINT_ASSERT(e) {\ + if ((e))\ + fprintf(stderr, "PrintAssert:%s (%s:%d)\ + error code:%d\n", __FUNCTION__,\ + __FILE__, __LINE__, e)\ + } +//# define PRINT_ASSERT(e) if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) %s\n",__FUNCTION__,__FILE__,__LINE__, Tfa98xx_GetErrorString(e)) + +#elif defined(__CODE_RED) +#include "app_global.h" +# ifdef DEBUG +# define _DEBUG(level, fmt, va...) TB_TRACE_INF(TbTracePfx2("tfa",\ + TB_FUNC, va)) +//printf(PREFIX "%s:%d: "fmt,__func__,__LINE__,##va); +# else +# define _DEBUG(level, fmt, va...) do {} while (0) +# endif + +# define MSG(fmt, ...) TB_TRACE_INF(TbTracePfx2("tfa", TB_FUNC, __VA_ARGS__)) +//printf(PREFIX "%s:%s:%d: "fmt,__FILE__,__func__,__LINE__,##va) +//TB_TRACE_INF(TbTracePfx2(APP_PFX,TB_FUNC,"path=%s, chan=%u, muted=%s, vol=%d\n", +// path->isRecording ? "recording" : "playback", +// i, +// channelVol.currentMuteValue ? "YES" : "NO", +// channelVol.currentVolumeValue +// )); +//# define _ERRORMSG(fmt,va...) TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,va)) +# define ERRORMSG(...) TB_TRACE_INF(TbTracePfx2("tfa", TB_FUNC, __VA_ARGS__)) +//fprintf(stderr, PREFIX "ERROR %s:%s:%d: "fmt,__FILE__,__func__,__LINE__, ##va) + +#define DEBUG0(x...) MSG(x) +#define DEBUG1(x...) _DEBUG(1, x) +#define DEBUG2(x...) _DEBUG(2, x) +#define DEBUG3(x...) _DEBUG(3, x) +//# define ERRORMSG(x...) _ERRORMSG(x) +#define PRINT(x...) TB_TRACE_INF(TbTracePfx2("tfa", TB_FUNC, x)) +//printf(x) +#define PRINT_ERROR(x...) TB_TRACE_INF(TbTracePfx2("tfa", TB_FUNC, x)) +//fprintf(stderr,__VA_ARGS__) +#define PRINT_FILE(file, x...) TB_TRACE_INF(TbTracePfx2("tfa", TB_FUNC, x)) +//fprintf(file,__VA_ARGS__) +#define PRINT_ASSERT(e) +//TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,Tfa98xx_GetErrorString(e))) +//if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) %s\n",__FUNCTION__,__FILE__,__LINE__, Tfa98xx_GetErrorString(e)) +#else +#include +/* user mode */ +# ifdef DEBUG +# define _DEBUG(level, fmt, va...) printf(PREFIX "%s:%d: "fmt, __func__,\ + __LINE__, ##va); +# else +# define _DEBUG(level, fmt, va...) do {} while (0) +# endif + +# define MSG(fmt, va...) printf(PREFIX "%s:%s:%d: "fmt, __FILE__, __func__,\ + __LINE__, ##va) +# define _ERRORMSG(fmt, va...) fprintf(stderr, PREFIX "ERROR %s:%s:%d: "fmt,\ + __FILE__, __func__, __LINE__, ##va) + +#define DEBUG0(x...) MSG(x) +#define DEBUG1(x...) _DEBUG(1, x) +#define DEBUG2(x...) _DEBUG(2, x) +#define DEBUG3(x...) _DEBUG(3, x) +#define ERRORMSG(x...) _ERRORMSG(x) +#define PRINT(x...) printf(x) +#define PRINT_ERROR(...) fprintf(stderr, __VA_ARGS__) +#define PRINT_FILE(file, ...) fprintf(file, __VA_ARGS__) +#define PRINT_ASSERT(e)if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d)\ + error code:%d\n", __FUNCTION__, __FILE__, __LINE__, e) +//# define PRINT_ASSERT(e) if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) %s\n", __FUNCTION__, __FILE__, __LINE__, Tfa98xx_GetErrorString(e)) + + +#endif /* WIN32 */ + +#endif /* user */ + +#endif /* _DBGPRINT_H --------------- */ diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index bcdb8914ec16b992e26aecb718e430e6e0477e05..e2f44fa46262d555c2d7078e802599686c442723 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -231,7 +231,7 @@ static const struct soc_enum es8328_rline_enum = ARRAY_SIZE(es8328_line_texts), es8328_line_texts); static const struct snd_kcontrol_new es8328_right_line_controls = - SOC_DAPM_ENUM("Route", es8328_lline_enum); + SOC_DAPM_ENUM("Route", es8328_rline_enum); /* Left Mixer */ static const struct snd_kcontrol_new es8328_left_mixer_controls[] = { diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 969283737787fd9d9a11512ef87f02f21daa5c0c..3633eb30dd1350b3f4417b73d8beb8caa4a5bf3d 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -876,10 +876,10 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("MIC BIAS External1", CDC_A_MICB_1_EN, 7, 0, pm8916_wcd_analog_enable_micbias_ext1, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0, pm8916_wcd_analog_enable_micbias_ext2, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0, pm8916_wcd_analog_enable_adc, diff --git a/sound/soc/codecs/tfa.h b/sound/soc/codecs/tfa.h new file mode 100644 index 0000000000000000000000000000000000000000..92410b7e76718ca7c7f84b5510353c7f084a818a --- /dev/null +++ b/sound/soc/codecs/tfa.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA_H_ +#define TFA_H_ + +/* set the limit for the container file length */ +#define TFA_MAX_CNT_LENGTH (256*1024) + +extern struct tfa_device **devs; + +/** + * tfa error return codes + */ +enum tfa_error { + tfa_error_ok, /**< no error */ + tfa_error_device, /**< no response from device */ + tfa_error_bad_param,/**< parameter no accepted */ + tfa_error_noclock, /**< required clock not present */ + tfa_error_timeout, /**< a timeout occurred */ + tfa_error_dsp, /**< a DSP error was returned */ + tfa_error_container,/**< no or wrong container file */ + tfa_error_max /**< impossible value, max enum */ +}; + +enum Tfa98xx_Error tfa_write_filters(struct tfa_device *tfa, int prof_idx); + +struct tfa_device **tfa_devs_create(int count); +void tfa_devs_destroy(int count); + +struct tfa_device **tfa_get_device_struct(void); + +int tfa_plop_noise_interrupt(struct tfa_device *tfa, int profile, int vstep); +void tfa_lp_mode_interrupt(struct tfa_device *tfa); + +#endif /* TFA_H_ */ diff --git a/sound/soc/codecs/tfa1_tfafieldnames.h b/sound/soc/codecs/tfa1_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..81fed6a34e4d10760095108e8de129cd200540b3 --- /dev/null +++ b/sound/soc/codecs/tfa1_tfafieldnames.h @@ -0,0 +1,921 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ +#define TFA9897_I2CVERSION 34 +typedef enum nxpTfa1BfEnumList { +TFA1_BF_VDDS = 0x0000, /*!< Power-on-reset flag */ +TFA1_BF_PLLS = 0x0010, /*!< PLL lock */ +TFA1_BF_OTDS = 0x0020, /*!< Over Temperature Protection alarm */ +TFA1_BF_OVDS = 0x0030, /*!< Over Voltage Protection alarm */ +TFA1_BF_UVDS = 0x0040, /*!< Under Voltage Protection alarm */ +TFA1_BF_OCDS = 0x0050, /*!< Over Current Protection alarm */ +TFA1_BF_CLKS = 0x0060, /*!< Clocks stable flag */ +TFA1_BF_CLIPS = 0x0070, /*!< Amplifier clipping */ +TFA1_BF_MTPB = 0x0080, /*!< MTP busy */ +TFA1_BF_NOCLK = 0x0090, /*!< Flag lost clock from clock generationunit*/ +TFA1_BF_SPKS = 0x00a0, /*!< Speaker error flag */ +TFA1_BF_ACS = 0x00b0, /*!< Cold Start flag */ +TFA1_BF_SWS = 0x00c0, /*!< Flag Engage */ +TFA1_BF_WDS = 0x00d0, /*!< Flag watchdog reset */ +TFA1_BF_AMPS = 0x00e0, /*!< Amplifier is enabled by manager */ +TFA1_BF_AREFS = 0x00f0, /*!< References are enabled by manager */ +TFA1_BF_BATS = 0x0109, /*!< Battery voltage readout; 0 .. 5.5 [V] */ +TFA1_BF_TEMPS = 0x0208, /*!< Temperature readout from the temperature + * sensor */ +TFA1_BF_REV = 0x030b, /*!< Device type number is B97 */ +TFA1_BF_RCV = 0x0420, /*!< Enable Receiver Mode */ +TFA1_BF_CHS12 = 0x0431, /*!< Channel Selection TDM input for Coolflux */ +TFA1_BF_INPLVL = 0x0450, /*!< Input level selection control */ +TFA1_BF_CHSA = 0x0461, /*!< Input selection for amplifier */ +TFA1_BF_I2SDOE = 0x04b0, /*!< Enable data output */ +TFA1_BF_AUDFS = 0x04c3, /*!< Audio sample rate setting */ +TFA1_BF_BSSCR = 0x0501, /*!< Protection Attack Time */ +TFA1_BF_BSST = 0x0523, /*!< ProtectionThreshold */ +TFA1_BF_BSSRL = 0x0561, /*!< Protection Maximum Reduction */ +TFA1_BF_BSSRR = 0x0582, /*!< Battery Protection Release Time */ +TFA1_BF_BSSHY = 0x05b1, /*!< Battery Protection Hysteresis */ +TFA1_BF_BSSR = 0x05e0, /*!< battery voltage for I2C read out only */ +TFA1_BF_BSSBY = 0x05f0, /*!< bypass clipper battery protection */ +TFA1_BF_DPSA = 0x0600, /*!< Enable dynamic powerstage activation */ +TFA1_BF_CFSM = 0x0650, /*!< Soft mute in CoolFlux */ +TFA1_BF_BSSS = 0x0670, /*!< BatSenseSteepness */ +TFA1_BF_VOL = 0x0687, /*!< volume control (in CoolFlux) */ +TFA1_BF_DCVO = 0x0702, /*!< Boost Voltage */ +TFA1_BF_DCMCC = 0x0733, /*!< Max boost coil current - step of 175 mA */ +TFA1_BF_DCIE = 0x07a0, /*!< Adaptive boost mode */ +TFA1_BF_DCSR = 0x07b0, /*!< Soft RampUp/Down mode for DCDC controller*/ +TFA1_BF_DCPAVG = 0x07c0, /*!< ctrl_peak2avg for analog part of DCDC */ +TFA1_BF_TROS = 0x0800, /*!< Select external temperature also the ext_temp + * will be put on the temp read out */ +TFA1_BF_EXTTS = 0x0818, /*!< external temperature setting to be given + * by host*/ +TFA1_BF_PWDN = 0x0900, /*!< Device Mode */ +TFA1_BF_I2CR = 0x0910, /*!< I2C Reset */ +TFA1_BF_CFE = 0x0920, /*!< Enable CoolFlux */ +TFA1_BF_AMPE = 0x0930, /*!< Enable Amplifier */ +TFA1_BF_DCA = 0x0940, /*!< EnableBoost */ +TFA1_BF_SBSL = 0x0950, /*!< Coolflux configured */ +TFA1_BF_AMPC = 0x0960, /*!< Selection on how Amplifier is enabled */ +TFA1_BF_DCDIS = 0x0970, /*!< DCDC not connected */ +TFA1_BF_PSDR = 0x0980, /*!< IDDQ test amplifier */ +TFA1_BF_DCCV = 0x0991, /*!< Coil Value */ +TFA1_BF_CCFD = 0x09b0, /*!< Selection CoolFlux Clock */ +TFA1_BF_INTPAD = 0x09c1, /*!< INT pad configuration control */ +TFA1_BF_IPLL = 0x09e0, /*!< PLL input reference clock selection */ +TFA1_BF_MTPK = 0x0b07, /*!< 5Ah, 90d To access KEY1_Protected registers + * (Default for engineering) */ +TFA1_BF_CVFDLY = 0x0c25, /*!< Fractional delay adjustment between current + and voltage sense */ +TFA1_BF_TDMPRF = 0x1011, /*!< TDM_usecase */ +TFA1_BF_TDMEN = 0x1030, /*!< TDM interface control */ +TFA1_BF_TDMCKINV = 0x1040, /*!< TDM clock inversion */ +TFA1_BF_TDMFSLN = 0x1053, /*!< TDM FS length */ +TFA1_BF_TDMFSPOL = 0x1090, /*!< TDM FS polarity */ +TFA1_BF_TDMSAMSZ = 0x10a4, /*!< TDM Sample Size for all tdm + sinks/sources */ +TFA1_BF_TDMSLOTS = 0x1103, /*!< Number of slots */ +TFA1_BF_TDMSLLN = 0x1144, /*!< Slot length */ +TFA1_BF_TDMBRMG = 0x1194, /*!< Bits remaining */ +TFA1_BF_TDMDDEL = 0x11e0, /*!< Data delay */ +TFA1_BF_TDMDADJ = 0x11f0, /*!< Data adjustment */ +TFA1_BF_TDMTXFRM = 0x1201, /*!< TXDATA format */ +TFA1_BF_TDMUUS0 = 0x1221, /*!< TXDATA format unused slot sd0 */ +TFA1_BF_TDMUUS1 = 0x1241, /*!< TXDATA format unused slot sd1 */ +TFA1_BF_TDMSI0EN = 0x1270, /*!< TDM sink0 enable */ +TFA1_BF_TDMSI1EN = 0x1280, /*!< TDM sink1 enable */ +TFA1_BF_TDMSI2EN = 0x1290, /*!< TDM sink2 enable */ +TFA1_BF_TDMSO0EN = 0x12a0, /*!< TDM source0 enable */ +TFA1_BF_TDMSO1EN = 0x12b0, /*!< TDM source1 enable */ +TFA1_BF_TDMSO2EN = 0x12c0, /*!< TDM source2 enable */ +TFA1_BF_TDMSI0IO = 0x12d0, /*!< tdm_sink0_io */ +TFA1_BF_TDMSI1IO = 0x12e0, /*!< tdm_sink1_io */ +TFA1_BF_TDMSI2IO = 0x12f0, /*!< tdm_sink2_io */ +TFA1_BF_TDMSO0IO = 0x1300, /*!< tdm_source0_io */ +TFA1_BF_TDMSO1IO = 0x1310, /*!< tdm_source1_io */ +TFA1_BF_TDMSO2IO = 0x1320, /*!< tdm_source2_io */ +TFA1_BF_TDMSI0SL = 0x1333, /*!< sink0_slot [GAIN IN] */ +TFA1_BF_TDMSI1SL = 0x1373, /*!< sink1_slot [CH1 IN] */ +TFA1_BF_TDMSI2SL = 0x13b3, /*!< sink2_slot [CH2 IN] */ +TFA1_BF_TDMSO0SL = 0x1403, /*!< source0_slot [GAIN OUT] */ +TFA1_BF_TDMSO1SL = 0x1443, /*!< source1_slot [Voltage Sense] */ +TFA1_BF_TDMSO2SL = 0x1483, /*!< source2_slot [Current Sense] */ +TFA1_BF_NBCK = 0x14c3, /*!< NBCK */ +TFA1_BF_INTOVDDS = 0x2000, /*!< flag_por_int_out */ +TFA1_BF_INTOPLLS = 0x2010, /*!< flag_pll_lock_int_out */ +TFA1_BF_INTOOTDS = 0x2020, /*!< flag_otpok_int_out */ +TFA1_BF_INTOOVDS = 0x2030, /*!< flag_ovpok_int_out */ +TFA1_BF_INTOUVDS = 0x2040, /*!< flag_uvpok_int_out */ +TFA1_BF_INTOOCDS = 0x2050, /*!< flag_ocp_alarm_int_out */ +TFA1_BF_INTOCLKS = 0x2060, /*!< flag_clocks_stable_int_out */ +TFA1_BF_INTOCLIPS = 0x2070, /*!< flag_clip_int_out */ +TFA1_BF_INTOMTPB = 0x2080, /*!< mtp_busy_int_out */ +TFA1_BF_INTONOCLK = 0x2090, /*!< flag_lost_clk_int_out */ +TFA1_BF_INTOSPKS = 0x20a0, /*!< flag_cf_speakererror_int_out */ +TFA1_BF_INTOACS = 0x20b0, /*!< flag_cold_started_int_out */ +TFA1_BF_INTOSWS = 0x20c0, /*!< flag_engage_int_out */ +TFA1_BF_INTOWDS = 0x20d0, /*!< flag_watchdog_reset_int_out */ +TFA1_BF_INTOAMPS = 0x20e0, /*!< flag_enbl_amp_int_out */ +TFA1_BF_INTOAREFS = 0x20f0, /*!< flag_enbl_ref_int_out */ +TFA1_BF_INTOACK = 0x2201, /*!< Interrupt status register output - + * Corresponding flag */ +TFA1_BF_INTIVDDS = 0x2300, /*!< flag_por_int_in */ +TFA1_BF_INTIPLLS = 0x2310, /*!< flag_pll_lock_int_in */ +TFA1_BF_INTIOTDS = 0x2320, /*!< flag_otpok_int_in */ +TFA1_BF_INTIOVDS = 0x2330, /*!< flag_ovpok_int_in */ +TFA1_BF_INTIUVDS = 0x2340, /*!< flag_uvpok_int_in */ +TFA1_BF_INTIOCDS = 0x2350, /*!< flag_ocp_alarm_int_in */ +TFA1_BF_INTICLKS = 0x2360, /*!< flag_clocks_stable_int_in */ +TFA1_BF_INTICLIPS = 0x2370, /*!< flag_clip_int_in */ +TFA1_BF_INTIMTPB = 0x2380, /*!< mtp_busy_int_in */ +TFA1_BF_INTINOCLK = 0x2390, /*!< flag_lost_clk_int_in */ +TFA1_BF_INTISPKS = 0x23a0, /*!< flag_cf_speakererror_int_in */ +TFA1_BF_INTIACS = 0x23b0, /*!< flag_cold_started_int_in */ +TFA1_BF_INTISWS = 0x23c0, /*!< flag_engage_int_in */ +TFA1_BF_INTIWDS = 0x23d0, /*!< flag_watchdog_reset_int_in */ +TFA1_BF_INTIAMPS = 0x23e0, /*!< flag_enbl_amp_int_in */ +TFA1_BF_INTIAREFS = 0x23f0, /*!< flag_enbl_ref_int_in */ +TFA1_BF_INTIACK = 0x2501, /*!< Interrupt register input */ +TFA1_BF_INTENVDDS = 0x2600, /*!< flag_por_int_enable */ +TFA1_BF_INTENPLLS = 0x2610, /*!< flag_pll_lock_int_enable */ +TFA1_BF_INTENOTDS = 0x2620, /*!< flag_otpok_int_enable */ +TFA1_BF_INTENOVDS = 0x2630, /*!< flag_ovpok_int_enable */ +TFA1_BF_INTENUVDS = 0x2640, /*!< flag_uvpok_int_enable */ +TFA1_BF_INTENOCDS = 0x2650, /*!< flag_ocp_alarm_int_enable */ +TFA1_BF_INTENCLKS = 0x2660, /*!< flag_clocks_stable_int_enable */ +TFA1_BF_INTENCLIPS = 0x2670, /*!< flag_clip_int_enable */ +TFA1_BF_INTENMTPB = 0x2680, /*!< mtp_busy_int_enable */ +TFA1_BF_INTENNOCLK = 0x2690, /*!< flag_lost_clk_int_enable */ +TFA1_BF_INTENSPKS = 0x26a0, /*!< flag_cf_speakererror_int_enable */ +TFA1_BF_INTENACS = 0x26b0, /*!< flag_cold_started_int_enable */ +TFA1_BF_INTENSWS = 0x26c0, /*!< flag_engage_int_enable */ +TFA1_BF_INTENWDS = 0x26d0, /*!< flag_watchdog_reset_int_enable */ +TFA1_BF_INTENAMPS = 0x26e0, /*!< flag_enbl_amp_int_enable */ +TFA1_BF_INTENAREFS = 0x26f0, /*!< flag_enbl_ref_int_enable */ +TFA1_BF_INTENACK = 0x2801, /*!< Interrupt enable register */ +TFA1_BF_INTPOLVDDS = 0x2900, /*!< flag_por_int_pol */ +TFA1_BF_INTPOLPLLS = 0x2910, /*!< flag_pll_lock_int_pol */ +TFA1_BF_INTPOLOTDS = 0x2920, /*!< flag_otpok_int_pol */ +TFA1_BF_INTPOLOVDS = 0x2930, /*!< flag_ovpok_int_pol */ +TFA1_BF_INTPOLUVDS = 0x2940, /*!< flag_uvpok_int_pol */ +TFA1_BF_INTPOLOCDS = 0x2950, /*!< flag_ocp_alarm_int_pol */ +TFA1_BF_INTPOLCLKS = 0x2960, /*!< flag_clocks_stable_int_pol */ +TFA1_BF_INTPOLCLIPS = 0x2970, /*!< flag_clip_int_pol */ +TFA1_BF_INTPOLMTPB = 0x2980, /*!< mtp_busy_int_pol */ +TFA1_BF_INTPOLNOCLK = 0x2990, /*!< flag_lost_clk_int_pol */ +TFA1_BF_INTPOLSPKS = 0x29a0, /*!< flag_cf_speakererror_int_pol */ +TFA1_BF_INTPOLACS = 0x29b0, /*!< flag_cold_started_int_pol */ +TFA1_BF_INTPOLSWS = 0x29c0, /*!< flag_engage_int_pol */ +TFA1_BF_INTPOLWDS = 0x29d0, /*!< flag_watchdog_reset_int_pol */ +TFA1_BF_INTPOLAMPS = 0x29e0, /*!< flag_enbl_amp_int_pol */ +TFA1_BF_INTPOLAREFS = 0x29f0, /*!< flag_enbl_ref_int_pol */ +TFA1_BF_INTPOLACK = 0x2b01, /*!< Interrupt status flags + * polarity register */ +TFA1_BF_CLIP = 0x4900, /*!< Bypass clip control */ +TFA1_BF_CIMTP = 0x62b0, /*!< start copying all the data from i2cregs_mtp + to mtp [Key 2 protected] */ +TFA1_BF_RST = 0x7000, /*!< Reset CoolFlux DSP */ +TFA1_BF_DMEM = 0x7011, /*!< Target memory for access */ +TFA1_BF_AIF = 0x7030, /*!< Autoincrement-flag for memory-address */ +TFA1_BF_CFINT = 0x7040, /*!< Interrupt CoolFlux DSP */ +TFA1_BF_REQ = 0x7087, /*!< request for access (8 channels) */ +TFA1_BF_REQCMD = 0x7080, /*!< Firmware event request rpc command */ +TFA1_BF_REQRST = 0x7090, /*!< Firmware event request reset restart */ +TFA1_BF_REQMIPS = 0x70a0, /*!< Firmware event request short on mips */ +TFA1_BF_REQMUTED = 0x70b0, /*!< Firmware event request mute sequence ready*/ +TFA1_BF_REQVOL = 0x70c0, /*!< Firmware event request volume ready */ +TFA1_BF_REQDMG = 0x70d0, /*!< Firmware event request speaker damage detected*/ +TFA1_BF_REQCAL = 0x70e0, /*!< Firmware event request calibration completed */ +TFA1_BF_REQRSV = 0x70f0, /*!< Firmware event request reserved */ +TFA1_BF_MADD = 0x710f, /*!< memory-address to be accessed */ +TFA1_BF_MEMA = 0x720f, /*!< activate memory access (24- or 32-bits data is + * written/read to/from memory */ +TFA1_BF_ERR = 0x7307, /*!< Coolflux error flags */ +TFA1_BF_ACK = 0x7387, /*!< acknowledge of requests (8 channels) */ +TFA1_BF_MTPOTC = 0x8000, /*!< Calibration schedule (key2 protected) */ +TFA1_BF_MTPEX = 0x8010, /*!< (key2 protected) */ +} nxpTfa1BfEnumList_t; +#define TFA1_NAMETABLE static tfaBfName_t Tfa1DatasheetNames[] = {\ +{ 0x0, "VDDS"}, /* Power-on-reset flag , */\ +{ 0x10, "PLLS"}, /* PLL lock , */\ +{ 0x20, "OTDS"}, /* Over Temperature Protection alarm , */\ +{ 0x30, "OVDS"}, /* Over Voltage Protection alarm , */\ +{ 0x40, "UVDS"}, /* Under Voltage Protection alarm , */\ +{ 0x50, "OCDS"}, /* Over Current Protection alarm , */\ +{ 0x60, "CLKS"}, /* Clocks stable flag , */\ +{ 0x70, "CLIPS"}, /* Amplifier clipping , */\ +{ 0x80, "MTPB"}, /* MTP busy , */\ +{ 0x90, "NOCLK"}, /* Flag lost clock from clock generation unit , */\ +{ 0xa0, "SPKS"}, /* Speaker error flag , */\ +{ 0xb0, "ACS"}, /* Cold Start flag , */\ +{ 0xc0, "SWS"}, /* Flag Engage , */\ +{ 0xd0, "WDS"}, /* Flag watchdog reset , */\ +{ 0xe0, "AMPS"}, /* Amplifier is enabled by manager , */\ +{ 0xf0, "AREFS"}, /* References are enabled by manager , */\ +{ 0x109, "BATS"}, /* Battery voltage readout; 0 .. 5.5 [V] , */\ +{ 0x208, "TEMPS"}, /* Temperature readout from the temperature sensor , */\ +{ 0x30b, "REV"}, /* Device type number is B97 , */\ +{ 0x420, "RCV"}, /* Enable Receiver Mode , */\ +{ 0x431, "CHS12"}, /* Channel Selection TDM input for Coolflux , */\ +{ 0x450, "INPLVL"}, /* Input level selection control , */\ +{ 0x461, "CHSA"}, /* Input selection for amplifier , */\ +{ 0x4b0, "I2SDOE"}, /* Enable data output , */\ +{ 0x4c3, "AUDFS"}, /* Audio sample rate setting , */\ +{ 0x501, "SSCR"}, /* Protection Attack Time , */\ +{ 0x523, "SST"}, /* ProtectionThreshold , */\ +{ 0x561, "SSRL"}, /* Protection Maximum Reduction , */\ +{ 0x582, "SSRR"}, /* Battery Protection Release Time , */\ +{ 0x5b1, "SSHY"}, /* Battery Protection Hysteresis , */\ +{ 0x5e0, "SSR"}, /* battery voltage for I2C read out only , */\ +{ 0x5f0, "SSBY"}, /* bypass clipper battery protection , */\ +{ 0x600, "DPSA"}, /* Enable dynamic powerstage activation , */\ +{ 0x650, "CFSM"}, /* Soft mute in CoolFlux , */\ +{ 0x670, "SSS"}, /* BatSenseSteepness , */\ +{ 0x687, "VOL"}, /* volume control (in CoolFlux) , */\ +{ 0x702, "DCVO"}, /* Boost Voltage , */\ +{ 0x733, "DCMCC"}, /* Max boost coil current - step of 175 mA , */\ +{ 0x7a0, "DCIE"}, /* Adaptive boost mode , */\ +{ 0x7b0, "DCSR"}, /* Soft RampUp/Down mode for DCDC controller , */\ +{ 0x7c0, "DCPAVG"}, /* ctrl_peak2avg for analog part of DCDC , */\ +{ 0x800, "TROS"}, /* Select external temperature also the ext_temp will be + * put on the temp read out , */\ +{ 0x818, "EXTTS"}, /* external temperature setting to be given by host , */\ +{ 0x900, "PWDN"}, /* Device Mode , */\ +{ 0x910, "I2CR"}, /* I2C Reset , */\ +{ 0x920, "CFE"}, /* Enable CoolFlux , */\ +{ 0x930, "AMPE"}, /* Enable Amplifier , */\ +{ 0x940, "DCA"}, /* EnableBoost , */\ +{ 0x950, "SBSL"}, /* Coolflux configured , */\ +{ 0x960, "AMPC"}, /* Selection on how Amplifier is enabled , */\ +{ 0x970, "DCDIS"}, /* DCDC not connected , */\ +{ 0x980, "PSDR"}, /* IDDQ test amplifier , */\ +{ 0x991, "DCCV"}, /* Coil Value , */\ +{ 0x9b0, "CCFD"}, /* Selection CoolFlux Clock , */\ +{ 0x9c1, "INTPAD"}, /* INT pad configuration control , */\ +{ 0x9e0, "IPLL"}, /* PLL input reference clock selection , */\ +{ 0xb07, "MTPK"}, /* 5Ah, 90d To access KEY1_Protected registers + * (Default for engineering), */\ +{ 0xc25, "CVFDLY"}, /* Fractional delay adjustment between current and + * voltage sense, */\ +{ 0x1011, "TDMPRF"}, /* TDM_usecase , */\ +{ 0x1030, "TDMEN"}, /* TDM interface control , */\ +{ 0x1040, "TDMCKINV"}, /* TDM clock inversion , */\ +{ 0x1053, "TDMFSLN"}, /* TDM FS length , */\ +{ 0x1090, "TDMFSPOL"}, /* TDM FS polarity , */\ +{ 0x10a4, "TDMSAMSZ"}, /* TDM Sample Size for all tdm sinks/sources , */\ +{ 0x1103, "TDMSLOTS"}, /* Number of slots , */\ +{ 0x1144, "TDMSLLN"}, /* Slot length , */\ +{ 0x1194, "TDMBRMG"}, /* Bits remaining , */\ +{ 0x11e0, "TDMDDEL"}, /* Data delay , */\ +{ 0x11f0, "TDMDADJ"}, /* Data adjustment , */\ +{ 0x1201, "TDMTXFRM"}, /* TXDATA format , */\ +{ 0x1221, "TDMUUS0"}, /* TXDATA format unused slot sd0 , */\ +{ 0x1241, "TDMUUS1"}, /* TXDATA format unused slot sd1 , */\ +{ 0x1270, "TDMSI0EN"}, /* TDM sink0 enable , */\ +{ 0x1280, "TDMSI1EN"}, /* TDM sink1 enable , */\ +{ 0x1290, "TDMSI2EN"}, /* TDM sink2 enable , */\ +{ 0x12a0, "TDMSO0EN"}, /* TDM source0 enable , */\ +{ 0x12b0, "TDMSO1EN"}, /* TDM source1 enable , */\ +{ 0x12c0, "TDMSO2EN"}, /* TDM source2 enable , */\ +{ 0x12d0, "TDMSI0IO"}, /* tdm_sink0_io , */\ +{ 0x12e0, "TDMSI1IO"}, /* tdm_sink1_io , */\ +{ 0x12f0, "TDMSI2IO"}, /* tdm_sink2_io , */\ +{ 0x1300, "TDMSO0IO"}, /* tdm_source0_io , */\ +{ 0x1310, "TDMSO1IO"}, /* tdm_source1_io , */\ +{ 0x1320, "TDMSO2IO"}, /* tdm_source2_io , */\ +{ 0x1333, "TDMSI0SL"}, /* sink0_slot [GAIN IN] , */\ +{ 0x1373, "TDMSI1SL"}, /* sink1_slot [CH1 IN] , */\ +{ 0x13b3, "TDMSI2SL"}, /* sink2_slot [CH2 IN] , */\ +{ 0x1403, "TDMSO0SL"}, /* source0_slot [GAIN OUT] , */\ +{ 0x1443, "TDMSO1SL"}, /* source1_slot [Voltage Sense] , */\ +{ 0x1483, "TDMSO2SL"}, /* source2_slot [Current Sense] , */\ +{ 0x14c3, "NBCK"}, /* NBCK , */\ +{ 0x2000, "INTOVDDS"}, /* flag_por_int_out , */\ +{ 0x2010, "INTOPLLS"}, /* flag_pll_lock_int_out , */\ +{ 0x2020, "INTOOTDS"}, /* flag_otpok_int_out , */\ +{ 0x2030, "INTOOVDS"}, /* flag_ovpok_int_out , */\ +{ 0x2040, "INTOUVDS"}, /* flag_uvpok_int_out , */\ +{ 0x2050, "INTOOCDS"}, /* flag_ocp_alarm_int_out , */\ +{ 0x2060, "INTOCLKS"}, /* flag_clocks_stable_int_out , */\ +{ 0x2070, "INTOCLIPS"}, /* flag_clip_int_out , */\ +{ 0x2080, "INTOMTPB"}, /* mtp_busy_int_out , */\ +{ 0x2090, "INTONOCLK"}, /* flag_lost_clk_int_out , */\ +{ 0x20a0, "INTOSPKS"}, /* flag_cf_speakererror_int_out , */\ +{ 0x20b0, "INTOACS"}, /* flag_cold_started_int_out , */\ +{ 0x20c0, "INTOSWS"}, /* flag_engage_int_out , */\ +{ 0x20d0, "INTOWDS"}, /* flag_watchdog_reset_int_out , */\ +{ 0x20e0, "INTOAMPS"}, /* flag_enbl_amp_int_out , */\ +{ 0x20f0, "INTOAREFS"}, /* flag_enbl_ref_int_out , */\ +{ 0x2201, "INTOACK"}, /* Interrupt status register output + * - Corresponding flag, */\ +{ 0x2300, "INTIVDDS"}, /* flag_por_int_in , */\ +{ 0x2310, "INTIPLLS"}, /* flag_pll_lock_int_in , */\ +{ 0x2320, "INTIOTDS"}, /* flag_otpok_int_in , */\ +{ 0x2330, "INTIOVDS"}, /* flag_ovpok_int_in , */\ +{ 0x2340, "INTIUVDS"}, /* flag_uvpok_int_in , */\ +{ 0x2350, "INTIOCDS"}, /* flag_ocp_alarm_int_in , */\ +{ 0x2360, "INTICLKS"}, /* flag_clocks_stable_int_in , */\ +{ 0x2370, "INTICLIPS"}, /* flag_clip_int_in , */\ +{ 0x2380, "INTIMTPB"}, /* mtp_busy_int_in , */\ +{ 0x2390, "INTINOCLK"}, /* flag_lost_clk_int_in , */\ +{ 0x23a0, "INTISPKS"}, /* flag_cf_speakererror_int_in , */\ +{ 0x23b0, "INTIACS"}, /* flag_cold_started_int_in , */\ +{ 0x23c0, "INTISWS"}, /* flag_engage_int_in , */\ +{ 0x23d0, "INTIWDS"}, /* flag_watchdog_reset_int_in , */\ +{ 0x23e0, "INTIAMPS"}, /* flag_enbl_amp_int_in , */\ +{ 0x23f0, "INTIAREFS"}, /* flag_enbl_ref_int_in , */\ +{ 0x2501, "INTIACK"}, /* Interrupt register input , */\ +{ 0x2600, "INTENVDDS"}, /* flag_por_int_enable , */\ +{ 0x2610, "INTENPLLS"}, /* flag_pll_lock_int_enable , */\ +{ 0x2620, "INTENOTDS"}, /* flag_otpok_int_enable , */\ +{ 0x2630, "INTENOVDS"}, /* flag_ovpok_int_enable , */\ +{ 0x2640, "INTENUVDS"}, /* flag_uvpok_int_enable , */\ +{ 0x2650, "INTENOCDS"}, /* flag_ocp_alarm_int_enable , */\ +{ 0x2660, "INTENCLKS"}, /* flag_clocks_stable_int_enable , */\ +{ 0x2670, "INTENCLIPS"}, /* flag_clip_int_enable , */\ +{ 0x2680, "INTENMTPB"}, /* mtp_busy_int_enable , */\ +{ 0x2690, "INTENNOCLK"}, /* flag_lost_clk_int_enable , */\ +{ 0x26a0, "INTENSPKS"}, /* flag_cf_speakererror_int_enable , */\ +{ 0x26b0, "INTENACS"}, /* flag_cold_started_int_enable , */\ +{ 0x26c0, "INTENSWS"}, /* flag_engage_int_enable , */\ +{ 0x26d0, "INTENWDS"}, /* flag_watchdog_reset_int_enable , */\ +{ 0x26e0, "INTENAMPS"}, /* flag_enbl_amp_int_enable , */\ +{ 0x26f0, "INTENAREFS"}, /* flag_enbl_ref_int_enable , */\ +{ 0x2801, "INTENACK"}, /* Interrupt enable register , */\ +{ 0x2900, "INTPOLVDDS"}, /* flag_por_int_pol , */\ +{ 0x2910, "INTPOLPLLS"}, /* flag_pll_lock_int_pol , */\ +{ 0x2920, "INTPOLOTDS"}, /* flag_otpok_int_pol , */\ +{ 0x2930, "INTPOLOVDS"}, /* flag_ovpok_int_pol , */\ +{ 0x2940, "INTPOLUVDS"}, /* flag_uvpok_int_pol , */\ +{ 0x2950, "INTPOLOCDS"}, /* flag_ocp_alarm_int_pol , */\ +{ 0x2960, "INTPOLCLKS"}, /* flag_clocks_stable_int_pol , */\ +{ 0x2970, "INTPOLCLIPS"}, /* flag_clip_int_pol , */\ +{ 0x2980, "INTPOLMTPB"}, /* mtp_busy_int_pol , */\ +{ 0x2990, "INTPOLNOCLK"}, /* flag_lost_clk_int_pol , */\ +{ 0x29a0, "INTPOLSPKS"}, /* flag_cf_speakererror_int_pol , */\ +{ 0x29b0, "INTPOLACS"}, /* flag_cold_started_int_pol , */\ +{ 0x29c0, "INTPOLSWS"}, /* flag_engage_int_pol , */\ +{ 0x29d0, "INTPOLWDS"}, /* flag_watchdog_reset_int_pol , */\ +{ 0x29e0, "INTPOLAMPS"}, /* flag_enbl_amp_int_pol , */\ +{ 0x29f0, "INTPOLAREFS"}, /* flag_enbl_ref_int_pol , */\ +{ 0x2b01, "INTPOLACK"}, /* Interrupt status flags polarity register , */\ +{ 0x4900, "CLIP"}, /* Bypass clip control , */\ +{ 0x62b0, "CIMTP"}, /* start copying all the data from i2cregs_mtp + * to mtp [Key 2 protected], */\ +{ 0x7000, "RST"}, /* Reset CoolFlux DSP , */\ +{ 0x7011, "DMEM"}, /* Target memory for access , */\ +{ 0x7030, "AIF"}, /* Autoincrement-flag for memory-address , */\ +{ 0x7040, "CFINT"}, /* Interrupt CoolFlux DSP , */\ +{ 0x7087, "REQ"}, /* request for access (8 channels) , */\ +{ 0x7080, "REQCMD"}, /* Firmware event request rpc command , */\ +{ 0x7090, "REQRST"}, /* Firmware event request reset restart , */\ +{ 0x70a0, "REQMIPS"}, /* Firmware event request short on mips , */\ +{ 0x70b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ +{ 0x70c0, "REQVOL"}, /* Firmware event request volume ready , */\ +{ 0x70d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ +{ 0x70e0, "REQCAL"}, /* Firmware event request calibration completed , */\ +{ 0x70f0, "REQRSV"}, /* Firmware event request reserved , */\ +{ 0x710f, "MADD"}, /* memory-address to be accessed , */\ +{ 0x720f, "MEMA"}, /* activate memory access (24- or 32-bits data is + * written/read to/from memory, */\ +{ 0x7307, "ERR"}, /* Coolflux error flags , */\ +{ 0x7387, "ACK"}, /* acknowledge of requests (8 channels) , */\ +{ 0x7380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ +{ 0x7390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ +{ 0x73a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ +{ 0x73b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready,*/\ +{ 0x73c0, "ACKVOL"}, /* Firmware event acknowledge volume ready ,*/\ +{ 0x73d0, "ACKDMG"}, /* Firmware event acknowledge speaker + * damage detected,*/\ +{ 0x73e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed,*/\ +{ 0x73f0, "ACKRSV"}, /* Firmware event acknowledge reserved ,*/\ +{ 0x8000, "MTPOTC"}, /* Calibration schedule (key2 protected) ,*/\ +{ 0x8010, "MTPEX"}, /* (key2 protected) ,*/\ +{ 0x8045, "SWPROFIL" },\ +{ 0x80a5, "SWVSTEP" },\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA1_BITNAMETABLE static tfaBfName_t Tfa1BitNames[] = {\ +{ 0x0, "flag_por"}, /* Power-on-reset flag , */\ +{ 0x10, "flag_pll_lock"}, /* PLL lock , */\ +{ 0x20, "flag_otpok"}, /* Over Temperature Protection alarm , */\ +{ 0x30, "flag_ovpok"}, /* Over Voltage Protection alarm , */\ +{ 0x40, "flag_uvpok"}, /* Under Voltage Protection alarm , */\ +{ 0x50, "flag_ocp_alarm"}, /* Over Current Protection alarm , */\ +{ 0x60, "flag_clocks_stable"}, /* Clocks stable flag , */\ +{ 0x70, "flag_clip"}, /* Amplifier clipping , */\ +{ 0x80, "mtp_busy"}, /* MTP busy , */\ +{ 0x90, "flag_lost_clk"}, /* Flag lost clock from clock generation unit , */\ +{ 0xa0, "flag_cf_speakererror"}, /* Speaker error flag , */\ +{ 0xb0, "flag_cold_started"}, /* Cold Start flag , */\ +{ 0xc0, "flag_engage"}, /* Flag Engage , */\ +{ 0xd0, "flag_watchdog_reset"}, /* Flag watchdog reset , */\ +{ 0xe0, "flag_enbl_amp"}, /* Amplifier is enabled by manager , */\ +{ 0xf0, "flag_enbl_ref"}, /* References are enabled by manager , */\ +{ 0x109, "bat_adc"}, /* Battery voltage readout; 0 .. 5.5 [V] , */\ +{ 0x208, "temp_adc"}, /* Temperature readout from the temperature sensor , */\ +{ 0x30b, "rev_reg"}, /* Device type number is B97 , */\ +{ 0x420, "ctrl_rcv"}, /* Enable Receiver Mode , */\ +{ 0x431, "chan_sel"}, /* Channel Selection TDM input for Coolflux , */\ +{ 0x450, "input_level"}, /* Input level selection control , */\ +{ 0x461, "vamp_sel"}, /* Input selection for amplifier , */\ +{ 0x4c3, "audio_fs"}, /* Audio sample rate setting , */\ +{ 0x501, "vbat_prot_attacktime"}, /* Protection Attack Time , */\ +{ 0x523, "vbat_prot_thlevel"}, /* ProtectionThreshold , */\ +{ 0x561, "vbat_prot_max_reduct"}, /* Protection Maximum Reduction , */\ +{ 0x582, "vbat_prot_release_t"}, /* Battery Protection Release Time , */\ +{ 0x5b1, "vbat_prot_hysterese"}, /* Battery Protection Hysteresis , */\ +{ 0x5d0, "reset_min_vbat"}, /* reset clipper , */\ +{ 0x5e0, "sel_vbat"}, /* battery voltage for I2C read out only , */\ +{ 0x5f0, "bypass_clipper"}, /* bypass clipper battery protection , */\ +{ 0x600, "dpsa"}, /* Enable dynamic powerstage activation , */\ +{ 0x650, "cf_mute"}, /* Soft mute in CoolFlux , */\ +{ 0x670, "batsense_steepness"}, /* BatSenseSteepness , */\ +{ 0x687, "vol"}, /* volume control (in CoolFlux) , */\ +{ 0x702, "boost_volt"}, /* Boost Voltage , */\ +{ 0x733, "boost_cur"}, /* Max boost coil current - step of 175 mA , */\ +{ 0x7a0, "boost_intel"}, /* Adaptive boost mode , */\ +{ 0x7b0, "boost_speed"}, /* Soft RampUp/Down mode for DCDC controller , */\ +{ 0x7c0, "boost_peak2avg"}, /* ctrl_peak2avg for analog part of DCDC , */\ +{ 0x800, "ext_temp_sel"}, /* Select external temperature also the ext_temp will be put on the temp read out , */\ +{ 0x818, "ext_temp"}, /* external temperature setting to be given by host , */\ +{ 0x8b2, "dcdc_synchronisation"}, /* DCDC synchronisation off + 7 positions , */\ +{ 0x900, "powerdown"}, /* Device Mode , */\ +{ 0x910, "reset"}, /* I2C Reset , */\ +{ 0x920, "enbl_coolflux"}, /* Enable CoolFlux , */\ +{ 0x930, "enbl_amplifier"}, /* Enable Amplifier , */\ +{ 0x940, "enbl_boost"}, /* EnableBoost , */\ +{ 0x950, "coolflux_configured"}, /* Coolflux configured , */\ +{ 0x960, "sel_enbl_amplifier"}, /* Selection on how Amplifier is enabled , */\ +{ 0x970, "dcdcoff_mode"}, /* DCDC not connected , */\ +{ 0x980, "iddqtest"}, /* IDDQ test amplifier , */\ +{ 0x991, "coil_value"}, /* Coil Value , */\ +{ 0x9b0, "sel_cf_clock"}, /* Selection CoolFlux Clock , */\ +{ 0x9c1, "int_pad_io"}, /* INT pad configuration control , */\ +{ 0x9e0, "sel_fs_bck"}, /* PLL input reference clock selection , */\ +{ 0x9f0, "sel_scl_cf_clock"}, /* Coolflux sub-system clock , */\ +{ 0xb07, "mtpkey2"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ +{ 0xc00, "enbl_volt_sense"}, /* Voltage sense enabling control bit , */\ +{ 0xc10, "vsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ +{ 0xc25, "vi_frac_delay"}, /* Fractional delay adjustment between current and voltage sense, */\ +{ 0xc80, "sel_voltsense_out"}, /* TDM output data selection control , */\ +{ 0xc90, "vsense_bypass_avg"}, /* Voltage Sense Average Block Bypass , */\ +{ 0xd05, "cf_frac_delay"}, /* Fractional delay adjustment between current and voltage sense by firmware, */\ +{ 0xe00, "bypass_dcdc_curr_prot"}, /* Control to switch off dcdc current reduction with bat protection, */\ +{ 0xe80, "disable_clock_sh_prot"}, /* disable clock_sh protection , */\ +{ 0xe96, "reserve_reg_1_15_9"}, /* , */\ +{ 0x1011, "tdm_usecase"}, /* TDM_usecase , */\ +{ 0x1030, "tdm_enable"}, /* TDM interface control , */\ +{ 0x1040, "tdm_clk_inversion"}, /* TDM clock inversion , */\ +{ 0x1053, "tdm_fs_ws_length"}, /* TDM FS length , */\ +{ 0x1090, "tdm_fs_ws_polarity"}, /* TDM FS polarity , */\ +{ 0x10a4, "tdm_sample_size"}, /* TDM Sample Size for all tdm sinks/sources , */\ +{ 0x1103, "tdm_nb_of_slots"}, /* Number of slots , */\ +{ 0x1144, "tdm_slot_length"}, /* Slot length , */\ +{ 0x1194, "tdm_bits_remaining"}, /* Bits remaining , */\ +{ 0x11e0, "tdm_data_delay"}, /* Data delay , */\ +{ 0x11f0, "tdm_data_adjustment"}, /* Data adjustment , */\ +{ 0x1201, "tdm_txdata_format"}, /* TXDATA format , */\ +{ 0x1221, "tdm_txdata_format_unused_slot_sd0"}, /* TXDATA format unused slot sd0 , */\ +{ 0x1241, "tdm_txdata_format_unused_slot_sd1"}, /* TXDATA format unused slot sd1 , */\ +{ 0x1270, "tdm_sink0_enable"}, /* TDM sink0 enable , */\ +{ 0x1280, "tdm_sink1_enable"}, /* TDM sink1 enable , */\ +{ 0x1290, "tdm_sink2_enable"}, /* TDM sink2 enable , */\ +{ 0x12a0, "tdm_source0_enable"}, /* TDM source0 enable , */\ +{ 0x12b0, "tdm_source1_enable"}, /* TDM source1 enable , */\ +{ 0x12c0, "tdm_source2_enable"}, /* TDM source2 enable , */\ +{ 0x12d0, "tdm_sink0_io"}, /* tdm_sink0_io , */\ +{ 0x12e0, "tdm_sink1_io"}, /* tdm_sink1_io , */\ +{ 0x12f0, "tdm_sink2_io"}, /* tdm_sink2_io , */\ +{ 0x1300, "tdm_source0_io"}, /* tdm_source0_io , */\ +{ 0x1310, "tdm_source1_io"}, /* tdm_source1_io , */\ +{ 0x1320, "tdm_source2_io"}, /* tdm_source2_io , */\ +{ 0x1333, "tdm_sink0_slot"}, /* sink0_slot [GAIN IN] , */\ +{ 0x1373, "tdm_sink1_slot"}, /* sink1_slot [CH1 IN] , */\ +{ 0x13b3, "tdm_sink2_slot"}, /* sink2_slot [CH2 IN] , */\ +{ 0x1403, "tdm_source0_slot"}, /* source0_slot [GAIN OUT] , */\ +{ 0x1443, "tdm_source1_slot"}, /* source1_slot [Voltage Sense] , */\ +{ 0x1483, "tdm_source2_slot"}, /* source2_slot [Current Sense] , */\ +{ 0x14c3, "tdm_nbck"}, /* NBCK , */\ +{ 0x1500, "flag_tdm_lut_error"}, /* TDM LUT error flag , */\ +{ 0x1512, "flag_tdm_status"}, /* TDM interface status bits , */\ +{ 0x1540, "flag_tdm_error"}, /* TDM interface error indicator , */\ +{ 0x2000, "flag_por_int_out"}, /* flag_por_int_out , */\ +{ 0x2010, "flag_pll_lock_int_out"}, /* flag_pll_lock_int_out , */\ +{ 0x2020, "flag_otpok_int_out"}, /* flag_otpok_int_out , */\ +{ 0x2030, "flag_ovpok_int_out"}, /* flag_ovpok_int_out , */\ +{ 0x2040, "flag_uvpok_int_out"}, /* flag_uvpok_int_out , */\ +{ 0x2050, "flag_ocp_alarm_int_out"}, /* flag_ocp_alarm_int_out , */\ +{ 0x2060, "flag_clocks_stable_int_out"}, /* flag_clocks_stable_int_out , */\ +{ 0x2070, "flag_clip_int_out"}, /* flag_clip_int_out , */\ +{ 0x2080, "mtp_busy_int_out"}, /* mtp_busy_int_out , */\ +{ 0x2090, "flag_lost_clk_int_out"}, /* flag_lost_clk_int_out , */\ +{ 0x20a0, "flag_cf_speakererror_int_out"}, /* flag_cf_speakererror_int_out , */\ +{ 0x20b0, "flag_cold_started_int_out"}, /* flag_cold_started_int_out , */\ +{ 0x20c0, "flag_engage_int_out"}, /* flag_engage_int_out , */\ +{ 0x20d0, "flag_watchdog_reset_int_out"}, /* flag_watchdog_reset_int_out , */\ +{ 0x20e0, "flag_enbl_amp_int_out"}, /* flag_enbl_amp_int_out , */\ +{ 0x20f0, "flag_enbl_ref_int_out"}, /* flag_enbl_ref_int_out , */\ +{ 0x2100, "flag_voutcomp_int_out"}, /* flag_voutcomp_int_out , */\ +{ 0x2110, "flag_voutcomp93_int_out"}, /* flag_voutcomp93_int_out , */\ +{ 0x2120, "flag_voutcomp86_int_out"}, /* flag_voutcomp86_int_out , */\ +{ 0x2130, "flag_hiz_int_out"}, /* flag_hiz_int_out , */\ +{ 0x2140, "flag_ocpokbst_int_out"}, /* flag_ocpokbst_int_out , */\ +{ 0x2150, "flag_peakcur_int_out"}, /* flag_peakcur_int_out , */\ +{ 0x2160, "flag_ocpokap_int_out"}, /* flag_ocpokap_int_out , */\ +{ 0x2170, "flag_ocpokan_int_out"}, /* flag_ocpokan_int_out , */\ +{ 0x2180, "flag_ocpokbp_int_out"}, /* flag_ocpokbp_int_out , */\ +{ 0x2190, "flag_ocpokbn_int_out"}, /* flag_ocpokbn_int_out , */\ +{ 0x21a0, "flag_adc10_ready_int_out"}, /* flag_adc10_ready_int_out , */\ +{ 0x21b0, "flag_clipa_high_int_out"}, /* flag_clipa_high_int_out , */\ +{ 0x21c0, "flag_clipa_low_int_out"}, /* flag_clipa_low_int_out , */\ +{ 0x21d0, "flag_clipb_high_int_out"}, /* flag_clipb_high_int_out , */\ +{ 0x21e0, "flag_clipb_low_int_out"}, /* flag_clipb_low_int_out , */\ +{ 0x21f0, "flag_tdm_error_int_out"}, /* flag_tdm_error_int_out , */\ +{ 0x2201, "interrupt_out3"}, /* Interrupt status register output - Corresponding flag, */\ +{ 0x2300, "flag_por_int_in"}, /* flag_por_int_in , */\ +{ 0x2310, "flag_pll_lock_int_in"}, /* flag_pll_lock_int_in , */\ +{ 0x2320, "flag_otpok_int_in"}, /* flag_otpok_int_in , */\ +{ 0x2330, "flag_ovpok_int_in"}, /* flag_ovpok_int_in , */\ +{ 0x2340, "flag_uvpok_int_in"}, /* flag_uvpok_int_in , */\ +{ 0x2350, "flag_ocp_alarm_int_in"}, /* flag_ocp_alarm_int_in , */\ +{ 0x2360, "flag_clocks_stable_int_in"}, /* flag_clocks_stable_int_in , */\ +{ 0x2370, "flag_clip_int_in"}, /* flag_clip_int_in , */\ +{ 0x2380, "mtp_busy_int_in"}, /* mtp_busy_int_in , */\ +{ 0x2390, "flag_lost_clk_int_in"}, /* flag_lost_clk_int_in , */\ +{ 0x23a0, "flag_cf_speakererror_int_in"}, /* flag_cf_speakererror_int_in , */\ +{ 0x23b0, "flag_cold_started_int_in"}, /* flag_cold_started_int_in , */\ +{ 0x23c0, "flag_engage_int_in"}, /* flag_engage_int_in , */\ +{ 0x23d0, "flag_watchdog_reset_int_in"}, /* flag_watchdog_reset_int_in , */\ +{ 0x23e0, "flag_enbl_amp_int_in"}, /* flag_enbl_amp_int_in , */\ +{ 0x23f0, "flag_enbl_ref_int_in"}, /* flag_enbl_ref_int_in , */\ +{ 0x2400, "flag_voutcomp_int_in"}, /* flag_voutcomp_int_in , */\ +{ 0x2410, "flag_voutcomp93_int_in"}, /* flag_voutcomp93_int_in , */\ +{ 0x2420, "flag_voutcomp86_int_in"}, /* flag_voutcomp86_int_in , */\ +{ 0x2430, "flag_hiz_int_in"}, /* flag_hiz_int_in , */\ +{ 0x2440, "flag_ocpokbst_int_in"}, /* flag_ocpokbst_int_in , */\ +{ 0x2450, "flag_peakcur_int_in"}, /* flag_peakcur_int_in , */\ +{ 0x2460, "flag_ocpokap_int_in"}, /* flag_ocpokap_int_in , */\ +{ 0x2470, "flag_ocpokan_int_in"}, /* flag_ocpokan_int_in , */\ +{ 0x2480, "flag_ocpokbp_int_in"}, /* flag_ocpokbp_int_in , */\ +{ 0x2490, "flag_ocpokbn_int_in"}, /* flag_ocpokbn_int_in , */\ +{ 0x24a0, "flag_adc10_ready_int_in"}, /* flag_adc10_ready_int_in , */\ +{ 0x24b0, "flag_clipa_high_int_in"}, /* flag_clipa_high_int_in , */\ +{ 0x24c0, "flag_clipa_low_int_in"}, /* flag_clipa_low_int_in , */\ +{ 0x24d0, "flag_clipb_high_int_in"}, /* flag_clipb_high_int_in , */\ +{ 0x24e0, "flag_clipb_low_int_in"}, /* flag_clipb_low_int_in , */\ +{ 0x24f0, "flag_tdm_error_int_in"}, /* flag_tdm_error_int_in , */\ +{ 0x2501, "interrupt_in3"}, /* Interrupt register input , */\ +{ 0x2600, "flag_por_int_enable"}, /* flag_por_int_enable , */\ +{ 0x2610, "flag_pll_lock_int_enable"}, /* flag_pll_lock_int_enable , */\ +{ 0x2620, "flag_otpok_int_enable"}, /* flag_otpok_int_enable , */\ +{ 0x2630, "flag_ovpok_int_enable"}, /* flag_ovpok_int_enable , */\ +{ 0x2640, "flag_uvpok_int_enable"}, /* flag_uvpok_int_enable , */\ +{ 0x2650, "flag_ocp_alarm_int_enable"}, /* flag_ocp_alarm_int_enable , */\ +{ 0x2660, "flag_clocks_stable_int_enable"}, /* flag_clocks_stable_int_enable , */\ +{ 0x2670, "flag_clip_int_enable"}, /* flag_clip_int_enable , */\ +{ 0x2680, "mtp_busy_int_enable"}, /* mtp_busy_int_enable , */\ +{ 0x2690, "flag_lost_clk_int_enable"}, /* flag_lost_clk_int_enable , */\ +{ 0x26a0, "flag_cf_speakererror_int_enable"}, /* flag_cf_speakererror_int_enable , */\ +{ 0x26b0, "flag_cold_started_int_enable"}, /* flag_cold_started_int_enable , */\ +{ 0x26c0, "flag_engage_int_enable"}, /* flag_engage_int_enable , */\ +{ 0x26d0, "flag_watchdog_reset_int_enable"}, /* flag_watchdog_reset_int_enable , */\ +{ 0x26e0, "flag_enbl_amp_int_enable"}, /* flag_enbl_amp_int_enable , */\ +{ 0x26f0, "flag_enbl_ref_int_enable"}, /* flag_enbl_ref_int_enable , */\ +{ 0x2700, "flag_voutcomp_int_enable"}, /* flag_voutcomp_int_enable , */\ +{ 0x2710, "flag_voutcomp93_int_enable"}, /* flag_voutcomp93_int_enable , */\ +{ 0x2720, "flag_voutcomp86_int_enable"}, /* flag_voutcomp86_int_enable , */\ +{ 0x2730, "flag_hiz_int_enable"}, /* flag_hiz_int_enable , */\ +{ 0x2740, "flag_ocpokbst_int_enable"}, /* flag_ocpokbst_int_enable , */\ +{ 0x2750, "flag_peakcur_int_enable"}, /* flag_peakcur_int_enable , */\ +{ 0x2760, "flag_ocpokap_int_enable"}, /* flag_ocpokap_int_enable , */\ +{ 0x2770, "flag_ocpokan_int_enable"}, /* flag_ocpokan_int_enable , */\ +{ 0x2780, "flag_ocpokbp_int_enable"}, /* flag_ocpokbp_int_enable , */\ +{ 0x2790, "flag_ocpokbn_int_enable"}, /* flag_ocpokbn_int_enable , */\ +{ 0x27a0, "flag_adc10_ready_int_enable"}, /* flag_adc10_ready_int_enable , */\ +{ 0x27b0, "flag_clipa_high_int_enable"}, /* flag_clipa_high_int_enable , */\ +{ 0x27c0, "flag_clipa_low_int_enable"}, /* flag_clipa_low_int_enable , */\ +{ 0x27d0, "flag_clipb_high_int_enable"}, /* flag_clipb_high_int_enable , */\ +{ 0x27e0, "flag_clipb_low_int_enable"}, /* flag_clipb_low_int_enable , */\ +{ 0x27f0, "flag_tdm_error_int_enable"}, /* flag_tdm_error_int_enable , */\ +{ 0x2801, "interrupt_enable3"}, /* Interrupt enable register , */\ +{ 0x2900, "flag_por_int_pol"}, /* flag_por_int_pol , */\ +{ 0x2910, "flag_pll_lock_int_pol"}, /* flag_pll_lock_int_pol , */\ +{ 0x2920, "flag_otpok_int_pol"}, /* flag_otpok_int_pol , */\ +{ 0x2930, "flag_ovpok_int_pol"}, /* flag_ovpok_int_pol , */\ +{ 0x2940, "flag_uvpok_int_pol"}, /* flag_uvpok_int_pol , */\ +{ 0x2950, "flag_ocp_alarm_int_pol"}, /* flag_ocp_alarm_int_pol , */\ +{ 0x2960, "flag_clocks_stable_int_pol"}, /* flag_clocks_stable_int_pol , */\ +{ 0x2970, "flag_clip_int_pol"}, /* flag_clip_int_pol , */\ +{ 0x2980, "mtp_busy_int_pol"}, /* mtp_busy_int_pol , */\ +{ 0x2990, "flag_lost_clk_int_pol"}, /* flag_lost_clk_int_pol , */\ +{ 0x29a0, "flag_cf_speakererror_int_pol"}, /* flag_cf_speakererror_int_pol , */\ +{ 0x29b0, "flag_cold_started_int_pol"}, /* flag_cold_started_int_pol , */\ +{ 0x29c0, "flag_engage_int_pol"}, /* flag_engage_int_pol , */\ +{ 0x29d0, "flag_watchdog_reset_int_pol"}, /* flag_watchdog_reset_int_pol , */\ +{ 0x29e0, "flag_enbl_amp_int_pol"}, /* flag_enbl_amp_int_pol , */\ +{ 0x29f0, "flag_enbl_ref_int_pol"}, /* flag_enbl_ref_int_pol , */\ +{ 0x2a00, "flag_voutcomp_int_pol"}, /* flag_voutcomp_int_pol , */\ +{ 0x2a10, "flag_voutcomp93_int_pol"}, /* flag_voutcomp93_int_pol , */\ +{ 0x2a20, "flag_voutcomp86_int_pol"}, /* flag_voutcomp86_int_pol , */\ +{ 0x2a30, "flag_hiz_int_pol"}, /* flag_hiz_int_pol , */\ +{ 0x2a40, "flag_ocpokbst_int_pol"}, /* flag_ocpokbst_int_pol , */\ +{ 0x2a50, "flag_peakcur_int_pol"}, /* flag_peakcur_int_pol , */\ +{ 0x2a60, "flag_ocpokap_int_pol"}, /* flag_ocpokap_int_pol , */\ +{ 0x2a70, "flag_ocpokan_int_pol"}, /* flag_ocpokan_int_pol , */\ +{ 0x2a80, "flag_ocpokbp_int_pol"}, /* flag_ocpokbp_int_pol , */\ +{ 0x2a90, "flag_ocpokbn_int_pol"}, /* flag_ocpokbn_int_pol , */\ +{ 0x2aa0, "flag_adc10_ready_int_pol"}, /* flag_adc10_ready_int_pol , */\ +{ 0x2ab0, "flag_clipa_high_int_pol"}, /* flag_clipa_high_int_pol , */\ +{ 0x2ac0, "flag_clipa_low_int_pol"}, /* flag_clipa_low_int_pol , */\ +{ 0x2ad0, "flag_clipb_high_int_pol"}, /* flag_clipb_high_int_pol , */\ +{ 0x2ae0, "flag_clipb_low_int_pol"}, /* flag_clipb_low_int_pol , */\ +{ 0x2af0, "flag_tdm_error_int_pol"}, /* flag_tdm_error_int_pol , */\ +{ 0x2b01, "status_polarity3"}, /* Interrupt status flags polarity register , */\ +{ 0x3000, "flag_voutcomp"}, /* flag_voutcomp, indication Vset is larger than Vbat, */\ +{ 0x3010, "flag_voutcomp93"}, /* flag_voutcomp93, indication Vset is larger than 1.07* Vbat, */\ +{ 0x3020, "flag_voutcomp86"}, /* flag_voutcomp86, indication Vset is larger than 1.14* Vbat, */\ +{ 0x3030, "flag_hiz"}, /* flag_hiz, indication Vbst is larger than Vbat , */\ +{ 0x3040, "flag_ocpokbst"}, /* flag_ocpokbst, indication no over current in boost converter pmos switch, */\ +{ 0x3050, "flag_peakcur"}, /* flag_peakcur, indication current is max in dcdc converter, */\ +{ 0x3060, "flag_ocpokap"}, /* flag_ocpokap, indication no over current in amplifier "a" pmos output stage, */\ +{ 0x3070, "flag_ocpokan"}, /* flag_ocpokan, indication no over current in amplifier "a" nmos output stage, */\ +{ 0x3080, "flag_ocpokbp"}, /* flag_ocpokbp, indication no over current in amplifier "b" pmos output stage, */\ +{ 0x3090, "flag_ocpokbn"}, /* flag_ocpokbn, indication no over current in amplifier"b" nmos output stage, */\ +{ 0x30a0, "flag_adc10_ready"}, /* flag_adc10_ready, indication adc10 is ready , */\ +{ 0x30b0, "flag_clipa_high"}, /* flag_clipa_high, indication pmos amplifier "a" is clipping, */\ +{ 0x30c0, "flag_clipa_low"}, /* flag_clipa_low, indication nmos amplifier "a" is clipping, */\ +{ 0x30d0, "flag_clipb_high"}, /* flag_clipb_high, indication pmos amplifier "b" is clipping, */\ +{ 0x30e0, "flag_clipb_low"}, /* flag_clipb_low, indication nmos amplifier "b" is clipping, */\ +{ 0x310f, "mtp_man_data_out"}, /* single word read from MTP (manual copy) , */\ +{ 0x3200, "key01_locked"}, /* key01_locked, indication key 1 is locked , */\ +{ 0x3210, "key02_locked"}, /* key02_locked, indication key 2 is locked , */\ +{ 0x3225, "mtp_ecc_tcout"}, /* mtp_ecc_tcout , */\ +{ 0x3280, "mtpctrl_valid_test_rd"}, /* mtp test readout for read , */\ +{ 0x3290, "mtpctrl_valid_test_wr"}, /* mtp test readout for write , */\ +{ 0x32a0, "flag_in_alarm_state"}, /* Alarm state , */\ +{ 0x32b0, "mtp_ecc_err2"}, /* two or more bit errors detected in MTP, can not reconstruct value, */\ +{ 0x32c0, "mtp_ecc_err1"}, /* one bit error detected in MTP, reconstructed value, */\ +{ 0x32d0, "mtp_mtp_hvf"}, /* high voltage ready flag for MTP , */\ +{ 0x32f0, "mtp_zero_check_fail"}, /* zero check failed (tbd) for MTP , */\ +{ 0x3309, "data_adc10_tempbat"}, /* data_adc10_tempbat[9;0], adc 10 data output for testing, */\ +{ 0x400f, "hid_code"}, /* 5A6Bh, 23147d to access registers (Default for engineering), */\ +{ 0x4100, "bypass_hp"}, /* Bypass_High Pass Filter , */\ +{ 0x4110, "hard_mute"}, /* Hard Mute , */\ +{ 0x4120, "soft_mute"}, /* Soft Mute , */\ +{ 0x4134, "pwm_delay"}, /* PWM DelayBits to set the delay , */\ +{ 0x4180, "pwm_shape"}, /* PWM Shape , */\ +{ 0x4190, "pwm_bitlength"}, /* PWM Bitlength in noise shaper , */\ +{ 0x4203, "drive"}, /* Drive bits to select amount of power stage amplifier, */\ +{ 0x4240, "reclock_pwm"}, /* , */\ +{ 0x4250, "reclock_voltsense"}, /* , */\ +{ 0x4281, "dpsalevel"}, /* DPSA Threshold level , */\ +{ 0x42a1, "dpsa_release"}, /* DPSA Release time , */\ +{ 0x42c0, "coincidence"}, /* Prevent simultaneously switching of output stage , */\ +{ 0x42d0, "kickback"}, /* Prevent double pulses of output stage , */\ +{ 0x4306, "drivebst"}, /* Drive bits to select the powertransistor sections boost converter, */\ +{ 0x43a0, "ocptestbst"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0);For new ocp (ctrl_reversebst is 1);, */\ +{ 0x43d0, "test_abistfft_enbl"}, /* FFT coolflux , */\ +{ 0x43f0, "test_bcontrol"}, /* test _bcontrol , */\ +{ 0x4400, "reversebst"}, /* OverCurrent Protection selection of power stage boost converter, */\ +{ 0x4410, "sensetest"}, /* Test option for the sense NMOS in booster for current mode control., */\ +{ 0x4420, "enbl_engagebst"}, /* Enable power stage dcdc controller , */\ +{ 0x4470, "enbl_slopecur"}, /* Enable bit of max-current dac , */\ +{ 0x4480, "enbl_voutcomp"}, /* Enable vout comparators , */\ +{ 0x4490, "enbl_voutcomp93"}, /* Enable vout-93 comparators , */\ +{ 0x44a0, "enbl_voutcomp86"}, /* Enable vout-86 comparators , */\ +{ 0x44b0, "enbl_hizcom"}, /* Enable hiz comparator , */\ +{ 0x44c0, "enbl_peakcur"}, /* Enable peak current , */\ +{ 0x44d0, "bypass_ovpglitch"}, /* Bypass OVP Glitch Filter , */\ +{ 0x44e0, "enbl_windac"}, /* Enable window dac , */\ +{ 0x44f0, "enbl_powerbst"}, /* Enable line of the powerstage , */\ +{ 0x4507, "ocp_thr"}, /* ocp_thr threshold level for OCP , */\ +{ 0x4580, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ +{ 0x4590, "bypass_ovp"}, /* Bypass OVP , */\ +{ 0x45a0, "bypass_uvp"}, /* Bypass UVP , */\ +{ 0x45b0, "bypass_otp"}, /* Bypass OTP , */\ +{ 0x45c0, "bypass_ocp"}, /* Bypass OCP , */\ +{ 0x45d0, "bypass_ocpcounter"}, /* BypassOCPCounter , */\ +{ 0x45e0, "bypass_lost_clk"}, /* Bypasslost_clk detector , */\ +{ 0x45f0, "vpalarm"}, /* vpalarm (uvp ovp handling) , */\ +{ 0x4600, "bypass_gc"}, /* bypass_gc, bypasses the CS gain correction , */\ +{ 0x4610, "cs_gain_control"}, /* gain control by means of MTP or i2c; 0 is MTP , */\ +{ 0x4627, "cs_gain"}, /* + / - 128 steps in steps of 1/4 percent 2's compliment, */\ +{ 0x46a0, "bypass_lp"}, /* bypass Low-Pass filter in temperature sensor , */\ +{ 0x46b0, "bypass_pwmcounter"}, /* bypass_pwmcounter , */\ +{ 0x46c0, "cs_negfixed"}, /* does not switch to neg , */\ +{ 0x46d2, "cs_neghyst"}, /* switches to neg depending on level , */\ +{ 0x4700, "switch_fb"}, /* switch_fb , */\ +{ 0x4713, "se_hyst"}, /* se_hyst , */\ +{ 0x4754, "se_level"}, /* se_level , */\ +{ 0x47a5, "ktemp"}, /* temperature compensation trimming , */\ +{ 0x4800, "cs_negin"}, /* negin , */\ +{ 0x4810, "cs_sein"}, /* cs_sein , */\ +{ 0x4820, "cs_coincidence"}, /* Coincidence current sense , */\ +{ 0x4830, "iddqtestbst"}, /* for iddq testing in powerstage of boost convertor , */\ +{ 0x4840, "coincidencebst"}, /* Switch protection on to prevent simultaneously switching power stages bst and amp, */\ +{ 0x4876, "delay_se_neg"}, /* delay of se and neg , */\ +{ 0x48e1, "cs_ttrack"}, /* sample & hold track time , */\ +{ 0x4900, "bypass_clip"}, /* Bypass clip control , */\ +{ 0x4920, "cf_cgate_off"}, /* to disable clock gating in the coolflux , */\ +{ 0x4940, "clipfast"}, /* clock switch for battery protection clipper, it switches back to old frequency, */\ +{ 0x4950, "cs_8ohm"}, /* 8 ohm mode for current sense (gain mode) , */\ +{ 0x4974, "delay_clock_sh"}, /* delay_sh, tunes S7H delay , */\ +{ 0x49c0, "inv_clksh"}, /* Invert the sample/hold clock for current sense ADC, */\ +{ 0x49d0, "inv_neg"}, /* Invert neg signal , */\ +{ 0x49e0, "inv_se"}, /* Invert se signal , */\ +{ 0x49f0, "setse"}, /* switches between Single Ende and differential mode; 1 is single ended, */\ +{ 0x4a12, "adc10_sel"}, /* select the input to convert the 10b ADC , */\ +{ 0x4a60, "adc10_reset"}, /* Global asynchronous reset (active HIGH) 10 bit ADC, */\ +{ 0x4a81, "adc10_test"}, /* Test mode selection signal 10 bit ADC , */\ +{ 0x4aa0, "bypass_lp_vbat"}, /* lp filter in batt sensor , */\ +{ 0x4ae0, "dc_offset"}, /* switch offset control on/off, is decimator offset control, */\ +{ 0x4af0, "tsense_hibias"}, /* bit to set the biasing in temp sensor to high , */\ +{ 0x4b00, "adc13_iset"}, /* Micadc Setting of current consumption. Debug use only, */\ +{ 0x4b14, "adc13_gain"}, /* Micadc gain setting (2-compl) , */\ +{ 0x4b61, "adc13_slowdel"}, /* Micadc Delay setting for internal clock. Debug use only, */\ +{ 0x4b83, "adc13_offset"}, /* Micadc ADC offset setting , */\ +{ 0x4bc0, "adc13_bsoinv"}, /* Micadc bit stream output invert mode for test , */\ +{ 0x4bd0, "adc13_resonator_enable"}, /* Micadc Give extra SNR with less stability. Debug use only, */\ +{ 0x4be0, "testmicadc"}, /* Mux at input of MICADC for test purpose , */\ +{ 0x4c0f, "abist_offset"}, /* offset control for ABIST testing , */\ +{ 0x4d05, "windac"}, /* for testing direct control windac , */\ +{ 0x4dc3, "pwm_dcc_cnt"}, /* control pwm duty cycle when enbl_pwm_dcc is 1 , */\ +{ 0x4e04, "slopecur"}, /* for testing direct control slopecur , */\ +{ 0x4e50, "ctrl_dem"}, /* dyn element matching control, rest of codes are optional, */\ +{ 0x4ed0, "enbl_pwm_dcc"}, /* to enable direct control of pwm duty cycle , */\ +{ 0x5007, "gain"}, /* Gain setting of the gain multiplier , */\ +{ 0x5081, "sourceb"}, /* Set OUTB to , */\ +{ 0x50a1, "sourcea"}, /* Set OUTA to , */\ +{ 0x50c1, "sourcebst"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ +{ 0x50e0, "tdm_enable_loopback"}, /* TDM loopback test , */\ +{ 0x5104, "pulselengthbst"}, /* pulse length setting test input for boost converter, */\ +{ 0x5150, "bypasslatchbst"}, /* bypass_latch in boost converter , */\ +{ 0x5160, "invertbst"}, /* invert pwmbst test signal , */\ +{ 0x5174, "pulselength"}, /* pulse length setting test input for amplifier , */\ +{ 0x51c0, "bypasslatch"}, /* bypass_latch in PWM source selection module , */\ +{ 0x51d0, "invertb"}, /* invert pwmb test signal , */\ +{ 0x51e0, "inverta"}, /* invert pwma test signal , */\ +{ 0x51f0, "bypass_ctrlloop"}, /* bypass_ctrlloop bypasses the control loop of the amplifier, */\ +{ 0x5210, "test_rdsona"}, /* tbd for rdson testing , */\ +{ 0x5220, "test_rdsonb"}, /* tbd for rdson testing , */\ +{ 0x5230, "test_rdsonbst"}, /* tbd for rdson testing , */\ +{ 0x5240, "test_cvia"}, /* tbd for rdson testing , */\ +{ 0x5250, "test_cvib"}, /* tbd for rdson testing , */\ +{ 0x5260, "test_cvibst"}, /* tbd for rdson testing , */\ +{ 0x5306, "digimuxa_sel"}, /* DigimuxA input selection control (see Digimux list for details), */\ +{ 0x5376, "digimuxb_sel"}, /* DigimuxB input selection control (see Digimux list for details), */\ +{ 0x5400, "hs_mode"}, /* hs_mode, high speed mode I2C bus , */\ +{ 0x5412, "test_parametric_io"}, /* test_parametric_io for testing pads , */\ +{ 0x5440, "enbl_ringo"}, /* enbl_ringo, for test purpose to check with ringo , */\ +{ 0x5456, "digimuxc_sel"}, /* DigimuxC input selection control (see Digimux list for details), */\ +{ 0x54c0, "dio_ehs"}, /* Slew control for DIO in output mode , */\ +{ 0x54d0, "gainio_ehs"}, /* Slew control for GAINIO in output mode , */\ +{ 0x550d, "enbl_amp"}, /* enbl_amp for testing to enable all analoge blocks in amplifier, */\ +{ 0x5600, "use_direct_ctrls"}, /* use_direct_ctrls, to overrule several functions direct for testing, */\ +{ 0x5610, "rst_datapath"}, /* rst_datapath, datapath reset , */\ +{ 0x5620, "rst_cgu"}, /* rst_cgu, cgu reset , */\ +{ 0x5637, "enbl_ref"}, /* for testing to enable all analoge blocks in references, */\ +{ 0x56b0, "enbl_engage"}, /* Enable output stage amplifier , */\ +{ 0x56c0, "use_direct_clk_ctrl"}, /* use_direct_clk_ctrl, to overrule several functions direct for testing, */\ +{ 0x56d0, "use_direct_pll_ctrl"}, /* use_direct_pll_ctrl, to overrule several functions direct for testing, */\ +{ 0x56e0, "use_direct_ctrls_2"}, /* use_direct_sourseamp_ctrls, to overrule several functions direct for testing, */\ +{ 0x5707, "anamux"}, /* Anamux control , */\ +{ 0x57c0, "ocptest"}, /* ctrl_ocptest, deactivates the over current protection in the power stages of the amplifier. The ocp flag signals stay active., */\ +{ 0x57e0, "otptest"}, /* otptest, test mode otp amplifier , */\ +{ 0x57f0, "reverse"}, /* 1: Normal mode, slope is controlled , */\ +{ 0x5813, "pll_selr"}, /* pll_selr , */\ +{ 0x5854, "pll_selp"}, /* pll_selp , */\ +{ 0x58a5, "pll_seli"}, /* pll_seli , */\ +{ 0x5950, "pll_mdec_msb"}, /* most significant bits of pll_mdec[16] , */\ +{ 0x5960, "pll_ndec_msb"}, /* most significant bits of pll_ndec[9] , */\ +{ 0x5970, "pll_frm"}, /* pll_frm , */\ +{ 0x5980, "pll_directi"}, /* pll_directi , */\ +{ 0x5990, "pll_directo"}, /* pll_directo , */\ +{ 0x59a0, "enbl_pll"}, /* enbl_pll , */\ +{ 0x59f0, "pll_bypass"}, /* pll_bypass , */\ +{ 0x5a0f, "tsig_freq"}, /* tsig_freq, internal sinus test generator, frequency control, */\ +{ 0x5b02, "tsig_freq_msb"}, /* select internal sinus test generator, frequency control msb bits, */\ +{ 0x5b30, "inject_tsig"}, /* inject_tsig, control bit to switch to internal sinus test generator, */\ +{ 0x5b44, "adc10_prog_sample"}, /* control ADC10 , */\ +{ 0x5c0f, "pll_mdec"}, /* bits 15..0 of pll_mdec[16;0] , */\ +{ 0x5d06, "pll_pdec"}, /* pll_pdec , */\ +{ 0x5d78, "pll_ndec"}, /* bits 8..0 of pll_ndec[9;0] , */\ +{ 0x6007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ +{ 0x6185, "mtp_ecc_tcin"}, /* Mtp_ecc_tcin , */\ +{ 0x6203, "mtp_man_address_in"}, /* address from I2C regs for writing one word single mtp, */\ +{ 0x6260, "mtp_ecc_eeb"}, /* enable code bit generation (active low!) , */\ +{ 0x6270, "mtp_ecc_ecb"}, /* enable correction signal (active low!) , */\ +{ 0x6280, "man_copy_mtp_to_iic"}, /* start copying single word from mtp to i2cregs_mtp , */\ +{ 0x6290, "man_copy_iic_to_mtp"}, /* start copying single word from i2cregs_mtp to mtp [Key 1 protected], */\ +{ 0x62a0, "auto_copy_mtp_to_iic"}, /* start copying all the data from mtp to i2cregs_mtp, */\ +{ 0x62b0, "auto_copy_iic_to_mtp"}, /* start copying all the data from i2cregs_mtp to mtp [Key 2 protected], */\ +{ 0x62d2, "mtp_speed_mode"}, /* Speed mode , */\ +{ 0x6340, "mtp_direct_enable"}, /* mtp_direct_enable (key1 protected) , */\ +{ 0x6350, "mtp_direct_wr"}, /* mtp_direct_wr (key1 protected) , */\ +{ 0x6360, "mtp_direct_rd"}, /* mtp_direct_rd (key1 protected) , */\ +{ 0x6370, "mtp_direct_rst"}, /* mtp_direct_rst (key1 protected) , */\ +{ 0x6380, "mtp_direct_ers"}, /* mtp_direct_ers (key1 protected) , */\ +{ 0x6390, "mtp_direct_prg"}, /* mtp_direct_prg (key1 protected) , */\ +{ 0x63a0, "mtp_direct_epp"}, /* mtp_direct_epp (key1 protected) , */\ +{ 0x63b4, "mtp_direct_test"}, /* mtp_direct_test (key1 protected) , */\ +{ 0x640f, "mtp_man_data_in"}, /* single word to be written to MTP (manual copy) , */\ +{ 0x7000, "cf_rst_dsp"}, /* Reset CoolFlux DSP , */\ +{ 0x7011, "cf_dmem"}, /* Target memory for access , */\ +{ 0x7030, "cf_aif"}, /* Autoincrement-flag for memory-address , */\ +{ 0x7040, "cf_int"}, /* Interrupt CoolFlux DSP , */\ +{ 0x7087, "cf_req"}, /* request for access (8 channels) , */\ +{ 0x710f, "cf_madd"}, /* memory-address to be accessed , */\ +{ 0x720f, "cf_mema"}, /* activate memory access (24- or 32-bits data is written/read to/from memory, */\ +{ 0x7307, "cf_err"}, /* Coolflux error flags , */\ +{ 0x7387, "cf_ack"}, /* acknowledge of requests (8 channels) , */\ +{ 0x8000, "calibration_onetime"}, /* Calibration schedule (key2 protected) , */\ +{ 0x8010, "calibr_ron_done"}, /* (key2 protected) , */\ +{ 0x8105, "calibr_vout_offset"}, /* calibr_vout_offset (DCDCoffset) 2's compliment (key1 protected), */\ +{ 0x8163, "calibr_delta_gain"}, /* delta gain for vamp (alpha) 2's compliment (key1 protected), */\ +{ 0x81a5, "calibr_offs_amp"}, /* offset for vamp (Ampoffset) 2's compliment (key1 protected), */\ +{ 0x8207, "calibr_gain_cs"}, /* gain current sense (Imeasalpha) 2's compliment (key1 protected), */\ +{ 0x8284, "calibr_temp_offset"}, /* temperature offset 2's compliment (key1 protected), */\ +{ 0x82d2, "calibr_temp_gain"}, /* temperature gain 2's compliment (key1 protected) , */\ +{ 0x830f, "calibr_ron"}, /* Ron resistance of coil (key1 protected) , */\ +{ 0x8505, "type_bits_HW"}, /* Key1_Protected_MTP5 , */\ +{ 0x8601, "type_bits_1_0_SW"}, /* MTP-control SW , */\ +{ 0x8681, "type_bits_8_9_SW"}, /* MTP-control SW , */\ +{ 0x870f, "type_bits2_SW"}, /* MTP-control SW2 , */\ +{ 0x8806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ +{ 0x8870, "htol_iic_addr_en"}, /* HTOL_I2C_Address_Enable , */\ +{ 0x8881, "ctrl_ovp_response"}, /* OVP response control , */\ +{ 0x88a0, "disable_ovp_alarm_state"}, /* OVP alarm state control , */\ +{ 0x88b0, "enbl_stretch_ovp"}, /* OVP alram strech control , */\ +{ 0x88c0, "cf_debug_mode"}, /* Coolflux debug mode , */\ +{ 0x8a0f, "production_data1"}, /* (key1 protected) , */\ +{ 0x8b0f, "production_data2"}, /* (key1 protected) , */\ +{ 0x8c0f, "production_data3"}, /* (key1 protected) , */\ +{ 0x8d0f, "production_data4"}, /* (key1 protected) , */\ +{ 0x8e0f, "production_data5"}, /* (key1 protected) , */\ +{ 0x8f0f, "production_data6"}, /* (key1 protected) , */\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa1_irq { +tfa1_irq_vdds = 0, +tfa1_irq_plls = 1, +tfa1_irq_ds = 2, +tfa1_irq_vds = 3, +tfa1_irq_uvds = 4, +tfa1_irq_cds = 5, +tfa1_irq_clks = 6, +tfa1_irq_clips = 7, +tfa1_irq_mtpb = 8, +tfa1_irq_clk = 9, +tfa1_irq_spks = 10, +tfa1_irq_acs = 11, +tfa1_irq_sws = 12, +tfa1_irq_wds = 13, +tfa1_irq_amps = 14, +tfa1_irq_arefs = 15, +tfa1_irq_ack = 32, +tfa1_irq_max = 33, +tfa1_irq_all = -1 /* all irqs */}; + +#define TFA1_IRQ_NAMETABLE static tfaIrqName_t Tfa1IrqNames[] = {\ +{ 0, "VDDS"},\ +{ 1, "PLLS"},\ +{ 2, "DS"},\ +{ 3, "VDS"},\ +{ 4, "UVDS"},\ +{ 5, "CDS"},\ +{ 6, "CLKS"},\ +{ 7, "CLIPS"},\ +{ 8, "MTPB"},\ +{ 9, "CLK"},\ +{ 10, "SPKS"},\ +{ 11, "ACS"},\ +{ 12, "SWS"},\ +{ 13, "WDS"},\ +{ 14, "AMPS"},\ +{ 15, "AREFS"},\ +{ 16, "16"},\ +{ 17, "17"},\ +{ 18, "18"},\ +{ 19, "19"},\ +{ 20, "20"},\ +{ 21, "21"},\ +{ 22, "22"},\ +{ 23, "23"},\ +{ 24, "24"},\ +{ 25, "25"},\ +{ 26, "26"},\ +{ 27, "27"},\ +{ 28, "28"},\ +{ 29, "29"},\ +{ 30, "30"},\ +{ 31, "31"},\ +{ 32, "ACK"},\ +{ 33, "33"},\ +}; diff --git a/sound/soc/codecs/tfa2_tfafieldnames_N1C.h b/sound/soc/codecs/tfa2_tfafieldnames_N1C.h new file mode 100644 index 0000000000000000000000000000000000000000..2bd61cc66de831ec9cec0418c728ac03c9d24f06 --- /dev/null +++ b/sound/soc/codecs/tfa2_tfafieldnames_N1C.h @@ -0,0 +1,1526 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ +#define TFA9888_I2CVERSION 18 +typedef enum nxpTfa2BfEnumList { + TFA2_BF_PWDN = 0x0000, /*!< Powerdown selection */ + TFA2_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA2_BF_CFE = 0x0020, /*!< Enable CoolFlux */ + TFA2_BF_AMPE = 0x0030, /*!< Activate Amplifier */ + TFA2_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ + TFA2_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA2_BF_AMPC = 0x0060, /*!< CoolFlux controls amplifier */ + TFA2_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA2_BF_FSSSEL = 0x0091, /*!< Audio sample reference */ + TFA2_BF_BYPOCP = 0x00b0, /*!< Bypass OCP */ + TFA2_BF_TSTOCP = 0x00c0, /*!< OCP testing control */ + TFA2_BF_AMPINSEL = 0x0101, /*!< Amplifier input selection */ + TFA2_BF_MANSCONF = 0x0120, /*!< I2C configured */ + TFA2_BF_MANCOLD = 0x0130, /*!< Execute cold start */ + TFA2_BF_MANAOOSC = 0x0140, /*!< Internal osc off at PWDN */ + TFA2_BF_MANROBOD = 0x0150, /*!< Reaction on BOD */ + TFA2_BF_BODE = 0x0160, /*!< BOD Enable */ + TFA2_BF_BODHYS = 0x0170, /*!< BOD Hysteresis */ + TFA2_BF_BODFILT = 0x0181, /*!< BOD filter */ + TFA2_BF_BODTHLVL = 0x01a1, /*!< BOD threshold */ + TFA2_BF_MUTETO = 0x01d0, /*!< Time out SB mute sequence */ + TFA2_BF_RCVNS = 0x01e0, /*!< Noise shaper selection */ + TFA2_BF_MANWDE = 0x01f0, /*!< Watchdog manager reaction */ + TFA2_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ + TFA2_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ + TFA2_BF_FRACTDEL = 0x0255, /*!< V/I Fractional delay */ + TFA2_BF_BYPHVBF = 0x02b0, /*!< Bypass HVBAT filter */ + TFA2_BF_LDOBYP = 0x02c0, /*!< Receiver LDO bypass */ + TFA2_BF_REV = 0x030f, /*!< Revision info */ + TFA2_BF_REFCKEXT = 0x0401, /*!< PLL external ref clock */ + TFA2_BF_REFCKSEL = 0x0420, /*!< PLL internal ref clock */ + TFA2_BF_SSLEFTE = 0x0500, /*!< Enable left channel */ + TFA2_BF_SSRIGHTE = 0x0510, /*!< Enable right channel */ + TFA2_BF_VSLEFTE = 0x0520, /*!< Voltage sense left */ + TFA2_BF_VSRIGHTE = 0x0530, /*!< Voltage sense right */ + TFA2_BF_CSLEFTE = 0x0540, /*!< Current sense left */ + TFA2_BF_CSRIGHTE = 0x0550, /*!< Current sense right */ + TFA2_BF_SSPDME = 0x0560, /*!< Sub-system PDM */ + TFA2_BF_STGAIN = 0x0d18, /*!< Side tone gain */ + TFA2_BF_PDMSMUTE = 0x0da0, /*!< Side tone soft mute */ + TFA2_BF_SWVSTEP = 0x0e06, /*!< Register for the host SW to record the current active vstep */ + TFA2_BF_VDDS = 0x1000, /*!< POR */ + TFA2_BF_PLLS = 0x1010, /*!< PLL lock */ + TFA2_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA2_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA2_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA2_BF_CLKS = 0x1050, /*!< Clocks stable */ + TFA2_BF_MTPB = 0x1060, /*!< MTP busy */ + TFA2_BF_NOCLK = 0x1070, /*!< Lost clock */ + TFA2_BF_SPKS = 0x1080, /*!< Speaker error */ + TFA2_BF_ACS = 0x1090, /*!< Cold Start */ + TFA2_BF_SWS = 0x10a0, /*!< Amplifier engage */ + TFA2_BF_WDS = 0x10b0, /*!< Watchdog */ + TFA2_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA2_BF_AREFS = 0x10d0, /*!< References enable */ + TFA2_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA2_BF_BODNOK = 0x10f0, /*!< BOD */ + TFA2_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA2_BF_DCDCA = 0x1110, /*!< DCDC active */ + TFA2_BF_DCOCPOK = 0x1120, /*!< DCDC OCP nmos */ + TFA2_BF_DCHVBAT = 0x1140, /*!< DCDC level 1x */ + TFA2_BF_DCH114 = 0x1150, /*!< DCDC level 1.14x */ + TFA2_BF_DCH107 = 0x1160, /*!< DCDC level 1.07x */ + TFA2_BF_STMUTEB = 0x1170, /*!< side tone (un)mute busy */ + TFA2_BF_STMUTE = 0x1180, /*!< side tone mute state */ + TFA2_BF_TDMLUTER = 0x1190, /*!< TDM LUT error */ + TFA2_BF_TDMSTAT = 0x11a2, /*!< TDM status bits */ + TFA2_BF_TDMERR = 0x11d0, /*!< TDM error */ + TFA2_BF_HAPTIC = 0x11e0, /*!< Status haptic driver */ + TFA2_BF_OCPOAPL = 0x1200, /*!< OCPOK pmos A left */ + TFA2_BF_OCPOANL = 0x1210, /*!< OCPOK nmos A left */ + TFA2_BF_OCPOBPL = 0x1220, /*!< OCPOK pmos B left */ + TFA2_BF_OCPOBNL = 0x1230, /*!< OCPOK nmos B left */ + TFA2_BF_CLIPAHL = 0x1240, /*!< Clipping A left to Vddp */ + TFA2_BF_CLIPALL = 0x1250, /*!< Clipping A left to gnd */ + TFA2_BF_CLIPBHL = 0x1260, /*!< Clipping B left to Vddp */ + TFA2_BF_CLIPBLL = 0x1270, /*!< Clipping B left to gnd */ + TFA2_BF_OCPOAPRC = 0x1280, /*!< OCPOK pmos A RCV */ + TFA2_BF_OCPOANRC = 0x1290, /*!< OCPOK nmos A RCV */ + TFA2_BF_OCPOBPRC = 0x12a0, /*!< OCPOK pmos B RCV */ + TFA2_BF_OCPOBNRC = 0x12b0, /*!< OCPOK nmos B RCV */ + TFA2_BF_RCVLDOR = 0x12c0, /*!< RCV LDO regulates */ + TFA2_BF_RCVLDOBR = 0x12d0, /*!< Receiver LDO ready */ + TFA2_BF_OCDSL = 0x12e0, /*!< OCP left amplifier */ + TFA2_BF_CLIPSL = 0x12f0, /*!< Amplifier left clipping */ + TFA2_BF_OCPOAPR = 0x1300, /*!< OCPOK pmos A right */ + TFA2_BF_OCPOANR = 0x1310, /*!< OCPOK nmos A right */ + TFA2_BF_OCPOBPR = 0x1320, /*!< OCPOK pmos B right */ + TFA2_BF_OCPOBNR = 0x1330, /*!< OCPOK nmos B right */ + TFA2_BF_CLIPAHR = 0x1340, /*!< Clipping A right to Vddp */ + TFA2_BF_CLIPALR = 0x1350, /*!< Clipping A right to gnd */ + TFA2_BF_CLIPBHR = 0x1360, /*!< Clipping B left to Vddp */ + TFA2_BF_CLIPBLR = 0x1370, /*!< Clipping B right to gnd */ + TFA2_BF_OCDSR = 0x1380, /*!< OCP right amplifier */ + TFA2_BF_CLIPSR = 0x1390, /*!< Amplifier right clipping */ + TFA2_BF_OCPOKMC = 0x13a0, /*!< OCPOK MICVDD */ + TFA2_BF_MANALARM = 0x13b0, /*!< Alarm state */ + TFA2_BF_MANWAIT1 = 0x13c0, /*!< Wait HW I2C settings */ + TFA2_BF_MANWAIT2 = 0x13d0, /*!< Wait CF config */ + TFA2_BF_MANMUTE = 0x13e0, /*!< Audio mute sequence */ + TFA2_BF_MANOPER = 0x13f0, /*!< Operating state */ + TFA2_BF_SPKSL = 0x1400, /*!< Left speaker status */ + TFA2_BF_SPKSR = 0x1410, /*!< Right speaker status */ + TFA2_BF_CLKOOR = 0x1420, /*!< External clock status */ + TFA2_BF_MANSTATE = 0x1433, /*!< Device manager status */ + TFA2_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA2_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA2_BF_TDMUC = 0x2003, /*!< Usecase setting */ + TFA2_BF_TDME = 0x2040, /*!< Enable interface */ + TFA2_BF_TDMMODE = 0x2050, /*!< Slave/master */ + TFA2_BF_TDMCLINV = 0x2060, /*!< Reception data to BCK clock */ + TFA2_BF_TDMFSLN = 0x2073, /*!< FS length (master mode only) */ + TFA2_BF_TDMFSPOL = 0x20b0, /*!< FS polarity */ + TFA2_BF_TDMNBCK = 0x20c3, /*!< N-BCK's in FS */ + TFA2_BF_TDMSLOTS = 0x2103, /*!< N-slots in Frame */ + TFA2_BF_TDMSLLN = 0x2144, /*!< N-bits in slot */ + TFA2_BF_TDMBRMG = 0x2194, /*!< N-bits remaining */ + TFA2_BF_TDMDEL = 0x21e0, /*!< data delay to FS */ + TFA2_BF_TDMADJ = 0x21f0, /*!< data adjustment */ + TFA2_BF_TDMOOMP = 0x2201, /*!< Received audio compression */ + TFA2_BF_TDMSSIZE = 0x2224, /*!< Sample size per slot */ + TFA2_BF_TDMTXDFO = 0x2271, /*!< Format unused bits */ + TFA2_BF_TDMTXUS0 = 0x2291, /*!< Format unused slots GAINIO */ + TFA2_BF_TDMTXUS1 = 0x22b1, /*!< Format unused slots DIO1 */ + TFA2_BF_TDMTXUS2 = 0x22d1, /*!< Format unused slots DIO2 */ + TFA2_BF_TDMLE = 0x2310, /*!< Control audio left */ + TFA2_BF_TDMRE = 0x2320, /*!< Control audio right */ + TFA2_BF_TDMVSRE = 0x2340, /*!< Control voltage sense right */ + TFA2_BF_TDMCSRE = 0x2350, /*!< Control current sense right */ + TFA2_BF_TDMVSLE = 0x2360, /*!< Voltage sense left control */ + TFA2_BF_TDMCSLE = 0x2370, /*!< Current sense left control */ + TFA2_BF_TDMCFRE = 0x2380, /*!< DSP out right control */ + TFA2_BF_TDMCFLE = 0x2390, /*!< DSP out left control */ + TFA2_BF_TDMCF3E = 0x23a0, /*!< AEC ref left control */ + TFA2_BF_TDMCF4E = 0x23b0, /*!< AEC ref right control */ + TFA2_BF_TDMPD1E = 0x23c0, /*!< PDM 1 control */ + TFA2_BF_TDMPD2E = 0x23d0, /*!< PDM 2 control */ + TFA2_BF_TDMLIO = 0x2421, /*!< IO audio left */ + TFA2_BF_TDMRIO = 0x2441, /*!< IO audio right */ + TFA2_BF_TDMVSRIO = 0x2481, /*!< IO voltage sense right */ + TFA2_BF_TDMCSRIO = 0x24a1, /*!< IO current sense right */ + TFA2_BF_TDMVSLIO = 0x24c1, /*!< IO voltage sense left */ + TFA2_BF_TDMCSLIO = 0x24e1, /*!< IO current sense left */ + TFA2_BF_TDMCFRIO = 0x2501, /*!< IO dspout right */ + TFA2_BF_TDMCFLIO = 0x2521, /*!< IO dspout left */ + TFA2_BF_TDMCF3IO = 0x2541, /*!< IO AEC ref left control */ + TFA2_BF_TDMCF4IO = 0x2561, /*!< IO AEC ref right control */ + TFA2_BF_TDMPD1IO = 0x2581, /*!< IO pdm1 */ + TFA2_BF_TDMPD2IO = 0x25a1, /*!< IO pdm2 */ + TFA2_BF_TDMLS = 0x2643, /*!< Position audio left */ + TFA2_BF_TDMRS = 0x2683, /*!< Position audio right */ + TFA2_BF_TDMVSRS = 0x2703, /*!< Position voltage sense right */ + TFA2_BF_TDMCSRS = 0x2743, /*!< Position current sense right */ + TFA2_BF_TDMVSLS = 0x2783, /*!< Position voltage sense left */ + TFA2_BF_TDMCSLS = 0x27c3, /*!< Position current sense left */ + TFA2_BF_TDMCFRS = 0x2803, /*!< Position dspout right */ + TFA2_BF_TDMCFLS = 0x2843, /*!< Position dspout left */ + TFA2_BF_TDMCF3S = 0x2883, /*!< Position AEC ref left control */ + TFA2_BF_TDMCF4S = 0x28c3, /*!< Position AEC ref right control */ + TFA2_BF_TDMPD1S = 0x2903, /*!< Position pdm1 */ + TFA2_BF_TDMPD2S = 0x2943, /*!< Position pdm2 */ + TFA2_BF_PDMSM = 0x3100, /*!< PDM control */ + TFA2_BF_PDMSTSEL = 0x3111, /*!< Side tone input */ + TFA2_BF_PDMLSEL = 0x3130, /*!< PDM data selection for left channel during PDM direct mode */ + TFA2_BF_PDMRSEL = 0x3140, /*!< PDM data selection for right channel during PDM direct mode */ + TFA2_BF_MICVDDE = 0x3150, /*!< Enable MICVDD */ + TFA2_BF_PDMCLRAT = 0x3201, /*!< PDM BCK/Fs ratio */ + TFA2_BF_PDMGAIN = 0x3223, /*!< PDM gain */ + TFA2_BF_PDMOSEL = 0x3263, /*!< PDM output selection - RE/FE data combination */ + TFA2_BF_SELCFHAPD = 0x32a0, /*!< Select the source for haptic data output (not for customer) */ + TFA2_BF_HAPTIME = 0x3307, /*!< Duration (ms) */ + TFA2_BF_HAPLEVEL = 0x3387, /*!< DC value (FFS) */ + TFA2_BF_GPIODIN = 0x3403, /*!< Receiving value */ + TFA2_BF_GPIOCTRL = 0x3500, /*!< GPIO master control over GPIO1/2 ports (not for customer) */ + TFA2_BF_GPIOCONF = 0x3513, /*!< Configuration */ + TFA2_BF_GPIODOUT = 0x3553, /*!< Transmitting value */ + TFA2_BF_ISTVDDS = 0x4000, /*!< Status POR */ + TFA2_BF_ISTPLLS = 0x4010, /*!< Status PLL lock */ + TFA2_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ + TFA2_BF_ISTOVDS = 0x4030, /*!< Status OVP alarm */ + TFA2_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ + TFA2_BF_ISTCLKS = 0x4050, /*!< Status clocks stable */ + TFA2_BF_ISTMTPB = 0x4060, /*!< Status MTP busy */ + TFA2_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ + TFA2_BF_ISTSPKS = 0x4080, /*!< Status speaker error */ + TFA2_BF_ISTACS = 0x4090, /*!< Status cold start */ + TFA2_BF_ISTSWS = 0x40a0, /*!< Status amplifier engage */ + TFA2_BF_ISTWDS = 0x40b0, /*!< Status watchdog */ + TFA2_BF_ISTAMPS = 0x40c0, /*!< Status amplifier enable */ + TFA2_BF_ISTAREFS = 0x40d0, /*!< Status Ref enable */ + TFA2_BF_ISTADCCR = 0x40e0, /*!< Status Control ADC */ + TFA2_BF_ISTBODNOK = 0x40f0, /*!< Status BOD */ + TFA2_BF_ISTBSTCU = 0x4100, /*!< Status DCDC current limiting */ + TFA2_BF_ISTBSTHI = 0x4110, /*!< Status DCDC active */ + TFA2_BF_ISTBSTOC = 0x4120, /*!< Status DCDC OCP */ + TFA2_BF_ISTBSTPKCUR = 0x4130, /*!< Status bst peakcur */ + TFA2_BF_ISTBSTVC = 0x4140, /*!< Status DCDC level 1x */ + TFA2_BF_ISTBST86 = 0x4150, /*!< Status DCDC level 1.14x */ + TFA2_BF_ISTBST93 = 0x4160, /*!< Status DCDC level 1.07x */ + TFA2_BF_ISTRCVLD = 0x4170, /*!< Status rcvldop ready */ + TFA2_BF_ISTOCPL = 0x4180, /*!< Status ocp alarm left */ + TFA2_BF_ISTOCPR = 0x4190, /*!< Status ocp alarm right */ + TFA2_BF_ISTMWSRC = 0x41a0, /*!< Status Waits HW I2C settings */ + TFA2_BF_ISTMWCFC = 0x41b0, /*!< Status waits CF config */ + TFA2_BF_ISTMWSMU = 0x41c0, /*!< Status Audio mute sequence */ + TFA2_BF_ISTCFMER = 0x41d0, /*!< Status cfma error */ + TFA2_BF_ISTCFMAC = 0x41e0, /*!< Status cfma ack */ + TFA2_BF_ISTCLKOOR = 0x41f0, /*!< Status flag_clk_out_of_range */ + TFA2_BF_ISTTDMER = 0x4200, /*!< Status tdm error */ + TFA2_BF_ISTCLPL = 0x4210, /*!< Status clip left */ + TFA2_BF_ISTCLPR = 0x4220, /*!< Status clip right */ + TFA2_BF_ISTOCPM = 0x4230, /*!< Status mic ocpok */ + TFA2_BF_ICLVDDS = 0x4400, /*!< Clear POR */ + TFA2_BF_ICLPLLS = 0x4410, /*!< Clear PLL lock */ + TFA2_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ + TFA2_BF_ICLOVDS = 0x4430, /*!< Clear OVP alarm */ + TFA2_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ + TFA2_BF_ICLCLKS = 0x4450, /*!< Clear clocks stable */ + TFA2_BF_ICLMTPB = 0x4460, /*!< Clear mtp busy */ + TFA2_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ + TFA2_BF_ICLSPKS = 0x4480, /*!< Clear speaker error */ + TFA2_BF_ICLACS = 0x4490, /*!< Clear cold started */ + TFA2_BF_ICLSWS = 0x44a0, /*!< Clear amplifier engage */ + TFA2_BF_ICLWDS = 0x44b0, /*!< Clear watchdog */ + TFA2_BF_ICLAMPS = 0x44c0, /*!< Clear enbl amp */ + TFA2_BF_ICLAREFS = 0x44d0, /*!< Clear ref enable */ + TFA2_BF_ICLADCCR = 0x44e0, /*!< Clear control ADC */ + TFA2_BF_ICLBODNOK = 0x44f0, /*!< Clear BOD */ + TFA2_BF_ICLBSTCU = 0x4500, /*!< Clear DCDC current limiting */ + TFA2_BF_ICLBSTHI = 0x4510, /*!< Clear DCDC active */ + TFA2_BF_ICLBSTOC = 0x4520, /*!< Clear DCDC OCP */ + TFA2_BF_ICLBSTPC = 0x4530, /*!< Clear bst peakcur */ + TFA2_BF_ICLBSTVC = 0x4540, /*!< Clear DCDC level 1x */ + TFA2_BF_ICLBST86 = 0x4550, /*!< Clear DCDC level 1.14x */ + TFA2_BF_ICLBST93 = 0x4560, /*!< Clear DCDC level 1.07x */ + TFA2_BF_ICLRCVLD = 0x4570, /*!< Clear rcvldop ready */ + TFA2_BF_ICLOCPL = 0x4580, /*!< Clear ocp alarm left */ + TFA2_BF_ICLOCPR = 0x4590, /*!< Clear ocp alarm right */ + TFA2_BF_ICLMWSRC = 0x45a0, /*!< Clear wait HW I2C settings */ + TFA2_BF_ICLMWCFC = 0x45b0, /*!< Clear wait cf config */ + TFA2_BF_ICLMWSMU = 0x45c0, /*!< Clear audio mute sequence */ + TFA2_BF_ICLCFMER = 0x45d0, /*!< Clear cfma err */ + TFA2_BF_ICLCFMAC = 0x45e0, /*!< Clear cfma ack */ + TFA2_BF_ICLCLKOOR = 0x45f0, /*!< Clear flag_clk_out_of_range */ + TFA2_BF_ICLTDMER = 0x4600, /*!< Clear tdm error */ + TFA2_BF_ICLCLPL = 0x4610, /*!< Clear clip left */ + TFA2_BF_ICLCLPR = 0x4620, /*!< Clear clip right */ + TFA2_BF_ICLOCPM = 0x4630, /*!< Clear mic ocpok */ + TFA2_BF_IEVDDS = 0x4800, /*!< Enable por */ + TFA2_BF_IEPLLS = 0x4810, /*!< Enable pll lock */ + TFA2_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ + TFA2_BF_IEOVDS = 0x4830, /*!< Enable OVP alarm */ + TFA2_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ + TFA2_BF_IECLKS = 0x4850, /*!< Enable clocks stable */ + TFA2_BF_IEMTPB = 0x4860, /*!< Enable mtp busy */ + TFA2_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ + TFA2_BF_IESPKS = 0x4880, /*!< Enable speaker error */ + TFA2_BF_IEACS = 0x4890, /*!< Enable cold started */ + TFA2_BF_IESWS = 0x48a0, /*!< Enable amplifier engage */ + TFA2_BF_IEWDS = 0x48b0, /*!< Enable watchdog */ + TFA2_BF_IEAMPS = 0x48c0, /*!< Enable enbl amp */ + TFA2_BF_IEAREFS = 0x48d0, /*!< Enable ref enable */ + TFA2_BF_IEADCCR = 0x48e0, /*!< Enable Control ADC */ + TFA2_BF_IEBODNOK = 0x48f0, /*!< Enable BOD */ + TFA2_BF_IEBSTCU = 0x4900, /*!< Enable DCDC current limiting */ + TFA2_BF_IEBSTHI = 0x4910, /*!< Enable DCDC active */ + TFA2_BF_IEBSTOC = 0x4920, /*!< Enable DCDC OCP */ + TFA2_BF_IEBSTPC = 0x4930, /*!< Enable bst peakcur */ + TFA2_BF_IEBSTVC = 0x4940, /*!< Enable DCDC level 1x */ + TFA2_BF_IEBST86 = 0x4950, /*!< Enable DCDC level 1.14x */ + TFA2_BF_IEBST93 = 0x4960, /*!< Enable DCDC level 1.07x */ + TFA2_BF_IERCVLD = 0x4970, /*!< Enable rcvldop ready */ + TFA2_BF_IEOCPL = 0x4980, /*!< Enable ocp alarm left */ + TFA2_BF_IEOCPR = 0x4990, /*!< Enable ocp alarm right */ + TFA2_BF_IEMWSRC = 0x49a0, /*!< Enable waits HW I2C settings */ + TFA2_BF_IEMWCFC = 0x49b0, /*!< Enable man wait cf config */ + TFA2_BF_IEMWSMU = 0x49c0, /*!< Enable man Audio mute sequence */ + TFA2_BF_IECFMER = 0x49d0, /*!< Enable cfma err */ + TFA2_BF_IECFMAC = 0x49e0, /*!< Enable cfma ack */ + TFA2_BF_IECLKOOR = 0x49f0, /*!< Enable flag_clk_out_of_range */ + TFA2_BF_IETDMER = 0x4a00, /*!< Enable tdm error */ + TFA2_BF_IECLPL = 0x4a10, /*!< Enable clip left */ + TFA2_BF_IECLPR = 0x4a20, /*!< Enable clip right */ + TFA2_BF_IEOCPM1 = 0x4a30, /*!< Enable mic ocpok */ + TFA2_BF_IPOVDDS = 0x4c00, /*!< Polarity por */ + TFA2_BF_IPOPLLS = 0x4c10, /*!< Polarity pll lock */ + TFA2_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ + TFA2_BF_IPOOVDS = 0x4c30, /*!< Polarity OVP alarm */ + TFA2_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ + TFA2_BF_IPOCLKS = 0x4c50, /*!< Polarity clocks stable */ + TFA2_BF_IPOMTPB = 0x4c60, /*!< Polarity mtp busy */ + TFA2_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ + TFA2_BF_IPOSPKS = 0x4c80, /*!< Polarity speaker error */ + TFA2_BF_IPOACS = 0x4c90, /*!< Polarity cold started */ + TFA2_BF_IPOSWS = 0x4ca0, /*!< Polarity amplifier engage */ + TFA2_BF_IPOWDS = 0x4cb0, /*!< Polarity watchdog */ + TFA2_BF_IPOAMPS = 0x4cc0, /*!< Polarity enbl amp */ + TFA2_BF_IPOAREFS = 0x4cd0, /*!< Polarity ref enable */ + TFA2_BF_IPOADCCR = 0x4ce0, /*!< Polarity Control ADC */ + TFA2_BF_IPOBODNOK = 0x4cf0, /*!< Polarity BOD */ + TFA2_BF_IPOBSTCU = 0x4d00, /*!< Polarity DCDC current limiting */ + TFA2_BF_IPOBSTHI = 0x4d10, /*!< Polarity DCDC active */ + TFA2_BF_IPOBSTOC = 0x4d20, /*!< Polarity DCDC OCP */ + TFA2_BF_IPOBSTPC = 0x4d30, /*!< Polarity bst peakcur */ + TFA2_BF_IPOBSTVC = 0x4d40, /*!< Polarity DCDC level 1x */ + TFA2_BF_IPOBST86 = 0x4d50, /*!< Polarity DCDC level 1.14x */ + TFA2_BF_IPOBST93 = 0x4d60, /*!< Polarity DCDC level 1.07x */ + TFA2_BF_IPORCVLD = 0x4d70, /*!< Polarity rcvldop ready */ + TFA2_BF_IPOOCPL = 0x4d80, /*!< Polarity ocp alarm left */ + TFA2_BF_IPOOCPR = 0x4d90, /*!< Polarity ocp alarm right */ + TFA2_BF_IPOMWSRC = 0x4da0, /*!< Polarity waits HW I2C settings */ + TFA2_BF_IPOMWCFC = 0x4db0, /*!< Polarity man wait cf config */ + TFA2_BF_IPOMWSMU = 0x4dc0, /*!< Polarity man audio mute sequence */ + TFA2_BF_IPOCFMER = 0x4dd0, /*!< Polarity cfma err */ + TFA2_BF_IPOCFMAC = 0x4de0, /*!< Polarity cfma ack */ + TFA2_BF_IPCLKOOR = 0x4df0, /*!< Polarity flag_clk_out_of_range */ + TFA2_BF_IPOTDMER = 0x4e00, /*!< Polarity tdm error */ + TFA2_BF_IPOCLPL = 0x4e10, /*!< Polarity clip left */ + TFA2_BF_IPOCLPR = 0x4e20, /*!< Polarity clip right */ + TFA2_BF_IPOOCPM = 0x4e30, /*!< Polarity mic ocpok */ + TFA2_BF_BSSCR = 0x5001, /*!< Battery protection attack Time */ + TFA2_BF_BSST = 0x5023, /*!< Battery protection threshold voltage level */ + TFA2_BF_BSSRL = 0x5061, /*!< Battery protection maximum reduction */ + TFA2_BF_BSSRR = 0x5082, /*!< Battery protection release time */ + TFA2_BF_BSSHY = 0x50b1, /*!< Battery protection hysteresis */ + TFA2_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA2_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA2_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ + TFA2_BF_INTSMUTE = 0x5110, /*!< Soft mute HW */ + TFA2_BF_CFSML = 0x5120, /*!< Soft mute FW left */ + TFA2_BF_CFSMR = 0x5130, /*!< Soft mute FW right */ + TFA2_BF_HPFBYPL = 0x5140, /*!< Bypass HPF left */ + TFA2_BF_HPFBYPR = 0x5150, /*!< Bypass HPF right */ + TFA2_BF_DPSAL = 0x5160, /*!< Enable DPSA left */ + TFA2_BF_DPSAR = 0x5170, /*!< Enable DPSA right */ + TFA2_BF_VOL = 0x5187, /*!< FW volume control for primary audio channel */ + TFA2_BF_HNDSFRCV = 0x5200, /*!< Selection receiver */ + TFA2_BF_CLIPCTRL = 0x5222, /*!< Clip control setting */ + TFA2_BF_AMPGAIN = 0x5257, /*!< Amplifier gain */ + TFA2_BF_SLOPEE = 0x52d0, /*!< Enables slope control */ + TFA2_BF_SLOPESET = 0x52e1, /*!< Set slope */ + TFA2_BF_VOLSEC = 0x5a07, /*!< FW volume control for secondary audio channel */ + TFA2_BF_SWPROFIL = 0x5a87, /*!< Software profile data */ + TFA2_BF_DCVO = 0x7002, /*!< Boost voltage */ + TFA2_BF_DCMCC = 0x7033, /*!< Max coil current */ + TFA2_BF_DCCV = 0x7071, /*!< Coil Value */ + TFA2_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ + TFA2_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ + TFA2_BF_DCSYNCP = 0x70b2, /*!< DCDC synchronization off + 7 positions */ + TFA2_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ + TFA2_BF_RST = 0x9000, /*!< Reset */ + TFA2_BF_DMEM = 0x9011, /*!< Target memory */ + TFA2_BF_AIF = 0x9030, /*!< Auto increment */ + TFA2_BF_CFINT = 0x9040, /*!< Interrupt - auto clear */ + TFA2_BF_CFCGATE = 0x9050, /*!< Coolflux clock gating disabling control */ + TFA2_BF_REQ = 0x9087, /*!< request for access (8 channels) */ + TFA2_BF_REQCMD = 0x9080, /*!< Firmware event request rpc command */ + TFA2_BF_REQRST = 0x9090, /*!< Firmware event request reset restart */ + TFA2_BF_REQMIPS = 0x90a0, /*!< Firmware event request short on mips */ + TFA2_BF_REQMUTED = 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA2_BF_REQVOL = 0x90c0, /*!< Firmware event request volume ready */ + TFA2_BF_REQDMG = 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA2_BF_REQCAL = 0x90e0, /*!< Firmware event request calibration completed */ + TFA2_BF_REQRSV = 0x90f0, /*!< Firmware event request reserved */ + TFA2_BF_MADD = 0x910f, /*!< Memory address */ + TFA2_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA2_BF_ERR = 0x9307, /*!< Error flags */ + TFA2_BF_ACK = 0x9387, /*!< Acknowledge of requests */ + TFA2_BF_ACKCMD = 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA2_BF_ACKRST = 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA2_BF_ACKMIPS = 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA2_BF_ACKMUTED = 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA2_BF_ACKVOL = 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA2_BF_ACKDMG = 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA2_BF_ACKCAL = 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA2_BF_ACKRSV = 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA2_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ + TFA2_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ + TFA2_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ + TFA2_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ + TFA2_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ + TFA2_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ + TFA2_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA2_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA2_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ + TFA2_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA2_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ + TFA2_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA2_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ + TFA2_BF_R25CL = 0xf40f, /*!< Ron resistance of left channel speaker coil */ + TFA2_BF_R25CR = 0xf50f, /*!< Ron resistance of right channel speaker coil */ +} nxpTfa2BfEnumList_t; +#define TFA2_NAMETABLE static tfaBfName_t Tfa2DatasheetNames[] = {\ + { 0x0, "PWDN"}, /* Powerdown selection , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux , */\ + { 0x30, "AMPE"}, /* Activate Amplifier , */\ + { 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux controls amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x91, "FSSSEL"}, /* Audio sample reference , */\ + { 0xb0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xc0, "TSTOCP"}, /* OCP testing control , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* I2C configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ + { 0x150, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x160, "BODE"}, /* BOD Enable , */\ + { 0x170, "BODHYS"}, /* BOD Hysteresis , */\ + { 0x181, "BODFILT"}, /* BOD filter , */\ + { 0x1a1, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1e0, "RCVNS"}, /* Noise shaper selection , */\ + { 0x1f0, "MANWDE"}, /* Watchdog manager reaction , */\ + { 0x203, "AUDFS"}, /* Sample rate (fs) , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ + { 0x2b0, "BYPHVBF"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "LDOBYP"}, /* Receiver LDO bypass , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ + { 0x500, "SSLEFTE"}, /* Enable left channel , */\ + { 0x510, "SSRIGHTE"}, /* Enable right channel , */\ + { 0x520, "VSLEFTE"}, /* Voltage sense left , */\ + { 0x530, "VSRIGHTE"}, /* Voltage sense right , */\ + { 0x540, "CSLEFTE"}, /* Current sense left , */\ + { 0x550, "CSRIGHTE"}, /* Current sense right , */\ + { 0x560, "SSPDME"}, /* Sub-system PDM , */\ + { 0xd18, "STGAIN"}, /* Side tone gain , */\ + { 0xda0, "PDMSMUTE"}, /* Side tone soft mute , */\ + { 0xe06, "SWVSTEP"}, /* Register for the host SW to record the current active vstep, */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "CLKS"}, /* Clocks stable , */\ + { 0x1060, "MTPB"}, /* MTP busy , */\ + { 0x1070, "NOCLK"}, /* Lost clock , */\ + { 0x1080, "SPKS"}, /* Speaker error , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "SWS"}, /* Amplifier engage , */\ + { 0x10b0, "WDS"}, /* Watchdog , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "STMUTEB"}, /* side tone (un)mute busy , */\ + { 0x1180, "STMUTE"}, /* side tone mute state , */\ + { 0x1190, "TDMLUTER"}, /* TDM LUT error , */\ + { 0x11a2, "TDMSTAT"}, /* TDM status bits , */\ + { 0x11d0, "TDMERR"}, /* TDM error , */\ + { 0x11e0, "HAPTIC"}, /* Status haptic driver , */\ + { 0x1200, "OCPOAPL"}, /* OCPOK pmos A left , */\ + { 0x1210, "OCPOANL"}, /* OCPOK nmos A left , */\ + { 0x1220, "OCPOBPL"}, /* OCPOK pmos B left , */\ + { 0x1230, "OCPOBNL"}, /* OCPOK nmos B left , */\ + { 0x1240, "CLIPAHL"}, /* Clipping A left to Vddp , */\ + { 0x1250, "CLIPALL"}, /* Clipping A left to gnd , */\ + { 0x1260, "CLIPBHL"}, /* Clipping B left to Vddp , */\ + { 0x1270, "CLIPBLL"}, /* Clipping B left to gnd , */\ + { 0x1280, "OCPOAPRC"}, /* OCPOK pmos A RCV , */\ + { 0x1290, "OCPOANRC"}, /* OCPOK nmos A RCV , */\ + { 0x12a0, "OCPOBPRC"}, /* OCPOK pmos B RCV , */\ + { 0x12b0, "OCPOBNRC"}, /* OCPOK nmos B RCV , */\ + { 0x12c0, "RCVLDOR"}, /* RCV LDO regulates , */\ + { 0x12d0, "RCVLDOBR"}, /* Receiver LDO ready , */\ + { 0x12e0, "OCDSL"}, /* OCP left amplifier , */\ + { 0x12f0, "CLIPSL"}, /* Amplifier left clipping , */\ + { 0x1300, "OCPOAPR"}, /* OCPOK pmos A right , */\ + { 0x1310, "OCPOANR"}, /* OCPOK nmos A right , */\ + { 0x1320, "OCPOBPR"}, /* OCPOK pmos B right , */\ + { 0x1330, "OCPOBNR"}, /* OCPOK nmos B right , */\ + { 0x1340, "CLIPAHR"}, /* Clipping A right to Vddp , */\ + { 0x1350, "CLIPALR"}, /* Clipping A right to gnd , */\ + { 0x1360, "CLIPBHR"}, /* Clipping B left to Vddp , */\ + { 0x1370, "CLIPBLR"}, /* Clipping B right to gnd , */\ + { 0x1380, "OCDSR"}, /* OCP right amplifier , */\ + { 0x1390, "CLIPSR"}, /* Amplifier right clipping , */\ + { 0x13a0, "OCPOKMC"}, /* OCPOK MICVDD , */\ + { 0x13b0, "MANALARM"}, /* Alarm state , */\ + { 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ + { 0x13d0, "MANWAIT2"}, /* Wait CF config , */\ + { 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x13f0, "MANOPER"}, /* Operating state , */\ + { 0x1400, "SPKSL"}, /* Left speaker status , */\ + { 0x1410, "SPKSR"}, /* Right speaker status , */\ + { 0x1420, "CLKOOR"}, /* External clock status , */\ + { 0x1433, "MANSTATE"}, /* Device manager status , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x2003, "TDMUC"}, /* Usecase setting , */\ + { 0x2040, "TDME"}, /* Enable interface , */\ + { 0x2050, "TDMMODE"}, /* Slave/master , */\ + { 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2073, "TDMFSLN"}, /* FS length (master mode only) , */\ + { 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ + { 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ + { 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x21e0, "TDMDEL"}, /* data delay to FS , */\ + { 0x21f0, "TDMADJ"}, /* data adjustment , */\ + { 0x2201, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x2291, "TDMTXUS0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "TDMTXUS1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "TDMTXUS2"}, /* Format unused slots DIO2 , */\ + { 0x2310, "TDMLE"}, /* Control audio left , */\ + { 0x2320, "TDMRE"}, /* Control audio right , */\ + { 0x2340, "TDMVSRE"}, /* Control voltage sense right , */\ + { 0x2350, "TDMCSRE"}, /* Control current sense right , */\ + { 0x2360, "TDMVSLE"}, /* Voltage sense left control , */\ + { 0x2370, "TDMCSLE"}, /* Current sense left control , */\ + { 0x2380, "TDMCFRE"}, /* DSP out right control , */\ + { 0x2390, "TDMCFLE"}, /* DSP out left control , */\ + { 0x23a0, "TDMCF3E"}, /* AEC ref left control , */\ + { 0x23b0, "TDMCF4E"}, /* AEC ref right control , */\ + { 0x23c0, "TDMPD1E"}, /* PDM 1 control , */\ + { 0x23d0, "TDMPD2E"}, /* PDM 2 control , */\ + { 0x2421, "TDMLIO"}, /* IO audio left , */\ + { 0x2441, "TDMRIO"}, /* IO audio right , */\ + { 0x2481, "TDMVSRIO"}, /* IO voltage sense right , */\ + { 0x24a1, "TDMCSRIO"}, /* IO current sense right , */\ + { 0x24c1, "TDMVSLIO"}, /* IO voltage sense left , */\ + { 0x24e1, "TDMCSLIO"}, /* IO current sense left , */\ + { 0x2501, "TDMCFRIO"}, /* IO dspout right , */\ + { 0x2521, "TDMCFLIO"}, /* IO dspout left , */\ + { 0x2541, "TDMCF3IO"}, /* IO AEC ref left control , */\ + { 0x2561, "TDMCF4IO"}, /* IO AEC ref right control , */\ + { 0x2581, "TDMPD1IO"}, /* IO pdm1 , */\ + { 0x25a1, "TDMPD2IO"}, /* IO pdm2 , */\ + { 0x2643, "TDMLS"}, /* Position audio left , */\ + { 0x2683, "TDMRS"}, /* Position audio right , */\ + { 0x2703, "TDMVSRS"}, /* Position voltage sense right , */\ + { 0x2743, "TDMCSRS"}, /* Position current sense right , */\ + { 0x2783, "TDMVSLS"}, /* Position voltage sense left , */\ + { 0x27c3, "TDMCSLS"}, /* Position current sense left , */\ + { 0x2803, "TDMCFRS"}, /* Position dspout right , */\ + { 0x2843, "TDMCFLS"}, /* Position dspout left , */\ + { 0x2883, "TDMCF3S"}, /* Position AEC ref left control , */\ + { 0x28c3, "TDMCF4S"}, /* Position AEC ref right control , */\ + { 0x2903, "TDMPD1S"}, /* Position pdm1 , */\ + { 0x2943, "TDMPD2S"}, /* Position pdm2 , */\ + { 0x3100, "PDMSM"}, /* PDM control , */\ + { 0x3111, "PDMSTSEL"}, /* Side tone input , */\ + { 0x3130, "PDMLSEL"}, /* PDM data selection for left channel during PDM direct mode, */\ + { 0x3140, "PDMRSEL"}, /* PDM data selection for right channel during PDM direct mode, */\ + { 0x3150, "MICVDDE"}, /* Enable MICVDD , */\ + { 0x3201, "PDMCLRAT"}, /* PDM BCK/Fs ratio , */\ + { 0x3223, "PDMGAIN"}, /* PDM gain , */\ + { 0x3263, "PDMOSEL"}, /* PDM output selection - RE/FE data combination , */\ + { 0x32a0, "SELCFHAPD"}, /* Select the source for haptic data output (not for customer), */\ + { 0x3307, "HAPTIME"}, /* Duration (ms) , */\ + { 0x3387, "HAPLEVEL"}, /* DC value (FFS) , */\ + { 0x3403, "GPIODIN"}, /* Receiving value , */\ + { 0x3500, "GPIOCTRL"}, /* GPIO master control over GPIO1/2 ports (not for customer), */\ + { 0x3513, "GPIOCONF"}, /* Configuration , */\ + { 0x3553, "GPIODOUT"}, /* Transmitting value , */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTPLLS"}, /* Status PLL lock , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOVDS"}, /* Status OVP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTCLKS"}, /* Status clocks stable , */\ + { 0x4060, "ISTMTPB"}, /* Status MTP busy , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTSPKS"}, /* Status speaker error , */\ + { 0x4090, "ISTACS"}, /* Status cold start , */\ + { 0x40a0, "ISTSWS"}, /* Status amplifier engage , */\ + { 0x40b0, "ISTWDS"}, /* Status watchdog , */\ + { 0x40c0, "ISTAMPS"}, /* Status amplifier enable , */\ + { 0x40d0, "ISTAREFS"}, /* Status Ref enable , */\ + { 0x40e0, "ISTADCCR"}, /* Status Control ADC , */\ + { 0x40f0, "ISTBODNOK"}, /* Status BOD , */\ + { 0x4100, "ISTBSTCU"}, /* Status DCDC current limiting , */\ + { 0x4110, "ISTBSTHI"}, /* Status DCDC active , */\ + { 0x4120, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4130, "ISTBSTPKCUR"}, /* Status bst peakcur , */\ + { 0x4140, "ISTBSTVC"}, /* Status DCDC level 1x , */\ + { 0x4150, "ISTBST86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "ISTBST93"}, /* Status DCDC level 1.07x , */\ + { 0x4170, "ISTRCVLD"}, /* Status rcvldop ready , */\ + { 0x4180, "ISTOCPL"}, /* Status ocp alarm left , */\ + { 0x4190, "ISTOCPR"}, /* Status ocp alarm right , */\ + { 0x41a0, "ISTMWSRC"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "ISTMWCFC"}, /* Status waits CF config , */\ + { 0x41c0, "ISTMWSMU"}, /* Status Audio mute sequence , */\ + { 0x41d0, "ISTCFMER"}, /* Status cfma error , */\ + { 0x41e0, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x41f0, "ISTCLKOOR"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "ISTTDMER"}, /* Status tdm error , */\ + { 0x4210, "ISTCLPL"}, /* Status clip left , */\ + { 0x4220, "ISTCLPR"}, /* Status clip right , */\ + { 0x4230, "ISTOCPM"}, /* Status mic ocpok , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLPLLS"}, /* Clear PLL lock , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOVDS"}, /* Clear OVP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLCLKS"}, /* Clear clocks stable , */\ + { 0x4460, "ICLMTPB"}, /* Clear mtp busy , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLSPKS"}, /* Clear speaker error , */\ + { 0x4490, "ICLACS"}, /* Clear cold started , */\ + { 0x44a0, "ICLSWS"}, /* Clear amplifier engage , */\ + { 0x44b0, "ICLWDS"}, /* Clear watchdog , */\ + { 0x44c0, "ICLAMPS"}, /* Clear enbl amp , */\ + { 0x44d0, "ICLAREFS"}, /* Clear ref enable , */\ + { 0x44e0, "ICLADCCR"}, /* Clear control ADC , */\ + { 0x44f0, "ICLBODNOK"}, /* Clear BOD , */\ + { 0x4500, "ICLBSTCU"}, /* Clear DCDC current limiting , */\ + { 0x4510, "ICLBSTHI"}, /* Clear DCDC active , */\ + { 0x4520, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4530, "ICLBSTPC"}, /* Clear bst peakcur , */\ + { 0x4540, "ICLBSTVC"}, /* Clear DCDC level 1x , */\ + { 0x4550, "ICLBST86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "ICLBST93"}, /* Clear DCDC level 1.07x , */\ + { 0x4570, "ICLRCVLD"}, /* Clear rcvldop ready , */\ + { 0x4580, "ICLOCPL"}, /* Clear ocp alarm left , */\ + { 0x4590, "ICLOCPR"}, /* Clear ocp alarm right , */\ + { 0x45a0, "ICLMWSRC"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "ICLMWCFC"}, /* Clear wait cf config , */\ + { 0x45c0, "ICLMWSMU"}, /* Clear audio mute sequence , */\ + { 0x45d0, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x45e0, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x45f0, "ICLCLKOOR"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "ICLTDMER"}, /* Clear tdm error , */\ + { 0x4610, "ICLCLPL"}, /* Clear clip left , */\ + { 0x4620, "ICLCLPR"}, /* Clear clip right , */\ + { 0x4630, "ICLOCPM"}, /* Clear mic ocpok , */\ + { 0x4800, "IEVDDS"}, /* Enable por , */\ + { 0x4810, "IEPLLS"}, /* Enable pll lock , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOVDS"}, /* Enable OVP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IECLKS"}, /* Enable clocks stable , */\ + { 0x4860, "IEMTPB"}, /* Enable mtp busy , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IESPKS"}, /* Enable speaker error , */\ + { 0x4890, "IEACS"}, /* Enable cold started , */\ + { 0x48a0, "IESWS"}, /* Enable amplifier engage , */\ + { 0x48b0, "IEWDS"}, /* Enable watchdog , */\ + { 0x48c0, "IEAMPS"}, /* Enable enbl amp , */\ + { 0x48d0, "IEAREFS"}, /* Enable ref enable , */\ + { 0x48e0, "IEADCCR"}, /* Enable Control ADC , */\ + { 0x48f0, "IEBODNOK"}, /* Enable BOD , */\ + { 0x4900, "IEBSTCU"}, /* Enable DCDC current limiting , */\ + { 0x4910, "IEBSTHI"}, /* Enable DCDC active , */\ + { 0x4920, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4930, "IEBSTPC"}, /* Enable bst peakcur , */\ + { 0x4940, "IEBSTVC"}, /* Enable DCDC level 1x , */\ + { 0x4950, "IEBST86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "IEBST93"}, /* Enable DCDC level 1.07x , */\ + { 0x4970, "IERCVLD"}, /* Enable rcvldop ready , */\ + { 0x4980, "IEOCPL"}, /* Enable ocp alarm left , */\ + { 0x4990, "IEOCPR"}, /* Enable ocp alarm right , */\ + { 0x49a0, "IEMWSRC"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "IEMWCFC"}, /* Enable man wait cf config , */\ + { 0x49c0, "IEMWSMU"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "IECFMER"}, /* Enable cfma err , */\ + { 0x49e0, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x49f0, "IECLKOOR"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "IETDMER"}, /* Enable tdm error , */\ + { 0x4a10, "IECLPL"}, /* Enable clip left , */\ + { 0x4a20, "IECLPR"}, /* Enable clip right , */\ + { 0x4a30, "IEOCPM1"}, /* Enable mic ocpok , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity por , */\ + { 0x4c10, "IPOPLLS"}, /* Polarity pll lock , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOVDS"}, /* Polarity OVP alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOCLKS"}, /* Polarity clocks stable , */\ + { 0x4c60, "IPOMTPB"}, /* Polarity mtp busy , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOSPKS"}, /* Polarity speaker error , */\ + { 0x4c90, "IPOACS"}, /* Polarity cold started , */\ + { 0x4ca0, "IPOSWS"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "IPOWDS"}, /* Polarity watchdog , */\ + { 0x4cc0, "IPOAMPS"}, /* Polarity enbl amp , */\ + { 0x4cd0, "IPOAREFS"}, /* Polarity ref enable , */\ + { 0x4ce0, "IPOADCCR"}, /* Polarity Control ADC , */\ + { 0x4cf0, "IPOBODNOK"}, /* Polarity BOD , */\ + { 0x4d00, "IPOBSTCU"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "IPOBSTHI"}, /* Polarity DCDC active , */\ + { 0x4d20, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "IPOBSTPC"}, /* Polarity bst peakcur , */\ + { 0x4d40, "IPOBSTVC"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "IPOBST86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "IPOBST93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d70, "IPORCVLD"}, /* Polarity rcvldop ready , */\ + { 0x4d80, "IPOOCPL"}, /* Polarity ocp alarm left , */\ + { 0x4d90, "IPOOCPR"}, /* Polarity ocp alarm right , */\ + { 0x4da0, "IPOMWSRC"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "IPOMWCFC"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "IPOMWSMU"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4de0, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4df0, "IPCLKOOR"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "IPOTDMER"}, /* Polarity tdm error , */\ + { 0x4e10, "IPOCLPL"}, /* Polarity clip left , */\ + { 0x4e20, "IPOCLPR"}, /* Polarity clip right , */\ + { 0x4e30, "IPOOCPM"}, /* Polarity mic ocpok , */\ + { 0x5001, "BSSCR"}, /* Battery protection attack Time , */\ + { 0x5023, "BSST"}, /* Battery protection threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery protection maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery protection release time , */\ + { 0x50b1, "BSSHY"}, /* Battery protection hysteresis , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5100, "BSSS"}, /* Vbat prot steepness , */\ + { 0x5110, "INTSMUTE"}, /* Soft mute HW , */\ + { 0x5120, "CFSML"}, /* Soft mute FW left , */\ + { 0x5130, "CFSMR"}, /* Soft mute FW right , */\ + { 0x5140, "HPFBYPL"}, /* Bypass HPF left , */\ + { 0x5150, "HPFBYPR"}, /* Bypass HPF right , */\ + { 0x5160, "DPSAL"}, /* Enable DPSA left , */\ + { 0x5170, "DPSAR"}, /* Enable DPSA right , */\ + { 0x5187, "VOL"}, /* FW volume control for primary audio channel , */\ + { 0x5200, "HNDSFRCV"}, /* Selection receiver , */\ + { 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x52d0, "SLOPEE"}, /* Enables slope control , */\ + { 0x52e1, "SLOPESET"}, /* Set slope , */\ + { 0x5a07, "VOLSEC"}, /* FW volume control for secondary audio channel , */\ + { 0x5a87, "SWPROFIL"}, /* Software profile data , */\ + { 0x7002, "DCVO"}, /* Boost voltage , */\ + { 0x7033, "DCMCC"}, /* Max coil current , */\ + { 0x7071, "DCCV"}, /* Coil Value , */\ + { 0x7090, "DCIE"}, /* Adaptive boost mode , */\ + { 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ + { 0x70b2, "DCSYNCP"}, /* DCDC synchronization off + 7 positions , */\ + { 0x70e0, "DCDIS"}, /* DCDC on/off , */\ + { 0x9000, "RST"}, /* Reset , */\ + { 0x9011, "DMEM"}, /* Target memory , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* Memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* Error flags , */\ + { 0x9387, "ACK"}, /* Acknowledge of requests , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* MTP KEY2 register , */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf40f, "R25CL"}, /* Ron resistance of left channel speaker coil , */\ + { 0xf50f, "R25CR"}, /* Ron resistance of right channel speaker coil , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA2_BITNAMETABLE static tfaBfName_t Tfa2BitNames[] = {\ + { 0x0, "powerdown"}, /* Powerdown selection , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux , */\ + { 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ + { 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux controls amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x91, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xc0, "test_ocp"}, /* OCP testing control , */\ + { 0x101, "vamp_sel"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* I2C configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "enbl_osc1m_auto_off"}, /* Internal osc off at PWDN , */\ + { 0x150, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x160, "enbl_bod"}, /* BOD Enable , */\ + { 0x170, "enbl_bod_hyst"}, /* BOD Hysteresis , */\ + { 0x181, "bod_delay"}, /* BOD filter , */\ + { 0x1a1, "bod_lvlsel"}, /* BOD threshold , */\ + { 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1e0, "pwm_sel_rcv_ns"}, /* Noise shaper selection , */\ + { 0x1f0, "man_enbl_watchdog"}, /* Watchdog manager reaction , */\ + { 0x203, "audio_fs"}, /* Sample rate (fs) , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ + { 0x2b0, "bypass_hvbat_filter"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "ctrl_rcvldop_bypass"}, /* Receiver LDO bypass , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ + { 0x500, "enbl_spkr_ss_left"}, /* Enable left channel , */\ + { 0x510, "enbl_spkr_ss_right"}, /* Enable right channel , */\ + { 0x520, "enbl_volsense_left"}, /* Voltage sense left , */\ + { 0x530, "enbl_volsense_right"}, /* Voltage sense right , */\ + { 0x540, "enbl_cursense_left"}, /* Current sense left , */\ + { 0x550, "enbl_cursense_right"}, /* Current sense right , */\ + { 0x560, "enbl_pdm_ss"}, /* Sub-system PDM , */\ + { 0xd00, "side_tone_gain_sel"}, /* PDM side tone gain selector , */\ + { 0xd18, "side_tone_gain"}, /* Side tone gain , */\ + { 0xda0, "mute_side_tone"}, /* Side tone soft mute , */\ + { 0xe06, "ctrl_digtoana"}, /* Register for the host SW to record the current active vstep, */\ + { 0xe70, "enbl_cmfb_left"}, /* Current sense common mode feedback control for left channel, */\ + { 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1060, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1070, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1080, "flag_cf_speakererror"}, /* Speaker error , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10b0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_soft_mute_busy"}, /* side tone (un)mute busy , */\ + { 0x1180, "flag_soft_mute_state"}, /* side tone mute state , */\ + { 0x1190, "flag_tdm_lut_error"}, /* TDM LUT error , */\ + { 0x11a2, "flag_tdm_status"}, /* TDM status bits , */\ + { 0x11d0, "flag_tdm_error"}, /* TDM error , */\ + { 0x11e0, "flag_haptic_busy"}, /* Status haptic driver , */\ + { 0x1200, "flag_ocpokap_left"}, /* OCPOK pmos A left , */\ + { 0x1210, "flag_ocpokan_left"}, /* OCPOK nmos A left , */\ + { 0x1220, "flag_ocpokbp_left"}, /* OCPOK pmos B left , */\ + { 0x1230, "flag_ocpokbn_left"}, /* OCPOK nmos B left , */\ + { 0x1240, "flag_clipa_high_left"}, /* Clipping A left to Vddp , */\ + { 0x1250, "flag_clipa_low_left"}, /* Clipping A left to gnd , */\ + { 0x1260, "flag_clipb_high_left"}, /* Clipping B left to Vddp , */\ + { 0x1270, "flag_clipb_low_left"}, /* Clipping B left to gnd , */\ + { 0x1280, "flag_ocpokap_rcv"}, /* OCPOK pmos A RCV , */\ + { 0x1290, "flag_ocpokan_rcv"}, /* OCPOK nmos A RCV , */\ + { 0x12a0, "flag_ocpokbp_rcv"}, /* OCPOK pmos B RCV , */\ + { 0x12b0, "flag_ocpokbn_rcv"}, /* OCPOK nmos B RCV , */\ + { 0x12c0, "flag_rcvldop_ready"}, /* RCV LDO regulates , */\ + { 0x12d0, "flag_rcvldop_bypassready"}, /* Receiver LDO ready , */\ + { 0x12e0, "flag_ocp_alarm_left"}, /* OCP left amplifier , */\ + { 0x12f0, "flag_clip_left"}, /* Amplifier left clipping , */\ + { 0x1300, "flag_ocpokap_right"}, /* OCPOK pmos A right , */\ + { 0x1310, "flag_ocpokan_right"}, /* OCPOK nmos A right , */\ + { 0x1320, "flag_ocpokbp_right"}, /* OCPOK pmos B right , */\ + { 0x1330, "flag_ocpokbn_right"}, /* OCPOK nmos B right , */\ + { 0x1340, "flag_clipa_high_right"}, /* Clipping A right to Vddp , */\ + { 0x1350, "flag_clipa_low_right"}, /* Clipping A right to gnd , */\ + { 0x1360, "flag_clipb_high_right"}, /* Clipping B left to Vddp , */\ + { 0x1370, "flag_clipb_low_right"}, /* Clipping B right to gnd , */\ + { 0x1380, "flag_ocp_alarm_right"}, /* OCP right amplifier , */\ + { 0x1390, "flag_clip_right"}, /* Amplifier right clipping , */\ + { 0x13a0, "flag_mic_ocpok"}, /* OCPOK MICVDD , */\ + { 0x13b0, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ + { 0x13d0, "flag_man_wait_cf_config"}, /* Wait CF config , */\ + { 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ + { 0x1400, "flag_cf_speakererror_left"}, /* Left speaker status , */\ + { 0x1410, "flag_cf_speakererror_right"}, /* Right speaker status , */\ + { 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1433, "man_state"}, /* Device manager status , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x2003, "tdm_usecase"}, /* Usecase setting , */\ + { 0x2040, "tdm_enable"}, /* Enable interface , */\ + { 0x2050, "tdm_mode"}, /* Slave/master , */\ + { 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2073, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ + { 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ + { 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ + { 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ + { 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "tdm_txdata_format_unused_slot_sd1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "tdm_txdata_format_unused_slot_sd2"}, /* Format unused slots DIO2 , */\ + { 0x2300, "tdm_sink0_enable"}, /* Control gainin (not used in DSP) , */\ + { 0x2310, "tdm_sink1_enable"}, /* Control audio left , */\ + { 0x2320, "tdm_sink2_enable"}, /* Control audio right , */\ + { 0x2330, "tdm_source0_enable"}, /* Control gainout (not used in DSP) , */\ + { 0x2340, "tdm_source1_enable"}, /* Control voltage sense right , */\ + { 0x2350, "tdm_source2_enable"}, /* Control current sense right , */\ + { 0x2360, "tdm_source3_enable"}, /* Voltage sense left control , */\ + { 0x2370, "tdm_source4_enable"}, /* Current sense left control , */\ + { 0x2380, "tdm_source5_enable"}, /* DSP out right control , */\ + { 0x2390, "tdm_source6_enable"}, /* DSP out left control , */\ + { 0x23a0, "tdm_source7_enable"}, /* AEC ref left control , */\ + { 0x23b0, "tdm_source8_enable"}, /* AEC ref right control , */\ + { 0x23c0, "tdm_source9_enable"}, /* PDM 1 control , */\ + { 0x23d0, "tdm_source10_enable"}, /* PDM 2 control , */\ + { 0x2401, "tdm_sink0_io"}, /* IO gainin (not used in DSP) , */\ + { 0x2421, "tdm_sink1_io"}, /* IO audio left , */\ + { 0x2441, "tdm_sink2_io"}, /* IO audio right , */\ + { 0x2461, "tdm_source0_io"}, /* IO gainout (not used in DSP) , */\ + { 0x2481, "tdm_source1_io"}, /* IO voltage sense right , */\ + { 0x24a1, "tdm_source2_io"}, /* IO current sense right , */\ + { 0x24c1, "tdm_source3_io"}, /* IO voltage sense left , */\ + { 0x24e1, "tdm_source4_io"}, /* IO current sense left , */\ + { 0x2501, "tdm_source5_io"}, /* IO dspout right , */\ + { 0x2521, "tdm_source6_io"}, /* IO dspout left , */\ + { 0x2541, "tdm_source7_io"}, /* IO AEC ref left control , */\ + { 0x2561, "tdm_source8_io"}, /* IO AEC ref right control , */\ + { 0x2581, "tdm_source9_io"}, /* IO pdm1 , */\ + { 0x25a1, "tdm_source10_io"}, /* IO pdm2 , */\ + { 0x2603, "tdm_sink0_slot"}, /* Position gainin (not used in DSP) , */\ + { 0x2643, "tdm_sink1_slot"}, /* Position audio left , */\ + { 0x2683, "tdm_sink2_slot"}, /* Position audio right , */\ + { 0x26c3, "tdm_source0_slot"}, /* Position gainout (not used in DSP) , */\ + { 0x2703, "tdm_source1_slot"}, /* Position voltage sense right , */\ + { 0x2743, "tdm_source2_slot"}, /* Position current sense right , */\ + { 0x2783, "tdm_source3_slot"}, /* Position voltage sense left , */\ + { 0x27c3, "tdm_source4_slot"}, /* Position current sense left , */\ + { 0x2803, "tdm_source5_slot"}, /* Position dspout right , */\ + { 0x2843, "tdm_source6_slot"}, /* Position dspout left , */\ + { 0x2883, "tdm_source7_slot"}, /* Position AEC ref left control , */\ + { 0x28c3, "tdm_source8_slot"}, /* Position AEC ref right control , */\ + { 0x2903, "tdm_source9_slot"}, /* Position pdm1 , */\ + { 0x2943, "tdm_source10_slot"}, /* Position pdm2 , */\ + { 0x3100, "pdm_mode"}, /* PDM control , */\ + { 0x3111, "pdm_side_tone_sel"}, /* Side tone input , */\ + { 0x3130, "pdm_left_sel"}, /* PDM data selection for left channel during PDM direct mode, */\ + { 0x3140, "pdm_right_sel"}, /* PDM data selection for right channel during PDM direct mode, */\ + { 0x3150, "enbl_micvdd"}, /* Enable MICVDD , */\ + { 0x3160, "bypass_micvdd_ocp"}, /* Bypass control for the MICVDD OCP flag processing , */\ + { 0x3201, "pdm_nbck"}, /* PDM BCK/Fs ratio , */\ + { 0x3223, "pdm_gain"}, /* PDM gain , */\ + { 0x3263, "sel_pdm_out_data"}, /* PDM output selection - RE/FE data combination , */\ + { 0x32a0, "sel_cf_haptic_data"}, /* Select the source for haptic data output (not for customer), */\ + { 0x3307, "haptic_duration"}, /* Duration (ms) , */\ + { 0x3387, "haptic_data"}, /* DC value (FFS) , */\ + { 0x3403, "gpio_datain"}, /* Receiving value , */\ + { 0x3500, "gpio_ctrl"}, /* GPIO master control over GPIO1/2 ports (not for customer), */\ + { 0x3513, "gpio_dir"}, /* Configuration , */\ + { 0x3553, "gpio_dataout"}, /* Transmitting value , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_pll_lock"}, /* Status PLL lock , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ovpok"}, /* Status OVP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_clocks_stable"}, /* Status clocks stable , */\ + { 0x4060, "int_out_flag_mtp_busy"}, /* Status MTP busy , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cf_speakererror"}, /* Status speaker error , */\ + { 0x4090, "int_out_flag_cold_started"}, /* Status cold start , */\ + { 0x40a0, "int_out_flag_engage"}, /* Status amplifier engage , */\ + { 0x40b0, "int_out_flag_watchdog_reset"}, /* Status watchdog , */\ + { 0x40c0, "int_out_flag_enbl_amp"}, /* Status amplifier enable , */\ + { 0x40d0, "int_out_flag_enbl_ref"}, /* Status Ref enable , */\ + { 0x40e0, "int_out_flag_adc10_ready"}, /* Status Control ADC , */\ + { 0x40f0, "int_out_flag_bod_vddd_nok"}, /* Status BOD , */\ + { 0x4100, "int_out_flag_bst_bstcur"}, /* Status DCDC current limiting , */\ + { 0x4110, "int_out_flag_bst_hiz"}, /* Status DCDC active , */\ + { 0x4120, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4130, "int_out_flag_bst_peakcur"}, /* Status bst peakcur , */\ + { 0x4140, "int_out_flag_bst_voutcomp"}, /* Status DCDC level 1x , */\ + { 0x4150, "int_out_flag_bst_voutcomp86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "int_out_flag_bst_voutcomp93"}, /* Status DCDC level 1.07x , */\ + { 0x4170, "int_out_flag_rcvldop_ready"}, /* Status rcvldop ready , */\ + { 0x4180, "int_out_flag_ocp_alarm_left"}, /* Status ocp alarm left , */\ + { 0x4190, "int_out_flag_ocp_alarm_right"}, /* Status ocp alarm right , */\ + { 0x41a0, "int_out_flag_man_wait_src_settings"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "int_out_flag_man_wait_cf_config"}, /* Status waits CF config , */\ + { 0x41c0, "int_out_flag_man_start_mute_audio"}, /* Status Audio mute sequence , */\ + { 0x41d0, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x41e0, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x41f0, "int_out_flag_clk_out_of_range"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "int_out_flag_tdm_error"}, /* Status tdm error , */\ + { 0x4210, "int_out_flag_clip_left"}, /* Status clip left , */\ + { 0x4220, "int_out_flag_clip_right"}, /* Status clip right , */\ + { 0x4230, "int_out_flag_mic_ocpok"}, /* Status mic ocpok , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_pll_lock"}, /* Clear PLL lock , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ovpok"}, /* Clear OVP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_clocks_stable"}, /* Clear clocks stable , */\ + { 0x4460, "int_in_flag_mtp_busy"}, /* Clear mtp busy , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cf_speakererror"}, /* Clear speaker error , */\ + { 0x4490, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44a0, "int_in_flag_engage"}, /* Clear amplifier engage , */\ + { 0x44b0, "int_in_flag_watchdog_reset"}, /* Clear watchdog , */\ + { 0x44c0, "int_in_flag_enbl_amp"}, /* Clear enbl amp , */\ + { 0x44d0, "int_in_flag_enbl_ref"}, /* Clear ref enable , */\ + { 0x44e0, "int_in_flag_adc10_ready"}, /* Clear control ADC , */\ + { 0x44f0, "int_in_flag_bod_vddd_nok"}, /* Clear BOD , */\ + { 0x4500, "int_in_flag_bst_bstcur"}, /* Clear DCDC current limiting , */\ + { 0x4510, "int_in_flag_bst_hiz"}, /* Clear DCDC active , */\ + { 0x4520, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4530, "int_in_flag_bst_peakcur"}, /* Clear bst peakcur , */\ + { 0x4540, "int_in_flag_bst_voutcomp"}, /* Clear DCDC level 1x , */\ + { 0x4550, "int_in_flag_bst_voutcomp86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "int_in_flag_bst_voutcomp93"}, /* Clear DCDC level 1.07x , */\ + { 0x4570, "int_in_flag_rcvldop_ready"}, /* Clear rcvldop ready , */\ + { 0x4580, "int_in_flag_ocp_alarm_left"}, /* Clear ocp alarm left , */\ + { 0x4590, "int_in_flag_ocp_alarm_right"}, /* Clear ocp alarm right , */\ + { 0x45a0, "int_in_flag_man_wait_src_settings"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "int_in_flag_man_wait_cf_config"}, /* Clear wait cf config , */\ + { 0x45c0, "int_in_flag_man_start_mute_audio"}, /* Clear audio mute sequence , */\ + { 0x45d0, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x45e0, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x45f0, "int_in_flag_clk_out_of_range"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ + { 0x4610, "int_in_flag_clip_left"}, /* Clear clip left , */\ + { 0x4620, "int_in_flag_clip_right"}, /* Clear clip right , */\ + { 0x4630, "int_in_flag_mic_ocpok"}, /* Clear mic ocpok , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable por , */\ + { 0x4810, "int_enable_flag_pll_lock"}, /* Enable pll lock , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ovpok"}, /* Enable OVP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_clocks_stable"}, /* Enable clocks stable , */\ + { 0x4860, "int_enable_flag_mtp_busy"}, /* Enable mtp busy , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cf_speakererror"}, /* Enable speaker error , */\ + { 0x4890, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48a0, "int_enable_flag_engage"}, /* Enable amplifier engage , */\ + { 0x48b0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog , */\ + { 0x48c0, "int_enable_flag_enbl_amp"}, /* Enable enbl amp , */\ + { 0x48d0, "int_enable_flag_enbl_ref"}, /* Enable ref enable , */\ + { 0x48e0, "int_enable_flag_adc10_ready"}, /* Enable Control ADC , */\ + { 0x48f0, "int_enable_flag_bod_vddd_nok"}, /* Enable BOD , */\ + { 0x4900, "int_enable_flag_bst_bstcur"}, /* Enable DCDC current limiting , */\ + { 0x4910, "int_enable_flag_bst_hiz"}, /* Enable DCDC active , */\ + { 0x4920, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4930, "int_enable_flag_bst_peakcur"}, /* Enable bst peakcur , */\ + { 0x4940, "int_enable_flag_bst_voutcomp"}, /* Enable DCDC level 1x , */\ + { 0x4950, "int_enable_flag_bst_voutcomp86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "int_enable_flag_bst_voutcomp93"}, /* Enable DCDC level 1.07x , */\ + { 0x4970, "int_enable_flag_rcvldop_ready"}, /* Enable rcvldop ready , */\ + { 0x4980, "int_enable_flag_ocp_alarm_left"}, /* Enable ocp alarm left , */\ + { 0x4990, "int_enable_flag_ocp_alarm_right"}, /* Enable ocp alarm right , */\ + { 0x49a0, "int_enable_flag_man_wait_src_settings"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "int_enable_flag_man_wait_cf_config"}, /* Enable man wait cf config , */\ + { 0x49c0, "int_enable_flag_man_start_mute_audio"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x49e0, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x49f0, "int_enable_flag_clk_out_of_range"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ + { 0x4a10, "int_enable_flag_clip_left"}, /* Enable clip left , */\ + { 0x4a20, "int_enable_flag_clip_right"}, /* Enable clip right , */\ + { 0x4a30, "int_enable_flag_mic_ocpok"}, /* Enable mic ocpok , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ + { 0x4c10, "int_polarity_flag_pll_lock"}, /* Polarity pll lock , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ovpok"}, /* Polarity OVP alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_clocks_stable"}, /* Polarity clocks stable , */\ + { 0x4c60, "int_polarity_flag_mtp_busy"}, /* Polarity mtp busy , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cf_speakererror"}, /* Polarity speaker error , */\ + { 0x4c90, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4ca0, "int_polarity_flag_engage"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog , */\ + { 0x4cc0, "int_polarity_flag_enbl_amp"}, /* Polarity enbl amp , */\ + { 0x4cd0, "int_polarity_flag_enbl_ref"}, /* Polarity ref enable , */\ + { 0x4ce0, "int_polarity_flag_adc10_ready"}, /* Polarity Control ADC , */\ + { 0x4cf0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity BOD , */\ + { 0x4d00, "int_polarity_flag_bst_bstcur"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "int_polarity_flag_bst_hiz"}, /* Polarity DCDC active , */\ + { 0x4d20, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "int_polarity_flag_bst_peakcur"}, /* Polarity bst peakcur , */\ + { 0x4d40, "int_polarity_flag_bst_voutcomp"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "int_polarity_flag_bst_voutcomp86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "int_polarity_flag_bst_voutcomp93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d70, "int_polarity_flag_rcvldop_ready"}, /* Polarity rcvldop ready , */\ + { 0x4d80, "int_polarity_flag_ocp_alarm_left"}, /* Polarity ocp alarm left , */\ + { 0x4d90, "int_polarity_flag_ocp_alarm_right"}, /* Polarity ocp alarm right , */\ + { 0x4da0, "int_polarity_flag_man_wait_src_settings"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "int_polarity_flag_man_wait_cf_config"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "int_polarity_flag_man_start_mute_audio"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4de0, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4df0, "int_polarity_flag_clk_out_of_range"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ + { 0x4e10, "int_polarity_flag_clip_left"}, /* Polarity clip left , */\ + { 0x4e20, "int_polarity_flag_clip_right"}, /* Polarity clip right , */\ + { 0x4e30, "int_polarity_flag_mic_ocpok"}, /* Polarity mic ocpok , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery protection attack Time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery protection threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery protection maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery protection release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery protection hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ + { 0x5110, "soft_mute"}, /* Soft mute HW , */\ + { 0x5120, "cf_mute_left"}, /* Soft mute FW left , */\ + { 0x5130, "cf_mute_right"}, /* Soft mute FW right , */\ + { 0x5140, "bypass_hp_left"}, /* Bypass HPF left , */\ + { 0x5150, "bypass_hp_right"}, /* Bypass HPF right , */\ + { 0x5160, "enbl_dpsa_left"}, /* Enable DPSA left , */\ + { 0x5170, "enbl_dpsa_right"}, /* Enable DPSA right , */\ + { 0x5187, "cf_volume"}, /* FW volume control for primary audio channel , */\ + { 0x5200, "ctrl_rcv"}, /* Selection receiver , */\ + { 0x5210, "ctrl_rcv_fb_100k"}, /* Selection of feedback resistor for receiver mode (not for customer), */\ + { 0x5222, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5257, "gain"}, /* Amplifier gain , */\ + { 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x52e1, "ctrl_slope"}, /* Set slope , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for battery protection, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "enbl_low_latency"}, /* CF low latency outputs for add module , */\ + { 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5420, "fb_hz"}, /* Feedback resistor set to high ohmic , */\ + { 0x5430, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5581, "dpsa_drive"}, /* Control of the number of power stage sections, total of 4 sections. Each section is 1/4 of the total power stages., */\ + { 0x560a, "enbl_amp_left"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually - Left channel, */\ + { 0x56b0, "enbl_engage_left"}, /* Enables/engage power stage and control loop - left channel, */\ + { 0x570a, "enbl_amp_right"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually - Right channel, */\ + { 0x57b0, "enbl_engage_right"}, /* Enables/engage power stage and control loop - right channel, */\ + { 0x5800, "hard_mute_left"}, /* Hard mute - PWM module left , */\ + { 0x5810, "hard_mute_right"}, /* Hard mute - PWM module right , */\ + { 0x5820, "pwm_shape"}, /* PWM shape , */\ + { 0x5830, "pwm_bitlength"}, /* PWM bit length in noise shaper , */\ + { 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ + { 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ + { 0x58b0, "enbl_pwm_phase_shift_left"}, /* Control for pwm phase shift, inverted function - left channel, */\ + { 0x58c0, "enbl_pwm_phase_shift_right"}, /* Control for pwm phase shift - right channel , */\ + { 0x5900, "ctrl_rcvldop_pulldown"}, /* Pulldown of LDO (2.7V) , */\ + { 0x5910, "ctrl_rcvldop_test_comp"}, /* Enable testing of LDO comparator , */\ + { 0x5920, "ctrl_rcvldop_test_loadedldo"}, /* Load connected to rcvldo , */\ + { 0x5930, "enbl_rcvldop"}, /* Enables the LDO (2.7) , */\ + { 0x5a07, "cf_volume_sec"}, /* FW volume control for secondary audio channel , */\ + { 0x5a87, "sw_profile"}, /* Software profile data , */\ + { 0x7002, "boost_volt"}, /* Boost voltage , */\ + { 0x7033, "boost_cur"}, /* Max coil current , */\ + { 0x7071, "bst_coil_value"}, /* Coil Value , */\ + { 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x70b2, "dcdc_synchronisation"}, /* DCDC synchronization off + 7 positions , */\ + { 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x71c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ + { 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7332, "bst_freq"}, /* DCDC bost frequency control , */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8040, "cs_dc_offset"}, /* Current sense decimator offset control , */\ + { 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8110, "invertpwm_left"}, /* Current sense common mode feedback pwm invert control for left channel, */\ + { 0x8122, "cmfb_gain_left"}, /* Current sense common mode feedback control gain for left channel, */\ + { 0x8154, "cmfb_offset_left"}, /* Current sense common mode feedback control offset for left channel, */\ + { 0x8200, "enbl_cmfb_right"}, /* Current sense common mode feedback control for right channel, */\ + { 0x8210, "invertpwm_right"}, /* Current sense common mode feedback pwm invert control for right channel, */\ + { 0x8222, "cmfb_gain_right"}, /* Current sense common mode feedback control gain for right channel, */\ + { 0x8254, "cmfb_offset_right"}, /* Current sense common mode feedback control offset for right channel, */\ + { 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ + { 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8600, "enbl_cs_adc_left"}, /* Enable current sense ADC , */\ + { 0x8610, "enbl_cs_inn1_left"}, /* Enable connection of current sense negative1 , */\ + { 0x8630, "enbl_cs_inp1_left"}, /* Enable connection of current sense positive1 , */\ + { 0x8650, "enbl_cs_ldo_left"}, /* Enable current sense LDO , */\ + { 0x8660, "enbl_cs_nofloating_n_left"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8670, "enbl_cs_nofloating_p_left"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8680, "enbl_cs_vbatldo_left"}, /* Enable of current sense LDO , */\ + { 0x8700, "enbl_cs_adc_right"}, /* Enable current sense ADC , */\ + { 0x8710, "enbl_cs_inn1_right"}, /* Enable connection of current sense negative1 , */\ + { 0x8730, "enbl_cs_inp1_right"}, /* Enable connection of current sense positive1 , */\ + { 0x8750, "enbl_cs_ldo_right"}, /* Enable current sense LDO , */\ + { 0x8760, "enbl_cs_nofloating_n_right"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8770, "enbl_cs_nofloating_p_right"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8780, "enbl_cs_vbatldo_right"}, /* Enable of current sense LDO , */\ + { 0x8800, "volsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ + { 0x8810, "volsense_dc_offset"}, /* Voltage sense decimator offset control , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset , */\ + { 0x9011, "cf_dmem"}, /* Target memory , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* Memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* Error flags , */\ + { 0x9387, "cf_ack"}, /* Acknowledge of requests , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0x980f, "ivt_addr0_msb"}, /* Coolflux interrupt vector table address0 MSB , */\ + { 0x990f, "ivt_addr0_lsb"}, /* Coolflux interrupt vector table address0 LSB , */\ + { 0x9a0f, "ivt_addr1_msb"}, /* Coolflux interrupt vector table address1 MSB , */\ + { 0x9b0f, "ivt_addr1_lsb"}, /* Coolflux interrupt vector table address1 LSB , */\ + { 0x9c0f, "ivt_addr2_msb"}, /* Coolflux interrupt vector table address2 MSB , */\ + { 0x9d0f, "ivt_addr2_lsb"}, /* Coolflux interrupt vector table address2 LSB , */\ + { 0x9e0f, "ivt_addr3_msb"}, /* Coolflux interrupt vector table address3 MSB , */\ + { 0x9f0f, "ivt_addr3_lsb"}, /* Coolflux interrupt vector table address3 LSB , */\ + { 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb050, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0xc3d0, "test_abistfft_enbl"}, /* FFT Coolflux , */\ + { 0xc3e0, "test_pwr_switch"}, /* Test mode for digital power switches core sw/mem sw/micvdd sw, */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc660, "bypass_diosw_ovp"}, /* Bypass ovp for memory switch diosw , */\ + { 0xc670, "enbl_powerswitch"}, /* Vddd core power switch control - overrules the manager control, */\ + { 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to GPIO1 (see Digimux list for details), */\ + { 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to GPIO2 (see Digimux list for details), */\ + { 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to GPIO3 (see Digimux list for details), */\ + { 0xc887, "digimuxd_sel"}, /* DigimuxD input selection control routed to GPIO4 (see Digimux list for details), */\ + { 0xc901, "dio1_ehs"}, /* Speed/load setting for DIO1 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc921, "dio2_ehs"}, /* Speed/load setting for DIO2 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc941, "gainio_ehs"}, /* Speed/load setting for GAINIO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc961, "pdmo_ehs"}, /* Speed/load setting for PDMO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9a1, "tdo_ehs"}, /* Speed/load setting for TDO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xca40, "enbl_anamux5"}, /* Enable anamux5 , */\ + { 0xca50, "enbl_anamux6"}, /* Enable anamux6 , */\ + { 0xca60, "enbl_anamux7"}, /* Enable anamux7 , */\ + { 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xcb54, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xcba4, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xcc04, "anamux5"}, /* Anamux selection control - anamux on TEST5 , */\ + { 0xcc54, "anamux6"}, /* Anamux selection control - anamux on TEST6 , */\ + { 0xcca4, "anamux7"}, /* Anamux selection control - anamux on TEST7 , */\ + { 0xcd05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ + { 0xcd64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ + { 0xcdb3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ + { 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ + { 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcec0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ + { 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd243, "tsig_gain_left"}, /* Test signal gain for left channel , */\ + { 0xd283, "tsig_gain_right"}, /* Test signal gain for right channel , */\ + { 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd506, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd570, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "calibr_gain_left"}, /* HW gain module - left channel (2's complement) , */\ + { 0xf1a5, "calibr_offset_left"}, /* Offset for amplifier, HW gain module - left channel (2's complement), */\ + { 0xf203, "calibr_gain_right"}, /* HW gain module - right channel (2's complement) , */\ + { 0xf245, "calibr_offset_right"}, /* Offset for amplifier, HW gain module - right channel (2's complement), */\ + { 0xf2a3, "calibr_rcvldop_trim"}, /* Trimming of LDO (2.7V) , */\ + { 0xf307, "calibr_gain_cs_left"}, /* Current sense gain - left channel (signed two's complement format), */\ + { 0xf387, "calibr_gain_cs_right"}, /* Current sense gain - right channel (signed two's complement format), */\ + { 0xf40f, "calibr_R25C_L"}, /* Ron resistance of left channel speaker coil , */\ + { 0xf50f, "calibr_R25C_R"}, /* Ron resistance of right channel speaker coil , */\ + { 0xf606, "ctrl_offset_a_left"}, /* Offset of left amplifier level shifter A , */\ + { 0xf686, "ctrl_offset_b_left"}, /* Offset of left amplifier level shifter B , */\ + { 0xf706, "ctrl_offset_a_right"}, /* Offset of right amplifier level shifter A , */\ + { 0xf786, "ctrl_offset_b_right"}, /* Offset of right amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ + { 0xf910, "mtp_lock_enbl_coolflux"}, /* Disable function enbl_coolflux , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Disable programming of max dcdc boost voltage , */\ + { 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf987, "type_bits_fw"}, /* MTP-control FW - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ + { 0xff05, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa2_irq { + tfa2_irq_stvdds = 0, + tfa2_irq_stplls = 1, + tfa2_irq_stotds = 2, + tfa2_irq_stovds = 3, + tfa2_irq_stuvds = 4, + tfa2_irq_stclks = 5, + tfa2_irq_stmtpb = 6, + tfa2_irq_stnoclk = 7, + tfa2_irq_stspks = 8, + tfa2_irq_stacs = 9, + tfa2_irq_stsws = 10, + tfa2_irq_stwds = 11, + tfa2_irq_stamps = 12, + tfa2_irq_starefs = 13, + tfa2_irq_stadccr = 14, + tfa2_irq_stbodnok = 15, + tfa2_irq_stbstcu = 16, + tfa2_irq_stbsthi = 17, + tfa2_irq_stbstoc = 18, + tfa2_irq_stbstpkcur = 19, + tfa2_irq_stbstvc = 20, + tfa2_irq_stbst86 = 21, + tfa2_irq_stbst93 = 22, + tfa2_irq_strcvld = 23, + tfa2_irq_stocpl = 24, + tfa2_irq_stocpr = 25, + tfa2_irq_stmwsrc = 26, + tfa2_irq_stmwcfc = 27, + tfa2_irq_stmwsmu = 28, + tfa2_irq_stcfmer = 29, + tfa2_irq_stcfmac = 30, + tfa2_irq_stclkoor = 31, + tfa2_irq_sttdmer = 32, + tfa2_irq_stclpl = 33, + tfa2_irq_stclpr = 34, + tfa2_irq_stocpm = 35, + tfa2_irq_max = 36, + tfa2_irq_all = -1 /* all irqs */}; + +#define TFA2_IRQ_NAMETABLE static tfaIrqName_t Tfa2IrqNames[] = {\ + { 0, "STVDDS"},\ + { 1, "STPLLS"},\ + { 2, "STOTDS"},\ + { 3, "STOVDS"},\ + { 4, "STUVDS"},\ + { 5, "STCLKS"},\ + { 6, "STMTPB"},\ + { 7, "STNOCLK"},\ + { 8, "STSPKS"},\ + { 9, "STACS"},\ + { 10, "STSWS"},\ + { 11, "STWDS"},\ + { 12, "STAMPS"},\ + { 13, "STAREFS"},\ + { 14, "STADCCR"},\ + { 15, "STBODNOK"},\ + { 16, "STBSTCU"},\ + { 17, "STBSTHI"},\ + { 18, "STBSTOC"},\ + { 19, "STBSTPKCUR"},\ + { 20, "STBSTVC"},\ + { 21, "STBST86"},\ + { 22, "STBST93"},\ + { 23, "STRCVLD"},\ + { 24, "STOCPL"},\ + { 25, "STOCPR"},\ + { 26, "STMWSRC"},\ + { 27, "STMWCFC"},\ + { 28, "STMWSMU"},\ + { 29, "STCFMER"},\ + { 30, "STCFMAC"},\ + { 31, "STCLKOOR"},\ + { 32, "STTDMER"},\ + { 33, "STCLPL"},\ + { 34, "STCLPR"},\ + { 35, "STOCPM"},\ + { 36, "36"},\ +}; diff --git a/sound/soc/codecs/tfa9872_tfafieldnames.h b/sound/soc/codecs/tfa9872_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..6dd639e01eac00c82f1c18e15d5ee3cdfb694cfc --- /dev/null +++ b/sound/soc/codecs/tfa9872_tfafieldnames.h @@ -0,0 +1,1221 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9872_TFAFIELDNAMES_H +#define _TFA9872_TFAFIELDNAMES_H + +#define TFA9872_I2CVERSION_N1A 26 +#define TFA9872_I2CVERSION_N1B 29 +#define TFA9872_I2CVERSION_N1B2 25 + +typedef enum nxpTfa9872BfEnumList { +TFA9872_BF_PWDN = 0x0000, /*!< Powerdown selection */ +TFA9872_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ +TFA9872_BF_AMPE = 0x0030, /*!< Activate Amplifier */ +TFA9872_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ +TFA9872_BF_INTP = 0x0071, /*!< Interrupt config */ +TFA9872_BF_BYPOCP = 0x00b0, /*!< Bypass OCP */ +TFA9872_BF_TSTOCP = 0x00c0, /*!< OCP testing control */ +TFA9872_BF_MANSCONF = 0x0120, /*!< I2C configured */ +TFA9872_BF_MANAOOSC = 0x0140, /*!< Internal osc off at PWDN */ +TFA9872_BF_MUTETO = 0x01d0, /*!< Time out SB mute sequence */ +TFA9872_BF_RCVNS = 0x01e0, /*!< Noise shaper selection */ +TFA9872_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ +TFA9872_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ +TFA9872_BF_FRACTDEL = 0x0255, /*!< V/I Fractional delay */ +TFA9872_BF_BYPHVBF = 0x02b0, /*!< Bypass HVBAT filter */ +TFA9872_BF_REV = 0x030f, /*!< Revision info */ +TFA9872_BF_REFCKEXT = 0x0401, /*!< PLL external ref clock */ +TFA9872_BF_REFCKSEL = 0x0420, /*!< PLL internal ref clock */ +TFA9872_BF_SSE = 0x0510, /*!< Enable speaker path */ +TFA9872_BF_VSE = 0x0530, /*!< Voltage sense */ +TFA9872_BF_CSE = 0x0550, /*!< Current sense */ +TFA9872_BF_SSPDME = 0x0560, /*!< Sub-system PDM */ +TFA9872_BF_PGAE = 0x0580, /*!< Enable PGA chop clock */ +TFA9872_BF_SSTDME = 0x0590, /*!< Sub-system TDM */ +TFA9872_BF_SSPBSTE = 0x05a0, /*!< Sub-system boost */ +TFA9872_BF_SSADCE = 0x05b0, /*!< Sub-system ADC */ +TFA9872_BF_SSFAIME = 0x05c0, /*!< Sub-system FAIM */ +TFA9872_BF_STGAIN = 0x0d18, /*!< Side tone gain */ +TFA9872_BF_STSMUTE = 0x0da0, /*!< Side tone soft mute */ +TFA9872_BF_ST1C = 0x0db0, /*!< side tone one s complement */ +TFA9872_BF_VDDS = 0x1000, /*!< POR */ +TFA9872_BF_PLLS = 0x1010, /*!< PLL lock */ +TFA9872_BF_OTDS = 0x1020, /*!< OTP alarm */ +TFA9872_BF_OVDS = 0x1030, /*!< OVP alarm */ +TFA9872_BF_UVDS = 0x1040, /*!< UVP alarm */ +TFA9872_BF_CLKS = 0x1050, /*!< Clocks stable */ +TFA9872_BF_MTPB = 0x1060, /*!< MTP busy */ +TFA9872_BF_NOCLK = 0x1070, /*!< Lost clock */ +TFA9872_BF_SWS = 0x10a0, /*!< Amplifier engage */ +TFA9872_BF_AMPS = 0x10c0, /*!< Amplifier enable */ +TFA9872_BF_AREFS = 0x10d0, /*!< References enable */ +TFA9872_BF_ADCCR = 0x10e0, /*!< Control ADC */ +TFA9872_BF_DCIL = 0x1100, /*!< DCDC current limiting */ +TFA9872_BF_DCDCA = 0x1110, /*!< DCDC active */ +TFA9872_BF_DCOCPOK = 0x1120, /*!< DCDC OCP nmos */ +TFA9872_BF_DCHVBAT = 0x1140, /*!< DCDC level 1x */ +TFA9872_BF_DCH114 = 0x1150, /*!< DCDC level 1.14x */ +TFA9872_BF_DCH107 = 0x1160, /*!< DCDC level 1.07x */ +TFA9872_BF_STMUTEB = 0x1170, /*!< side tone (un)mute busy */ +TFA9872_BF_STMUTE = 0x1180, /*!< side tone mute state */ +TFA9872_BF_TDMLUTER = 0x1190, /*!< TDM LUT error */ +TFA9872_BF_TDMSTAT = 0x11a2, /*!< TDM status bits */ +TFA9872_BF_TDMERR = 0x11d0, /*!< TDM error */ +TFA9872_BF_OCPOAP = 0x1300, /*!< OCPOK pmos A */ +TFA9872_BF_OCPOAN = 0x1310, /*!< OCPOK nmos A */ +TFA9872_BF_OCPOBP = 0x1320, /*!< OCPOK pmos B */ +TFA9872_BF_OCPOBN = 0x1330, /*!< OCPOK nmos B */ +TFA9872_BF_CLIPAH = 0x1340, /*!< Clipping A to Vddp */ +TFA9872_BF_CLIPAL = 0x1350, /*!< Clipping A to gnd */ +TFA9872_BF_CLIPBH = 0x1360, /*!< Clipping B to Vddp */ +TFA9872_BF_CLIPBL = 0x1370, /*!< Clipping B to gnd */ +TFA9872_BF_OCDS = 0x1380, /*!< OCP amplifier */ +TFA9872_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ +TFA9872_BF_OCPOKMC = 0x13a0, /*!< OCPOK MICVDD */ +TFA9872_BF_MANALARM = 0x13b0, /*!< Alarm state */ +TFA9872_BF_MANWAIT1 = 0x13c0, /*!< Wait HW I2C settings */ +TFA9872_BF_MANMUTE = 0x13e0, /*!< Audio mute sequence */ +TFA9872_BF_MANOPER = 0x13f0, /*!< Operating state */ +TFA9872_BF_CLKOOR = 0x1420, /*!< External clock status */ +TFA9872_BF_MANSTATE = 0x1433, /*!< Device manager status */ +TFA9872_BF_DCMODE = 0x1471, /*!< DCDC mode status bits */ +TFA9872_BF_BATS = 0x1509, /*!< Battery voltage (V) */ +TFA9872_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ +TFA9872_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/9.5 V) */ +TFA9872_BF_TDME = 0x2040, /*!< Enable interface */ +TFA9872_BF_TDMMODE = 0x2050, /*!< Slave/master */ +TFA9872_BF_TDMCLINV = 0x2060, /*!< Reception data to BCK clock */ +TFA9872_BF_TDMFSLN = 0x2073, /*!< FS length (master mode only) */ +TFA9872_BF_TDMFSPOL = 0x20b0, /*!< FS polarity */ +TFA9872_BF_TDMNBCK = 0x20c3, /*!< N-BCK's in FS */ +TFA9872_BF_TDMSLOTS = 0x2103, /*!< N-slots in Frame */ +TFA9872_BF_TDMSLLN = 0x2144, /*!< N-bits in slot */ +TFA9872_BF_TDMBRMG = 0x2194, /*!< N-bits remaining */ +TFA9872_BF_TDMDEL = 0x21e0, /*!< data delay to FS */ +TFA9872_BF_TDMADJ = 0x21f0, /*!< data adjustment */ +TFA9872_BF_TDMOOMP = 0x2201, /*!< Received audio compression */ +TFA9872_BF_TDMSSIZE = 0x2224, /*!< Sample size per slot */ +TFA9872_BF_TDMTXDFO = 0x2271, /*!< Format unused bits */ +TFA9872_BF_TDMTXUS0 = 0x2291, /*!< Format unused slots DATAO */ +TFA9872_BF_TDMSPKE = 0x2300, /*!< Control audio tdm channel in 0 (spkr + dcdc) */ +TFA9872_BF_TDMDCE = 0x2310, /*!< Control audio tdm channel in 1 (dcdc) */ +TFA9872_BF_TDMCSE = 0x2330, /*!< current sense vbat temperature and vddp feedback */ +TFA9872_BF_TDMVSE = 0x2340, /*!< Voltage sense vbat temperature and vddp feedback */ +TFA9872_BF_TDMSPKS = 0x2603, /*!< tdm slot for sink 0 (speaker + dcdc) */ +TFA9872_BF_TDMDCS = 0x2643, /*!< tdm slot for sink 1 (dcdc) */ +TFA9872_BF_TDMCSS = 0x26c3, /*!< Slot Position of current sense vbat temperature and vddp feedback */ +TFA9872_BF_TDMVSS = 0x2703, /*!< Slot Position of Voltage sense vbat temperature and vddp feedback */ +TFA9872_BF_PDMSTSEL = 0x3111, /*!< Side tone input */ +TFA9872_BF_ISTVDDS = 0x4000, /*!< Status POR */ +TFA9872_BF_ISTPLLS = 0x4010, /*!< Status PLL lock */ +TFA9872_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ +TFA9872_BF_ISTOVDS = 0x4030, /*!< Status OVP alarm */ +TFA9872_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ +TFA9872_BF_ISTCLKS = 0x4050, /*!< Status clocks stable */ +TFA9872_BF_ISTMTPB = 0x4060, /*!< Status MTP busy */ +TFA9872_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ +TFA9872_BF_ISTSWS = 0x40a0, /*!< Status amplifier engage */ +TFA9872_BF_ISTAMPS = 0x40c0, /*!< Status amplifier enable */ +TFA9872_BF_ISTAREFS = 0x40d0, /*!< Status Ref enable */ +TFA9872_BF_ISTADCCR = 0x40e0, /*!< Status Control ADC */ +TFA9872_BF_ISTBSTCU = 0x4100, /*!< Status DCDC current limiting */ +TFA9872_BF_ISTBSTHI = 0x4110, /*!< Status DCDC active */ +TFA9872_BF_ISTBSTOC = 0x4120, /*!< Status DCDC OCP */ +TFA9872_BF_ISTBSTPKCUR = 0x4130, /*!< Status bst peakcur */ +TFA9872_BF_ISTBSTVC = 0x4140, /*!< Status DCDC level 1x */ +TFA9872_BF_ISTBST86 = 0x4150, /*!< Status DCDC level 1.14x */ +TFA9872_BF_ISTBST93 = 0x4160, /*!< Status DCDC level 1.07x */ +TFA9872_BF_ISTOCPR = 0x4190, /*!< Status ocp alarm */ +TFA9872_BF_ISTMWSRC = 0x41a0, /*!< Status Waits HW I2C settings */ +TFA9872_BF_ISTMWSMU = 0x41c0, /*!< Status Audio mute sequence */ +TFA9872_BF_ISTCLKOOR = 0x41f0, /*!< Status flag_clk_out_of_range */ +TFA9872_BF_ISTTDMER = 0x4200, /*!< Status tdm error */ +TFA9872_BF_ISTCLPR = 0x4220, /*!< Status clip */ +TFA9872_BF_ISTLP0 = 0x4240, /*!< Status low power mode0 */ +TFA9872_BF_ISTLP1 = 0x4250, /*!< Status low power mode1 */ +TFA9872_BF_ISTLA = 0x4260, /*!< Status low noise detection */ +TFA9872_BF_ISTVDDPH = 0x4270, /*!< Status VDDP greater than VBAT */ +TFA9872_BF_ICLVDDS = 0x4400, /*!< Clear POR */ +TFA9872_BF_ICLPLLS = 0x4410, /*!< Clear PLL lock */ +TFA9872_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ +TFA9872_BF_ICLOVDS = 0x4430, /*!< Clear OVP alarm */ +TFA9872_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ +TFA9872_BF_ICLCLKS = 0x4450, /*!< Clear clocks stable */ +TFA9872_BF_ICLMTPB = 0x4460, /*!< Clear mtp busy */ +TFA9872_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ +TFA9872_BF_ICLSWS = 0x44a0, /*!< Clear amplifier engage */ +TFA9872_BF_ICLAMPS = 0x44c0, /*!< Clear enbl amp */ +TFA9872_BF_ICLAREFS = 0x44d0, /*!< Clear ref enable */ +TFA9872_BF_ICLADCCR = 0x44e0, /*!< Clear control ADC */ +TFA9872_BF_ICLBSTCU = 0x4500, /*!< Clear DCDC current limiting */ +TFA9872_BF_ICLBSTHI = 0x4510, /*!< Clear DCDC active */ +TFA9872_BF_ICLBSTOC = 0x4520, /*!< Clear DCDC OCP */ +TFA9872_BF_ICLBSTPC = 0x4530, /*!< Clear bst peakcur */ +TFA9872_BF_ICLBSTVC = 0x4540, /*!< Clear DCDC level 1x */ +TFA9872_BF_ICLBST86 = 0x4550, /*!< Clear DCDC level 1.14x */ +TFA9872_BF_ICLBST93 = 0x4560, /*!< Clear DCDC level 1.07x */ +TFA9872_BF_ICLOCPR = 0x4590, /*!< Clear ocp alarm */ +TFA9872_BF_ICLMWSRC = 0x45a0, /*!< Clear wait HW I2C settings */ +TFA9872_BF_ICLMWSMU = 0x45c0, /*!< Clear audio mute sequence */ +TFA9872_BF_ICLCLKOOR = 0x45f0, /*!< Clear flag_clk_out_of_range */ +TFA9872_BF_ICLTDMER = 0x4600, /*!< Clear tdm error */ +TFA9872_BF_ICLCLPR = 0x4620, /*!< Clear clip */ +TFA9872_BF_ICLLP0 = 0x4640, /*!< Clear low power mode0 */ +TFA9872_BF_ICLLP1 = 0x4650, /*!< Clear low power mode1 */ +TFA9872_BF_ICLLA = 0x4660, /*!< Clear low noise detection */ +TFA9872_BF_ICLVDDPH = 0x4670, /*!< Clear VDDP greater then VBAT */ +TFA9872_BF_IEVDDS = 0x4800, /*!< Enable por */ +TFA9872_BF_IEPLLS = 0x4810, /*!< Enable pll lock */ +TFA9872_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ +TFA9872_BF_IEOVDS = 0x4830, /*!< Enable OVP alarm */ +TFA9872_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ +TFA9872_BF_IECLKS = 0x4850, /*!< Enable clocks stable */ +TFA9872_BF_IEMTPB = 0x4860, /*!< Enable mtp busy */ +TFA9872_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ +TFA9872_BF_IESWS = 0x48a0, /*!< Enable amplifier engage */ +TFA9872_BF_IEAMPS = 0x48c0, /*!< Enable enbl amp */ +TFA9872_BF_IEAREFS = 0x48d0, /*!< Enable ref enable */ +TFA9872_BF_IEADCCR = 0x48e0, /*!< Enable Control ADC */ +TFA9872_BF_IEBSTCU = 0x4900, /*!< Enable DCDC current limiting */ +TFA9872_BF_IEBSTHI = 0x4910, /*!< Enable DCDC active */ +TFA9872_BF_IEBSTOC = 0x4920, /*!< Enable DCDC OCP */ +TFA9872_BF_IEBSTPC = 0x4930, /*!< Enable bst peakcur */ +TFA9872_BF_IEBSTVC = 0x4940, /*!< Enable DCDC level 1x */ +TFA9872_BF_IEBST86 = 0x4950, /*!< Enable DCDC level 1.14x */ +TFA9872_BF_IEBST93 = 0x4960, /*!< Enable DCDC level 1.07x */ +TFA9872_BF_IEOCPR = 0x4990, /*!< Enable ocp alarm */ +TFA9872_BF_IEMWSRC = 0x49a0, /*!< Enable waits HW I2C settings */ +TFA9872_BF_IEMWSMU = 0x49c0, /*!< Enable man Audio mute sequence */ +TFA9872_BF_IECLKOOR = 0x49f0, /*!< Enable flag_clk_out_of_range */ +TFA9872_BF_IETDMER = 0x4a00, /*!< Enable tdm error */ +TFA9872_BF_IECLPR = 0x4a20, /*!< Enable clip */ +TFA9872_BF_IELP0 = 0x4a40, /*!< Enable low power mode0 */ +TFA9872_BF_IELP1 = 0x4a50, /*!< Enable low power mode1 */ +TFA9872_BF_IELA = 0x4a60, /*!< Enable low noise detection */ +TFA9872_BF_IEVDDPH = 0x4a70, /*!< Enable VDDP greater tehn VBAT */ +TFA9872_BF_IPOVDDS = 0x4c00, /*!< Polarity por */ +TFA9872_BF_IPOPLLS = 0x4c10, /*!< Polarity pll lock */ +TFA9872_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ +TFA9872_BF_IPOOVDS = 0x4c30, /*!< Polarity OVP alarm */ +TFA9872_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ +TFA9872_BF_IPOCLKS = 0x4c50, /*!< Polarity clocks stable */ +TFA9872_BF_IPOMTPB = 0x4c60, /*!< Polarity mtp busy */ +TFA9872_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ +TFA9872_BF_IPOSWS = 0x4ca0, /*!< Polarity amplifier engage */ +TFA9872_BF_IPOAMPS = 0x4cc0, /*!< Polarity enbl amp */ +TFA9872_BF_IPOAREFS = 0x4cd0, /*!< Polarity ref enable */ +TFA9872_BF_IPOADCCR = 0x4ce0, /*!< Polarity Control ADC */ +TFA9872_BF_IPOBSTCU = 0x4d00, /*!< Polarity DCDC current limiting */ +TFA9872_BF_IPOBSTHI = 0x4d10, /*!< Polarity DCDC active */ +TFA9872_BF_IPOBSTOC = 0x4d20, /*!< Polarity DCDC OCP */ +TFA9872_BF_IPOBSTPC = 0x4d30, /*!< Polarity bst peakcur */ +TFA9872_BF_IPOBSTVC = 0x4d40, /*!< Polarity DCDC level 1x */ +TFA9872_BF_IPOBST86 = 0x4d50, /*!< Polarity DCDC level 1.14x */ +TFA9872_BF_IPOBST93 = 0x4d60, /*!< Polarity DCDC level 1.07x */ +TFA9872_BF_IPOOCPR = 0x4d90, /*!< Polarity ocp alarm */ +TFA9872_BF_IPOMWSRC = 0x4da0, /*!< Polarity waits HW I2C settings */ +TFA9872_BF_IPOMWSMU = 0x4dc0, /*!< Polarity man audio mute sequence */ +TFA9872_BF_IPCLKOOR = 0x4df0, /*!< Polarity flag_clk_out_of_range */ +TFA9872_BF_IPOTDMER = 0x4e00, /*!< Polarity tdm error */ +TFA9872_BF_IPOCLPR = 0x4e20, /*!< Polarity clip right */ +TFA9872_BF_IPOLP0 = 0x4e40, /*!< Polarity low power mode0 */ +TFA9872_BF_IPOLP1 = 0x4e50, /*!< Polarity low power mode1 */ +TFA9872_BF_IPOLA = 0x4e60, /*!< Polarity low noise mode */ +TFA9872_BF_IPOVDDPH = 0x4e70, /*!< Polarity VDDP greater than VBAT */ +TFA9872_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time */ +TFA9872_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ +TFA9872_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ +TFA9872_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ +TFA9872_BF_BSSBY = 0x50f0, /*!< Bypass battery safeguard */ +TFA9872_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ +TFA9872_BF_INTSMUTE = 0x5110, /*!< Soft mute HW */ +TFA9872_BF_HPFBYP = 0x5150, /*!< Bypass HPF */ +TFA9872_BF_DPSA = 0x5170, /*!< Enable DPSA */ +TFA9872_BF_CLIPCTRL = 0x5222, /*!< Clip control setting */ +TFA9872_BF_AMPGAIN = 0x5257, /*!< Amplifier gain */ +TFA9872_BF_SLOPEE = 0x52d0, /*!< Enables slope control */ +TFA9872_BF_SLOPESET = 0x52e0, /*!< Slope speed setting (bin. coded) */ +TFA9872_BF_PGAGAIN = 0x6081, /*!< PGA gain selection */ +TFA9872_BF_PGALPE = 0x60b0, /*!< Lowpass enable */ +TFA9872_BF_LPM0BYP = 0x6110, /*!< bypass low power idle mode */ +TFA9872_BF_TDMDCG = 0x6123, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ +TFA9872_BF_TDMSPKG = 0x6163, /*!< Total gain depending on INPLEV setting (channel 0) */ +TFA9872_BF_STIDLEEN = 0x61b0, /*!< enable idle feature for channel 1 */ +TFA9872_BF_LNMODE = 0x62e1, /*!< ctrl select mode */ +TFA9872_BF_LPM1MODE = 0x64e1, /*!< low power mode control */ +TFA9872_BF_LPM1DIS = 0x65c0, /*!< low power mode1 detector control */ +TFA9872_BF_TDMSRCMAP = 0x6801, /*!< tdm source mapping */ +TFA9872_BF_TDMSRCAS = 0x6821, /*!< Sensed value A */ +TFA9872_BF_TDMSRCBS = 0x6841, /*!< Sensed value B */ +TFA9872_BF_ANCSEL = 0x6881, /*!< anc input */ +TFA9872_BF_ANC1C = 0x68a0, /*!< ANC one s complement */ +TFA9872_BF_SAMMODE = 0x6901, /*!< sam enable */ +TFA9872_BF_SAMSEL = 0x6920, /*!< sam source */ +TFA9872_BF_PDMOSELH = 0x6931, /*!< pdm out value when pdm_clk is higth */ +TFA9872_BF_PDMOSELL = 0x6951, /*!< pdm out value when pdm_clk is low */ +TFA9872_BF_SAMOSEL = 0x6970, /*!< ram output on mode sam and audio */ +TFA9872_BF_LP0 = 0x6e00, /*!< low power mode 0 detection */ +TFA9872_BF_LP1 = 0x6e10, /*!< low power mode 1 detection */ +TFA9872_BF_LA = 0x6e20, /*!< low amplitude detection */ +TFA9872_BF_VDDPH = 0x6e30, /*!< vddp greater than vbat */ +TFA9872_BF_DELCURCOMP = 0x6f02, /*!< delay to allign compensation signal with current sense signal */ +TFA9872_BF_SIGCURCOMP = 0x6f40, /*!< polarity of compensation for current sense */ +TFA9872_BF_ENCURCOMP = 0x6f50, /*!< enable current sense compensation */ +TFA9872_BF_SELCLPPWM = 0x6f60, /*!< Select pwm clip flag */ +TFA9872_BF_LVLCLPPWM = 0x6f72, /*!< set the amount of pwm pulse that may be skipped before clip-flag is triggered */ +TFA9872_BF_DCVOS = 0x7002, /*!< Second boost voltage level */ +TFA9872_BF_DCMCC = 0x7033, /*!< Max coil current */ +TFA9872_BF_DCCV = 0x7071, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ +TFA9872_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ +TFA9872_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ +TFA9872_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ +TFA9872_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ +TFA9872_BF_DCVOF = 0x7402, /*!< 1st boost voltage level */ +TFA9872_BF_DCTRACK = 0x7430, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ +TFA9872_BF_DCTRIP = 0x7444, /*!< 1st Adaptive boost trip levels, effective only when DCIE is set to 1 */ +TFA9872_BF_DCHOLD = 0x7494, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ +TFA9872_BF_DCTRIP2 = 0x7534, /*!< 2nd Adaptive boost trip levels, effective only when DCIE is set to 1 */ +TFA9872_BF_DCTRIPT = 0x7584, /*!< Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ +TFA9872_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ +TFA9872_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ +TFA9872_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ +TFA9872_BF_CMTPI = 0xa350, /*!< Start copying all the data from mtp to I2C mtp registers */ +TFA9872_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ +TFA9872_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ +TFA9872_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ +TFA9872_BF_EXTTS = 0xb108, /*!< External temperature (C) */ +TFA9872_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ +TFA9872_BF_SWPROFIL = 0xee0f, /*!< Software profile data */ +TFA9872_BF_SWVSTEP = 0xef0f, /*!< Software vstep information */ +TFA9872_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ +TFA9872_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ +TFA9872_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ +TFA9872_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ +TFA9872_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ +TFA9872_BF_CUSTINFO = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ +TFA9872_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9872BfEnumList_t; +#define TFA9872_NAMETABLE static tfaBfName_t Tfa9872DatasheetNames[] = {\ +{ 0x0, "PWDN"}, /* Powerdown selection , */\ +{ 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ +{ 0x30, "AMPE"}, /* Activate Amplifier , */\ +{ 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ +{ 0x71, "INTP"}, /* Interrupt config , */\ +{ 0xb0, "BYPOCP"}, /* Bypass OCP , */\ +{ 0xc0, "TSTOCP"}, /* OCP testing control , */\ +{ 0x120, "MANSCONF"}, /* I2C configured , */\ +{ 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ +{ 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ +{ 0x1e0, "RCVNS"}, /* Noise shaper selection , */\ +{ 0x203, "AUDFS"}, /* Sample rate (fs) , */\ +{ 0x240, "INPLEV"}, /* TDM output attenuation , */\ +{ 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ +{ 0x2b0, "BYPHVBF"}, /* Bypass HVBAT filter , */\ +{ 0x30f, "REV"}, /* Revision info , */\ +{ 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ +{ 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ +{ 0x510, "SSE"}, /* Enable speaker path , */\ +{ 0x530, "VSE"}, /* Voltage sense , */\ +{ 0x550, "CSE"}, /* Current sense , */\ +{ 0x560, "SSPDME"}, /* Sub-system PDM , */\ +{ 0x580, "PGAE"}, /* Enable PGA chop clock , */\ +{ 0x590, "SSTDME"}, /* Sub-system TDM , */\ +{ 0x5a0, "SSPBSTE"}, /* Sub-system boost , */\ +{ 0x5b0, "SSADCE"}, /* Sub-system ADC , */\ +{ 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ +{ 0xd18, "STGAIN"}, /* Side tone gain , */\ +{ 0xda0, "STSMUTE"}, /* Side tone soft mute , */\ +{ 0xdb0, "ST1C"}, /* side tone one s complement , */\ +{ 0x1000, "VDDS"}, /* POR , */\ +{ 0x1010, "PLLS"}, /* PLL lock , */\ +{ 0x1020, "OTDS"}, /* OTP alarm , */\ +{ 0x1030, "OVDS"}, /* OVP alarm , */\ +{ 0x1040, "UVDS"}, /* UVP alarm , */\ +{ 0x1050, "CLKS"}, /* Clocks stable , */\ +{ 0x1060, "MTPB"}, /* MTP busy , */\ +{ 0x1070, "NOCLK"}, /* Lost clock , */\ +{ 0x10a0, "SWS"}, /* Amplifier engage , */\ +{ 0x10c0, "AMPS"}, /* Amplifier enable , */\ +{ 0x10d0, "AREFS"}, /* References enable , */\ +{ 0x10e0, "ADCCR"}, /* Control ADC , */\ +{ 0x1100, "DCIL"}, /* DCDC current limiting , */\ +{ 0x1110, "DCDCA"}, /* DCDC active , */\ +{ 0x1120, "DCOCPOK"}, /* DCDC OCP nmos , */\ +{ 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ +{ 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ +{ 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ +{ 0x1170, "STMUTEB"}, /* side tone (un)mute busy , */\ +{ 0x1180, "STMUTE"}, /* side tone mute state , */\ +{ 0x1190, "TDMLUTER"}, /* TDM LUT error , */\ +{ 0x11a2, "TDMSTAT"}, /* TDM status bits , */\ +{ 0x11d0, "TDMERR"}, /* TDM error , */\ +{ 0x1300, "OCPOAP"}, /* OCPOK pmos A , */\ +{ 0x1310, "OCPOAN"}, /* OCPOK nmos A , */\ +{ 0x1320, "OCPOBP"}, /* OCPOK pmos B , */\ +{ 0x1330, "OCPOBN"}, /* OCPOK nmos B , */\ +{ 0x1340, "CLIPAH"}, /* Clipping A to Vddp , */\ +{ 0x1350, "CLIPAL"}, /* Clipping A to gnd , */\ +{ 0x1360, "CLIPBH"}, /* Clipping B to Vddp , */\ +{ 0x1370, "CLIPBL"}, /* Clipping B to gnd , */\ +{ 0x1380, "OCDS"}, /* OCP amplifier , */\ +{ 0x1390, "CLIPS"}, /* Amplifier clipping , */\ +{ 0x13a0, "OCPOKMC"}, /* OCPOK MICVDD , */\ +{ 0x13b0, "MANALARM"}, /* Alarm state , */\ +{ 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ +{ 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ +{ 0x13f0, "MANOPER"}, /* Operating state , */\ +{ 0x1420, "CLKOOR"}, /* External clock status , */\ +{ 0x1433, "MANSTATE"}, /* Device manager status , */\ +{ 0x1471, "DCMODE"}, /* DCDC mode status bits , */\ +{ 0x1509, "BATS"}, /* Battery voltage (V) , */\ +{ 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ +{ 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/9.5 V) , */\ +{ 0x2040, "TDME"}, /* Enable interface , */\ +{ 0x2050, "TDMMODE"}, /* Slave/master , */\ +{ 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ +{ 0x2073, "TDMFSLN"}, /* FS length (master mode only) , */\ +{ 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ +{ 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ +{ 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ +{ 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ +{ 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ +{ 0x21e0, "TDMDEL"}, /* data delay to FS , */\ +{ 0x21f0, "TDMADJ"}, /* data adjustment , */\ +{ 0x2201, "TDMOOMP"}, /* Received audio compression , */\ +{ 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ +{ 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ +{ 0x2291, "TDMTXUS0"}, /* Format unused slots DATAO , */\ +{ 0x2300, "TDMSPKE"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ +{ 0x2310, "TDMDCE"}, /* Control audio tdm channel in 1 (dcdc) , */\ +{ 0x2330, "TDMCSE"}, /* current sense vbat temperature and vddp feedback , */\ +{ 0x2340, "TDMVSE"}, /* Voltage sense vbat temperature and vddp feedback , */\ +{ 0x2603, "TDMSPKS"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ +{ 0x2643, "TDMDCS"}, /* tdm slot for sink 1 (dcdc) , */\ +{ 0x26c3, "TDMCSS"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ +{ 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ +{ 0x3111, "PDMSTSEL"}, /* Side tone input , */\ +{ 0x4000, "ISTVDDS"}, /* Status POR , */\ +{ 0x4010, "ISTPLLS"}, /* Status PLL lock , */\ +{ 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ +{ 0x4030, "ISTOVDS"}, /* Status OVP alarm , */\ +{ 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ +{ 0x4050, "ISTCLKS"}, /* Status clocks stable , */\ +{ 0x4060, "ISTMTPB"}, /* Status MTP busy , */\ +{ 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ +{ 0x40a0, "ISTSWS"}, /* Status amplifier engage , */\ +{ 0x40c0, "ISTAMPS"}, /* Status amplifier enable , */\ +{ 0x40d0, "ISTAREFS"}, /* Status Ref enable , */\ +{ 0x40e0, "ISTADCCR"}, /* Status Control ADC , */\ +{ 0x4100, "ISTBSTCU"}, /* Status DCDC current limiting , */\ +{ 0x4110, "ISTBSTHI"}, /* Status DCDC active , */\ +{ 0x4120, "ISTBSTOC"}, /* Status DCDC OCP , */\ +{ 0x4130, "ISTBSTPKCUR"}, /* Status bst peakcur , */\ +{ 0x4140, "ISTBSTVC"}, /* Status DCDC level 1x , */\ +{ 0x4150, "ISTBST86"}, /* Status DCDC level 1.14x , */\ +{ 0x4160, "ISTBST93"}, /* Status DCDC level 1.07x , */\ +{ 0x4190, "ISTOCPR"}, /* Status ocp alarm , */\ +{ 0x41a0, "ISTMWSRC"}, /* Status Waits HW I2C settings , */\ +{ 0x41c0, "ISTMWSMU"}, /* Status Audio mute sequence , */\ +{ 0x41f0, "ISTCLKOOR"}, /* Status flag_clk_out_of_range , */\ +{ 0x4200, "ISTTDMER"}, /* Status tdm error , */\ +{ 0x4220, "ISTCLPR"}, /* Status clip , */\ +{ 0x4240, "ISTLP0"}, /* Status low power mode0 , */\ +{ 0x4250, "ISTLP1"}, /* Status low power mode1 , */\ +{ 0x4260, "ISTLA"}, /* Status low noise detection , */\ +{ 0x4270, "ISTVDDPH"}, /* Status VDDP greater than VBAT , */\ +{ 0x4400, "ICLVDDS"}, /* Clear POR , */\ +{ 0x4410, "ICLPLLS"}, /* Clear PLL lock , */\ +{ 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ +{ 0x4430, "ICLOVDS"}, /* Clear OVP alarm , */\ +{ 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ +{ 0x4450, "ICLCLKS"}, /* Clear clocks stable , */\ +{ 0x4460, "ICLMTPB"}, /* Clear mtp busy , */\ +{ 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ +{ 0x44a0, "ICLSWS"}, /* Clear amplifier engage , */\ +{ 0x44c0, "ICLAMPS"}, /* Clear enbl amp , */\ +{ 0x44d0, "ICLAREFS"}, /* Clear ref enable , */\ +{ 0x44e0, "ICLADCCR"}, /* Clear control ADC , */\ +{ 0x4500, "ICLBSTCU"}, /* Clear DCDC current limiting , */\ +{ 0x4510, "ICLBSTHI"}, /* Clear DCDC active , */\ +{ 0x4520, "ICLBSTOC"}, /* Clear DCDC OCP , */\ +{ 0x4530, "ICLBSTPC"}, /* Clear bst peakcur , */\ +{ 0x4540, "ICLBSTVC"}, /* Clear DCDC level 1x , */\ +{ 0x4550, "ICLBST86"}, /* Clear DCDC level 1.14x , */\ +{ 0x4560, "ICLBST93"}, /* Clear DCDC level 1.07x , */\ +{ 0x4590, "ICLOCPR"}, /* Clear ocp alarm , */\ +{ 0x45a0, "ICLMWSRC"}, /* Clear wait HW I2C settings , */\ +{ 0x45c0, "ICLMWSMU"}, /* Clear audio mute sequence , */\ +{ 0x45f0, "ICLCLKOOR"}, /* Clear flag_clk_out_of_range , */\ +{ 0x4600, "ICLTDMER"}, /* Clear tdm error , */\ +{ 0x4620, "ICLCLPR"}, /* Clear clip , */\ +{ 0x4640, "ICLLP0"}, /* Clear low power mode0 , */\ +{ 0x4650, "ICLLP1"}, /* Clear low power mode1 , */\ +{ 0x4660, "ICLLA"}, /* Clear low noise detection , */\ +{ 0x4670, "ICLVDDPH"}, /* Clear VDDP greater then VBAT , */\ +{ 0x4800, "IEVDDS"}, /* Enable por , */\ +{ 0x4810, "IEPLLS"}, /* Enable pll lock , */\ +{ 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ +{ 0x4830, "IEOVDS"}, /* Enable OVP alarm , */\ +{ 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ +{ 0x4850, "IECLKS"}, /* Enable clocks stable , */\ +{ 0x4860, "IEMTPB"}, /* Enable mtp busy , */\ +{ 0x4870, "IENOCLK"}, /* Enable lost clk , */\ +{ 0x48a0, "IESWS"}, /* Enable amplifier engage , */\ +{ 0x48c0, "IEAMPS"}, /* Enable enbl amp , */\ +{ 0x48d0, "IEAREFS"}, /* Enable ref enable , */\ +{ 0x48e0, "IEADCCR"}, /* Enable Control ADC , */\ +{ 0x4900, "IEBSTCU"}, /* Enable DCDC current limiting , */\ +{ 0x4910, "IEBSTHI"}, /* Enable DCDC active , */\ +{ 0x4920, "IEBSTOC"}, /* Enable DCDC OCP , */\ +{ 0x4930, "IEBSTPC"}, /* Enable bst peakcur , */\ +{ 0x4940, "IEBSTVC"}, /* Enable DCDC level 1x , */\ +{ 0x4950, "IEBST86"}, /* Enable DCDC level 1.14x , */\ +{ 0x4960, "IEBST93"}, /* Enable DCDC level 1.07x , */\ +{ 0x4990, "IEOCPR"}, /* Enable ocp alarm , */\ +{ 0x49a0, "IEMWSRC"}, /* Enable waits HW I2C settings , */\ +{ 0x49c0, "IEMWSMU"}, /* Enable man Audio mute sequence , */\ +{ 0x49f0, "IECLKOOR"}, /* Enable flag_clk_out_of_range , */\ +{ 0x4a00, "IETDMER"}, /* Enable tdm error , */\ +{ 0x4a20, "IECLPR"}, /* Enable clip , */\ +{ 0x4a40, "IELP0"}, /* Enable low power mode0 , */\ +{ 0x4a50, "IELP1"}, /* Enable low power mode1 , */\ +{ 0x4a60, "IELA"}, /* Enable low noise detection , */\ +{ 0x4a70, "IEVDDPH"}, /* Enable VDDP greater tehn VBAT , */\ +{ 0x4c00, "IPOVDDS"}, /* Polarity por , */\ +{ 0x4c10, "IPOPLLS"}, /* Polarity pll lock , */\ +{ 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ +{ 0x4c30, "IPOOVDS"}, /* Polarity OVP alarm , */\ +{ 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ +{ 0x4c50, "IPOCLKS"}, /* Polarity clocks stable , */\ +{ 0x4c60, "IPOMTPB"}, /* Polarity mtp busy , */\ +{ 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ +{ 0x4ca0, "IPOSWS"}, /* Polarity amplifier engage , */\ +{ 0x4cc0, "IPOAMPS"}, /* Polarity enbl amp , */\ +{ 0x4cd0, "IPOAREFS"}, /* Polarity ref enable , */\ +{ 0x4ce0, "IPOADCCR"}, /* Polarity Control ADC , */\ +{ 0x4d00, "IPOBSTCU"}, /* Polarity DCDC current limiting , */\ +{ 0x4d10, "IPOBSTHI"}, /* Polarity DCDC active , */\ +{ 0x4d20, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ +{ 0x4d30, "IPOBSTPC"}, /* Polarity bst peakcur , */\ +{ 0x4d40, "IPOBSTVC"}, /* Polarity DCDC level 1x , */\ +{ 0x4d50, "IPOBST86"}, /* Polarity DCDC level 1.14x , */\ +{ 0x4d60, "IPOBST93"}, /* Polarity DCDC level 1.07x , */\ +{ 0x4d90, "IPOOCPR"}, /* Polarity ocp alarm , */\ +{ 0x4da0, "IPOMWSRC"}, /* Polarity waits HW I2C settings , */\ +{ 0x4dc0, "IPOMWSMU"}, /* Polarity man audio mute sequence , */\ +{ 0x4df0, "IPCLKOOR"}, /* Polarity flag_clk_out_of_range , */\ +{ 0x4e00, "IPOTDMER"}, /* Polarity tdm error , */\ +{ 0x4e20, "IPOCLPR"}, /* Polarity clip right , */\ +{ 0x4e40, "IPOLP0"}, /* Polarity low power mode0 , */\ +{ 0x4e50, "IPOLP1"}, /* Polarity low power mode1 , */\ +{ 0x4e60, "IPOLA"}, /* Polarity low noise mode , */\ +{ 0x4e70, "IPOVDDPH"}, /* Polarity VDDP greater than VBAT , */\ +{ 0x5001, "BSSCR"}, /* Battery Safeguard attack time , */\ +{ 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ +{ 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ +{ 0x50e0, "BSSR"}, /* Battery voltage read out , */\ +{ 0x50f0, "BSSBY"}, /* Bypass battery safeguard , */\ +{ 0x5100, "BSSS"}, /* Vbat prot steepness , */\ +{ 0x5110, "INTSMUTE"}, /* Soft mute HW , */\ +{ 0x5150, "HPFBYP"}, /* Bypass HPF , */\ +{ 0x5170, "DPSA"}, /* Enable DPSA , */\ +{ 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ +{ 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ +{ 0x52d0, "SLOPEE"}, /* Enables slope control , */\ +{ 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ +{ 0x6081, "PGAGAIN"}, /* PGA gain selection , */\ +{ 0x60b0, "PGALPE"}, /* Lowpass enable , */\ +{ 0x6110, "LPM0BYP"}, /* bypass low power idle mode , */\ +{ 0x6123, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ +{ 0x6163, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ +{ 0x61b0, "STIDLEEN"}, /* enable idle feature for channel 1 , */\ +{ 0x62e1, "LNMODE"}, /* ctrl select mode , */\ +{ 0x64e1, "LPM1MODE"}, /* low power mode control , */\ +{ 0x65c0, "LPM1DIS"}, /* low power mode1 detector control , */\ +{ 0x6801, "TDMSRCMAP"}, /* tdm source mapping , */\ +{ 0x6821, "TDMSRCAS"}, /* Sensed value A , */\ +{ 0x6841, "TDMSRCBS"}, /* Sensed value B , */\ +{ 0x6881, "ANCSEL"}, /* anc input , */\ +{ 0x68a0, "ANC1C"}, /* ANC one s complement , */\ +{ 0x6901, "SAMMODE"}, /* sam enable , */\ +{ 0x6920, "SAMSEL"}, /* sam source , */\ +{ 0x6931, "PDMOSELH"}, /* pdm out value when pdm_clk is higth , */\ +{ 0x6951, "PDMOSELL"}, /* pdm out value when pdm_clk is low , */\ +{ 0x6970, "SAMOSEL"}, /* ram output on mode sam and audio , */\ +{ 0x6e00, "LP0"}, /* low power mode 0 detection , */\ +{ 0x6e10, "LP1"}, /* low power mode 1 detection , */\ +{ 0x6e20, "LA"}, /* low amplitude detection , */\ +{ 0x6e30, "VDDPH"}, /* vddp greater than vbat , */\ +{ 0x6f02, "DELCURCOMP"}, /* delay to allign compensation signal with current sense signal, */\ +{ 0x6f40, "SIGCURCOMP"}, /* polarity of compensation for current sense , */\ +{ 0x6f50, "ENCURCOMP"}, /* enable current sense compensation , */\ +{ 0x6f60, "SELCLPPWM"}, /* Select pwm clip flag , */\ +{ 0x6f72, "LVLCLPPWM"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ +{ 0x7002, "DCVOS"}, /* Second boost voltage level , */\ +{ 0x7033, "DCMCC"}, /* Max coil current , */\ +{ 0x7071, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ +{ 0x7090, "DCIE"}, /* Adaptive boost mode , */\ +{ 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ +{ 0x70e0, "DCDIS"}, /* DCDC on/off , */\ +{ 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ +{ 0x7402, "DCVOF"}, /* 1st boost voltage level , */\ +{ 0x7430, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ +{ 0x7444, "DCTRIP"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7494, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ +{ 0x7534, "DCTRIP2"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7584, "DCTRIPT"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ +{ 0xa107, "MTPK"}, /* MTP KEY2 register , */\ +{ 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ +{ 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ +{ 0xa350, "CMTPI"}, /* Start copying all the data from mtp to I2C mtp registers, */\ +{ 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ +{ 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ +{ 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ +{ 0xb108, "EXTTS"}, /* External temperature (C) , */\ +{ 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ +{ 0xee0f, "SWPROFIL"}, /* Software profile data , */\ +{ 0xef0f, "SWVSTEP"}, /* Software vstep information , */\ +{ 0xf000, "MTPOTC"}, /* Calibration schedule , */\ +{ 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ +{ 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ +{ 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ +{ 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ +{ 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ +{ 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9872_BITNAMETABLE static tfaBfName_t Tfa9872BitNames[] = {\ +{ 0x0, "powerdown"}, /* Powerdown selection , */\ +{ 0x10, "reset"}, /* I2C Reset - Auto clear , */\ +{ 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ +{ 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ +{ 0x71, "int_pad_io"}, /* Interrupt config , */\ +{ 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ +{ 0xc0, "test_ocp"}, /* OCP testing control , */\ +{ 0x120, "src_set_configured"}, /* I2C configured , */\ +{ 0x140, "enbl_osc1m_auto_off"}, /* Internal osc off at PWDN , */\ +{ 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ +{ 0x203, "audio_fs"}, /* Sample rate (fs) , */\ +{ 0x240, "input_level"}, /* TDM output attenuation , */\ +{ 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ +{ 0x2b0, "bypass_hvbat_filter"}, /* Bypass HVBAT filter , */\ +{ 0x2d0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ +{ 0x30f, "device_rev"}, /* Revision info , */\ +{ 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ +{ 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ +{ 0x510, "enbl_spkr_ss"}, /* Enable speaker path , */\ +{ 0x530, "enbl_volsense"}, /* Voltage sense , */\ +{ 0x550, "enbl_cursense"}, /* Current sense , */\ +{ 0x560, "enbl_pdm_ss"}, /* Sub-system PDM , */\ +{ 0x580, "enbl_pga_chop"}, /* Enable PGA chop clock , */\ +{ 0x590, "enbl_tdm_ss"}, /* Sub-system TDM , */\ +{ 0x5a0, "enbl_bst_ss"}, /* Sub-system boost , */\ +{ 0x5b0, "enbl_adc_ss"}, /* Sub-system ADC , */\ +{ 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ +{ 0xd18, "side_tone_gain"}, /* Side tone gain , */\ +{ 0xda0, "mute_side_tone"}, /* Side tone soft mute , */\ +{ 0xdb0, "side_tone_1scomplement"}, /* side tone one s complement , */\ +{ 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ +{ 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ +{ 0x1000, "flag_por"}, /* POR , */\ +{ 0x1010, "flag_pll_lock"}, /* PLL lock , */\ +{ 0x1020, "flag_otpok"}, /* OTP alarm , */\ +{ 0x1030, "flag_ovpok"}, /* OVP alarm , */\ +{ 0x1040, "flag_uvpok"}, /* UVP alarm , */\ +{ 0x1050, "flag_clocks_stable"}, /* Clocks stable , */\ +{ 0x1060, "flag_mtp_busy"}, /* MTP busy , */\ +{ 0x1070, "flag_lost_clk"}, /* Lost clock , */\ +{ 0x10a0, "flag_engage"}, /* Amplifier engage , */\ +{ 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ +{ 0x10d0, "flag_enbl_ref"}, /* References enable , */\ +{ 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ +{ 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ +{ 0x1110, "flag_bst_hiz"}, /* DCDC active , */\ +{ 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos , */\ +{ 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ +{ 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ +{ 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ +{ 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ +{ 0x1170, "flag_soft_mute_busy"}, /* side tone (un)mute busy , */\ +{ 0x1180, "flag_soft_mute_state"}, /* side tone mute state , */\ +{ 0x1190, "flag_tdm_lut_error"}, /* TDM LUT error , */\ +{ 0x11a2, "flag_tdm_status"}, /* TDM status bits , */\ +{ 0x11d0, "flag_tdm_error"}, /* TDM error , */\ +{ 0x1300, "flag_ocpokap"}, /* OCPOK pmos A , */\ +{ 0x1310, "flag_ocpokan"}, /* OCPOK nmos A , */\ +{ 0x1320, "flag_ocpokbp"}, /* OCPOK pmos B , */\ +{ 0x1330, "flag_ocpokbn"}, /* OCPOK nmos B , */\ +{ 0x1340, "flag_clipa_high"}, /* Clipping A to Vddp , */\ +{ 0x1350, "flag_clipa_low"}, /* Clipping A to gnd , */\ +{ 0x1360, "flag_clipb_high"}, /* Clipping B to Vddp , */\ +{ 0x1370, "flag_clipb_low"}, /* Clipping B to gnd , */\ +{ 0x1380, "flag_ocp_alarm"}, /* OCP amplifier , */\ +{ 0x1390, "flag_clip"}, /* Amplifier clipping , */\ +{ 0x13b0, "flag_man_alarm_state"}, /* Alarm state , */\ +{ 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ +{ 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ +{ 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ +{ 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ +{ 0x1433, "man_state"}, /* Device manager status , */\ +{ 0x1471, "status_bst_mode"}, /* DCDC mode status bits , */\ +{ 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ +{ 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ +{ 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/9.5 V) , */\ +{ 0x2040, "tdm_enable"}, /* Enable interface , */\ +{ 0x2050, "tdm_mode"}, /* Slave/master , */\ +{ 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ +{ 0x2073, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ +{ 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ +{ 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ +{ 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ +{ 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ +{ 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ +{ 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ +{ 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ +{ 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ +{ 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ +{ 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ +{ 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots DATAO , */\ +{ 0x2300, "tdm_sink0_enable"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ +{ 0x2310, "tdm_sink1_enable"}, /* Control audio tdm channel in 1 (dcdc) , */\ +{ 0x2330, "tdm_source0_enable"}, /* current sense vbat temperature and vddp feedback , */\ +{ 0x2340, "tdm_source1_enable"}, /* Voltage sense vbat temperature and vddp feedback , */\ +{ 0x2603, "tdm_sink0_slot"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ +{ 0x2643, "tdm_sink1_slot"}, /* tdm slot for sink 1 (dcdc) , */\ +{ 0x26c3, "tdm_source0_slot"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ +{ 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ +{ 0x3111, "pdm_side_tone_sel"}, /* Side tone input , */\ +{ 0x3201, "pdm_nbck"}, /* PDM BCK/Fs ratio , */\ +{ 0x4000, "int_out_flag_por"}, /* Status POR , */\ +{ 0x4010, "int_out_flag_pll_lock"}, /* Status PLL lock , */\ +{ 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ +{ 0x4030, "int_out_flag_ovpok"}, /* Status OVP alarm , */\ +{ 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ +{ 0x4050, "int_out_flag_clocks_stable"}, /* Status clocks stable , */\ +{ 0x4060, "int_out_flag_mtp_busy"}, /* Status MTP busy , */\ +{ 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ +{ 0x40a0, "int_out_flag_engage"}, /* Status amplifier engage , */\ +{ 0x40c0, "int_out_flag_enbl_amp"}, /* Status amplifier enable , */\ +{ 0x40d0, "int_out_flag_enbl_ref"}, /* Status Ref enable , */\ +{ 0x40e0, "int_out_flag_adc10_ready"}, /* Status Control ADC , */\ +{ 0x4100, "int_out_flag_bst_bstcur"}, /* Status DCDC current limiting , */\ +{ 0x4110, "int_out_flag_bst_hiz"}, /* Status DCDC active , */\ +{ 0x4120, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ +{ 0x4130, "int_out_flag_bst_peakcur"}, /* Status bst peakcur , */\ +{ 0x4140, "int_out_flag_bst_voutcomp"}, /* Status DCDC level 1x , */\ +{ 0x4150, "int_out_flag_bst_voutcomp86"}, /* Status DCDC level 1.14x , */\ +{ 0x4160, "int_out_flag_bst_voutcomp93"}, /* Status DCDC level 1.07x , */\ +{ 0x4190, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ +{ 0x41a0, "int_out_flag_man_wait_src_settings"}, /* Status Waits HW I2C settings , */\ +{ 0x41c0, "int_out_flag_man_start_mute_audio"}, /* Status Audio mute sequence , */\ +{ 0x41f0, "int_out_flag_clk_out_of_range"}, /* Status flag_clk_out_of_range , */\ +{ 0x4200, "int_out_flag_tdm_error"}, /* Status tdm error , */\ +{ 0x4220, "int_out_flag_clip"}, /* Status clip , */\ +{ 0x4240, "int_out_flag_lp_detect_mode0"}, /* Status low power mode0 , */\ +{ 0x4250, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 , */\ +{ 0x4260, "int_out_flag_low_amplitude"}, /* Status low noise detection , */\ +{ 0x4270, "int_out_flag_vddp_gt_vbat"}, /* Status VDDP greater than VBAT , */\ +{ 0x4400, "int_in_flag_por"}, /* Clear POR , */\ +{ 0x4410, "int_in_flag_pll_lock"}, /* Clear PLL lock , */\ +{ 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ +{ 0x4430, "int_in_flag_ovpok"}, /* Clear OVP alarm , */\ +{ 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ +{ 0x4450, "int_in_flag_clocks_stable"}, /* Clear clocks stable , */\ +{ 0x4460, "int_in_flag_mtp_busy"}, /* Clear mtp busy , */\ +{ 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ +{ 0x44a0, "int_in_flag_engage"}, /* Clear amplifier engage , */\ +{ 0x44c0, "int_in_flag_enbl_amp"}, /* Clear enbl amp , */\ +{ 0x44d0, "int_in_flag_enbl_ref"}, /* Clear ref enable , */\ +{ 0x44e0, "int_in_flag_adc10_ready"}, /* Clear control ADC , */\ +{ 0x4500, "int_in_flag_bst_bstcur"}, /* Clear DCDC current limiting , */\ +{ 0x4510, "int_in_flag_bst_hiz"}, /* Clear DCDC active , */\ +{ 0x4520, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ +{ 0x4530, "int_in_flag_bst_peakcur"}, /* Clear bst peakcur , */\ +{ 0x4540, "int_in_flag_bst_voutcomp"}, /* Clear DCDC level 1x , */\ +{ 0x4550, "int_in_flag_bst_voutcomp86"}, /* Clear DCDC level 1.14x , */\ +{ 0x4560, "int_in_flag_bst_voutcomp93"}, /* Clear DCDC level 1.07x , */\ +{ 0x4590, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ +{ 0x45a0, "int_in_flag_man_wait_src_settings"}, /* Clear wait HW I2C settings , */\ +{ 0x45c0, "int_in_flag_man_start_mute_audio"}, /* Clear audio mute sequence , */\ +{ 0x45f0, "int_in_flag_clk_out_of_range"}, /* Clear flag_clk_out_of_range , */\ +{ 0x4600, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ +{ 0x4620, "int_in_flag_clip"}, /* Clear clip , */\ +{ 0x4640, "int_in_flag_lp_detect_mode0"}, /* Clear low power mode0 , */\ +{ 0x4650, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 , */\ +{ 0x4660, "int_in_flag_low_amplitude"}, /* Clear low noise detection , */\ +{ 0x4670, "int_in_flag_vddp_gt_vbat"}, /* Clear VDDP greater then VBAT , */\ +{ 0x4800, "int_enable_flag_por"}, /* Enable por , */\ +{ 0x4810, "int_enable_flag_pll_lock"}, /* Enable pll lock , */\ +{ 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ +{ 0x4830, "int_enable_flag_ovpok"}, /* Enable OVP alarm , */\ +{ 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ +{ 0x4850, "int_enable_flag_clocks_stable"}, /* Enable clocks stable , */\ +{ 0x4860, "int_enable_flag_mtp_busy"}, /* Enable mtp busy , */\ +{ 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ +{ 0x48a0, "int_enable_flag_engage"}, /* Enable amplifier engage , */\ +{ 0x48c0, "int_enable_flag_enbl_amp"}, /* Enable enbl amp , */\ +{ 0x48d0, "int_enable_flag_enbl_ref"}, /* Enable ref enable , */\ +{ 0x48e0, "int_enable_flag_adc10_ready"}, /* Enable Control ADC , */\ +{ 0x4900, "int_enable_flag_bst_bstcur"}, /* Enable DCDC current limiting , */\ +{ 0x4910, "int_enable_flag_bst_hiz"}, /* Enable DCDC active , */\ +{ 0x4920, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ +{ 0x4930, "int_enable_flag_bst_peakcur"}, /* Enable bst peakcur , */\ +{ 0x4940, "int_enable_flag_bst_voutcomp"}, /* Enable DCDC level 1x , */\ +{ 0x4950, "int_enable_flag_bst_voutcomp86"}, /* Enable DCDC level 1.14x , */\ +{ 0x4960, "int_enable_flag_bst_voutcomp93"}, /* Enable DCDC level 1.07x , */\ +{ 0x4990, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ +{ 0x49a0, "int_enable_flag_man_wait_src_settings"}, /* Enable waits HW I2C settings , */\ +{ 0x49c0, "int_enable_flag_man_start_mute_audio"}, /* Enable man Audio mute sequence , */\ +{ 0x49f0, "int_enable_flag_clk_out_of_range"}, /* Enable flag_clk_out_of_range , */\ +{ 0x4a00, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ +{ 0x4a20, "int_enable_flag_clip"}, /* Enable clip , */\ +{ 0x4a40, "int_enable_flag_lp_detect_mode0"}, /* Enable low power mode0 , */\ +{ 0x4a50, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 , */\ +{ 0x4a60, "int_enable_flag_low_amplitude"}, /* Enable low noise detection , */\ +{ 0x4a70, "int_enable_flag_vddp_gt_vbat"}, /* Enable VDDP greater tehn VBAT , */\ +{ 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ +{ 0x4c10, "int_polarity_flag_pll_lock"}, /* Polarity pll lock , */\ +{ 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ +{ 0x4c30, "int_polarity_flag_ovpok"}, /* Polarity OVP alarm , */\ +{ 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ +{ 0x4c50, "int_polarity_flag_clocks_stable"}, /* Polarity clocks stable , */\ +{ 0x4c60, "int_polarity_flag_mtp_busy"}, /* Polarity mtp busy , */\ +{ 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ +{ 0x4ca0, "int_polarity_flag_engage"}, /* Polarity amplifier engage , */\ +{ 0x4cc0, "int_polarity_flag_enbl_amp"}, /* Polarity enbl amp , */\ +{ 0x4cd0, "int_polarity_flag_enbl_ref"}, /* Polarity ref enable , */\ +{ 0x4ce0, "int_polarity_flag_adc10_ready"}, /* Polarity Control ADC , */\ +{ 0x4d00, "int_polarity_flag_bst_bstcur"}, /* Polarity DCDC current limiting , */\ +{ 0x4d10, "int_polarity_flag_bst_hiz"}, /* Polarity DCDC active , */\ +{ 0x4d20, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ +{ 0x4d30, "int_polarity_flag_bst_peakcur"}, /* Polarity bst peakcur , */\ +{ 0x4d40, "int_polarity_flag_bst_voutcomp"}, /* Polarity DCDC level 1x , */\ +{ 0x4d50, "int_polarity_flag_bst_voutcomp86"}, /* Polarity DCDC level 1.14x , */\ +{ 0x4d60, "int_polarity_flag_bst_voutcomp93"}, /* Polarity DCDC level 1.07x , */\ +{ 0x4d90, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ +{ 0x4da0, "int_polarity_flag_man_wait_src_settings"}, /* Polarity waits HW I2C settings , */\ +{ 0x4dc0, "int_polarity_flag_man_start_mute_audio"}, /* Polarity man audio mute sequence , */\ +{ 0x4df0, "int_polarity_flag_clk_out_of_range"}, /* Polarity flag_clk_out_of_range , */\ +{ 0x4e00, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ +{ 0x4e20, "int_polarity_flag_clip"}, /* Polarity clip right , */\ +{ 0x4e40, "int_polarity_flag_lp_detect_mode0"}, /* Polarity low power mode0 , */\ +{ 0x4e50, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 , */\ +{ 0x4e60, "int_polarity_flag_low_amplitude"}, /* Polarity low noise mode , */\ +{ 0x4e70, "int_polarity_flag_vddp_gt_vbat"}, /* Polarity VDDP greater than VBAT , */\ +{ 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time , */\ +{ 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ +{ 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ +{ 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ +{ 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ +{ 0x50f0, "bypass_clipper"}, /* Bypass battery safeguard , */\ +{ 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ +{ 0x5110, "soft_mute"}, /* Soft mute HW , */\ +{ 0x5150, "bypass_hp"}, /* Bypass HPF , */\ +{ 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ +{ 0x5222, "ctrl_cc"}, /* Clip control setting , */\ +{ 0x5257, "gain"}, /* Amplifier gain , */\ +{ 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ +{ 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ +{ 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ +{ 0x5321, "dpsa_release"}, /* DPSA Release time , */\ +{ 0x5340, "clipfast"}, /* Clock selection for HW clipper for Battery Safeguard, */\ +{ 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ +{ 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ +{ 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ +{ 0x5420, "fb_hz"}, /* Feedback resistor set to high ohmic , */\ +{ 0x5430, "icomp_engage"}, /* Engage of icomp , */\ +{ 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ +{ 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ +{ 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ +{ 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ +{ 0x5582, "dpsa_drive"}, /* Drive setting (bin. coded) , */\ +{ 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ +{ 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ +{ 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ +{ 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ +{ 0x5820, "pwm_shape"}, /* PWM shape , */\ +{ 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ +{ 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ +{ 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ +{ 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ +{ 0x6081, "pga_gain_set"}, /* PGA gain selection , */\ +{ 0x60b0, "pga_lowpass_enable"}, /* Lowpass enable , */\ +{ 0x60c0, "pga_pwr_enable"}, /* Power enable, directcontrol mode only , */\ +{ 0x60d0, "pga_switch_enable"}, /* Switch enable, directcontrol mode only , */\ +{ 0x60e0, "pga_switch_aux_enable"}, /* Switch enable aux, directcontrol mode only , */\ +{ 0x6100, "force_idle"}, /* force low power in idle mode , */\ +{ 0x6110, "bypass_idle"}, /* bypass low power idle mode , */\ +{ 0x6123, "ctrl_attl"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ +{ 0x6163, "ctrl_attr"}, /* Total gain depending on INPLEV setting (channel 0), */\ +{ 0x61a0, "idle_cnt"}, /* idle counter , */\ +{ 0x61b0, "enbl_idle_ch1"}, /* enable idle feature for channel 1 , */\ +{ 0x6265, "zero_lvl"}, /* low noise gain switch zero trigger level , */\ +{ 0x62c1, "ctrl_fb_classd"}, /* class D gain ctrl_fb_50k ctrl_fb_100k , */\ +{ 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ +{ 0x6305, "threshold_lvl"}, /* low noise gain switch trigger level , */\ +{ 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ +{ 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ +{ 0x6465, "lpm1_zero_lvl"}, /* low power mode1 zero crossing detection level , */\ +{ 0x64e1, "lpm1_mode"}, /* low power mode control , */\ +{ 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 amplitude trigger level , */\ +{ 0x6565, "lpm1_hold_time"}, /* low power mode1 detector ctrl hold time before low audio is reckoned to be low audio, */\ +{ 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ +{ 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ +{ 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ +{ 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ +{ 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ +{ 0x6700, "enbl_minion"}, /* Enables minion (small) power stage , */\ +{ 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ +{ 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtred vs unfiltered compare , */\ +{ 0x6801, "tdm_source_mapping"}, /* tdm source mapping , */\ +{ 0x6821, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ +{ 0x6841, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ +{ 0x6881, "pdm_anc_sel"}, /* anc input , */\ +{ 0x68a0, "anc_1scomplement"}, /* ANC one s complement , */\ +{ 0x6901, "sam_mode"}, /* sam enable , */\ +{ 0x6920, "sam_src"}, /* sam source , */\ +{ 0x6931, "pdmdat_h_sel"}, /* pdm out value when pdm_clk is higth , */\ +{ 0x6951, "pdmdat_l_sel"}, /* pdm out value when pdm_clk is low , */\ +{ 0x6970, "sam_spkr_sel"}, /* ram output on mode sam and audio , */\ +{ 0x6a02, "rst_min_vbat_delay"}, /* rst_min_vbat delay (nb fs) , */\ +{ 0x6b00, "disable_auto_engage"}, /* disable auto engange , */\ +{ 0x6b10, "sel_tdm_data_valid"}, /* select tdm valid for speaker subsystem , */\ +{ 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ +{ 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ +{ 0x6c69, "spare_out"}, /* spare_out , */\ +{ 0x6d0f, "spare_in"}, /* spare_in , */\ +{ 0x6e00, "flag_lp_detect_mode0"}, /* low power mode 0 detection , */\ +{ 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ +{ 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ +{ 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ +{ 0x6f02, "cursense_comp_delay"}, /* delay to allign compensation signal with current sense signal, */\ +{ 0x6f40, "cursense_comp_sign"}, /* polarity of compensation for current sense , */\ +{ 0x6f50, "enbl_cursense_comp"}, /* enable current sense compensation , */\ +{ 0x6f60, "sel_clip_pwms"}, /* Select pwm clip flag , */\ +{ 0x6f72, "pwms_clip_lvl"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ +{ 0x7002, "scnd_boost_voltage"}, /* Second boost voltage level , */\ +{ 0x7033, "boost_cur"}, /* Max coil current , */\ +{ 0x7071, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ +{ 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ +{ 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ +{ 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ +{ 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ +{ 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ +{ 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ +{ 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ +{ 0x71c1, "bst_slope"}, /* Boost slope speed , */\ +{ 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ +{ 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ +{ 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ +{ 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ +{ 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ +{ 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ +{ 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ +{ 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ +{ 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ +{ 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ +{ 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ +{ 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ +{ 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ +{ 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ +{ 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ +{ 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ +{ 0x7402, "frst_boost_voltage"}, /* 1st boost voltage level , */\ +{ 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ +{ 0x7444, "boost_trip_lvl_1st"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ +{ 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ +{ 0x74f0, "ignore_flag_voutcomp86"}, /* Ignore flag_voutcomp86 , */\ +{ 0x7502, "track_decay"}, /* DCDC Boost decay speed after a peak value, effective only when boost_track is set to 1, */\ +{ 0x7534, "boost_trip_lvl_2nd"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7584, "boost_trip_lvl_track"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ +{ 0x7620, "pga_test_ldo_bypass"}, /* bypass internal PGA LDO , */\ +{ 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ +{ 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ +{ 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ +{ 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ +{ 0x8087, "cs_gain"}, /* Current sense gain , */\ +{ 0x8200, "enbl_cmfb"}, /* Current sense common mode feedback control , */\ +{ 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ +{ 0x8222, "cmfb_gain"}, /* Current sense common mode feedback control gain , */\ +{ 0x8254, "cmfb_offset"}, /* Current sense common mode feedback control offset , */\ +{ 0x82a0, "cs_sam_set"}, /* Enable SAM input for current sense , */\ +{ 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ +{ 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ +{ 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ +{ 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ +{ 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ +{ 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ +{ 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ +{ 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ +{ 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ +{ 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ +{ 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ +{ 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ +{ 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ +{ 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ +{ 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC , */\ +{ 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ +{ 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ +{ 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ +{ 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ +{ 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ +{ 0x8760, "enbl_cs_nofloating_n"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ +{ 0x8770, "enbl_cs_nofloating_p"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ +{ 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ +{ 0x8800, "volsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ +{ 0x8810, "vol_cur_sense_dc_offset"}, /* voltage and current sense decimator offset control, */\ +{ 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ +{ 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ +{ 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ +{ 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ +{ 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ +{ 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ +{ 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ +{ 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ +{ 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ +{ 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ +{ 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ +{ 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ +{ 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ +{ 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ +{ 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ +{ 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ +{ 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ +{ 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ +{ 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ +{ 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ +{ 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ +{ 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ +{ 0xb050, "bypass_otp"}, /* Bypass OTP , */\ +{ 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ +{ 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ +{ 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ +{ 0xb108, "ext_temp"}, /* External temperature (C) , */\ +{ 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ +{ 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ +{ 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ +{ 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ +{ 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ +{ 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ +{ 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ +{ 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ +{ 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ +{ 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ +{ 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ +{ 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ +{ 0xc300, "bypasslatch"}, /* Bypass latch , */\ +{ 0xc311, "sourcea"}, /* Set OUTA to , */\ +{ 0xc331, "sourceb"}, /* Set OUTB to , */\ +{ 0xc350, "inverta"}, /* Invert pwma test signal , */\ +{ 0xc360, "invertb"}, /* Invert pwmb test signal , */\ +{ 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ +{ 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ +{ 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ +{ 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ +{ 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ +{ 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ +{ 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ +{ 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ +{ 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ +{ 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ +{ 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ +{ 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ +{ 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ +{ 0xc510, "test_discrete"}, /* Test function noise measurement , */\ +{ 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ +{ 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ +{ 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ +{ 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ +{ 0xc5b0, "pga_test_enable"}, /* Enable PGA test mode , */\ +{ 0xc5c0, "pga_test_offset_enable"}, /* Enable PGA test offset , */\ +{ 0xc5d0, "pga_test_shortinput_enable"}, /* Enable PGA test shortinput , */\ +{ 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ +{ 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ +{ 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ +{ 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO (see Digimux list for details), */\ +{ 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT (see Digimux list for details), */\ +{ 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to PDMDAT (see Digimux list for details), */\ +{ 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ +{ 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ +{ 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ +{ 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ +{ 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ +{ 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ +{ 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ +{ 0xcb54, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ +{ 0xcba4, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ +{ 0xcd05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ +{ 0xcd64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ +{ 0xcdb3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ +{ 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ +{ 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ +{ 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ +{ 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ +{ 0xcec0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ +{ 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ +{ 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ +{ 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ +{ 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ +{ 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ +{ 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ +{ 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ +{ 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ +{ 0xd283, "tsig_gain"}, /* Test signal gain , */\ +{ 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ +{ 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ +{ 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ +{ 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ +{ 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ +{ 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ +{ 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ +{ 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ +{ 0xd580, "enbl_clk_out_of_range"}, /* Clock out of range , */\ +{ 0xd621, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ +{ 0xd641, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ +{ 0xd661, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ +{ 0xd701, "pdmdat_ehs"}, /* Speed/load setting for PDMDAT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd721, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd740, "bck_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd750, "datai_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd760, "pdmclk_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd800, "source_in_testmode"}, /* tdm source in test mode (return only current and voltage sense), */\ +{ 0xd810, "gainatt_feedback"}, /* gainatt feedback to tdm , */\ +{ 0xd822, "test_parametric_io"}, /* test io parametric , */\ +{ 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ +{ 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ +{ 0xd880, "bst_dcmbst"}, /* dcm boost , */\ +{ 0xd890, "pdm_loopback"}, /* pdm loop back to tdm , */\ +{ 0xd8a1, "force_pga_clock"}, /* force pga clock , */\ +{ 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ +{ 0xee0f, "sw_profile"}, /* Software profile data , */\ +{ 0xef0f, "sw_vstep"}, /* Software vstep information , */\ +{ 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ +{ 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ +{ 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ +{ 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ +{ 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ +{ 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ +{ 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ +{ 0xf163, "spare_mpt1_9_6"}, /* HW gain module - left channel (2's complement) , */\ +{ 0xf1a5, "spare_mpt1_15_10"}, /* Offset for amplifier, HW gain module - left channel (2's complement), */\ +{ 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ +{ 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ +{ 0xf2a3, "spare_mpt2_13_10"}, /* Trimming of LDO (2.7V) , */\ +{ 0xf307, "spare_mpt3_7_0"}, /* SPARE , */\ +{ 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ +{ 0xf40f, "spare_mtp4_15_0"}, /* SPARE , */\ +{ 0xf50f, "calibr_R25C_R"}, /* Ron resistance of speaker coil , */\ +{ 0xf606, "spare_mpt6_6_0"}, /* SPARE , */\ +{ 0xf686, "spare_mpt6_14_8"}, /* Offset of left amplifier level shifter B , */\ +{ 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ +{ 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ +{ 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ +{ 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ +{ 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ +{ 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ +{ 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ +{ 0xf910, "disable_sam_mode"}, /* Disable same mode , */\ +{ 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ +{ 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Disable programming of max dcdc boost voltage , */\ +{ 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ +{ 0xf980, "mtp_enbl_amp_in_state_alarm"}, /* Enbl_amp in alarm state , */\ +{ 0xf990, "mtp_enbl_pwm_delay_clock_gating"}, /* pwm delay clock auto gating , */\ +{ 0xf9a0, "mtp_enbl_ocp_clock_gating"}, /* ocpclock auto gating , */\ +{ 0xf9b0, "mtp_gate_cgu_clock_for_test"}, /* cgu test clock control , */\ +{ 0xf9c3, "spare_mtp9_15_12"}, /* MTP-control FW - See Firmware I2C API document for details, */\ +{ 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ +{ 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ +{ 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ +{ 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ +{ 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ +{ 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9872_irq { +tfa9872_irq_stvdds = 0, +tfa9872_irq_stplls = 1, +tfa9872_irq_stotds = 2, +tfa9872_irq_stovds = 3, +tfa9872_irq_stuvds = 4, +tfa9872_irq_stclks = 5, +tfa9872_irq_stmtpb = 6, +tfa9872_irq_stnoclk = 7, +tfa9872_irq_stsws = 10, +tfa9872_irq_stamps = 12, +tfa9872_irq_starefs = 13, +tfa9872_irq_stadccr = 14, +tfa9872_irq_stbstcu = 16, +tfa9872_irq_stbsthi = 17, +tfa9872_irq_stbstoc = 18, +tfa9872_irq_stbstpkcur = 19, +tfa9872_irq_stbstvc = 20, +tfa9872_irq_stbst86 = 21, +tfa9872_irq_stbst93 = 22, +tfa9872_irq_stocpr = 25, +tfa9872_irq_stmwsrc = 26, +tfa9872_irq_stmwsmu = 28, +tfa9872_irq_stclkoor = 31, +tfa9872_irq_sttdmer = 32, +tfa9872_irq_stclpr = 34, +tfa9872_irq_stlp0 = 36, +tfa9872_irq_stlp1 = 37, +tfa9872_irq_stla = 38, +tfa9872_irq_stvddph = 39, +tfa9872_irq_max = 40, +tfa9872_irq_all = -1 /* all irqs */}; + +#define TFA9872_IRQ_NAMETABLE static tfaIrqName_t Tfa9872IrqNames[] = {\ +{ 0, "STVDDS"},\ +{ 1, "STPLLS"},\ +{ 2, "STOTDS"},\ +{ 3, "STOVDS"},\ +{ 4, "STUVDS"},\ +{ 5, "STCLKS"},\ +{ 6, "STMTPB"},\ +{ 7, "STNOCLK"},\ +{ 8, "8"},\ +{ 9, "9"},\ +{ 10, "STSWS"},\ +{ 11, "11"},\ +{ 12, "STAMPS"},\ +{ 13, "STAREFS"},\ +{ 14, "STADCCR"},\ +{ 15, "15"},\ +{ 16, "STBSTCU"},\ +{ 17, "STBSTHI"},\ +{ 18, "STBSTOC"},\ +{ 19, "STBSTPKCUR"},\ +{ 20, "STBSTVC"},\ +{ 21, "STBST86"},\ +{ 22, "STBST93"},\ +{ 23, "23"},\ +{ 24, "24"},\ +{ 25, "STOCPR"},\ +{ 26, "STMWSRC"},\ +{ 27, "27"},\ +{ 28, "STMWSMU"},\ +{ 29, "29"},\ +{ 30, "30"},\ +{ 31, "STCLKOOR"},\ +{ 32, "STTDMER"},\ +{ 33, "33"},\ +{ 34, "STCLPR"},\ +{ 35, "35"},\ +{ 36, "STLP0"},\ +{ 37, "STLP1"},\ +{ 38, "STLA"},\ +{ 39, "STVDDPH"},\ +{ 40, "40"},\ +}; +#endif /* _TFA9872_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa9874_tfafieldnames.h b/sound/soc/codecs/tfa9874_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..5c6a23361c1f857ae1431288cdc7ca560a7ff56d --- /dev/null +++ b/sound/soc/codecs/tfa9874_tfafieldnames.h @@ -0,0 +1,836 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9874_TFAFIELDNAMES_H +#define _TFA9874_TFAFIELDNAMES_H + + +#define TFA9874_I2CVERSION 1.16 + +typedef enum nxpTfa9874BfEnumList { +TFA9874_BF_PWDN = 0x0000, /*!< Powerdown selection */ +TFA9874_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ +TFA9874_BF_AMPE = 0x0030, /*!< Activate Amplifier */ +TFA9874_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ +TFA9874_BF_INTP = 0x0071, /*!< Interrupt config */ +TFA9874_BF_BYPOCP = 0x00b0, /*!< Bypass OCP */ +TFA9874_BF_TSTOCP = 0x00c0, /*!< OCP testing control */ +TFA9874_BF_MANSCONF = 0x0120, /*!< I2C configured */ +TFA9874_BF_MANAOOSC = 0x0140, /*!< Internal osc off at PWDN */ +TFA9874_BF_MUTETO = 0x01d0, /*!< Time out SB mute sequence */ +TFA9874_BF_OPENMTP = 0x01e0, /*!< Control for FAIM protection */ +TFA9874_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ +TFA9874_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ +TFA9874_BF_FRACTDEL = 0x0255, /*!< V/I Fractional delay */ +TFA9874_BF_REV = 0x030f, /*!< Revision info */ +TFA9874_BF_REFCKEXT = 0x0401, /*!< PLL external ref clock */ +TFA9874_BF_REFCKSEL = 0x0420, /*!< PLL internal ref clock */ +TFA9874_BF_SSFAIME = 0x05c0, /*!< Sub-system FAIM */ +TFA9874_BF_AMPOCRT = 0x0802, /*!< Amplifier on-off criteria for shutdown */ +TFA9874_BF_VDDS = 0x1000, /*!< POR */ +TFA9874_BF_DCOCPOK = 0x1010, /*!< DCDC OCP nmos (sticky register , clear on read) */ +TFA9874_BF_OTDS = 0x1020, /*!< OTP alarm (sticky register , clear on read) */ +TFA9874_BF_OCDS = 0x1030, /*!< OCP amplifier (sticky register , clear on read) */ +TFA9874_BF_UVDS = 0x1040, /*!< UVP alarm (sticky register , clear on read) */ +TFA9874_BF_MANALARM = 0x1050, /*!< Alarm state */ +TFA9874_BF_TDMERR = 0x1060, /*!< TDM error */ +TFA9874_BF_NOCLK = 0x1070, /*!< Lost clock (sticky register , clear on read) */ +TFA9874_BF_DCIL = 0x1100, /*!< DCDC current limiting */ +TFA9874_BF_DCDCA = 0x1110, /*!< DCDC active (sticky register , clear on read) */ +TFA9874_BF_DCHVBAT = 0x1130, /*!< DCDC level 1x */ +TFA9874_BF_DCH114 = 0x1140, /*!< DCDC level 1.14x */ +TFA9874_BF_DCH107 = 0x1150, /*!< DCDC level 1.07x */ +TFA9874_BF_PLLS = 0x1160, /*!< PLL lock */ +TFA9874_BF_CLKS = 0x1170, /*!< Clocks stable */ +TFA9874_BF_TDMLUTER = 0x1180, /*!< TDM LUT error */ +TFA9874_BF_TDMSTAT = 0x1192, /*!< TDM status bits */ +TFA9874_BF_MTPB = 0x11c0, /*!< MTP busy */ +TFA9874_BF_SWS = 0x11d0, /*!< Amplifier engage */ +TFA9874_BF_AMPS = 0x11e0, /*!< Amplifier enable */ +TFA9874_BF_AREFS = 0x11f0, /*!< References enable */ +TFA9874_BF_OCPOAP = 0x1300, /*!< OCPOK pmos A */ +TFA9874_BF_OCPOAN = 0x1310, /*!< OCPOK nmos A */ +TFA9874_BF_OCPOBP = 0x1320, /*!< OCPOK pmos B */ +TFA9874_BF_OCPOBN = 0x1330, /*!< OCPOK nmos B */ +TFA9874_BF_OVDS = 0x1380, /*!< OVP alarm */ +TFA9874_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ +TFA9874_BF_ADCCR = 0x13a0, /*!< Control ADC */ +TFA9874_BF_MANWAIT1 = 0x13c0, /*!< Wait HW I2C settings */ +TFA9874_BF_MANMUTE = 0x13e0, /*!< Audio mute sequence */ +TFA9874_BF_MANOPER = 0x13f0, /*!< Operating state */ +TFA9874_BF_CLKOOR = 0x1420, /*!< External clock status */ +TFA9874_BF_MANSTATE = 0x1433, /*!< Device manager status */ +TFA9874_BF_DCMODE = 0x1471, /*!< DCDC mode status bits */ +TFA9874_BF_BATS = 0x1509, /*!< Battery voltage (V) */ +TFA9874_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ +TFA9874_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/13 V) */ +TFA9874_BF_TDME = 0x2040, /*!< Enable interface */ +TFA9874_BF_TDMMODE = 0x2050, /*!< Slave/master */ +TFA9874_BF_TDMCLINV = 0x2060, /*!< Reception data to BCK clock */ +TFA9874_BF_TDMFSLN = 0x2073, /*!< FS length (master mode only) */ +TFA9874_BF_TDMFSPOL = 0x20b0, /*!< FS polarity */ +TFA9874_BF_TDMNBCK = 0x20c3, /*!< N-BCK's in FS */ +TFA9874_BF_TDMSLOTS = 0x2103, /*!< N-slots in Frame */ +TFA9874_BF_TDMSLLN = 0x2144, /*!< N-bits in slot */ +TFA9874_BF_TDMBRMG = 0x2194, /*!< N-bits remaining */ +TFA9874_BF_TDMDEL = 0x21e0, /*!< data delay to FS */ +TFA9874_BF_TDMADJ = 0x21f0, /*!< data adjustment */ +TFA9874_BF_TDMOOMP = 0x2201, /*!< Received audio compression */ +TFA9874_BF_TDMSSIZE = 0x2224, /*!< Sample size per slot */ +TFA9874_BF_TDMTXDFO = 0x2271, /*!< Format unused bits */ +TFA9874_BF_TDMTXUS0 = 0x2291, /*!< Format unused slots DATAO */ +TFA9874_BF_TDMSPKE = 0x2300, /*!< Control audio tdm channel in 0 (spkr + dcdc) */ +TFA9874_BF_TDMDCE = 0x2310, /*!< Control audio tdm channel in 1 (dcdc) */ +TFA9874_BF_TDMCSE = 0x2330, /*!< current sense vbat temperature and vddp feedback */ +TFA9874_BF_TDMVSE = 0x2340, /*!< Voltage sense vbat temperature and vddp feedback */ +TFA9874_BF_TDMSPKS = 0x2603, /*!< tdm slot for sink 0 (speaker + dcdc) */ +TFA9874_BF_TDMDCS = 0x2643, /*!< tdm slot for sink 1 (dcdc) */ +TFA9874_BF_TDMCSS = 0x26c3, /*!< Slot Position of current sense vbat temperature and vddp feedback */ +TFA9874_BF_TDMVSS = 0x2703, /*!< Slot Position of Voltage sense vbat temperature and vddp feedback */ +TFA9874_BF_ISTVDDS = 0x4000, /*!< Status POR */ +TFA9874_BF_ISTBSTOC = 0x4010, /*!< Status DCDC OCP */ +TFA9874_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ +TFA9874_BF_ISTOCPR = 0x4030, /*!< Status ocp alarm */ +TFA9874_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ +TFA9874_BF_ISTMANALARM = 0x4050, /*!< Status nanager Alarm state */ +TFA9874_BF_ISTTDMER = 0x4060, /*!< Status tdm error */ +TFA9874_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ +TFA9874_BF_ICLVDDS = 0x4400, /*!< Clear POR */ +TFA9874_BF_ICLBSTOC = 0x4410, /*!< Clear DCDC OCP */ +TFA9874_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ +TFA9874_BF_ICLOCPR = 0x4430, /*!< Clear ocp alarm */ +TFA9874_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ +TFA9874_BF_ICLMANALARM = 0x4450, /*!< clear nanager Alarm state */ +TFA9874_BF_ICLTDMER = 0x4460, /*!< Clear tdm error */ +TFA9874_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ +TFA9874_BF_IEVDDS = 0x4800, /*!< Enable por */ +TFA9874_BF_IEBSTOC = 0x4810, /*!< Enable DCDC OCP */ +TFA9874_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ +TFA9874_BF_IEOCPR = 0x4830, /*!< Enable ocp alarm */ +TFA9874_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ +TFA9874_BF_IEMANALARM = 0x4850, /*!< Enable nanager Alarm state */ +TFA9874_BF_IETDMER = 0x4860, /*!< Enable tdm error */ +TFA9874_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ +TFA9874_BF_IPOVDDS = 0x4c00, /*!< Polarity por */ +TFA9874_BF_IPOBSTOC = 0x4c10, /*!< Polarity DCDC OCP */ +TFA9874_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ +TFA9874_BF_IPOOCPR = 0x4c30, /*!< Polarity ocp alarm */ +TFA9874_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ +TFA9874_BF_IPOMANALARM = 0x4c50, /*!< Polarity nanager Alarm state */ +TFA9874_BF_IPOTDMER = 0x4c60, /*!< Polarity tdm error */ +TFA9874_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ +TFA9874_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time */ +TFA9874_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ +TFA9874_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ +TFA9874_BF_VBATFLTL = 0x5080, /*!< vbat filter limit */ +TFA9874_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ +TFA9874_BF_BSSBY = 0x50f0, /*!< Bypass battery safeguard */ +TFA9874_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ +TFA9874_BF_HPFBYP = 0x5150, /*!< Bypass HPF */ +TFA9874_BF_DPSA = 0x5170, /*!< Enable DPSA */ +TFA9874_BF_CLIPCTRL = 0x5222, /*!< Clip control setting */ +TFA9874_BF_AMPGAIN = 0x5257, /*!< Amplifier gain */ +TFA9874_BF_SLOPEE = 0x52d0, /*!< Enables slope control */ +TFA9874_BF_SLOPESET = 0x52e0, /*!< Slope speed setting (bin. coded) */ +TFA9874_BF_TDMDCG = 0x6123, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ +TFA9874_BF_TDMSPKG = 0x6163, /*!< Total gain depending on INPLEV setting (channel 0) */ +TFA9874_BF_LNMODE = 0x62e1, /*!< ctrl select mode */ +TFA9874_BF_LPM1MODE = 0x64e1, /*!< low power mode control */ +TFA9874_BF_TDMSRCMAP = 0x6802, /*!< tdm source mapping */ +TFA9874_BF_TDMSRCAS = 0x6831, /*!< Sensed value A */ +TFA9874_BF_TDMSRCBS = 0x6851, /*!< Sensed value B */ +TFA9874_BF_TDMSRCACLIP = 0x6871, /*!< clip information (analog /digital) for source0 */ +TFA9874_BF_TDMSRCBCLIP = 0x6891, /*!< clip information (analog /digital) for source1 */ +TFA9874_BF_LP1 = 0x6e10, /*!< low power mode 1 detection */ +TFA9874_BF_LA = 0x6e20, /*!< low amplitude detection */ +TFA9874_BF_VDDPH = 0x6e30, /*!< vddp greater than vbat */ +TFA9874_BF_DELCURCOMP = 0x6f02, /*!< delay to allign compensation signal with current sense signal */ +TFA9874_BF_SIGCURCOMP = 0x6f40, /*!< polarity of compensation for current sense */ +TFA9874_BF_ENCURCOMP = 0x6f50, /*!< enable current sense compensation */ +TFA9874_BF_LVLCLPPWM = 0x6f72, /*!< set the amount of pwm pulse that may be skipped before clip-flag is triggered */ +TFA9874_BF_DCMCC = 0x7033, /*!< Max coil current */ +TFA9874_BF_DCCV = 0x7071, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ +TFA9874_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ +TFA9874_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ +TFA9874_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ +TFA9874_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ +TFA9874_BF_DCTRACK = 0x7430, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ +TFA9874_BF_DCTRIP = 0x7444, /*!< 1st Adaptive boost trip levels, effective only when DCIE is set to 1 */ +TFA9874_BF_DCHOLD = 0x7494, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ +TFA9874_BF_DCINT = 0x74e0, /*!< Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1 */ +TFA9874_BF_DCTRIP2 = 0x7534, /*!< 2nd Adaptive boost trip levels, effective only when DCIE is set to 1 */ +TFA9874_BF_DCTRIPT = 0x7584, /*!< Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ +TFA9874_BF_DCTRIPHYSTE = 0x75f0, /*!< Enable hysteresis on booster trip levels */ +TFA9874_BF_DCVOF = 0x7635, /*!< First boost voltage level */ +TFA9874_BF_DCVOS = 0x7695, /*!< Second boost voltage level */ +TFA9874_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ +TFA9874_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ +TFA9874_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ +TFA9874_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ +TFA9874_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ +TFA9874_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ +TFA9874_BF_EXTTS = 0xb108, /*!< External temperature (C) */ +TFA9874_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ +TFA9874_BF_SWPROFIL = 0xee0f, /*!< Software profile data */ +TFA9874_BF_SWVSTEP = 0xef0f, /*!< Software vstep information */ +TFA9874_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ +TFA9874_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ +TFA9874_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ +TFA9874_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ +TFA9874_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ +TFA9874_BF_CUSTINFO = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ +TFA9874_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9874BfEnumList_t; +#define TFA9874_NAMETABLE static tfaBfName_t Tfa9874DatasheetNames[] = {\ +{ 0x0, "PWDN"}, /* Powerdown selection , */\ +{ 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ +{ 0x30, "AMPE"}, /* Activate Amplifier , */\ +{ 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ +{ 0x71, "INTP"}, /* Interrupt config , */\ +{ 0xb0, "BYPOCP"}, /* Bypass OCP , */\ +{ 0xc0, "TSTOCP"}, /* OCP testing control , */\ +{ 0x120, "MANSCONF"}, /* I2C configured , */\ +{ 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ +{ 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ +{ 0x1e0, "OPENMTP"}, /* Control for FAIM protection , */\ +{ 0x203, "AUDFS"}, /* Sample rate (fs) , */\ +{ 0x240, "INPLEV"}, /* TDM output attenuation , */\ +{ 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ +{ 0x30f, "REV"}, /* Revision info , */\ +{ 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ +{ 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ +{ 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ +{ 0x802, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ +{ 0x1000, "VDDS"}, /* POR , */\ +{ 0x1010, "DCOCPOK"}, /* DCDC OCP nmos (sticky register , clear on read) , */\ +{ 0x1020, "OTDS"}, /* OTP alarm (sticky register , clear on read) , */\ +{ 0x1030, "OCDS"}, /* OCP amplifier (sticky register , clear on read), */\ +{ 0x1040, "UVDS"}, /* UVP alarm (sticky register , clear on read) , */\ +{ 0x1050, "MANALARM"}, /* Alarm state , */\ +{ 0x1060, "TDMERR"}, /* TDM error , */\ +{ 0x1070, "NOCLK"}, /* Lost clock (sticky register , clear on read) , */\ +{ 0x1100, "DCIL"}, /* DCDC current limiting , */\ +{ 0x1110, "DCDCA"}, /* DCDC active (sticky register , clear on read) , */\ +{ 0x1130, "DCHVBAT"}, /* DCDC level 1x , */\ +{ 0x1140, "DCH114"}, /* DCDC level 1.14x , */\ +{ 0x1150, "DCH107"}, /* DCDC level 1.07x , */\ +{ 0x1160, "PLLS"}, /* PLL lock , */\ +{ 0x1170, "CLKS"}, /* Clocks stable , */\ +{ 0x1180, "TDMLUTER"}, /* TDM LUT error , */\ +{ 0x1192, "TDMSTAT"}, /* TDM status bits , */\ +{ 0x11c0, "MTPB"}, /* MTP busy , */\ +{ 0x11d0, "SWS"}, /* Amplifier engage , */\ +{ 0x11e0, "AMPS"}, /* Amplifier enable , */\ +{ 0x11f0, "AREFS"}, /* References enable , */\ +{ 0x1300, "OCPOAP"}, /* OCPOK pmos A , */\ +{ 0x1310, "OCPOAN"}, /* OCPOK nmos A , */\ +{ 0x1320, "OCPOBP"}, /* OCPOK pmos B , */\ +{ 0x1330, "OCPOBN"}, /* OCPOK nmos B , */\ +{ 0x1380, "OVDS"}, /* OVP alarm , */\ +{ 0x1390, "CLIPS"}, /* Amplifier clipping , */\ +{ 0x13a0, "ADCCR"}, /* Control ADC , */\ +{ 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ +{ 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ +{ 0x13f0, "MANOPER"}, /* Operating state , */\ +{ 0x1420, "CLKOOR"}, /* External clock status , */\ +{ 0x1433, "MANSTATE"}, /* Device manager status , */\ +{ 0x1471, "DCMODE"}, /* DCDC mode status bits , */\ +{ 0x1509, "BATS"}, /* Battery voltage (V) , */\ +{ 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ +{ 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ +{ 0x2040, "TDME"}, /* Enable interface , */\ +{ 0x2050, "TDMMODE"}, /* Slave/master , */\ +{ 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ +{ 0x2073, "TDMFSLN"}, /* FS length (master mode only) , */\ +{ 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ +{ 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ +{ 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ +{ 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ +{ 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ +{ 0x21e0, "TDMDEL"}, /* data delay to FS , */\ +{ 0x21f0, "TDMADJ"}, /* data adjustment , */\ +{ 0x2201, "TDMOOMP"}, /* Received audio compression , */\ +{ 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ +{ 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ +{ 0x2291, "TDMTXUS0"}, /* Format unused slots DATAO , */\ +{ 0x2300, "TDMSPKE"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ +{ 0x2310, "TDMDCE"}, /* Control audio tdm channel in 1 (dcdc) , */\ +{ 0x2330, "TDMCSE"}, /* current sense vbat temperature and vddp feedback , */\ +{ 0x2340, "TDMVSE"}, /* Voltage sense vbat temperature and vddp feedback , */\ +{ 0x2603, "TDMSPKS"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ +{ 0x2643, "TDMDCS"}, /* tdm slot for sink 1 (dcdc) , */\ +{ 0x26c3, "TDMCSS"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ +{ 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ +{ 0x4000, "ISTVDDS"}, /* Status POR , */\ +{ 0x4010, "ISTBSTOC"}, /* Status DCDC OCP , */\ +{ 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ +{ 0x4030, "ISTOCPR"}, /* Status ocp alarm , */\ +{ 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ +{ 0x4050, "ISTMANALARM"}, /* Status nanager Alarm state , */\ +{ 0x4060, "ISTTDMER"}, /* Status tdm error , */\ +{ 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ +{ 0x4400, "ICLVDDS"}, /* Clear POR , */\ +{ 0x4410, "ICLBSTOC"}, /* Clear DCDC OCP , */\ +{ 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ +{ 0x4430, "ICLOCPR"}, /* Clear ocp alarm , */\ +{ 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ +{ 0x4450, "ICLMANALARM"}, /* clear nanager Alarm state , */\ +{ 0x4460, "ICLTDMER"}, /* Clear tdm error , */\ +{ 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ +{ 0x4800, "IEVDDS"}, /* Enable por , */\ +{ 0x4810, "IEBSTOC"}, /* Enable DCDC OCP , */\ +{ 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ +{ 0x4830, "IEOCPR"}, /* Enable ocp alarm , */\ +{ 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ +{ 0x4850, "IEMANALARM"}, /* Enable nanager Alarm state , */\ +{ 0x4860, "IETDMER"}, /* Enable tdm error , */\ +{ 0x4870, "IENOCLK"}, /* Enable lost clk , */\ +{ 0x4c00, "IPOVDDS"}, /* Polarity por , */\ +{ 0x4c10, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ +{ 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ +{ 0x4c30, "IPOOCPR"}, /* Polarity ocp alarm , */\ +{ 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ +{ 0x4c50, "IPOMANALARM"}, /* Polarity nanager Alarm state , */\ +{ 0x4c60, "IPOTDMER"}, /* Polarity tdm error , */\ +{ 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ +{ 0x5001, "BSSCR"}, /* Battery Safeguard attack time , */\ +{ 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ +{ 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ +{ 0x5080, "VBATFLTL"}, /* vbat filter limit , */\ +{ 0x50e0, "BSSR"}, /* Battery voltage read out , */\ +{ 0x50f0, "BSSBY"}, /* Bypass battery safeguard , */\ +{ 0x5100, "BSSS"}, /* Vbat prot steepness , */\ +{ 0x5150, "HPFBYP"}, /* Bypass HPF , */\ +{ 0x5170, "DPSA"}, /* Enable DPSA , */\ +{ 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ +{ 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ +{ 0x52d0, "SLOPEE"}, /* Enables slope control , */\ +{ 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ +{ 0x6123, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ +{ 0x6163, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ +{ 0x62e1, "LNMODE"}, /* ctrl select mode , */\ +{ 0x64e1, "LPM1MODE"}, /* low power mode control , */\ +{ 0x6802, "TDMSRCMAP"}, /* tdm source mapping , */\ +{ 0x6831, "TDMSRCAS"}, /* Sensed value A , */\ +{ 0x6851, "TDMSRCBS"}, /* Sensed value B , */\ +{ 0x6871, "TDMSRCACLIP"}, /* clip information (analog /digital) for source0 , */\ +{ 0x6891, "TDMSRCBCLIP"}, /* clip information (analog /digital) for source1 , */\ +{ 0x6e10, "LP1"}, /* low power mode 1 detection , */\ +{ 0x6e20, "LA"}, /* low amplitude detection , */\ +{ 0x6e30, "VDDPH"}, /* vddp greater than vbat , */\ +{ 0x6f02, "DELCURCOMP"}, /* delay to allign compensation signal with current sense signal, */\ +{ 0x6f40, "SIGCURCOMP"}, /* polarity of compensation for current sense , */\ +{ 0x6f50, "ENCURCOMP"}, /* enable current sense compensation , */\ +{ 0x6f72, "LVLCLPPWM"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ +{ 0x7033, "DCMCC"}, /* Max coil current , */\ +{ 0x7071, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ +{ 0x7090, "DCIE"}, /* Adaptive boost mode , */\ +{ 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ +{ 0x70e0, "DCDIS"}, /* DCDC on/off , */\ +{ 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ +{ 0x7430, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ +{ 0x7444, "DCTRIP"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7494, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ +{ 0x74e0, "DCINT"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ +{ 0x7534, "DCTRIP2"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7584, "DCTRIPT"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ +{ 0x75f0, "DCTRIPHYSTE"}, /* Enable hysteresis on booster trip levels , */\ +{ 0x7635, "DCVOF"}, /* First boost voltage level , */\ +{ 0x7695, "DCVOS"}, /* Second boost voltage level , */\ +{ 0xa107, "MTPK"}, /* MTP KEY2 register , */\ +{ 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ +{ 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ +{ 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ +{ 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ +{ 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ +{ 0xb108, "EXTTS"}, /* External temperature (C) , */\ +{ 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ +{ 0xee0f, "SWPROFIL"}, /* Software profile data , */\ +{ 0xef0f, "SWVSTEP"}, /* Software vstep information , */\ +{ 0xf000, "MTPOTC"}, /* Calibration schedule , */\ +{ 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ +{ 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ +{ 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ +{ 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ +{ 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ +{ 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9874_BITNAMETABLE static tfaBfName_t Tfa9874BitNames[] = {\ +{ 0x0, "powerdown"}, /* Powerdown selection , */\ +{ 0x10, "reset"}, /* I2C Reset - Auto clear , */\ +{ 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ +{ 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ +{ 0x71, "int_pad_io"}, /* Interrupt config , */\ +{ 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ +{ 0xc0, "test_ocp"}, /* OCP testing control , */\ +{ 0x120, "src_set_configured"}, /* I2C configured , */\ +{ 0x140, "enbl_osc1m_auto_off"}, /* Internal osc off at PWDN , */\ +{ 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ +{ 0x1e0, "unprotect_faim"}, /* Control for FAIM protection , */\ +{ 0x203, "audio_fs"}, /* Sample rate (fs) , */\ +{ 0x240, "input_level"}, /* TDM output attenuation , */\ +{ 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ +{ 0x2d0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ +{ 0x30f, "device_rev"}, /* Revision info , */\ +{ 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ +{ 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ +{ 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ +{ 0x802, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ +{ 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ +{ 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ +{ 0x1000, "flag_por"}, /* POR , */\ +{ 0x1010, "flag_bst_ocpok"}, /* DCDC OCP nmos (sticky register , clear on read) , */\ +{ 0x1020, "flag_otpok"}, /* OTP alarm (sticky register , clear on read) , */\ +{ 0x1030, "flag_ocp_alarm"}, /* OCP amplifier (sticky register , clear on read), */\ +{ 0x1040, "flag_uvpok"}, /* UVP alarm (sticky register , clear on read) , */\ +{ 0x1050, "flag_man_alarm_state"}, /* Alarm state , */\ +{ 0x1060, "flag_tdm_error"}, /* TDM error , */\ +{ 0x1070, "flag_lost_clk"}, /* Lost clock (sticky register , clear on read) , */\ +{ 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ +{ 0x1110, "flag_bst_hiz"}, /* DCDC active (sticky register , clear on read) , */\ +{ 0x1120, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ +{ 0x1130, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ +{ 0x1140, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ +{ 0x1150, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ +{ 0x1160, "flag_pll_lock"}, /* PLL lock , */\ +{ 0x1170, "flag_clocks_stable"}, /* Clocks stable , */\ +{ 0x1180, "flag_tdm_lut_error"}, /* TDM LUT error , */\ +{ 0x1192, "flag_tdm_status"}, /* TDM status bits , */\ +{ 0x11c0, "flag_mtp_busy"}, /* MTP busy , */\ +{ 0x11d0, "flag_engage"}, /* Amplifier engage , */\ +{ 0x11e0, "flag_enbl_amp"}, /* Amplifier enable , */\ +{ 0x11f0, "flag_enbl_ref"}, /* References enable , */\ +{ 0x1300, "flag_ocpokap"}, /* OCPOK pmos A , */\ +{ 0x1310, "flag_ocpokan"}, /* OCPOK nmos A , */\ +{ 0x1320, "flag_ocpokbp"}, /* OCPOK pmos B , */\ +{ 0x1330, "flag_ocpokbn"}, /* OCPOK nmos B , */\ +{ 0x1380, "flag_ovpok"}, /* OVP alarm , */\ +{ 0x1390, "flag_clip"}, /* Amplifier clipping , */\ +{ 0x13a0, "flag_adc10_ready"}, /* Control ADC , */\ +{ 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ +{ 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ +{ 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ +{ 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ +{ 0x1433, "man_state"}, /* Device manager status , */\ +{ 0x1471, "status_bst_mode"}, /* DCDC mode status bits , */\ +{ 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ +{ 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ +{ 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ +{ 0x2040, "tdm_enable"}, /* Enable interface , */\ +{ 0x2050, "tdm_mode"}, /* Slave/master , */\ +{ 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ +{ 0x2073, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ +{ 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ +{ 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ +{ 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ +{ 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ +{ 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ +{ 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ +{ 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ +{ 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ +{ 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ +{ 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ +{ 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots DATAO , */\ +{ 0x2300, "tdm_sink0_enable"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ +{ 0x2310, "tdm_sink1_enable"}, /* Control audio tdm channel in 1 (dcdc) , */\ +{ 0x2330, "tdm_source0_enable"}, /* current sense vbat temperature and vddp feedback , */\ +{ 0x2340, "tdm_source1_enable"}, /* Voltage sense vbat temperature and vddp feedback , */\ +{ 0x2603, "tdm_sink0_slot"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ +{ 0x2643, "tdm_sink1_slot"}, /* tdm slot for sink 1 (dcdc) , */\ +{ 0x26c3, "tdm_source0_slot"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ +{ 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ +{ 0x4000, "int_out_flag_por"}, /* Status POR , */\ +{ 0x4010, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ +{ 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ +{ 0x4030, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ +{ 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ +{ 0x4050, "int_out_flag_man_alarm_state"}, /* Status nanager Alarm state , */\ +{ 0x4060, "int_out_flag_tdm_error"}, /* Status tdm error , */\ +{ 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ +{ 0x4400, "int_in_flag_por"}, /* Clear POR , */\ +{ 0x4410, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ +{ 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ +{ 0x4430, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ +{ 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ +{ 0x4450, "int_in_flag_man_alarm_state"}, /* clear nanager Alarm state , */\ +{ 0x4460, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ +{ 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ +{ 0x4800, "int_enable_flag_por"}, /* Enable por , */\ +{ 0x4810, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ +{ 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ +{ 0x4830, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ +{ 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ +{ 0x4850, "int_enable_flag_man_alarm_state"}, /* Enable nanager Alarm state , */\ +{ 0x4860, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ +{ 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ +{ 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ +{ 0x4c10, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ +{ 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ +{ 0x4c30, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ +{ 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ +{ 0x4c50, "int_polarity_flag_man_alarm_state"}, /* Polarity nanager Alarm state , */\ +{ 0x4c60, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ +{ 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ +{ 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time , */\ +{ 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ +{ 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ +{ 0x5080, "vbat_flt_limit"}, /* vbat filter limit , */\ +{ 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ +{ 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ +{ 0x50f0, "bypass_clipper"}, /* Bypass battery safeguard , */\ +{ 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ +{ 0x5150, "bypass_hp"}, /* Bypass HPF , */\ +{ 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ +{ 0x5222, "ctrl_cc"}, /* Clip control setting , */\ +{ 0x5257, "gain"}, /* Amplifier gain , */\ +{ 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ +{ 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ +{ 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ +{ 0x5321, "dpsa_release"}, /* DPSA Release time , */\ +{ 0x5340, "clipfast"}, /* Clock selection for HW clipper for Battery Safeguard, */\ +{ 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ +{ 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ +{ 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ +{ 0x5430, "icomp_engage"}, /* Engage of icomp , */\ +{ 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ +{ 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ +{ 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ +{ 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ +{ 0x5582, "dpsa_drive"}, /* Drive setting (bin. coded) , */\ +{ 0x5690, "sel_pwm_delay_src"}, /* Control for selection for PWM delay line source , */\ +{ 0x56a1, "enbl_odd_up_even_down"}, /* Control for PWM reference sawtooth generartion , */\ +{ 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ +{ 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ +{ 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ +{ 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ +{ 0x5820, "pwm_shape"}, /* PWM shape , */\ +{ 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ +{ 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ +{ 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ +{ 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ +{ 0x6123, "ctrl_attl"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ +{ 0x6163, "ctrl_attr"}, /* Total gain depending on INPLEV setting (channel 0), */\ +{ 0x6265, "zero_lvl"}, /* low noise gain switch zero trigger level , */\ +{ 0x62c1, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ +{ 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ +{ 0x6305, "threshold_lvl"}, /* low noise gain switch trigger level , */\ +{ 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ +{ 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ +{ 0x6465, "lpm1_zero_lvl"}, /* low power mode1 zero crossing detection level , */\ +{ 0x64e1, "lpm1_mode"}, /* low power mode control , */\ +{ 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 amplitude trigger level , */\ +{ 0x6565, "lpm1_hold_time"}, /* low power mode1 detector ctrl hold time before low audio is reckoned to be low audio, */\ +{ 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ +{ 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ +{ 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ +{ 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ +{ 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ +{ 0x6700, "enbl_minion"}, /* Enables minion (small) power stage , */\ +{ 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ +{ 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtred vs unfiltered compare , */\ +{ 0x6761, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ +{ 0x6802, "tdm_source_mapping"}, /* tdm source mapping , */\ +{ 0x6831, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ +{ 0x6851, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ +{ 0x6871, "tdm_source0_clip_sel"}, /* clip information (analog /digital) for source0 , */\ +{ 0x6891, "tdm_source1_clip_sel"}, /* clip information (analog /digital) for source1 , */\ +{ 0x6a02, "rst_min_vbat_delay"}, /* rst_min_vbat delay (nb fs) , */\ +{ 0x6b00, "disable_auto_engage"}, /* disable auto engange , */\ +{ 0x6b10, "disable_engage"}, /* disable engange , */\ +{ 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ +{ 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ +{ 0x6c69, "spare_out"}, /* spare_out , */\ +{ 0x6d0f, "spare_in"}, /* spare_in , */\ +{ 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ +{ 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ +{ 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ +{ 0x6f02, "cursense_comp_delay"}, /* delay to allign compensation signal with current sense signal, */\ +{ 0x6f40, "cursense_comp_sign"}, /* polarity of compensation for current sense , */\ +{ 0x6f50, "enbl_cursense_comp"}, /* enable current sense compensation , */\ +{ 0x6f72, "pwms_clip_lvl"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ +{ 0x7033, "boost_cur"}, /* Max coil current , */\ +{ 0x7071, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ +{ 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ +{ 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ +{ 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ +{ 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ +{ 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ +{ 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ +{ 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ +{ 0x71c1, "bst_slope"}, /* Boost slope speed , */\ +{ 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ +{ 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ +{ 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ +{ 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ +{ 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ +{ 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ +{ 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ +{ 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ +{ 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ +{ 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ +{ 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ +{ 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ +{ 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ +{ 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ +{ 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ +{ 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ +{ 0x7360, "bst_use_new_zercur_detect"}, /* Enable new zero current detection for boost control, */\ +{ 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ +{ 0x7444, "boost_trip_lvl_1st"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ +{ 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ +{ 0x74f0, "ignore_flag_voutcomp86"}, /* Determines the maximum PWM frequency be the most efficient in relation to the Booster inductor value, */\ +{ 0x7534, "boost_trip_lvl_2nd"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7584, "boost_trip_lvl_track"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ +{ 0x75f0, "enbl_trip_hyst"}, /* Enable hysteresis on booster trip levels , */\ +{ 0x7635, "frst_boost_voltage"}, /* First boost voltage level , */\ +{ 0x7695, "scnd_boost_voltage"}, /* Second boost voltage level , */\ +{ 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ +{ 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ +{ 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ +{ 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ +{ 0x8087, "cs_gain"}, /* Current sense gain , */\ +{ 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ +{ 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ +{ 0x8364, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ +{ 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ +{ 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ +{ 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ +{ 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ +{ 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ +{ 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ +{ 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ +{ 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ +{ 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ +{ 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ +{ 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ +{ 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ +{ 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ +{ 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC , */\ +{ 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ +{ 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ +{ 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ +{ 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ +{ 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ +{ 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ +{ 0x8790, "enbl_dc_filter"}, /* Control for enabling the DC blocking filter for voltage and current sense, */\ +{ 0x8801, "volsense_pwm_sel"}, /* Voltage sense source selection control , */\ +{ 0x8850, "vs_gain_control"}, /* Voltage sense gain control , */\ +{ 0x8860, "vs_bypass_gc"}, /* Bypasses the VS gain correction , */\ +{ 0x8870, "vs_igen_supply"}, /* Switch internal supply of current generator , */\ +{ 0x8887, "vs_gain"}, /* voltage sense gain , */\ +{ 0x8c00, "vs_adc_bsoinv"}, /* Bitstream inversion for voltage sense ADC , */\ +{ 0x8c40, "vs_adc_nortz"}, /* Return to zero for voltage sense ADC , */\ +{ 0x8c90, "vs_adc_slowdel"}, /* Select delay for voltage sense ADC (internal decision circuitry), */\ +{ 0x8d10, "vs_classd_tran_skip"}, /* Skip voltage sense connection during a classD amplifier transition, */\ +{ 0x8d30, "vs_inn_short"}, /* Short voltage sense negative to common mode , */\ +{ 0x8d40, "vs_inp_short"}, /* Short voltage sense positive to common mode , */\ +{ 0x8d50, "vs_ldo_bypass"}, /* Bypass voltage sense LDO , */\ +{ 0x8d60, "vs_ldo_pulldown"}, /* Pull down voltage sense LDO, only valid if left_enbl_cs_ldo is high, */\ +{ 0x8d74, "vs_ldo_voset"}, /* Voltage sense LDO voltage level setting (two's complement), */\ +{ 0x8f00, "enbl_vs_adc"}, /* Enable voltage sense ADC (Direct Control only only others done by manager), */\ +{ 0x8f10, "enbl_vs_inn1"}, /* Enable connection of voltage sense negative1 , */\ +{ 0x8f20, "enbl_vs_inn2"}, /* Enable connection of voltage sense negative2 , */\ +{ 0x8f30, "enbl_vs_inp1"}, /* Enable connection of voltage sense positive1 , */\ +{ 0x8f40, "enbl_vs_inp2"}, /* Enable connection of voltage sense positive2 , */\ +{ 0x8f50, "enbl_vs_ldo"}, /* Enable voltage sense LDO (Direct Control only only others done by manager), */\ +{ 0x8f80, "enbl_vs_vbatldo"}, /* Enable of voltage sense LDO (Direct Control only others done by manager), */\ +{ 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ +{ 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ +{ 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ +{ 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ +{ 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ +{ 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ +{ 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ +{ 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ +{ 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ +{ 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ +{ 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ +{ 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ +{ 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ +{ 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ +{ 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ +{ 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ +{ 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ +{ 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ +{ 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ +{ 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ +{ 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ +{ 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ +{ 0xb050, "bypass_otp"}, /* Bypass OTP , */\ +{ 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ +{ 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ +{ 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ +{ 0xb108, "ext_temp"}, /* External temperature (C) , */\ +{ 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ +{ 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ +{ 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ +{ 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ +{ 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ +{ 0xc0c0, "use_direct_vs_ctrls"}, /* voltage sense Direct control to overrule several functions for testing, */\ +{ 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ +{ 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ +{ 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ +{ 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ +{ 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ +{ 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ +{ 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ +{ 0xc300, "bypasslatch"}, /* Bypass latch , */\ +{ 0xc311, "sourcea"}, /* Set OUTA to , */\ +{ 0xc331, "sourceb"}, /* Set OUTB to , */\ +{ 0xc350, "inverta"}, /* Invert pwma test signal , */\ +{ 0xc360, "invertb"}, /* Invert pwmb test signal , */\ +{ 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ +{ 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ +{ 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ +{ 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ +{ 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ +{ 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ +{ 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ +{ 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ +{ 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ +{ 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ +{ 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ +{ 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ +{ 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ +{ 0xc510, "test_discrete"}, /* Test function noise measurement , */\ +{ 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ +{ 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ +{ 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ +{ 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ +{ 0xc580, "test_enbl_vs"}, /* Enable for digimux mode of voltage sense , */\ +{ 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ +{ 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ +{ 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ +{ 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO (see Digimux list for details), */\ +{ 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT (see Digimux list for details), */\ +{ 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to PDMDAT (see Digimux list for details), */\ +{ 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ +{ 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ +{ 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ +{ 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ +{ 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ +{ 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ +{ 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ +{ 0xcb53, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ +{ 0xcba3, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ +{ 0xcd05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ +{ 0xcd64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ +{ 0xcdb3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ +{ 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ +{ 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ +{ 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ +{ 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ +{ 0xcec0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ +{ 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ +{ 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ +{ 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ +{ 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ +{ 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ +{ 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ +{ 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ +{ 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ +{ 0xd283, "tsig_gain"}, /* Test signal gain , */\ +{ 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ +{ 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ +{ 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ +{ 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ +{ 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ +{ 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ +{ 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ +{ 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ +{ 0xd580, "enbl_clk_out_of_range"}, /* Clock out of range , */\ +{ 0xd621, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ +{ 0xd641, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ +{ 0xd661, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ +{ 0xd721, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd740, "bck_ehs"}, /* High-speed and standard/fast mode selection for BCK IO cell (see IIC3V3 IO cell datasheet), */\ +{ 0xd750, "datai_ehs"}, /* High-speed and standard/fast mode selection for DATAI IO cell (see IIC3V3 IO cell datasheet), */\ +{ 0xd800, "source_in_testmode"}, /* tdm source in test mode (return only current and voltage sense), */\ +{ 0xd810, "gainatt_feedback"}, /* gainatt feedback to tdm , */\ +{ 0xd822, "test_parametric_io"}, /* test io parametric , */\ +{ 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ +{ 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ +{ 0xd880, "bst_dcmbst"}, /* dcm boost , */\ +{ 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ +{ 0xee0f, "sw_profile"}, /* Software profile data , */\ +{ 0xef0f, "sw_vstep"}, /* Software vstep information , */\ +{ 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ +{ 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ +{ 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ +{ 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ +{ 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ +{ 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ +{ 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ +{ 0xf169, "spare_mpt1_15_6"}, /* SPARE , */\ +{ 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ +{ 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ +{ 0xf2a5, "spare_mtp2_15_10"}, /* SPARE , */\ +{ 0xf307, "calibr_gain_vs"}, /* Voltage sense gain , */\ +{ 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ +{ 0xf407, "spare_mtp4_15_0"}, /* SPARE , */\ +{ 0xf487, "vs_trim"}, /* VS Trimming , */\ +{ 0xf50f, "calibr_R25C_R"}, /* Ron resistance of speaker coil , */\ +{ 0xf60f, "spare_mpt6_6_0"}, /* SPARE , */\ +{ 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ +{ 0xf770, "spare_mtp7_07"}, /* SPARE , */\ +{ 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ +{ 0xf7f0, "spare_mtp7_15"}, /* SPARE , */\ +{ 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ +{ 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ +{ 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ +{ 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ +{ 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ +{ 0xf910, "spare_mtp9_1"}, /* SPARE , */\ +{ 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ +{ 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Force Boost in follower mode , */\ +{ 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ +{ 0xf980, "spare_mtp9_8"}, /* SPARE , */\ +{ 0xf990, "mtp_enbl_pwm_delay_clock_gating"}, /* pwm delay clock auto gating , */\ +{ 0xf9a0, "mtp_enbl_ocp_clock_gating"}, /* ocpclock auto gating , */\ +{ 0xf9b0, "mtp_gate_cgu_clock_for_test"}, /* cgu test clock control , */\ +{ 0xf9c0, "mtp_tdm_pad_sel"}, /* tdm pad selection , */\ +{ 0xf9d2, "spare_mtp9_15_12"}, /* MTP-control FW - See Firmware I2C API document for details, */\ +{ 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ +{ 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ +{ 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ +{ 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ +{ 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ +{ 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ +{ 0xff87, "spare_mtp7_15_08"}, /* SPARE , */\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9874_irq { + tfa9874_irq_stvdds = 0, + tfa9874_irq_stbstoc = 1, + tfa9874_irq_stotds = 2, + tfa9874_irq_stocpr = 3, + tfa9874_irq_stuvds = 4, + tfa9874_irq_stmanalarm = 5, + tfa9874_irq_sttdmer = 6, + tfa9874_irq_stnoclk = 7, + tfa9874_irq_max = 8, + tfa9874_irq_all = -1 /* all irqs */}; + +#define TFA9874_IRQ_NAMETABLE static tfaIrqName_t Tfa9874IrqNames[] = {\ + { 0, "STVDDS"},\ + { 1, "STBSTOC"},\ + { 2, "STOTDS"},\ + { 3, "STOCPR"},\ + { 4, "STUVDS"},\ + { 5, "STMANALARM"},\ + { 6, "STTDMER"},\ + { 7, "STNOCLK"},\ + { 8, "8"},\ +}; +#endif /* _TFA9874_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa9878_tfafieldnames.h b/sound/soc/codecs/tfa9878_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..f626372b07c9a21b2922a580e5ab7b765dea9a66 --- /dev/null +++ b/sound/soc/codecs/tfa9878_tfafieldnames.h @@ -0,0 +1,973 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9878_TFAFIELDNAMES_H +#define _TFA9878_TFAFIELDNAMES_H + + +#define TFA9878_I2CVERSION 12 + +typedef enum nxpTfa9878BfEnumList { + TFA9878_BF_PWDN = 0x0000, /*!< Powerdown selection */ + TFA9878_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9878_BF_AMPE = 0x0030, /*!< Activate Amplifier */ + TFA9878_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ + TFA9878_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9878_BF_FSSSEL = 0x0090, /*!< Audio sample reference */ + TFA9878_BF_BYPOCP = 0x00b0, /*!< Bypass OCP */ + TFA9878_BF_TSTOCP = 0x00c0, /*!< OCP testing control */ + TFA9878_BF_AMPINSEL = 0x0101, /*!< Amplifier input selection */ + TFA9878_BF_MANSCONF = 0x0120, /*!< I2C configured */ + TFA9878_BF_DCINSEL = 0x0131, /*!< VAMP_OUT2 input selection */ + TFA9878_BF_MUTETO = 0x0160, /*!< Time out SB mute sequence */ + TFA9878_BF_MANROBOD = 0x0170, /*!< Reaction on BOD */ + TFA9878_BF_BODE = 0x0180, /*!< Enable BOD (only in direct control mode) */ + TFA9878_BF_BODHYS = 0x0190, /*!< Enable Hysteresis of BOD */ + TFA9878_BF_BODFILT = 0x01a1, /*!< BOD filter */ + TFA9878_BF_BODTHLVL = 0x01c1, /*!< BOD threshold */ + TFA9878_BF_OPENMTP = 0x01e0, /*!< Control for FAIM protection */ + TFA9878_BF_DISFCRBST = 0x01f0, /*!< disable boost control with FRCBST */ + TFA9878_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ + TFA9878_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ + TFA9878_BF_FRACTDEL = 0x0255, /*!< V/I Fractional delay */ + TFA9878_BF_AMPINPSEL = 0x02b1, /*!< amp input selection */ + TFA9878_BF_PDMRATE = 0x02d0, /*!< Pdm rate */ + TFA9878_BF_REV = 0x030f, /*!< Revision info */ + TFA9878_BF_REFCKEXT = 0x0401, /*!< PLL external ref clock */ + TFA9878_BF_REFCKSEL = 0x0420, /*!< PLL internal ref clock */ + TFA9878_BF_SWCLKSEL = 0x0432, /*!< Sound Wire clock frequnecy */ + TFA9878_BF_MANAOOSC = 0x0460, /*!< Internal osc off at PWDN */ + TFA9878_BF_FSSYNCEN = 0x0480, /*!< Enable FS synchronisation for clock divider */ + TFA9878_BF_CLKREFSYNCEN = 0x0490, /*!< Enable PLL reference clock synchronisation for clock divider */ + TFA9878_BF_AUTOFROSEL = 0x04a0, /*!< override automatic OSC selection mechanism */ + TFA9878_BF_SWFRSYNC = 0x04b0, /*!< Selection SW signal reference for Stream Synchronization */ + TFA9878_BF_CGUSYNCDCG = 0x0500, /*!< Clock gating control for CGU synchronisation module */ + TFA9878_BF_FRCCLKSPKR = 0x0510, /*!< force active the speaker sub-system clock when in idle power */ + TFA9878_BF_SSFAIME = 0x05c0, /*!< Sub-system FAIM */ + TFA9878_BF_CLKCHKLO = 0x0707, /*!< Clock check Low Threshold */ + TFA9878_BF_CLKCHKHI = 0x0787, /*!< Clock check Higher Threshold */ + TFA9878_BF_AMPOCRT = 0x0802, /*!< Amplifier on-off criteria for shutdown */ + TFA9878_BF_VDDS = 0x1000, /*!< POR */ + TFA9878_BF_DCOCPOK = 0x1010, /*!< DCDC OCP nmos (sticky register , clear on read) */ + TFA9878_BF_OTDS = 0x1020, /*!< OTP alarm (sticky register , clear on read) */ + TFA9878_BF_OCDS = 0x1030, /*!< OCP amplifier (sticky register , clear on read) */ + TFA9878_BF_UVDS = 0x1040, /*!< UVP alarm (sticky register , clear on read) */ + TFA9878_BF_MANALARM = 0x1050, /*!< Alarm state */ + TFA9878_BF_CLKS = 0x1060, /*!< Clocks stable */ + TFA9878_BF_MTPB = 0x1070, /*!< MTP busy */ + TFA9878_BF_NOCLK = 0x1080, /*!< Lost clock (sticky register , clear on read) */ + TFA9878_BF_BODNOK = 0x1090, /*!< BOD Flag - VDD NOT OK */ + TFA9878_BF_TDMERR = 0x10a0, /*!< TDM error */ + TFA9878_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9878_BF_DCDCA = 0x1110, /*!< DCDC active (sticky register , clear on read) */ + TFA9878_BF_DCDCPC = 0x1120, /*!< Indicates current is max in DC-to-DC converter */ + TFA9878_BF_DCHVBAT = 0x1130, /*!< DCDC level 1x */ + TFA9878_BF_DCH114 = 0x1140, /*!< DCDC level 1.14x */ + TFA9878_BF_DCH107 = 0x1150, /*!< DCDC level 1.07x */ + TFA9878_BF_PLLS = 0x1160, /*!< PLL lock */ + TFA9878_BF_TDMLUTER = 0x1180, /*!< TDM LUT error */ + TFA9878_BF_CLKOOR = 0x11c0, /*!< External clock status */ + TFA9878_BF_SWS = 0x11d0, /*!< Amplifier engage */ + TFA9878_BF_AMPS = 0x11e0, /*!< Amplifier enable */ + TFA9878_BF_AREFS = 0x11f0, /*!< References enable */ + TFA9878_BF_OCPOAP = 0x1300, /*!< OCPOK pmos B */ + TFA9878_BF_OCPOAN = 0x1310, /*!< OCPOK pmos A */ + TFA9878_BF_OCPOBP = 0x1320, /*!< OCPOK nmos B */ + TFA9878_BF_OCPOBN = 0x1330, /*!< OCPOK nmos A */ + TFA9878_BF_OVDS = 0x1380, /*!< OVP alarm */ + TFA9878_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ + TFA9878_BF_ADCCR = 0x13a0, /*!< Control ADC */ + TFA9878_BF_MANWAIT1 = 0x13c0, /*!< Wait HW I2C settings */ + TFA9878_BF_MANMUTE = 0x13e0, /*!< Audio mute sequence */ + TFA9878_BF_MANOPER = 0x13f0, /*!< Operating state */ + TFA9878_BF_TDMSTAT = 0x1402, /*!< TDM status bits */ + TFA9878_BF_MANSTATE = 0x1433, /*!< Device manager status */ + TFA9878_BF_AMPSTE = 0x1473, /*!< Amplifier control status */ + TFA9878_BF_DCMODE = 0x14b1, /*!< DCDC mode status bits */ + TFA9878_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9878_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9878_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/13 V) */ + TFA9878_BF_TDME = 0x2000, /*!< Enable interface */ + TFA9878_BF_TDMSLOTS = 0x2013, /*!< N-slots in Frame */ + TFA9878_BF_TDMCLINV = 0x2060, /*!< Reception data to BCK clock */ + TFA9878_BF_TDMFSLN = 0x2073, /*!< FS length */ + TFA9878_BF_TDMFSPOL = 0x20b0, /*!< FS polarity */ + TFA9878_BF_TDMNBCK = 0x20c3, /*!< N-BCK's in FS */ + TFA9878_BF_TDMSLLN = 0x2144, /*!< N-bits in slot */ + TFA9878_BF_TDMBRMG = 0x2194, /*!< N-bits remaining */ + TFA9878_BF_TDMDEL = 0x21e0, /*!< data delay to FS */ + TFA9878_BF_TDMADJ = 0x21f0, /*!< data adjustment */ + TFA9878_BF_TDMOOMP = 0x2201, /*!< Received audio compression */ + TFA9878_BF_TDMSSIZE = 0x2224, /*!< Sample size per slot */ + TFA9878_BF_TDMTXDFO = 0x2271, /*!< Format unused bits */ + TFA9878_BF_TDMTXUS0 = 0x2291, /*!< Format unused slots DATAO */ + TFA9878_BF_TDMSPKE = 0x2300, /*!< Control audio tdm channel in 0 */ + TFA9878_BF_TDMDCE = 0x2310, /*!< Control audio tdm channel in 1 */ + TFA9878_BF_TDMCSE = 0x2330, /*!< current sense vbat temperature and vddp feedback */ + TFA9878_BF_TDMVSE = 0x2340, /*!< Voltage sense vbat temperature and vddp feedback */ + TFA9878_BF_TDMSPKS = 0x2603, /*!< tdm slot for sink 0 */ + TFA9878_BF_TDMDCS = 0x2643, /*!< tdm slot for sink 1 */ + TFA9878_BF_TDMCSS = 0x26c3, /*!< Slot Position of current sense vbat temperature and vddp feedback */ + TFA9878_BF_TDMVSS = 0x2703, /*!< Slot Position of Voltage sense vbat temperature and vddp feedback */ + TFA9878_BF_ISTVDDS = 0x4000, /*!< Status POR */ + TFA9878_BF_ISTBSTOC = 0x4010, /*!< Status DCDC OCP */ + TFA9878_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ + TFA9878_BF_ISTOCPR = 0x4030, /*!< Status ocp alarm */ + TFA9878_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ + TFA9878_BF_ISTMANALARM = 0x4050, /*!< Status nanager Alarm state */ + TFA9878_BF_ISTTDMER = 0x4060, /*!< Status tdm error */ + TFA9878_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ + TFA9878_BF_ISTBODNOK = 0x4080, /*!< Status BOD event */ + TFA9878_BF_ICLVDDS = 0x4400, /*!< Clear POR */ + TFA9878_BF_ICLBSTOC = 0x4410, /*!< Clear DCDC OCP */ + TFA9878_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ + TFA9878_BF_ICLOCPR = 0x4430, /*!< Clear ocp alarm */ + TFA9878_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ + TFA9878_BF_ICLMANALARM = 0x4450, /*!< Clear manager Alarm state */ + TFA9878_BF_ICLTDMER = 0x4460, /*!< Clear tdm error */ + TFA9878_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ + TFA9878_BF_ICLBODNOK = 0x4480, /*!< Clear BOD event */ + TFA9878_BF_IEVDDS = 0x4800, /*!< Enable por */ + TFA9878_BF_IEBSTOC = 0x4810, /*!< Enable DCDC OCP */ + TFA9878_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ + TFA9878_BF_IEOCPR = 0x4830, /*!< Enable ocp alarm */ + TFA9878_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ + TFA9878_BF_IEMANALARM = 0x4850, /*!< Enable nanager Alarm state */ + TFA9878_BF_IETDMER = 0x4860, /*!< Enable tdm error */ + TFA9878_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ + TFA9878_BF_IEBODNOK = 0x4880, /*!< Enable BOD trigger */ + TFA9878_BF_IPOVDDS = 0x4c00, /*!< Polarity por */ + TFA9878_BF_IPOBSTOC = 0x4c10, /*!< Polarity DCDC OCP */ + TFA9878_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ + TFA9878_BF_IPOOCPR = 0x4c30, /*!< Polarity ocp alarm */ + TFA9878_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ + TFA9878_BF_IPOMANALARM = 0x4c50, /*!< Polarity nanager Alarm state */ + TFA9878_BF_IPOTDMER = 0x4c60, /*!< Polarity tdm error */ + TFA9878_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ + TFA9878_BF_IPOBODNOK = 0x4c80, /*!< Polarity BOD trigger */ + TFA9878_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time (with K = 1 at sample rate fs of 32kHz, 44,1 kHz or 48kHz ; with K = 2 at sample rate fs 16 kHz . With K =0.5 at sample rate of 96 kHz) */ + TFA9878_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ + TFA9878_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ + TFA9878_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9878_BF_BSSBY = 0x50f0, /*!< Bypass battery safeguard */ + TFA9878_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ + TFA9878_BF_HPFBYP = 0x5150, /*!< Bypass HPF */ + TFA9878_BF_DPSA = 0x5170, /*!< Enable DPSA */ + TFA9878_BF_CLIPCTRL = 0x5222, /*!< Clip control setting */ + TFA9878_BF_AMPGAIN = 0x5257, /*!< Amplifier gain */ + TFA9878_BF_SLOPEE = 0x52d0, /*!< Enables slope control */ + TFA9878_BF_SLOPESET = 0x52e0, /*!< Slope speed setting (bin. coded) */ + TFA9878_BF_BYPDLYLINE = 0x52f0, /*!< Bypass the interpolator delay line */ + TFA9878_BF_TDMDCG = 0x5f23, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ + TFA9878_BF_TDMSPKG = 0x5f63, /*!< Total gain depending on INPLEV setting (channel 0) */ + TFA9878_BF_IPM = 0x60e1, /*!< Idle power mode control */ + TFA9878_BF_LNMODE = 0x62e1, /*!< ctrl select mode */ + TFA9878_BF_LPM1MODE = 0x64e1, /*!< low power mode control */ + TFA9878_BF_TDMSRCMAP = 0x6802, /*!< tdm source mapping */ + TFA9878_BF_TDMSRCAS = 0x6831, /*!< Sensed value A */ + TFA9878_BF_TDMSRCBS = 0x6851, /*!< Sensed value B */ + TFA9878_BF_TDMSRCACLIP = 0x6871, /*!< clip information (analog /digital) for source0 */ + TFA9878_BF_TDMSRCBCLIP = 0x6891, /*!< clip information (analog /digital) for source1 */ + TFA9878_BF_LP0 = 0x6e00, /*!< Idle power mode */ + TFA9878_BF_LP1 = 0x6e10, /*!< low power mode 1 detection */ + TFA9878_BF_LA = 0x6e20, /*!< low amplitude detection */ + TFA9878_BF_VDDPH = 0x6e30, /*!< vddp greater than vbat */ + TFA9878_BF_DELCURCOMP = 0x6f02, /*!< delay to allign compensation signal with current sense signal */ + TFA9878_BF_SIGCURCOMP = 0x6f40, /*!< polarity of compensation for current sense */ + TFA9878_BF_ENCURCOMP = 0x6f50, /*!< enable current sense compensation */ + TFA9878_BF_LVLCLPPWM = 0x6f72, /*!< set the amount of pwm pulse that may be skipped before clip-flag is triggered */ + TFA9878_BF_DCMCC = 0x7003, /*!< Max coil current */ + TFA9878_BF_DCCV = 0x7041, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9878_BF_DCIE = 0x7060, /*!< Adaptive boost mode */ + TFA9878_BF_DCSR = 0x7070, /*!< Soft ramp up/down */ + TFA9878_BF_DCOVL = 0x7085, /*!< Threshold level to activate active overshoot control */ + TFA9878_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ + TFA9878_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ + TFA9878_BF_DCTRACK = 0x7430, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ + TFA9878_BF_DCTRIP = 0x7444, /*!< 1st Adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9878_BF_DCHOLD = 0x7494, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ + TFA9878_BF_DCINT = 0x74e0, /*!< Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1 */ + TFA9878_BF_DCTRIP2 = 0x7534, /*!< 2nd Adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9878_BF_DCTRIPT = 0x7584, /*!< Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9878_BF_DCTRIPHYSTE = 0x75f0, /*!< Enable hysteresis on booster trip levels */ + TFA9878_BF_DCVOF = 0x7635, /*!< First boost voltage level */ + TFA9878_BF_DCVOS = 0x7695, /*!< Second boost voltage level */ + TFA9878_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ + TFA9878_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ + TFA9878_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ + TFA9878_BF_MTPADDR = 0xa302, /*!< MTP address from I2C register for read/writing mtp in manual single word mode */ + TFA9878_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9878_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9878_BF_MTPWRMSB = 0xa70f, /*!< MSB word of write data for MTP manual write */ + TFA9878_BF_MTPWRLSB = 0xa80f, /*!< LSB word of write data for MTP manual write */ + TFA9878_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9878_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9878_BF_PLLINSI = 0xcd05, /*!< PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9878_BF_PLLINSP = 0xcd64, /*!< PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9878_BF_PLLINSR = 0xcdb3, /*!< PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9878_BF_PLLBDSEL = 0xcdf0, /*!< PLL bandwidth selection control, USE WITH CAUTION */ + TFA9878_BF_PLLNDEC = 0xce09, /*!< PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLMDECM = 0xcea0, /*!< MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLBP = 0xceb0, /*!< PLL bypass control during functional mode */ + TFA9878_BF_PLLDI = 0xcec0, /*!< PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLDO = 0xced0, /*!< PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLCLKSTB = 0xcee0, /*!< PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLFRM = 0xcef0, /*!< PLL free running mode control in functional mode */ + TFA9878_BF_PLLMDECL = 0xcf0f, /*!< Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLPDEC = 0xd006, /*!< PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLDCTRL = 0xd070, /*!< Enabled PLL direct control mode, overrules the PLL LUT with I2C register values */ + TFA9878_BF_PLLLIMOFF = 0xd090, /*!< PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1 */ + TFA9878_BF_PLLSTRTM = 0xd0a2, /*!< PLL startup time selection control */ + TFA9878_BF_SWPROFIL = 0xe00f, /*!< Software profile data */ + TFA9878_BF_SWVSTEP = 0xe10f, /*!< Software vstep information */ + TFA9878_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ + TFA9878_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9878_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ + TFA9878_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9878_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9878_BF_CUSTINFO = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9878_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9878BfEnumList_t; +#define TFA9878_NAMETABLE static tfaBfName_t Tfa9878DatasheetNames[] = {\ + { 0x0, "PWDN"}, /* Powerdown selection , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x30, "AMPE"}, /* Activate Amplifier , */\ + { 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x90, "FSSSEL"}, /* Audio sample reference , */\ + { 0xb0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xc0, "TSTOCP"}, /* OCP testing control , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* I2C configured , */\ + { 0x131, "DCINSEL"}, /* VAMP_OUT2 input selection , */\ + { 0x160, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x170, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x180, "BODE"}, /* Enable BOD (only in direct control mode) , */\ + { 0x190, "BODHYS"}, /* Enable Hysteresis of BOD , */\ + { 0x1a1, "BODFILT"}, /* BOD filter , */\ + { 0x1c1, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1e0, "OPENMTP"}, /* Control for FAIM protection , */\ + { 0x1f0, "DISFCRBST"}, /* disable boost control with FRCBST , */\ + { 0x203, "AUDFS"}, /* Sample rate (fs) , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ + { 0x2b1, "AMPINPSEL"}, /* amp input selection , */\ + { 0x2d0, "PDMRATE"}, /* Pdm rate , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ + { 0x432, "SWCLKSEL"}, /* Sound Wire clock frequnecy , */\ + { 0x460, "MANAOOSC"}, /* Internal osc off at PWDN , */\ + { 0x480, "FSSYNCEN"}, /* Enable FS synchronisation for clock divider , */\ + { 0x490, "CLKREFSYNCEN"}, /* Enable PLL reference clock synchronisation for clock divider, */\ + { 0x4a0, "AUTOFROSEL"}, /* override automatic OSC selection mechanism , */\ + { 0x4b0, "SWFRSYNC"}, /* Selection SW signal reference for Stream Synchronization , */\ + { 0x500, "CGUSYNCDCG"}, /* Clock gating control for CGU synchronisation module, */\ + { 0x510, "FRCCLKSPKR"}, /* force active the speaker sub-system clock when in idle power, */\ + { 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ + { 0x707, "CLKCHKLO"}, /* Clock check Low Threshold , */\ + { 0x787, "CLKCHKHI"}, /* Clock check Higher Threshold , */\ + { 0x802, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "DCOCPOK"}, /* DCDC OCP nmos (sticky register , clear on read) , */\ + { 0x1020, "OTDS"}, /* OTP alarm (sticky register , clear on read) , */\ + { 0x1030, "OCDS"}, /* OCP amplifier (sticky register , clear on read), */\ + { 0x1040, "UVDS"}, /* UVP alarm (sticky register , clear on read) , */\ + { 0x1050, "MANALARM"}, /* Alarm state , */\ + { 0x1060, "CLKS"}, /* Clocks stable , */\ + { 0x1070, "MTPB"}, /* MTP busy , */\ + { 0x1080, "NOCLK"}, /* Lost clock (sticky register , clear on read) , */\ + { 0x1090, "BODNOK"}, /* BOD Flag - VDD NOT OK , */\ + { 0x10a0, "TDMERR"}, /* TDM error , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active (sticky register , clear on read) , */\ + { 0x1120, "DCDCPC"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1130, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1140, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1150, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1160, "PLLS"}, /* PLL lock , */\ + { 0x1180, "TDMLUTER"}, /* TDM LUT error , */\ + { 0x11c0, "CLKOOR"}, /* External clock status , */\ + { 0x11d0, "SWS"}, /* Amplifier engage , */\ + { 0x11e0, "AMPS"}, /* Amplifier enable , */\ + { 0x11f0, "AREFS"}, /* References enable , */\ + { 0x1300, "OCPOAP"}, /* OCPOK pmos B , */\ + { 0x1310, "OCPOAN"}, /* OCPOK pmos A , */\ + { 0x1320, "OCPOBP"}, /* OCPOK nmos B , */\ + { 0x1330, "OCPOBN"}, /* OCPOK nmos A , */\ + { 0x1380, "OVDS"}, /* OVP alarm , */\ + { 0x1390, "CLIPS"}, /* Amplifier clipping , */\ + { 0x13a0, "ADCCR"}, /* Control ADC , */\ + { 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ + { 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x13f0, "MANOPER"}, /* Operating state , */\ + { 0x1402, "TDMSTAT"}, /* TDM status bits , */\ + { 0x1433, "MANSTATE"}, /* Device manager status , */\ + { 0x1473, "AMPSTE"}, /* Amplifier control status , */\ + { 0x14b1, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x2000, "TDME"}, /* Enable interface , */\ + { 0x2013, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2073, "TDMFSLN"}, /* FS length , */\ + { 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ + { 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ + { 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x21e0, "TDMDEL"}, /* data delay to FS , */\ + { 0x21f0, "TDMADJ"}, /* data adjustment , */\ + { 0x2201, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x2291, "TDMTXUS0"}, /* Format unused slots DATAO , */\ + { 0x2300, "TDMSPKE"}, /* Control audio tdm channel in 0 , */\ + { 0x2310, "TDMDCE"}, /* Control audio tdm channel in 1 , */\ + { 0x2330, "TDMCSE"}, /* current sense vbat temperature and vddp feedback , */\ + { 0x2340, "TDMVSE"}, /* Voltage sense vbat temperature and vddp feedback , */\ + { 0x2603, "TDMSPKS"}, /* tdm slot for sink 0 , */\ + { 0x2643, "TDMDCS"}, /* tdm slot for sink 1 , */\ + { 0x26c3, "TDMCSS"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ + { 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOCPR"}, /* Status ocp alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTMANALARM"}, /* Status nanager Alarm state , */\ + { 0x4060, "ISTTDMER"}, /* Status tdm error , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTBODNOK"}, /* Status BOD event , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOCPR"}, /* Clear ocp alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLMANALARM"}, /* Clear manager Alarm state , */\ + { 0x4460, "ICLTDMER"}, /* Clear tdm error , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLBODNOK"}, /* Clear BOD event , */\ + { 0x4800, "IEVDDS"}, /* Enable por , */\ + { 0x4810, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOCPR"}, /* Enable ocp alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IEMANALARM"}, /* Enable nanager Alarm state , */\ + { 0x4860, "IETDMER"}, /* Enable tdm error , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IEBODNOK"}, /* Enable BOD trigger , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity por , */\ + { 0x4c10, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOMANALARM"}, /* Polarity nanager Alarm state , */\ + { 0x4c60, "IPOTDMER"}, /* Polarity tdm error , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOBODNOK"}, /* Polarity BOD trigger , */\ + { 0x5001, "BSSCR"}, /* Battery Safeguard attack time (with K = 1 at sample rate fs of 32kHz, 44,1 kHz or 48kHz ; with K = 2 at sample rate fs 16 kHz . With K =0.5 at sample rate of 96 kHz), */\ + { 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass battery safeguard , */\ + { 0x5100, "BSSS"}, /* Vbat prot steepness , */\ + { 0x5150, "HPFBYP"}, /* Bypass HPF , */\ + { 0x5170, "DPSA"}, /* Enable DPSA , */\ + { 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x52d0, "SLOPEE"}, /* Enables slope control , */\ + { 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ + { 0x52f0, "BYPDLYLINE"}, /* Bypass the interpolator delay line , */\ + { 0x5f23, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5f63, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x60e1, "IPM"}, /* Idle power mode control , */\ + { 0x62e1, "LNMODE"}, /* ctrl select mode , */\ + { 0x64e1, "LPM1MODE"}, /* low power mode control , */\ + { 0x6802, "TDMSRCMAP"}, /* tdm source mapping , */\ + { 0x6831, "TDMSRCAS"}, /* Sensed value A , */\ + { 0x6851, "TDMSRCBS"}, /* Sensed value B , */\ + { 0x6871, "TDMSRCACLIP"}, /* clip information (analog /digital) for source0 , */\ + { 0x6891, "TDMSRCBCLIP"}, /* clip information (analog /digital) for source1 , */\ + { 0x6e00, "LP0"}, /* Idle power mode , */\ + { 0x6e10, "LP1"}, /* low power mode 1 detection , */\ + { 0x6e20, "LA"}, /* low amplitude detection , */\ + { 0x6e30, "VDDPH"}, /* vddp greater than vbat , */\ + { 0x6f02, "DELCURCOMP"}, /* delay to allign compensation signal with current sense signal, */\ + { 0x6f40, "SIGCURCOMP"}, /* polarity of compensation for current sense , */\ + { 0x6f50, "ENCURCOMP"}, /* enable current sense compensation , */\ + { 0x6f72, "LVLCLPPWM"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7003, "DCMCC"}, /* Max coil current , */\ + { 0x7041, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7060, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7070, "DCSR"}, /* Soft ramp up/down , */\ + { 0x7085, "DCOVL"}, /* Threshold level to activate active overshoot control, */\ + { 0x70e0, "DCDIS"}, /* DCDC on/off , */\ + { 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7430, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7444, "DCTRIP"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7494, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x74e0, "DCINT"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7534, "DCTRIP2"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7584, "DCTRIPT"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x75f0, "DCTRIPHYSTE"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7635, "DCVOF"}, /* First boost voltage level , */\ + { 0x7695, "DCVOS"}, /* Second boost voltage level , */\ + { 0xa107, "MTPK"}, /* MTP KEY2 register , */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "MTPADDR"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "MTPWRMSB"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "MTPWRLSB"}, /* LSB word of write data for MTP manual write , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xcd05, "PLLINSI"}, /* PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcd64, "PLLINSP"}, /* PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcdb3, "PLLINSR"}, /* PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcdf0, "PLLBDSEL"}, /* PLL bandwidth selection control, USE WITH CAUTION , */\ + { 0xce09, "PLLNDEC"}, /* PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcea0, "PLLMDECM"}, /* MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xceb0, "PLLBP"}, /* PLL bypass control during functional mode , */\ + { 0xcec0, "PLLDI"}, /* PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xced0, "PLLDO"}, /* PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcee0, "PLLCLKSTB"}, /* PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcef0, "PLLFRM"}, /* PLL free running mode control in functional mode , */\ + { 0xcf0f, "PLLMDECL"}, /* Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xd006, "PLLPDEC"}, /* PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xd070, "PLLDCTRL"}, /* Enabled PLL direct control mode, overrules the PLL LUT with I2C register values, */\ + { 0xd090, "PLLLIMOFF"}, /* PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1, */\ + { 0xd0a2, "PLLSTRTM"}, /* PLL startup time selection control , */\ + { 0xe00f, "SWPROFIL"}, /* Software profile data , */\ + { 0xe10f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9878_BITNAMETABLE static tfaBfName_t Tfa9878BitNames[] = {\ + { 0x0, "powerdown"}, /* Powerdown selection , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ + { 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x90, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xc0, "test_ocp"}, /* OCP testing control , */\ + { 0xd0, "sel_man_wait_time"}, /* Manager wait time selection control , */\ + { 0x101, "vamp_sel1"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* I2C configured , */\ + { 0x131, "vamp_sel2"}, /* VAMP_OUT2 input selection , */\ + { 0x160, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x170, "man_enbl_brown"}, /* Reaction on BOD , */\ + { 0x180, "bod_enbl"}, /* Enable BOD (only in direct control mode) , */\ + { 0x190, "bod_hyst_enbl"}, /* Enable Hysteresis of BOD , */\ + { 0x1a1, "bod_delay_set"}, /* BOD filter , */\ + { 0x1c1, "bod_lvl_set"}, /* BOD threshold , */\ + { 0x1e0, "unprotect_faim"}, /* Control for FAIM protection , */\ + { 0x1f0, "disable_frcbst"}, /* disable boost control with FRCBST , */\ + { 0x203, "audio_fs"}, /* Sample rate (fs) , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ + { 0x2b1, "amp_input_sel"}, /* amp input selection , */\ + { 0x2d0, "pdm_rate"}, /* Pdm rate , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ + { 0x432, "sw_clk_sel"}, /* Sound Wire clock frequnecy , */\ + { 0x460, "enbl_osc_auto_off"}, /* Internal osc off at PWDN , */\ + { 0x480, "enbl_fs_sync"}, /* Enable FS synchronisation for clock divider , */\ + { 0x490, "enbl_clkref_sync"}, /* Enable PLL reference clock synchronisation for clock divider, */\ + { 0x4a0, "override_auto_sel_osc"}, /* override automatic OSC selection mechanism , */\ + { 0x4b0, "sw_sync_sel"}, /* Selection SW signal reference for Stream Synchronization , */\ + { 0x500, "disable_cgu_sync_cgate"}, /* Clock gating control for CGU synchronisation module, */\ + { 0x510, "force_spkr_clk"}, /* force active the speaker sub-system clock when in idle power, */\ + { 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ + { 0x707, "clkchk_th_lo"}, /* Clock check Low Threshold , */\ + { 0x787, "clkchk_th_hi"}, /* Clock check Higher Threshold , */\ + { 0x802, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_bst_ocpok"}, /* DCDC OCP nmos (sticky register , clear on read) , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm (sticky register , clear on read) , */\ + { 0x1030, "flag_ocp_alarm"}, /* OCP amplifier (sticky register , clear on read), */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm (sticky register , clear on read) , */\ + { 0x1050, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x1060, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1070, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1080, "flag_lost_clk"}, /* Lost clock (sticky register , clear on read) , */\ + { 0x1090, "flag_bod_vddd_nok"}, /* BOD Flag - VDD NOT OK , */\ + { 0x10a0, "flag_tdm_error"}, /* TDM error , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active (sticky register , clear on read) , */\ + { 0x1120, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1130, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1140, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1150, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1160, "flag_pll_lock"}, /* PLL lock , */\ + { 0x1180, "flag_tdm_lut_error"}, /* TDM LUT error , */\ + { 0x11c0, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x11d0, "flag_engage"}, /* Amplifier engage , */\ + { 0x11e0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x11f0, "flag_enbl_ref"}, /* References enable , */\ + { 0x1300, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1310, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1320, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1330, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1380, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1390, "flag_clip"}, /* Amplifier clipping , */\ + { 0x13a0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ + { 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ + { 0x1402, "flag_tdm_status"}, /* TDM status bits , */\ + { 0x1433, "man_state"}, /* Device manager status , */\ + { 0x1473, "amp_ctrl_state"}, /* Amplifier control status , */\ + { 0x14b1, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x2000, "tdm_enable"}, /* Enable interface , */\ + { 0x2013, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2073, "tdm_fs_ws_length"}, /* FS length , */\ + { 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ + { 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ + { 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ + { 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots DATAO , */\ + { 0x2300, "tdm_sink0_enable"}, /* Control audio tdm channel in 0 , */\ + { 0x2310, "tdm_sink1_enable"}, /* Control audio tdm channel in 1 , */\ + { 0x2330, "tdm_source0_enable"}, /* current sense vbat temperature and vddp feedback , */\ + { 0x2340, "tdm_source1_enable"}, /* Voltage sense vbat temperature and vddp feedback , */\ + { 0x2603, "tdm_sink0_slot"}, /* tdm slot for sink 0 , */\ + { 0x2643, "tdm_sink1_slot"}, /* tdm slot for sink 1 , */\ + { 0x26c3, "tdm_source0_slot"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ + { 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_man_alarm_state"}, /* Status nanager Alarm state , */\ + { 0x4060, "int_out_flag_tdm_error"}, /* Status tdm error , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_bod_vddd_nok"}, /* Status BOD event , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_man_alarm_state"}, /* Clear manager Alarm state , */\ + { 0x4460, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_bod_vddd_nok"}, /* Clear BOD event , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable por , */\ + { 0x4810, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_man_alarm_state"}, /* Enable nanager Alarm state , */\ + { 0x4860, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_bod_vddd_nok"}, /* Enable BOD trigger , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ + { 0x4c10, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_man_alarm_state"}, /* Polarity nanager Alarm state , */\ + { 0x4c60, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_bod_vddd_nok"}, /* Polarity BOD trigger , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time (with K = 1 at sample rate fs of 32kHz, 44,1 kHz or 48kHz ; with K = 2 at sample rate fs 16 kHz . With K =0.5 at sample rate of 96 kHz), */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass battery safeguard , */\ + { 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ + { 0x5150, "bypass_hp"}, /* Bypass HPF , */\ + { 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0x5222, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5257, "gain"}, /* Amplifier gain , */\ + { 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ + { 0x52f0, "bypass_dly_line"}, /* Bypass the interpolator delay line , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5350, "bypass_lp"}, /* Bypass the low pass filter inside temperature sensor, */\ + { 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5430, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x5463, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5500, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5513, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5552, "dpsa_drive"}, /* Drive setting (bin. coded) , */\ + { 0x5600, "ref_iref_enbl"}, /* Enable of reference current for OCP , */\ + { 0x5631, "ref_irefdist_set_ctrl"}, /* Scaling of reference current for OCP , */\ + { 0x5652, "ref_irefdist_test_enbl"}, /* Enable of test-function of distribution of reference current, used for OCP. When enabled, the current will to to anamux iso powerstages. Using e.g. 011 it will add the current of powerstage P and N., */\ + { 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ + { 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ + { 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ + { 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ + { 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ + { 0x5900, "pwm_clk_sel"}, /* Control for selection for PWM delay line source , */\ + { 0x5910, "sel_pwm_delay_src"}, /* Control for selection for PWM delay line source , */\ + { 0x5f23, "ctrl_attl"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5f63, "ctrl_attr"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x6005, "idle_power_cal_offset"}, /* Idle power mode detector ctrl cal_offset from gain module , */\ + { 0x6065, "idle_power_zero_lvl"}, /* IIdle power mode zero crossing detection level , */\ + { 0x60e1, "idle_power_mode"}, /* Idle power mode control , */\ + { 0x6105, "idle_power_threshold_lvl"}, /* Idle power mode amplitude trigger level , */\ + { 0x6165, "idle_power_hold_time"}, /* Idle power mode detector ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x61c0, "disable_idle_power_mode"}, /* Idle power mode detector control , */\ + { 0x6265, "zero_lvl"}, /* low noise gain switch zero trigger level , */\ + { 0x62c1, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ + { 0x6305, "threshold_lvl"}, /* low noise gain switch trigger level , */\ + { 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x6465, "lpm1_zero_lvl"}, /* low power mode1 zero crossing detection level , */\ + { 0x64e1, "lpm1_mode"}, /* low power mode control , */\ + { 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 amplitude trigger level , */\ + { 0x6565, "lpm1_hold_time"}, /* low power mode1 detector ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ + { 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ + { 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x6700, "enbl_minion"}, /* Enables minion (small) power stage , */\ + { 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ + { 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtred vs unfiltered compare , */\ + { 0x6761, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x6802, "tdm_source_mapping"}, /* tdm source mapping , */\ + { 0x6831, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ + { 0x6851, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ + { 0x6871, "tdm_source0_clip_sel"}, /* clip information (analog /digital) for source0 , */\ + { 0x6891, "tdm_source1_clip_sel"}, /* clip information (analog /digital) for source1 , */\ + { 0x6a02, "rst_min_vbat_delay"}, /* rst_min_vbat delay (nb fs) , */\ + { 0x6b00, "disable_auto_engage"}, /* disable auto engange , */\ + { 0x6b10, "disable_engage"}, /* disable engange , */\ + { 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x6c69, "spare_out"}, /* spare_out , */\ + { 0x6d0f, "spare_in"}, /* spare_in , */\ + { 0x6e00, "flag_idle_power_mode"}, /* Idle power mode , */\ + { 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ + { 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ + { 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ + { 0x6f02, "cursense_comp_delay"}, /* delay to allign compensation signal with current sense signal, */\ + { 0x6f40, "cursense_comp_sign"}, /* polarity of compensation for current sense , */\ + { 0x6f50, "enbl_cursense_comp"}, /* enable current sense compensation , */\ + { 0x6f72, "pwms_clip_lvl"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7003, "boost_cur"}, /* Max coil current , */\ + { 0x7041, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7060, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7070, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x7085, "overshoot_correction_lvl"}, /* Threshold level to activate active overshoot control, */\ + { 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x71c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ + { 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7360, "bst_use_new_zercur_detect"}, /* Enable new zero current detection for boost control, */\ + { 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7444, "boost_trip_lvl_1st"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x74f0, "ignore_flag_voutcomp86"}, /* Determines the maximum PWM frequency be the most efficient in relation to the Booster inductor value, */\ + { 0x7534, "boost_trip_lvl_2nd"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7584, "boost_trip_lvl_track"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x75f0, "enbl_trip_hyst"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7635, "frst_boost_voltage"}, /* First boost voltage level , */\ + { 0x7695, "scnd_boost_voltage"}, /* Second boost voltage level , */\ + { 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ + { 0x8364, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC , */\ + { 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ + { 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ + { 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ + { 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ + { 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ + { 0x8790, "enbl_dc_filter"}, /* Control for enabling the DC blocking filter for voltage and current sense, */\ + { 0x8850, "vs_gain_control"}, /* Voltage sense gain control , */\ + { 0x8860, "vs_bypass_gc"}, /* Bypasses the VS gain correction , */\ + { 0x8887, "vs_gain"}, /* voltage sense gain , */\ + { 0x8c00, "vs_adc_bsoinv"}, /* Bitstream inversion for voltage sense ADC , */\ + { 0x8c40, "vs_adc_nortz"}, /* Return to zero for voltage sense ADC , */\ + { 0x8c90, "vs_adc_slowdel"}, /* Select delay for voltage sense ADC (internal decision circuitry), */\ + { 0x8d30, "vs_inn_short"}, /* Short voltage sense negative to common mode , */\ + { 0x8d40, "vs_inp_short"}, /* Short voltage sense positive to common mode , */\ + { 0x8d50, "vs_ldo_bypass"}, /* Bypass voltage sense LDO , */\ + { 0x8d60, "vs_ldo_pulldown"}, /* Pull down voltage sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8d74, "vs_ldo_voset"}, /* Voltage sense LDO voltage level setting (two's complement), */\ + { 0x8f00, "enbl_vs_adc"}, /* Enable voltage sense ADC (Direct Control only only others done by manager), */\ + { 0x8f10, "enbl_vs_inn1"}, /* Enable connection of voltage sense negative1 , */\ + { 0x8f20, "enbl_vs_inn2"}, /* Enable connection of voltage sense negative2 , */\ + { 0x8f30, "enbl_vs_inp1"}, /* Enable connection of voltage sense positive1 , */\ + { 0x8f40, "enbl_vs_inp2"}, /* Enable connection of voltage sense positive2 , */\ + { 0x8f50, "enbl_vs_ldo"}, /* Enable voltage sense LDO (Direct Control only only others done by manager), */\ + { 0x8f80, "enbl_vs_vbatldo"}, /* Enable of voltage sense LDO (Direct Control only others done by manager), */\ + { 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb050, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0c0, "use_direct_vs_ctrls"}, /* voltage sense Direct control to overrule several functions for testing, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "enbl_pll"}, /* Enables PLL in I2C direct control mode only , */\ + { 0xc0f0, "enbl_fro"}, /* Enables FRO8M in I2C direct control mode only , */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs ), */\ + { 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc580, "test_enbl_vs"}, /* Enable for digimux mode of voltage sense , */\ + { 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO (see Digimux list for details), */\ + { 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT (see Digimux list for details), */\ + { 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to ADS1 (see Digimux list for details), */\ + { 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xc9d1, "sw_hs_mode"}, /* Speed/load setting for SW IO cell, clk or data mode range (see SWMF IO cell datasheet), */\ + { 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xcac0, "open_frcbst_ensw_switch"}, /* Save test2 configuration before enable anamux2 (open test2 switch and save test2 setting) , */\ + { 0xcb04, "anamux2"}, /* Anamux selection control - anamux on FRCBST/TEST2 , */\ + { 0xcb53, "anamux3"}, /* Anamux selection control - anamux on VSN/TEST3 , */\ + { 0xcba3, "anamux4"}, /* Anamux selection control - anamux on VSP/TEST4 , */\ + { 0xcd05, "pll_inseli"}, /* PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcd64, "pll_inselp"}, /* PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcdb3, "pll_inselr"}, /* PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcdf0, "pll_bandsel"}, /* PLL bandwidth selection control, USE WITH CAUTION , */\ + { 0xce09, "pll_ndec"}, /* PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcea0, "pll_mdec_msb"}, /* MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xceb0, "pll_bypass"}, /* PLL bypass control during functional mode , */\ + { 0xcec0, "pll_directi"}, /* PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xced0, "pll_directo"}, /* PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcee0, "pll_frm_clockstable"}, /* PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcef0, "pll_frm"}, /* PLL free running mode control in functional mode , */\ + { 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xd006, "pll_pdec"}, /* PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xd070, "use_direct_pll_ctrl"}, /* Enabled PLL direct control mode, overrules the PLL LUT with I2C register values, */\ + { 0xd090, "pll_limup_off"}, /* PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1, */\ + { 0xd0a2, "sel_pll_startup_time"}, /* PLL startup time selection control , */\ + { 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd283, "tsig_gain"}, /* Test signal gain , */\ + { 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd580, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xd721, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xd740, "bck_ehs"}, /* High-speed and standard/fast mode selection for BCK IO cell (see IIC3V3 IO cell datasheet), */\ + { 0xd750, "datai_ehs"}, /* High-speed and standard/fast mode selection for DATAI IO cell (see IIC3V3 IO cell datasheet), */\ + { 0xd800, "source_in_testmode"}, /* tdm source in test mode (return only current and voltage sense), */\ + { 0xd810, "gainatt_tdm_feedback"}, /* gainatt feedback to tdm , */\ + { 0xd822, "test_parametric_io"}, /* test io parametric , */\ + { 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ + { 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ + { 0xd880, "bst_dcmbst"}, /* dcm boost , */\ + { 0xd890, "gainatt_sw_feedback"}, /* gainatt feedback to sw , */\ + { 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ + { 0xd900, "enbl_frocal"}, /* Enable FRO calibration , */\ + { 0xd910, "start_fro_calibration"}, /* Start FRO8 Calibration , */\ + { 0xd920, "enbl_irefcal"}, /* Enable IREF calibration , */\ + { 0xd930, "start_iref_calibration"}, /* Start IREF Calibration , */\ + { 0xda00, "fro_calibration_done"}, /* FRO8 Calibration done - Read Only , */\ + { 0xda15, "fro_auto_trim_val"}, /* Calibration value from Auto Calibration block, to be written into MTP - Read Only, */\ + { 0xda80, "iref_calibration_done"}, /* IREF Calibration done - Read Only , */\ + { 0xda94, "iref_auto_trim_val"}, /* Calibration value from Auto Calibration block, to be written into MTP - Read Only, */\ + { 0xdae0, "iref_calibration_error"}, /* IREF Calibration done - Read Only , */\ + { 0xe00f, "sw_profile"}, /* Software profile data , */\ + { 0xe10f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf169, "spare_mtp1_15_6"}, /* SPARE , */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf2a4, "optimal_pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0xf2f0, "enbl_optimal_pwm_delay"}, /* optimized pwm delay function enabled , */\ + { 0xf307, "calibr_gain_vs1"}, /* Voltage sense gain when external voltage sensing input is selected, */\ + { 0xf387, "calibr_gain_vs2"}, /* Voltage sense gain when internal voltage sensing input is selected, */\ + { 0xf407, "vs_trim1"}, /* VS Trimming when external voltage sensing input is selected, */\ + { 0xf487, "vs_trim2"}, /* VS Trimming when internal voltage sensing input is selected, */\ + { 0xf50f, "calibr_R25C_R"}, /* Ron resistance of speaker coil , */\ + { 0xf607, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf687, "spare_mpt6_15_06"}, /* SPARE , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf770, "spare_mtp7_07"}, /* SPARE , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf7f0, "spare_mtp7_15"}, /* SPARE , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ + { 0xf910, "spare_mtp9_1"}, /* SPARE , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Force Boost in follower mode , */\ + { 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf980, "spare_mtp9_8"}, /* SPARE , */\ + { 0xf990, "mtp_enbl_pwm_delay_clock_gating"}, /* pwm delay clock auto gating , */\ + { 0xf9a0, "mtp_enbl_ocp_clock_gating"}, /* ocpclock auto gating , */\ + { 0xf9b0, "mtp_gate_cgu_clock_for_test"}, /* cgu test clock control , */\ + { 0xf9c0, "mtp_tdm_pad_sel"}, /* tdm pad selection , */\ + { 0xf9d2, "spare_mtp9_15_12"}, /* MTP-control FW - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ + { 0xff05, "fro_trim"}, /* 8 MHz oscillator trim code , */\ + { 0xff61, "fro_shortnwell"}, /* Short 4 or 6 n-well resistors , */\ + { 0xff81, "fro_boost"}, /* Self bias current selection , */\ + { 0xffa4, "calibr_iref_trim"}, /* Trimming control of reference current for OCP , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9878_irq { + tfa9878_irq_stvdds = 0, + tfa9878_irq_stbstoc = 1, + tfa9878_irq_stotds = 2, + tfa9878_irq_stocpr = 3, + tfa9878_irq_stuvds = 4, + tfa9878_irq_stmanalarm = 5, + tfa9878_irq_sttdmer = 6, + tfa9878_irq_stnoclk = 7, + tfa9878_irq_stbodnok = 8, + tfa9878_irq_max = 9, + tfa9878_irq_all = -1 /* all irqs */}; + +#define TFA9878_IRQ_NAMETABLE static tfaIrqName_t Tfa9878IrqNames[] = {\ + { 0, "STVDDS"},\ + { 1, "STBSTOC"},\ + { 2, "STOTDS"},\ + { 3, "STOCPR"},\ + { 4, "STUVDS"},\ + { 5, "STMANALARM"},\ + { 6, "STTDMER"},\ + { 7, "STNOCLK"},\ + { 8, "STBODNOK"},\ + { 9, "9"},\ +}; +#endif /* _TFA9878_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa9887_tfafieldnames.h b/sound/soc/codecs/tfa9887_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..b85ca5b44a25c75e5411910a31bd05cc2d92ddd5 --- /dev/null +++ b/sound/soc/codecs/tfa9887_tfafieldnames.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ +#define TFA9887_I2CVERSION 34 +#define TFA9895_I2CVERSION 34 +#define TFA9887_NAMETABLE static tfaBfName_t Tfa9887DatasheetNames[] = {\ + { 0x402, "I2SF"}, /* I2SFormat data 1 input: , */\ + { 0x431, "CHS12"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "CHS3"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x4b0, "I2SDOE"}, /* Enable data output , */\ + { 0x4c3, "I2SSR"}, /* sample rate setting , */\ + { 0x500, "BSSBY"}, /* , */\ + { 0x511, "BSSCR"}, /* 00 = 0.56 dB/Sample , */\ + { 0x532, "BSST"}, /* 000 = 2.92V , */\ + { 0x5f0, "I2SDOC"}, /* selection data out , */\ + { 0xa02, "DOLS"}, /* Output selection dataout left channel , */\ + { 0xa32, "DORS"}, /* Output selection dataout right channel , */\ + { 0xa62, "SPKL"}, /* Selection speaker induction , */\ + { 0xa91, "SPKR"}, /* Selection speaker impedance , */\ + { 0xab3, "DCFG"}, /* DCDC speaker current compensation gain , */\ + { 0x4134, "PWMDEL"}, /* PWM DelayBits to set the delay , */\ + { 0x4180, "PWMSH"}, /* PWM Shape , */\ + { 0x4190, "PWMRE"}, /* PWM Bitlength in noise shaper , */\ + { 0x48e1, "TCC"}, /* sample & hold track time: , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9887_BITNAMETABLE static tfaBfName_t Tfa9887BitNames[] = {\ + { 0x402, "i2s_seti"}, /* I2SFormat data 1 input: , */\ + { 0x431, "chan_sel1"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "lr_sw_i2si2"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "input_sel"}, /* Input selection for amplifier , */\ + { 0x4b0, "enbl_datao"}, /* Enable data output , */\ + { 0x4c3, "i2s_fs"}, /* sample rate setting , */\ + { 0x500, "bypass_clipper"}, /* , */\ + { 0x511, "vbat_prot_attacktime[1:0]"}, /* 00 = 0.56 dB/Sample , */\ + { 0x532, "vbat_prot_thlevel[2:0]"}, /* 000 = 2.92V , */\ + { 0x5d0, "reset_min_vbat"}, /* to reset the clipper via I2C in case the CF is bypassed, */\ + { 0x5f0, "datao_sel"}, /* selection data out , */\ + { 0xa02, "sel_i2so_l"}, /* Output selection dataout left channel , */\ + { 0xa32, "sel_i2so_r"}, /* Output selection dataout right channel , */\ + { 0xa62, "ctrl_spkr_coil"}, /* Selection speaker induction , */\ + { 0xa91, "ctrl_spr_res"}, /* Selection speaker impedance , */\ + { 0xab3, "ctrl_dcdc_spkr_i_comp_gain"}, /* DCDC speaker current compensation gain , */\ + { 0xaf0, "ctrl_dcdc_spkr_i_comp_sign"}, /* DCDC speaker current compensation sign , */\ + { 0x4100, "bypass_hp"}, /* bypass_hp, to bypass the hp filter byhind the CoolFlux, */\ + { 0x4110, "hard_mute"}, /* hard mute setting in HW , */\ + { 0x4120, "soft_mute"}, /* Soft mute setting in HW , */\ + { 0x4134, "PWM_Delay[4:0]"}, /* PWM DelayBits to set the delay , */\ + { 0x4180, "PWM_Shape"}, /* PWM Shape , */\ + { 0x4190, "PWM_BitLength"}, /* PWM Bitlength in noise shaper , */\ + { 0x4800, "ctrl_negin"}, /* , */\ + { 0x4810, "ctrl_cs_sein"}, /* , */\ + { 0x4820, "ctrl_coincidencecs"}, /* HIGH => Prevent dcdc switching during clk_cs_clksh, */\ + { 0x4876, "delay_se_neg[6:0]"}, /* delayshiftse2 , */\ + { 0x48e1, "ctrl_cs_ttrack[1:0]"}, /* sample & hold track time: , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + diff --git a/sound/soc/codecs/tfa9890_tfafieldnames.h b/sound/soc/codecs/tfa9890_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..ad043bc83148eb8899ade4199a0938de17495b3c --- /dev/null +++ b/sound/soc/codecs/tfa9890_tfafieldnames.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ +#define TFA9890_I2CVERSION 34 +#define TFA9890_NAMETABLE static tfaBfName_t Tfa9890DatasheetNames[] = {\ + { 0x402, "I2SF"}, /* I2SFormat data 1 input: , */\ + { 0x431, "CHS12"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "CHS3"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x481, "I2SDOC"}, /* selection data out , */\ + { 0x4a0, "DISP"}, /* idp protection , */\ + { 0x4b0, "I2SDOE"}, /* Enable data output , */\ + { 0x4c3, "I2SSR"}, /* sample rate setting , */\ + { 0x732, "DCMCC"}, /* Max boost coil current - step of 500 mA , */\ + { 0x9c0, "CCFD"}, /* Selection CoolFlux Clock , */\ + { 0x9d0, "ISEL"}, /* selection input 1 or 2 , */\ + { 0xa02, "DOLS"}, /* Output selection dataout left channel , */\ + { 0xa32, "DORS"}, /* Output selection dataout right channel , */\ + { 0xa62, "SPKL"}, /* Selection speaker induction , */\ + { 0xa91, "SPKR"}, /* Selection speaker impedance , */\ + { 0xab3, "DCFG"}, /* DCDC speaker current compensation gain , */\ + { 0xf00, "VDDD"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "OTDD"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "OVDD"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "UVDD"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "OCDD"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "CLKD"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "DCCD"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "SPKD"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "WDD"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xf90, "LCLK"}, /* mask flag_lost_clk for interupt generation , */\ + { 0xfe0, "INT"}, /* enabling interrupt , */\ + { 0xff0, "INTP"}, /* Setting polarity interupt , */\ + { 0x8f0f, "VERSION"}, /* (key1 protected) , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9890_BITNAMETABLE static tfaBfName_t Tfa9890BitNames[] = {\ + { 0x402, "i2s_seti"}, /* I2SFormat data 1 input: , */\ + { 0x431, "chan_sel1"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "lr_sw_i2si2"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "input_sel"}, /* Input selection for amplifier , */\ + { 0x481, "datao_sel"}, /* selection data out , */\ + { 0x4a0, "disable_idp"}, /* idp protection , */\ + { 0x4b0, "enbl_datao"}, /* Enable data output , */\ + { 0x4c3, "i2s_fs"}, /* sample rate setting , */\ + { 0x732, "ctrl_bstcur"}, /* Max boost coil current - step of 500 mA , */\ + { 0x9c0, "sel_cf_clk"}, /* Selection CoolFlux Clock , */\ + { 0x9d0, "intf_sel"}, /* selection input 1 or 2 , */\ + { 0xa02, "sel_i2so_l"}, /* Output selection dataout left channel , */\ + { 0xa32, "sel_i2so_r"}, /* Output selection dataout right channel , */\ + { 0xa62, "ctrl_spkr_coil"}, /* Selection speaker induction , */\ + { 0xa91, "ctrl_spr_res"}, /* Selection speaker impedance , */\ + { 0xab3, "ctrl_dcdc_spkr_i_comp_gain"}, /* DCDC speaker current compensation gain , */\ + { 0xaf0, "ctrl_dcdc_spkr_i_comp_sign"}, /* DCDC speaker current compensation sign , */\ + { 0xf00, "flag_por_mask"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "flag_otpok_mask"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "flag_ovpok_mask"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "flag_uvpok_mask"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "flag_ocp_alarm_mask"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "flag_clocks_stable_mask"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "flag_pwrokbst_mask"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "flag_cf_speakererror_mask"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "flag_watchdog_reset_mask"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xf90, "flag_lost_clk_mask"}, /* mask flag_lost_clk for interupt generation , */\ + { 0xfe0, "enable_interrupt"}, /* enabling interrupt , */\ + { 0xff0, "invert_int_polarity"}, /* Setting polarity interupt , */\ + { 0x4700, "switch_fb"}, /* switch_fb , */\ + { 0x4713, "se_hyst"}, /* se_hyst , */\ + { 0x4754, "se_level"}, /* se_level , */\ + { 0x47a5, "ktemp"}, /* temperature compensation trimming , */\ + { 0x8f0f, "production_data6"}, /* (key1 protected) , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + diff --git a/sound/soc/codecs/tfa9891_tfafieldnames.h b/sound/soc/codecs/tfa9891_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..8aa691f5bf061563d2e3dfdbf7f2e592a67e3a26 --- /dev/null +++ b/sound/soc/codecs/tfa9891_tfafieldnames.h @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA_INC_TFA9891_TFAFIELDNAMES_H_ +#define TFA_INC_TFA9891_TFAFIELDNAMES_H_ + +#define TFA9891_I2CVERSION 13 + + +#define TFA9891_NAMETABLE static tfaBfName_t Tfa9891DatasheetNames[] = {\ + { 0x0, "VDDS"}, /* POR , */\ + { 0x10, "PLLS"}, /* PLL , */\ + { 0x20, "OTDS"}, /* OTP , */\ + { 0x30, "OVDS"}, /* OVP , */\ + { 0x40, "UVDS"}, /* UVP , */\ + { 0x50, "OCDS"}, /* OCP , */\ + { 0x60, "CLKS"}, /* Clocks , */\ + { 0x70, "CLIPS"}, /* CLIP , */\ + { 0x80, "MTPB"}, /* MTP , */\ + { 0x90, "DCCS"}, /* BOOST , */\ + { 0xa0, "SPKS"}, /* Speaker , */\ + { 0xb0, "ACS"}, /* cold start flag , */\ + { 0xc0, "SWS"}, /* flag engage , */\ + { 0xd0, "WDS"}, /* flag watchdog reset , */\ + { 0xe0, "AMPS"}, /* amplifier is enabled by manager , */\ + { 0xf0, "AREFS"}, /* references are enabled by manager , */\ + { 0x109, "BATS"}, /* Battery voltage readout; 0[V]..5.5[V] , */\ + { 0x208, "TEMPS"}, /* Temperature readout , */\ + { 0x307, "REV"}, /* Device Revision , */\ + { 0x402, "I2SF"}, /* I2SFormat data 1 input , */\ + { 0x431, "CHS12"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "CHS3"}, /* Channel Selection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x481, "I2SDOC"}, /* Selection for I2S data out , */\ + { 0x4a0, "DISP"}, /* idp protection , */\ + { 0x4b0, "I2SDOE"}, /* Enable data output , */\ + { 0x4c3, "I2SSR"}, /* sample rate setting , */\ + { 0x501, "BSSCR"}, /* ProtectionAttackTime , */\ + { 0x523, "BSST"}, /* ProtectionThreshold , */\ + { 0x561, "BSSRL"}, /* ProtectionMaximumReduction , */\ + { 0x582, "BSSRR"}, /* Protection Release Timer , */\ + { 0x5b1, "BSSHY"}, /* ProtectionHysterese , */\ + { 0x5e0, "BSSR"}, /* battery voltage for I2C read out only , */\ + { 0x5f0, "BSSBY"}, /* bypass clipper battery protection , */\ + { 0x600, "DPSA"}, /* Enable dynamic powerstage activation , */\ + { 0x613, "AMPSL"}, /* control slope , */\ + { 0x650, "CFSM"}, /* Soft mute in CoolFlux , */\ + { 0x670, "BSSS"}, /* batsensesteepness , */\ + { 0x687, "VOL"}, /* volume control (in CoolFlux) , */\ + { 0x702, "DCVO"}, /* Boost voltage , */\ + { 0x732, "DCMCC"}, /* Max boost coil current , */\ + { 0x7a0, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7b0, "DCSR"}, /* Soft RampUp/Down mode for DCDC controller , */\ + { 0x800, "TROS"}, /* select external temperature also the ext_temp will be put on the temp read out , */\ + { 0x818, "EXTTS"}, /* external temperature setting to be given by host , */\ + { 0x900, "PWDN"}, /* ON/OFF , */\ + { 0x910, "I2CR"}, /* I2CReset , */\ + { 0x920, "CFE"}, /* EnableCoolFlux , */\ + { 0x930, "AMPE"}, /* EnableAmplifier , */\ + { 0x940, "DCA"}, /* EnableBoost , */\ + { 0x950, "SBSL"}, /* Coolflux configured , */\ + { 0x960, "AMPC"}, /* Selection on how AmplifierEnabling , */\ + { 0x970, "DCDIS"}, /* DCDC not connected , */\ + { 0x980, "PSDR"}, /* Iddq test amplifier , */\ + { 0x991, "DCCV"}, /* Coil Value , */\ + { 0x9b1, "CCFD"}, /* Selection CoolFluxClock , */\ + { 0x9d0, "ISEL"}, /* Interface Selection , */\ + { 0x9e0, "IPLL"}, /* selection input PLL for lock , */\ + { 0xa02, "DOLS"}, /* Output selection dataout left channel , */\ + { 0xa32, "DORS"}, /* Output selection dataout right channel , */\ + { 0xa62, "SPKL"}, /* Selection speaker induction , */\ + { 0xa91, "SPKR"}, /* Selection speaker impedance , */\ + { 0xab3, "DCFG"}, /* DCDC speaker current compensation gain , */\ + { 0xb07, "MTPK"}, /* MTP KEY2 register , */\ + { 0xf00, "VDDD"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "OTDD"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "OVDD"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "UVDD"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "OCDD"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "CLKD"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "DCCD"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "SPKD"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "WDD"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xfe0, "INT"}, /* enabling interrupt , */\ + { 0xff0, "INTP"}, /* Setting polarity interupt , */\ + { 0x1000, "PDMSEL"}, /* Audio input interface mode , */\ + { 0x1010, "I2SMOUTEN"}, /* I2S Master enable (CLK and WS pads) , */\ + { 0x1021, "PDMORSEL"}, /* PDM Output right channel source selection , */\ + { 0x1041, "PDMOLSEL"}, /* PDM Output Left/Mono channel source selection , */\ + { 0x1061, "PADSEL"}, /* Output interface mode and ball selection , */\ + { 0x1100, "PDMOSDEN"}, /* Secure delay Cell , */\ + { 0x1110, "PDMOSDCF"}, /* Rising Falling Resync control Mux , */\ + { 0x1140, "SAAMEN"}, /* Speaker As a Mic feature ON/OFF , */\ + { 0x1150, "SAAMLPEN"}, /* speaker_as_mic low power mode (only in PDM_out mode), */\ + { 0x1160, "PDMOINTEN"}, /* PDM output interpolation ratio , */\ + { 0x1203, "PDMORG1"}, /* PDM Interpolator Right Channel DS4 G1 Gain Value , */\ + { 0x1243, "PDMORG2"}, /* PDM Interpolator Right Channel DS4 G2 Gain Value , */\ + { 0x1303, "PDMOLG1"}, /* PDM Interpolator Left Channel DS4 G1 Gain Value , */\ + { 0x1343, "PDMOLG2"}, /* PDM Interpolator Left Channel DS4 G2 Gain Value , */\ + { 0x2202, "SAAMGAIN"}, /* pga gain , */\ + { 0x2250, "SAAMPGACTRL"}, /* 0 = active input common mode voltage source at the attenuator/PGA level, */\ + { 0x2500, "PLLCCOSEL"}, /* pll cco frequency , */\ + { 0x4600, "CSBYPGC"}, /* bypass_gc, bypasses the CS gain correction , */\ + { 0x4900, "CLIP"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x4910, "CLIP2"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x62b0, "CIMTP"}, /* start copying all the data from i2cregs_mtp to mtp [Key 2 protected], */\ + { 0x7000, "RST"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "DMEM"}, /* Target memory for access , */\ + { 0x7030, "AIF"}, /* Autoincrement-flag for memory-address , */\ + { 0x7040, "CFINT"}, /* Interrupt CoolFlux DSP , */\ + { 0x7087, "REQ"}, /* request for access (8 channels) , */\ + { 0x710f, "MADD"}, /* memory-address to be accessed , */\ + { 0x720f, "MEMA"}, /* activate memory access (24- or 32-bits data is written/read to/from memory, */\ + { 0x7307, "ERR"}, /* cf error Flags , */\ + { 0x7387, "ACK"}, /* acknowledge of requests (8 channels")" , */\ + { 0x8000, "MTPOTC"}, /* Calibration schedule (key2 protected) , */\ + { 0x8010, "MTPEX"}, /* (key2 protected) calibration of Ron has been executed, */\ + { 0x8045, "SWPROFIL" },\ + { 0x80a5, "SWVSTEP" },\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9891_BITNAMETABLE static tfaBfName_t Tfa9891BitNames[] = {\ + { 0x0, "POR"}, /* POR , */\ + { 0x10, "PLL_LOCK"}, /* PLL , */\ + { 0x20, "flag_otpok"}, /* OTP , */\ + { 0x30, "flag_ovpok"}, /* OVP , */\ + { 0x40, "flag_uvpok"}, /* UVP , */\ + { 0x50, "flag_OCP_alarm"}, /* OCP , */\ + { 0x60, "flag_clocks_stable"}, /* Clocks , */\ + { 0x70, "CLIP"}, /* CLIP , */\ + { 0x80, "mtp_busy"}, /* MTP , */\ + { 0x90, "flag_pwrokbst"}, /* BOOST , */\ + { 0xa0, "flag_cf_speakererror"}, /* Speaker , */\ + { 0xb0, "flag_cold_started"}, /* cold start flag , */\ + { 0xc0, "flag_engage"}, /* flag engage , */\ + { 0xd0, "flag_watchdog_reset"}, /* flag watchdog reset , */\ + { 0xe0, "flag_enbl_amp"}, /* amplifier is enabled by manager , */\ + { 0xf0, "flag_enbl_ref"}, /* references are enabled by manager , */\ + { 0x109, "bat_adc"}, /* Battery voltage readout; 0[V]..5.5[V] , */\ + { 0x208, "temp_adc"}, /* Temperature readout , */\ + { 0x307, "rev_reg"}, /* Device Revision , */\ + { 0x402, "i2s_seti"}, /* I2SFormat data 1 input , */\ + { 0x431, "chan_sel1"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "lr_sw_i2si2"}, /* Channel Selection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "input_sel"}, /* Input selection for amplifier , */\ + { 0x481, "datao_sel"}, /* Selection for I2S data out , */\ + { 0x4a0, "disable_idp"}, /* idp protection , */\ + { 0x4b0, "enbl_datao"}, /* Enable data output , */\ + { 0x4c3, "i2s_fs"}, /* sample rate setting , */\ + { 0x501, "vbat_prot_attacktime"}, /* ProtectionAttackTime , */\ + { 0x523, "vbat_prot_thlevel"}, /* ProtectionThreshold , */\ + { 0x561, "vbat_prot_max_reduct"}, /* ProtectionMaximumReduction , */\ + { 0x582, "vbat_prot_release_t"}, /* Protection Release Timer , */\ + { 0x5b1, "vbat_prot_hysterese"}, /* ProtectionHysterese , */\ + { 0x5d0, "reset_min_vbat"}, /* reset clipper , */\ + { 0x5e0, "sel_vbat"}, /* battery voltage for I2C read out only , */\ + { 0x5f0, "bypass_clipper"}, /* bypass clipper battery protection , */\ + { 0x600, "dpsa"}, /* Enable dynamic powerstage activation , */\ + { 0x613, "ctrl_slope"}, /* control slope , */\ + { 0x650, "cf_mute"}, /* Soft mute in CoolFlux , */\ + { 0x660, "sel_other_vamp"}, /* Input selection for the second channel of the DCDC inteligent mode detector, */\ + { 0x670, "ctrl_batsensesteepness"}, /* batsensesteepness , */\ + { 0x687, "vol"}, /* volume control (in CoolFlux) , */\ + { 0x702, "ctrl_bstvolt"}, /* Boost voltage , */\ + { 0x732, "ctrl_bstcur"}, /* Max boost coil current , */\ + { 0x761, "ctrl_slopebst_1_0"}, /* Setting for the slope of the boost converter power stage, */\ + { 0x781, "ctrl_slopebst_3_2"}, /* Setting for the part of the power transistor voltage to be used in peak current mode control, */\ + { 0x7a0, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7b0, "boost_speed"}, /* Soft RampUp/Down mode for DCDC controller , */\ + { 0x7c1, "ctrl_delay_comp_dcdc"}, /* delay compensation in current patg compared to delay in the audio path (relative) , */\ + { 0x7e0, "boost_input"}, /* Selection intelligent boost detector input , */\ + { 0x7f0, "ctrl_supplysense"}, /* ADC10 input selection , */\ + { 0x800, "ext_temp_sel"}, /* select external temperature also the ext_temp will be put on the temp read out , */\ + { 0x818, "ext_temp"}, /* external temperature setting to be given by host , */\ + { 0x8a0, "ctrl_spk_coilpvp_bst"}, /* Peak voltage protection boost converter , */\ + { 0x8b2, "ctrl_dcdc_synchronisation"}, /* DCDC synchronisation off + 7 positions , */\ + { 0x8e0, "ctrl_cs_samplevalid"}, /* sample valid moment for CS in single sample moment mode, */\ + { 0x900, "PowerDown"}, /* ON/OFF , */\ + { 0x910, "reset"}, /* I2CReset , */\ + { 0x920, "enbl_coolflux"}, /* EnableCoolFlux , */\ + { 0x930, "enbl_amplifier"}, /* EnableAmplifier , */\ + { 0x940, "enbl_boost"}, /* EnableBoost , */\ + { 0x950, "cf_configured"}, /* Coolflux configured , */\ + { 0x960, "sel_enbl_amplifier"}, /* Selection on how AmplifierEnabling , */\ + { 0x970, "dcdcoff_mode"}, /* DCDC not connected , */\ + { 0x980, "cttr_iddqtest"}, /* Iddq test amplifier , */\ + { 0x991, "ctrl_coil_value"}, /* Coil Value , */\ + { 0x9b1, "ctrl_sel_cf_clock"}, /* Selection CoolFluxClock , */\ + { 0x9d0, "intf_sel"}, /* Interface Selection , */\ + { 0x9e0, "sel_ws_bck"}, /* selection input PLL for lock , */\ + { 0xa02, "sel_i2so_l"}, /* Output selection dataout left channel , */\ + { 0xa32, "sel_i2so_r"}, /* Output selection dataout right channel , */\ + { 0xa62, "ctrl_spkr_coil"}, /* Selection speaker induction , */\ + { 0xa91, "ctrl_spr_res"}, /* Selection speaker impedance , */\ + { 0xab3, "ctrl_dcdc_spkr_i_comp_gain"}, /* DCDC speaker current compensation gain , */\ + { 0xaf0, "ctrl_dcdc_spkr_i_comp_sign"}, /* DCDC speaker current compensation sign , */\ + { 0xb07, "MTP_key2"}, /* MTP KEY2 register , */\ + { 0xc0c, "clk_sync_delay"}, /* Delay count for clock synchronisation , */\ + { 0xcf0, "enbl_clk_sync"}, /* Enable CGU clock synchronisation , */\ + { 0xd0c, "adc_sync_delay"}, /* Delay count for ADC synchronisation , */\ + { 0xdf0, "enable_adc_sync"}, /* Enable ADC synchronisation , */\ + { 0xe00, "bypass_dcdc_curr_prot"}, /* to switch off dcdc reduction with bat prot , */\ + { 0xe24, "ctrl_digtoana6_2"}, /* for extra connections digital to analog , */\ + { 0xe70, "switch_on_icomp"}, /* icomp dem switch , */\ + { 0xe87, "reserve_reg_1_7_0"}, /* reserved , */\ + { 0xf00, "flag_por_mask"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "flag_otpok_mask"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "flag_ovpok_mask"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "flag_uvpok_mask"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "flag_ocp_alarm_mask"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "flag_clocks_stable_mask"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "flag_pwrokbst_mask"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "flag_cf_speakererror_mask"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "flag_watchdog_reset_mask"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xf90, "flag_lost_clk_mask"}, /* mask flag_lost_clk for interupt generation , */\ + { 0xfe0, "enable_interrupt"}, /* enabling interrupt , */\ + { 0xff0, "invert_int_polarity"}, /* Setting polarity interupt , */\ + { 0x1000, "pdm_i2s_input"}, /* Audio input interface mode , */\ + { 0x1010, "I2S_master_ena"}, /* I2S Master enable (CLK and WS pads) , */\ + { 0x1021, "pdm_out_sel_r"}, /* PDM Output right channel source selection , */\ + { 0x1041, "pdm_out_sel_l"}, /* PDM Output Left/Mono channel source selection , */\ + { 0x1061, "micdat_out_sel"}, /* Output interface mode and ball selection , */\ + { 0x1100, "secure_dly"}, /* Secure delay Cell , */\ + { 0x1110, "d_out_valid_rf_mux"}, /* Rising Falling Resync control Mux , */\ + { 0x1140, "Speak_As_Mic_en"}, /* Speaker As a Mic feature ON/OFF , */\ + { 0x1150, "speak_as_mic_lp_mode"}, /* speaker_as_mic low power mode (only in PDM_out mode), */\ + { 0x1160, "pdm_out_rate"}, /* PDM output interpolation ratio , */\ + { 0x1203, "ds4_g1_r"}, /* PDM Interpolator Right Channel DS4 G1 Gain Value , */\ + { 0x1243, "ds4_g2_r"}, /* PDM Interpolator Right Channel DS4 G2 Gain Value , */\ + { 0x1303, "ds4_g1_l"}, /* PDM Interpolator Left Channel DS4 G1 Gain Value , */\ + { 0x1343, "ds4_g2_l"}, /* PDM Interpolator Left Channel DS4 G2 Gain Value , */\ + { 0x1400, "clk_secure_dly"}, /* Secure delay Cell on clock path , */\ + { 0x1410, "data_secure_dly"}, /* Secure delay Cell enable on PDM data path , */\ + { 0x2202, "Ctrl_saam_pga_gain"}, /* pga gain , */\ + { 0x2250, "ctrl_saam_pga_src"}, /* 0 = active input common mode voltage source at the attenuator/PGA level, */\ + { 0x2300, "flag_saam_spare"}, /* spare flag , */\ + { 0x2400, "ctrl_saam_pga_tm"}, /* enables PGA test mode , */\ + { 0x2500, "pll_fcco"}, /* pll cco frequency , */\ + { 0x3000, "flag_hi_small"}, /* positive small window dcdc converter , */\ + { 0x3010, "flag_hi_large"}, /* positive large window dcdc converter , */\ + { 0x3020, "flag_lo_small"}, /* negative small window dcdc converter , */\ + { 0x3030, "flag_lo_large"}, /* negative large window dcdc converter , */\ + { 0x3040, "flag_voutcomp"}, /* flag_voutcomp, indication Vset is larger than Vbat, */\ + { 0x3050, "flag_voutcomp93"}, /* flag_voutcomp93, indication Vset is larger than 1.07* Vbat , */\ + { 0x3060, "flag_voutcomp86"}, /* flag_voutcomp86, indication Vset is larger than 1.14* Vbat , */\ + { 0x3070, "flag_hiz"}, /* flag_hiz, indication Vbst is larger than Vbat , */\ + { 0x3080, "flag_hi_peak"}, /* flag_hi_peak, indication hi_peak , */\ + { 0x3090, "flag_ocpokbst"}, /* flag_ocpokbst, indication no over current in boost converter pmos switch, */\ + { 0x30a0, "flag_peakcur"}, /* flag_peakcur, indication current is max in dcdc converter, */\ + { 0x30b0, "flag_ocpokap"}, /* flag_ocpokap, indication no over current in amplifier "a" pmos output stage, */\ + { 0x30c0, "flag_ocpokan"}, /* flag_ocpokan, indication no over current in amplifier "a" nmos output stage, */\ + { 0x30d0, "flag_ocpokbp"}, /* flag_ocpokbp, indication no over current in amplifier "b" pmos output stage, */\ + { 0x30e0, "flag_ocpokbn"}, /* flag_ocpokbn, indication no over current in amplifier"b" nmos output stage, */\ + { 0x30f0, "lost_clk"}, /* lost_clk, lost clock indication CGU , */\ + { 0x310f, "mtp_man_data_out"}, /* single word read from MTP (manual copy) , */\ + { 0x3200, "key01_locked"}, /* key01_locked, indication key 1 is locked , */\ + { 0x3210, "key02_locked"}, /* key02_locked, indication key 2 is locked , */\ + { 0x3225, "mtp_ecc_tcout"}, /* mtp_ecc_tcout , */\ + { 0x3280, "mtpctrl_valid_test_rd"}, /* mtp test readout for read , */\ + { 0x3290, "mtpctrl_valid_test_wr"}, /* mtp test readout for write , */\ + { 0x32a0, "flag_in_alarm_state"}, /* alarm state , */\ + { 0x32b0, "mtp_ecc_err2"}, /* two or more bit errors detected in MTP, can not reconstruct value, */\ + { 0x32c0, "mtp_ecc_err1"}, /* one bit error detected in MTP, reconstructed value, */\ + { 0x32d0, "mtp_mtp_hvf"}, /* high voltage ready flag for MTP , */\ + { 0x32f0, "mtp_zero_check_fail"}, /* zero check failed (tbd) for MTP , */\ + { 0x3300, "flag_adc10_ready"}, /* flag_adc10_ready, indication adc10 is ready , */\ + { 0x3310, "flag_clipa_high"}, /* flag_clipa_high, indication pmos amplifier "a" is clipping, */\ + { 0x3320, "flag_clipa_low"}, /* flag_clipa_low, indication nmos amplifier "a" is clipping, */\ + { 0x3330, "flag_clipb_high"}, /* flag_clipb_high, indication pmos amplifier "b" is clipping, */\ + { 0x3340, "flag_clipb_low"}, /* flag_clipb_low, indication nmos amplifier "b" is clipping, */\ + { 0x3359, "data_adc10_tempbat"}, /* adc 10 data output for testing , */\ + { 0x33f0, "flag_vddd_comp_nok"}, /* power switch flag 2 for testing , */\ + { 0x400f, "hid_code"}, /* hidden code , */\ + { 0x4100, "bypass_hp"}, /* Bypass_High Pass Filter , */\ + { 0x4110, "hard_mute"}, /* Hard Mute , */\ + { 0x4120, "soft_mute"}, /* Soft Mute , */\ + { 0x4134, "PWM_Delay"}, /* PWM DelayBits to set the delay , */\ + { 0x4180, "PWM_Shape"}, /* PWM Shape , */\ + { 0x4190, "PWM_BitLength"}, /* PWM Bitlength in noise shaper , */\ + { 0x4207, "ctrl_drive"}, /* drive bits to select amount of power stages amplifier, */\ + { 0x4281, "dpsalevel"}, /* DPSA Threshold level , */\ + { 0x42a1, "dpsa_release"}, /* DPSA Release time , */\ + { 0x42c0, "ctrl_coincidence"}, /* Prevent simultaneously switching of output stage , */\ + { 0x42d0, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x42e0, "ctrl_test_sdeltaoffset"}, /* ctrl_test_sdeltaoffset , */\ + { 0x42f0, "ctrl_test_sdeltaclk"}, /* ctrl_test_sdeltaclk , */\ + { 0x4309, "ctrl_drivebst"}, /* Drive bits to select the powertransistor sections boost converter, */\ + { 0x43a0, "ctrl_ocptestbst"}, /* Boost OCP. , */\ + { 0x43c0, "enbl_hi_peak"}, /* enable for high peak comparator , */\ + { 0x43d0, "test_abistfft_enbl"}, /* FFT coolflux , */\ + { 0x43e0, "ctrl_sensetest_amp"}, /* sensetest amplifier , */\ + { 0x43f0, "test_bcontrol"}, /* test _bcontrol , */\ + { 0x4400, "ctrl_reversebst"}, /* OverCurrent Protection selection of power stage boost converter, */\ + { 0x4410, "ctrl_sensetest"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0x4420, "enbl_engagebst"}, /* Enable power stage dcdc controller , */\ + { 0x4430, "enbl_hi_small"}, /* Enable bit of hi (small) comparator , */\ + { 0x4440, "enbl_hi_large"}, /* Enable bit of hi (large) comparator , */\ + { 0x4450, "enbl_lo_small"}, /* Enable bit of lo (small) comparator , */\ + { 0x4460, "enbl_lo_large"}, /* Enable bit of lo (large) comparator , */\ + { 0x4470, "enbl_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x4480, "enbl_voutcomp"}, /* Enable vout comparators , */\ + { 0x4490, "enbl_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x44a0, "enbl_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x44b0, "enbl_hizcom"}, /* Enable hiz comparator , */\ + { 0x44c0, "enbl_pcdac"}, /* Enable peak current dac , */\ + { 0x44d0, "enbl_pccomp"}, /* Enable peak current comparator , */\ + { 0x44e0, "enbl_windac"}, /* Enable window dac , */\ + { 0x44f0, "enbl_powerbst"}, /* Enable line of the powerstage , */\ + { 0x4507, "ocp_thr"}, /* ocp_thr threshold level for OCP , */\ + { 0x4580, "bypass_glitchfilter"}, /* Bypass glitchfilter , */\ + { 0x4590, "bypass_ovp"}, /* Bypass OVP , */\ + { 0x45a0, "bypass_uvp"}, /* Bypass UVP , */\ + { 0x45b0, "bypass_otp"}, /* Bypass OTP , */\ + { 0x45c0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0x45d0, "bypass_ocpcounter"}, /* BypassOCPCounter , */\ + { 0x45e0, "bypass_lost_clk"}, /* Bypasslost_clk detector , */\ + { 0x45f0, "vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0x4600, "bypass_gc"}, /* bypass_gc, bypasses the CS gain correction , */\ + { 0x4610, "cs_gain_control"}, /* gain control by means of MTP or i2c , */\ + { 0x4627, "cs_gain"}, /* + / - 128 steps in steps of 1/4 % 2's compliment , */\ + { 0x46a0, "bypass_lp"}, /* bypass Low-Pass filter in temperature sensor , */\ + { 0x46b0, "bypass_pwmcounter"}, /* bypass_pwmcounter , */\ + { 0x46c0, "ctrl_cs_negfixed"}, /* does not switch to neg , */\ + { 0x46d2, "ctrl_cs_neghyst"}, /* switches to neg depending on level , */\ + { 0x4700, "switch_fb"}, /* switch_fb , */\ + { 0x4713, "se_hyst"}, /* se_hyst , */\ + { 0x4754, "se_level"}, /* se_level , */\ + { 0x47a5, "ktemp"}, /* temperature compensation trimming , */\ + { 0x4800, "ctrl_negin"}, /* negin , */\ + { 0x4810, "ctrl_cs_sein"}, /* cs_sein , */\ + { 0x4820, "ctrl_coincidencecs"}, /* Coincidence current sense , */\ + { 0x4830, "ctrl_iddqtestbst"}, /* for iddq testing in powerstage of boost convertor , */\ + { 0x4840, "ctrl_coincidencebst"}, /* Switch protection on to prevent simultaniously switching power stages bst and amp, */\ + { 0x4851, "clock_sh_sel"}, /* Clock SH selection , */\ + { 0x4876, "delay_se_neg"}, /* delay of se and neg , */\ + { 0x48e1, "ctrl_cs_ttrack"}, /* sample & hold track time , */\ + { 0x4900, "ctrl_bypassclip"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x4910, "ctrl_bypassclip2"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x4920, "ctrl_clkgateCFoff"}, /* to disable clock gating in the coolflux , */\ + { 0x4930, "ctrl_testabst"}, /* testabst , */\ + { 0x4940, "ctrl_clipfast"}, /* clock switch for battery protection clipper, it switches back to old frequency, */\ + { 0x4950, "ctrl_cs_8ohm"}, /* 8 ohm mode for current sense (gain mode) , */\ + { 0x4960, "reserved"}, /* reserved , */\ + { 0x4974, "delay_clock_sh"}, /* delay_sh, tunes S7H delay , */\ + { 0x49c0, "inv_clksh"}, /* Invert the sample/hold clock for current sense ADC, */\ + { 0x49d0, "inv_neg"}, /* Invert neg signal , */\ + { 0x49e0, "inv_se"}, /* Invert se signal , */\ + { 0x49f0, "setse"}, /* switches between Single Ende and differentail mode, */\ + { 0x4a12, "ctrl_adc10_sel"}, /* select the input to convert the 10b ADC , */\ + { 0x4a60, "ctrl_adc10_reset"}, /* Global asynchronous reset (active HIGH) 10 bit ADC, */\ + { 0x4a81, "ctrl_adc10_test"}, /* Test mode selection signal 10 bit ADC , */\ + { 0x4aa0, "ctrl_bypass_lp_vbat"}, /* lp filter in batt sensor , */\ + { 0x4ae0, "ctrl_dc_offset"}, /* switch offset control on/off, is decimator offset control, */\ + { 0x4af0, "ctrl_tsense_hibias"}, /* bit to set the biasing in temp sensor to high , */\ + { 0x4b00, "ctrl_adc13_iset"}, /* Micadc Setting of current consumption. Debug use only, */\ + { 0x4b14, "ctrl_adc13_gain"}, /* Micadc gain setting (2-compl) , */\ + { 0x4b61, "ctrl_adc13_slowdel"}, /* Micadc Delay setting for internal clock. Debug use only, */\ + { 0x4b83, "ctrl_adc13_offset"}, /* Micadc ADC offset setting , */\ + { 0x4bc0, "ctrl_adc13_bsoinv"}, /* Micadc bit stream output invert mode for test , */\ + { 0x4bd0, "ctrl_adc13_resonator_enable"}, /* Micadc Give extra SNR with less stability. Debug use only, */\ + { 0x4be0, "ctrl_testmicadc"}, /* Mux at input of MICADC for test purpose , */\ + { 0x4c0f, "ctrl_offset"}, /* offset control for ABIST testing , */\ + { 0x4d05, "ctrl_windac"}, /* for testing direct control windac , */\ + { 0x4d65, "ctrl_peakcur"}, /* Control peakcur , */\ + { 0x4dc3, "pwm_dcc_cnt"}, /* control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0x4e04, "ctrl_slopecur"}, /* for testing direct control slopecur , */\ + { 0x4e53, "ctrl_dem"}, /* dyn element matching control, rest of codes are optional, */\ + { 0x4e93, "ctrl_demmismatch"}, /* dyn element matching add offset , */\ + { 0x4ed0, "enbl_pwm_dcc"}, /* to enable direct control of pwm duty cycle , */\ + { 0x5007, "gain"}, /* gain setting of the gain multiplier gain need to increase with factor 1.41 (3dB), */\ + { 0x5081, "ctrl_sourceb"}, /* Set OUTB to , */\ + { 0x50a1, "ctrl_sourcea"}, /* Set OUTA to , */\ + { 0x50c1, "ctrl_sourcebst"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0x50e1, "ctrl_test_mono"}, /* ABIST mode to add both amplifier halfs as stereo or one amplifier half as mono, */\ + { 0x5104, "pulselengthbst"}, /* pulselength setting test input for boost converter , */\ + { 0x5150, "ctrl_bypasslatchbst"}, /* bypass_latch in boost converter , */\ + { 0x5160, "invertbst"}, /* invert pwmbst test signal , */\ + { 0x5174, "pulselength"}, /* pulselength setting test input for amplifier , */\ + { 0x51c0, "ctrl_bypasslatch"}, /* bypass_latch in boost convert , */\ + { 0x51d0, "invertb"}, /* invert pwmb test signal , */\ + { 0x51e0, "inverta"}, /* invert pwma test signal , */\ + { 0x51f0, "ctrl_bypass_ctrlloop"}, /* bypass_ctrlloop bypasses the control loop of the amplifier, */\ + { 0x5200, "ctrl_test_discrete"}, /* tbd for rdson testing , */\ + { 0x5210, "ctrl_test_rdsona"}, /* tbd for rdson testing , */\ + { 0x5220, "ctrl_test_rdsonb"}, /* tbd for rdson testing , */\ + { 0x5230, "ctrl_test_rdsonbst"}, /* tbd for rdson testing , */\ + { 0x5240, "ctrl_test_cvia"}, /* tbd for rdson testing , */\ + { 0x5250, "ctrl_test_cvib"}, /* tbd for rdson testing , */\ + { 0x5260, "ctrl_test_cvibst"}, /* tbd for rdson testing , */\ + { 0x5290, "test_bypass_pwmdiscretea"}, /* for testing ( ABIST) , */\ + { 0x52a0, "test_bypass_pwmdiscreteb"}, /* for testing ( ABIST) , */\ + { 0x52b0, "ctrl_clipc_forcehigh"}, /* test signal for clipcontrol , */\ + { 0x52c0, "ctrl_clipc_forcelow"}, /* test signal for clipcontrol , */\ + { 0x52d0, "ctrl_test_sdelta"}, /* for testing ( ABIST) , */\ + { 0x52e0, "ctrl_test_swhvp"}, /* for testing ( ABIST) , */\ + { 0x52f0, "test_gain_reduction"}, /* test gain reduction , */\ + { 0x5303, "ctrl_digimux_out_test1"}, /* Digimux TEST1 out , */\ + { 0x5343, "ctrl_digimux_out_test2"}, /* Digimux TEST2 out. output flag_clipa_low depending on cntr_bypassclip setting, */\ + { 0x5383, "ctrl_digimux_out_data1"}, /* Digimux DATA1 out (output flag_clipb_high depending on cntr_bypassclip setting), */\ + { 0x53c3, "ctrl_digimux_out_data3"}, /* Digimux DATA3 out (output flag_clipx_x depending on cntr_bypassclip setting), */\ + { 0x5400, "hs_mode"}, /* hs_mode, high speed mode I2C bus , */\ + { 0x5412, "test_parametric_io"}, /* test_parametric_io for testing pads , */\ + { 0x5440, "enbl_ringo"}, /* enbl_ringo, for test purpose to check with ringo , */\ + { 0x5480, "ctrl_cliplevel"}, /* Clip level , */\ + { 0x5491, "ctrl_anamux_sel"}, /* anamux selection , */\ + { 0x54b0, "test_vdddsw_dio"}, /* to overrule the power switches for memory , */\ + { 0x54c0, "ctrl_bypass_diosw_ovp"}, /* To disable the overvoltage protection of vddd_dio_sw, */\ + { 0x54d0, "test_vddd_sw"}, /* test vdd sw , */\ + { 0x54e0, "test_vddd_sw_comp"}, /* test vdd sw comp , */\ + { 0x550e, "enbl_amp"}, /* enbl_amp for testing to enable all analoge blocks in amplifier, */\ + { 0x55f0, "fr_fsp"}, /* extr free running clock mode for testing , */\ + { 0x5600, "use_direct_ctrls"}, /* use_direct_ctrls, to overrule several functions direct for testing, */\ + { 0x5610, "rst_datapath"}, /* rst_datapath, datapath reset , */\ + { 0x5620, "rst_cgu"}, /* rst_cgu, cgu reset , */\ + { 0x5637, "enbl_ref"}, /* for testing to enable all analoge blocks in references, */\ + { 0x56b0, "enbl_engage"}, /* Enable output stage amplifier , */\ + { 0x56c0, "use_direct_clk_ctrl"}, /* use_direct_clk_ctrl, to overrule several functions direct for testing, */\ + { 0x56d0, "use_direct_pll_ctrl"}, /* use_direct_pll_ctrl, to overrule several functions direct for test, */\ + { 0x56e0, "use_direct_ctrls_2"}, /* use_direct_sourseamp_ctrls, to overrule several functions direct for testing, */\ + { 0x5707, "ctrl_anamux_out_test1"}, /* Anamux control , */\ + { 0x5782, "ctrl_zero"}, /* Bandwith control feedbackloop , */\ + { 0x57b0, "enbl_ldo_stress"}, /* LDO stress function frinch capacitors , */\ + { 0x57c0, "ctrl_ocptest"}, /* ctrl_ocptest, deactivates the over current protection in the power stages of the amplifier. The ocp flag signals stay active., */\ + { 0x57e0, "ctrl_otptest"}, /* otptest, test mode otp amplifier , */\ + { 0x57f0, "ctrl_reverse"}, /* CTRL revers , */\ + { 0x5802, "pll_mdec_msb"}, /* most significant bits pll_mdec , */\ + { 0x5833, "pll_selr"}, /* pll_selr , */\ + { 0x5874, "pll_selp"}, /* pll_selp , */\ + { 0x58c3, "pll_seli"}, /* pll_seli , */\ + { 0x5900, "pll_psel"}, /* pll_psel , */\ + { 0x5910, "use_direct_pll_psel"}, /* use_direct_pll_psel , */\ + { 0x5923, "nbck"}, /* NBCK , */\ + { 0x5960, "auto_nbck"}, /* AUTO_NBCK , */\ + { 0x5970, "pll_frm"}, /* pll_frm , */\ + { 0x5980, "pll_directi"}, /* pll_directi , */\ + { 0x5990, "pll_directo"}, /* pll_directo , */\ + { 0x59a0, "enbl_PLL"}, /* enbl_PLL , */\ + { 0x59b0, "sel_clkout"}, /* SEL_CLKOUT , */\ + { 0x59e0, "fr_lost_clk"}, /* fr_lost_clk , */\ + { 0x59f0, "pll_bypass"}, /* pll_bypass , */\ + { 0x5a0f, "tsig_freq"}, /* tsig_freq, internal sinus test generator, frequency control, */\ + { 0x5b02, "tsig_freq_msb"}, /* select internal sinus test generator, frequency control msb bits, */\ + { 0x5b30, "inject_tsig"}, /* inject_tsig, control bit to switch to internal sinus test generator, */\ + { 0x5b44, "ctrl_adc10_prog_sample"}, /* control ADC10 , */\ + { 0x5c01, "pll_ndec_msb"}, /* most significant bits of pll_ndec , */\ + { 0x5c2d, "pll_mdec"}, /* bits 13..0 of pll_mdec , */\ + { 0x5d06, "pll_pdec"}, /* pll_pdec , */\ + { 0x5d87, "pll_ndec"}, /* bits 7..0 of pll_ndec , */\ + { 0x5e00, "pdm_ch_sel_reg"}, /* PDM channel selection , */\ + { 0x5e10, "pdm_iis_rst_reg"}, /* PDM Interface reset , */\ + { 0x5e20, "clk_src_sel_reg"}, /* WS Source Selection , */\ + { 0x5e70, "pdm_resync_bypass"}, /* PDM resynchronization bypass , */\ + { 0x6007, "MTP_key1"}, /* MTP Key1 , */\ + { 0x6185, "mtp_ecc_tcin"}, /* Mtp_ecc_tcin , */\ + { 0x6203, "mtp_man_address_in"}, /* address from i2cregs for writing one word single mtp, */\ + { 0x6260, "mtp_ecc_eeb"}, /* enable code bit generation (active low!) , */\ + { 0x6270, "mtp_ecc_ecb"}, /* enable correction signal (active low!) , */\ + { 0x6280, "man_copy_mtp_to_iic"}, /* start copying single word from mtp to i2cregs_mtp , */\ + { 0x6290, "man_copy_iic_to_mtp"}, /* start copying single word from i2cregs_mtp to mtp [Key 1 protected], */\ + { 0x62a0, "auto_copy_mtp_to_iic"}, /* start copying all the data from mtp to i2cregs_mtp, */\ + { 0x62b0, "auto_copy_iic_to_mtp"}, /* start copying all the data from i2cregs_mtp to mtp [Key 2 protected], */\ + { 0x62d2, "mtp_speed_mode"}, /* Speed mode , */\ + { 0x6340, "mtp_dircet_enable"}, /* mtp_direct_enable (key1 protected) , */\ + { 0x6350, "mtp_direct_wr"}, /* mtp_direct_wr (key1 protected) direct value for mtp pin wr. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6360, "mtp_direct_rd"}, /* mtp_direct_rd (key1 protected) direct value for mtp pin rd. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6370, "mtp_direct_rst"}, /* mtp_direct_rst (key1 protected) direct value for mtp pin rst. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6380, "mtp_direct_ers"}, /* mtp_direct_ers (key1 protected) direct value for mtp pin ers. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6390, "mtp_direct_prg"}, /* mtp_direct_prg (key1 protected) direct value for mtp pin prg. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x63a0, "mtp_direct_epp"}, /* mtp_direct_epp (key1 protected) direct value for mtp pin epp. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x63b4, "mtp_direct_test"}, /* mtp_direct_test (key1 protected) , */\ + { 0x640f, "mtp_man_data_in"}, /* single wordt be written to MTP (manual copy) , */\ + { 0x7000, "cf_rst_dsp"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "cf_dmem"}, /* Target memory for access , */\ + { 0x7030, "cf_aif"}, /* Autoincrement-flag for memory-address , */\ + { 0x7040, "cf_int"}, /* Interrupt CoolFlux DSP , */\ + { 0x7087, "cf_req"}, /* request for access (8 channels) , */\ + { 0x710f, "cf_madd"}, /* memory-address to be accessed , */\ + { 0x720f, "cf_mema"}, /* activate memory access (24- or 32-bits data is written/read to/from memory, */\ + { 0x7307, "cf_err"}, /* cf error Flags , */\ + { 0x7387, "cf_ack"}, /* acknowledge of requests (8 channels")" , */\ + { 0x8000, "calibration_onetime"}, /* Calibration schedule (key2 protected) , */\ + { 0x8010, "calibr_ron_done"}, /* (key2 protected) calibration of Ron has been executed, */\ + { 0x8105, "calibr_vout_offset"}, /* calibr_vout_offset (DCDCoffset) 2's compliment (key1 protected), */\ + { 0x8163, "calibr_delta_gain"}, /* delta gain for vamp (alpha) 2's compliment (key1 protected), */\ + { 0x81a5, "calibr_offs_amp"}, /* offset for vamp (Ampoffset) 2's compliment (key1 protected), */\ + { 0x8207, "calibr_gain_cs"}, /* gain current sense (Imeasalpha) 2's compliment (key1 protected), */\ + { 0x8284, "calibr_temp_offset"}, /* temperature offset 2's compliment (key1 protected), */\ + { 0x82d2, "calibr_temp_gain"}, /* temperature gain 2's compliment (key1 protected) , */\ + { 0x830f, "calibr_ron"}, /* Ron resistance of coil (key1 protected) , */\ + { 0x8406, "ctrl_offset_a"}, /* Offset of amplifier level shifter , */\ + { 0x8486, "ctrl_offset_b"}, /* Offset of amplifier level shifter , */\ + { 0x850f, "type_bits_HW"}, /* HW Bits , */\ + { 0x860f, "type_bits1_SW"}, /* MTP-control SW1 , */\ + { 0x870f, "type_bits2_SW"}, /* MTP-control SW2 , */\ + { 0x8a0f, "production_data1"}, /* (key1 protected) , */\ + { 0x8b0f, "production_data2"}, /* (key1 protected) , */\ + { 0x8c0f, "production_data3"}, /* (key1 protected) , */\ + { 0x8d0f, "production_data4"}, /* (key1 protected) , */\ + { 0x8e0f, "production_data5"}, /* (key1 protected) , */\ + { 0x8f0f, "production_data6"}, /* (key1 protected) , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + + +#endif /* TFA_INC_TFA9891_TFAFIELDNAMES_H_ */ diff --git a/sound/soc/codecs/tfa9894_tfafieldnames.h b/sound/soc/codecs/tfa9894_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..327c15eef5bf5688d57dc5afc769d2e1787df3b4 --- /dev/null +++ b/sound/soc/codecs/tfa9894_tfafieldnames.h @@ -0,0 +1,1072 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9894_TFAFIELDNAMES_H +#define _TFA9894_TFAFIELDNAMES_H + + +#define TFA9894_I2CVERSION 17.0 + +typedef enum nxpTfa9894BfEnumList { + TFA9894_BF_PWDN = 0x0000, /*!< Powerdown control */ + TFA9894_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9894_BF_CFE = 0x0020, /*!< Enable CoolFlux DSP */ + TFA9894_BF_AMPE = 0x0030, /*!< Enable Amplifier */ + TFA9894_BF_DCA = 0x0040, /*!< Enable DCDC Boost converter */ + TFA9894_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA9894_BF_AMPC = 0x0060, /*!< CoolFlux control over amplifier */ + TFA9894_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9894_BF_FSSSEL = 0x0090, /*!< Audio sample reference */ + TFA9894_BF_BYPOCP = 0x00a0, /*!< Bypass OCP */ + TFA9894_BF_TSTOCP = 0x00b0, /*!< OCP testing control */ + TFA9894_BF_BSSS = 0x00c0, /*!< Vbat protection steepness */ + TFA9894_BF_HPFBYP = 0x00d0, /*!< Bypass High Pass Filter */ + TFA9894_BF_DPSA = 0x00e0, /*!< Enable DPSA */ + TFA9894_BF_AMPINSEL = 0x0101, /*!< Amplifier input selection */ + TFA9894_BF_MANSCONF = 0x0120, /*!< Device I2C settings configured */ + TFA9894_BF_MANCOLD = 0x0130, /*!< Execute cold start */ + TFA9894_BF_MANROBOD = 0x0140, /*!< Reaction on BOD */ + TFA9894_BF_BODE = 0x0150, /*!< Enable BOD (only in direct control mode) */ + TFA9894_BF_BODHYS = 0x0160, /*!< Enable Hysteresis of BOD */ + TFA9894_BF_BODFILT = 0x0171, /*!< BOD filter */ + TFA9894_BF_BODTHLVL = 0x0191, /*!< BOD threshold */ + TFA9894_BF_MUTETO = 0x01b0, /*!< Time out SB mute sequence */ + TFA9894_BF_MANWDE = 0x01c0, /*!< Watchdog enable */ + TFA9894_BF_OPENMTP = 0x01e0, /*!< Control for FAIM protection */ + TFA9894_BF_FAIMVBGOVRRL = 0x01f0, /*!< Overrule the enabling of VBG for faim erase/write access */ + TFA9894_BF_AUDFS = 0x0203, /*!< Audio sample rate Fs */ + TFA9894_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ + TFA9894_BF_FRACTDEL = 0x0255, /*!< Current sense fractional delay */ + TFA9894_BF_TDMPRES = 0x02b1, /*!< Control for HW manager */ + TFA9894_BF_AMPOCRT = 0x02d2, /*!< Amplifier on-off criteria for shutdown */ + TFA9894_BF_REV = 0x030f, /*!< Revision info */ + TFA9894_BF_REFCKEXT = 0x0401, /*!< PLL external reference clock */ + TFA9894_BF_REFCKSEL = 0x0420, /*!< PLL internal reference clock */ + TFA9894_BF_MCLKSEL = 0x0432, /*!< Master Clock Selection */ + TFA9894_BF_MANAOOSC = 0x0460, /*!< Internal OSC1M off at PWDN */ + TFA9894_BF_ACKCLDDIS = 0x0470, /*!< Automatic PLL reference clock selection for cold start */ + TFA9894_BF_SPKSSEN = 0x0510, /*!< Enable speaker sub-system */ + TFA9894_BF_MTPSSEN = 0x0520, /*!< Enable FAIM sub-system */ + TFA9894_BF_WDTCLKEN = 0x0530, /*!< Enable Coolflux watchdog clock */ + TFA9894_BF_VDDS = 0x1000, /*!< POR */ + TFA9894_BF_PLLS = 0x1010, /*!< PLL Lock */ + TFA9894_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA9894_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA9894_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA9894_BF_OCDS = 0x1050, /*!< OCP amplifier (sticky register, clear on read) */ + TFA9894_BF_CLKS = 0x1060, /*!< Clocks stable */ + TFA9894_BF_MTPB = 0x1070, /*!< MTP busy */ + TFA9894_BF_NOCLK = 0x1080, /*!< Lost clock */ + TFA9894_BF_ACS = 0x1090, /*!< Cold Start */ + TFA9894_BF_WDS = 0x10a0, /*!< Watchdog */ + TFA9894_BF_SWS = 0x10b0, /*!< Amplifier engage */ + TFA9894_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA9894_BF_AREFS = 0x10d0, /*!< References enable */ + TFA9894_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA9894_BF_BODNOK = 0x10f0, /*!< BOD Flag - VDD NOT OK */ + TFA9894_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9894_BF_DCDCA = 0x1110, /*!< DCDC active (sticky register, clear on read) */ + TFA9894_BF_DCOCPOK = 0x1120, /*!< DCDC OCP nmos (sticky register, clear on read) */ + TFA9894_BF_DCHVBAT = 0x1140, /*!< DCDC level 1x */ + TFA9894_BF_DCH114 = 0x1150, /*!< DCDC level 1.14x */ + TFA9894_BF_DCH107 = 0x1160, /*!< DCDC level 1.07x */ + TFA9894_BF_SPKS = 0x1170, /*!< Speaker status */ + TFA9894_BF_CLKOOR = 0x1180, /*!< External clock status */ + TFA9894_BF_MANALARM = 0x1190, /*!< Alarm state */ + TFA9894_BF_TDMERR = 0x11a0, /*!< TDM error */ + TFA9894_BF_TDMLUTER = 0x11b0, /*!< TDM lookup table error */ + TFA9894_BF_OCPOAP = 0x1200, /*!< OCPOK pmos A */ + TFA9894_BF_OCPOAN = 0x1210, /*!< OCPOK nmos A */ + TFA9894_BF_OCPOBP = 0x1220, /*!< OCPOK pmos B */ + TFA9894_BF_OCPOBN = 0x1230, /*!< OCPOK nmos B */ + TFA9894_BF_CLIPS = 0x1240, /*!< Amplifier clipping */ + TFA9894_BF_MANMUTE = 0x1250, /*!< Audio mute sequence */ + TFA9894_BF_MANOPER = 0x1260, /*!< Device in Operating state */ + TFA9894_BF_LP1 = 0x1270, /*!< Low power MODE1 detection */ + TFA9894_BF_LA = 0x1280, /*!< Low amplitude detection */ + TFA9894_BF_VDDPH = 0x1290, /*!< VDDP greater than VBAT flag */ + TFA9894_BF_TDMSTAT = 0x1402, /*!< TDM Status bits */ + TFA9894_BF_MANSTATE = 0x1433, /*!< Device Manager status */ + TFA9894_BF_DCMODE = 0x14b1, /*!< DCDC mode status bits */ + TFA9894_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9894_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9894_BF_VDDPS = 0x1709, /*!< IC VDDP voltage (1023*VDDP/13V) */ + TFA9894_BF_TDME = 0x2000, /*!< Enable interface */ + TFA9894_BF_TDMSPKE = 0x2010, /*!< Control audio tdm channel in sink0 */ + TFA9894_BF_TDMDCE = 0x2020, /*!< Control audio tdm channel in sink1 */ + TFA9894_BF_TDMCSE = 0x2030, /*!< Source 0 enable */ + TFA9894_BF_TDMVSE = 0x2040, /*!< Source 1 enable */ + TFA9894_BF_TDMCFE = 0x2050, /*!< Source 2 enable */ + TFA9894_BF_TDMCF2E = 0x2060, /*!< Source 3 enable */ + TFA9894_BF_TDMCLINV = 0x2070, /*!< Reception data to BCK clock */ + TFA9894_BF_TDMFSPOL = 0x2080, /*!< FS polarity */ + TFA9894_BF_TDMDEL = 0x2090, /*!< Data delay to FS */ + TFA9894_BF_TDMADJ = 0x20a0, /*!< Data adjustment */ + TFA9894_BF_TDMOOMP = 0x20b1, /*!< Received audio compression */ + TFA9894_BF_TDMNBCK = 0x2103, /*!< TDM NBCK - Bit clock to FS ratio */ + TFA9894_BF_TDMFSLN = 0x2143, /*!< FS length (master mode only) */ + TFA9894_BF_TDMSLOTS = 0x2183, /*!< N-slots in Frame */ + TFA9894_BF_TDMTXDFO = 0x21c1, /*!< Format unused bits */ + TFA9894_BF_TDMTXUS = 0x21e1, /*!< Format unused slots DATAO */ + TFA9894_BF_TDMSLLN = 0x2204, /*!< N-bits in slot */ + TFA9894_BF_TDMBRMG = 0x2254, /*!< N-bits remaining */ + TFA9894_BF_TDMSSIZE = 0x22a4, /*!< Sample size per slot */ + TFA9894_BF_TDMSPKS = 0x2303, /*!< TDM slot for sink 0 */ + TFA9894_BF_TDMDCS = 0x2343, /*!< TDM slot for sink 1 */ + TFA9894_BF_TDMCFSEL = 0x2381, /*!< TDM Source 2 data selection */ + TFA9894_BF_TDMCF2SEL = 0x23a1, /*!< TDM Source 3 data selection */ + TFA9894_BF_TDMCSS = 0x2403, /*!< Slot Position of source 0 data */ + TFA9894_BF_TDMVSS = 0x2443, /*!< Slot Position of source 1 data */ + TFA9894_BF_TDMCFS = 0x2483, /*!< Slot Position of source 2 data */ + TFA9894_BF_TDMCF2S = 0x24c3, /*!< Slot Position of source 3 data */ + TFA9894_BF_ISTVDDS = 0x4000, /*!< Status POR */ + TFA9894_BF_ISTBSTOC = 0x4010, /*!< Status DCDC OCP */ + TFA9894_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ + TFA9894_BF_ISTOCPR = 0x4030, /*!< Status OCP alarm */ + TFA9894_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ + TFA9894_BF_ISTMANALARM = 0x4050, /*!< Status manager alarm state */ + TFA9894_BF_ISTTDMER = 0x4060, /*!< Status TDM error */ + TFA9894_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ + TFA9894_BF_ISTCFMER = 0x4080, /*!< Status cfma error */ + TFA9894_BF_ISTCFMAC = 0x4090, /*!< Status cfma ack */ + TFA9894_BF_ISTSPKS = 0x40a0, /*!< Status coolflux speaker error */ + TFA9894_BF_ISTACS = 0x40b0, /*!< Status cold started */ + TFA9894_BF_ISTWDS = 0x40c0, /*!< Status watchdog reset */ + TFA9894_BF_ISTBODNOK = 0x40d0, /*!< Status brown out detect */ + TFA9894_BF_ISTLP1 = 0x40e0, /*!< Status low power mode1 detect */ + TFA9894_BF_ISTCLKOOR = 0x40f0, /*!< Status clock out of range */ + TFA9894_BF_ICLVDDS = 0x4400, /*!< Clear POR */ + TFA9894_BF_ICLBSTOC = 0x4410, /*!< Clear DCDC OCP */ + TFA9894_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ + TFA9894_BF_ICLOCPR = 0x4430, /*!< Clear OCP alarm */ + TFA9894_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ + TFA9894_BF_ICLMANALARM = 0x4450, /*!< Clear manager alarm state */ + TFA9894_BF_ICLTDMER = 0x4460, /*!< Clear TDM error */ + TFA9894_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ + TFA9894_BF_ICLCFMER = 0x4480, /*!< Clear cfma err */ + TFA9894_BF_ICLCFMAC = 0x4490, /*!< Clear cfma ack */ + TFA9894_BF_ICLSPKS = 0x44a0, /*!< Clear coolflux speaker error */ + TFA9894_BF_ICLACS = 0x44b0, /*!< Clear cold started */ + TFA9894_BF_ICLWDS = 0x44c0, /*!< Clear watchdog reset */ + TFA9894_BF_ICLBODNOK = 0x44d0, /*!< Clear brown out detect */ + TFA9894_BF_ICLLP1 = 0x44e0, /*!< Clear low power mode1 detect */ + TFA9894_BF_ICLCLKOOR = 0x44f0, /*!< Clear clock out of range */ + TFA9894_BF_IEVDDS = 0x4800, /*!< Enable POR */ + TFA9894_BF_IEBSTOC = 0x4810, /*!< Enable DCDC OCP */ + TFA9894_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ + TFA9894_BF_IEOCPR = 0x4830, /*!< Enable OCP alarm */ + TFA9894_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ + TFA9894_BF_IEMANALARM = 0x4850, /*!< Enable Manager Alarm state */ + TFA9894_BF_IETDMER = 0x4860, /*!< Enable TDM error */ + TFA9894_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ + TFA9894_BF_IECFMER = 0x4880, /*!< Enable cfma err */ + TFA9894_BF_IECFMAC = 0x4890, /*!< Enable cfma ack */ + TFA9894_BF_IESPKS = 0x48a0, /*!< Enable coolflux speaker error */ + TFA9894_BF_IEACS = 0x48b0, /*!< Enable cold started */ + TFA9894_BF_IEWDS = 0x48c0, /*!< Enable watchdog reset */ + TFA9894_BF_IEBODNOK = 0x48d0, /*!< Enable brown out detect */ + TFA9894_BF_IELP1 = 0x48e0, /*!< Enable low power mode1 detect */ + TFA9894_BF_IECLKOOR = 0x48f0, /*!< Enable clock out of range */ + TFA9894_BF_IPOVDDS = 0x4c00, /*!< Polarity POR */ + TFA9894_BF_IPOBSTOC = 0x4c10, /*!< Polarity DCDC OCP */ + TFA9894_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ + TFA9894_BF_IPOOCPR = 0x4c30, /*!< Polarity ocp alarm */ + TFA9894_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ + TFA9894_BF_IPOMANALARM = 0x4c50, /*!< Polarity manager alarm state */ + TFA9894_BF_IPOTDMER = 0x4c60, /*!< Polarity TDM error */ + TFA9894_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ + TFA9894_BF_IPOCFMER = 0x4c80, /*!< Polarity cfma err */ + TFA9894_BF_IPOCFMAC = 0x4c90, /*!< Polarity cfma ack */ + TFA9894_BF_IPOSPKS = 0x4ca0, /*!< Polarity coolflux speaker error */ + TFA9894_BF_IPOACS = 0x4cb0, /*!< Polarity cold started */ + TFA9894_BF_IPOWDS = 0x4cc0, /*!< Polarity watchdog reset */ + TFA9894_BF_IPOBODNOK = 0x4cd0, /*!< Polarity brown out detect */ + TFA9894_BF_IPOLP1 = 0x4ce0, /*!< Polarity low power mode1 detect */ + TFA9894_BF_IPOCLKOOR = 0x4cf0, /*!< Polarity clock out of range */ + TFA9894_BF_BSSCR = 0x5001, /*!< Battery safeguard attack time */ + TFA9894_BF_BSST = 0x5023, /*!< Battery safeguard threshold voltage level */ + TFA9894_BF_BSSRL = 0x5061, /*!< Battery safeguard maximum reduction */ + TFA9894_BF_BSSRR = 0x5082, /*!< Battery safeguard release time */ + TFA9894_BF_BSSHY = 0x50b1, /*!< Battery Safeguard hysteresis */ + TFA9894_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9894_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA9894_BF_CFSM = 0x5130, /*!< Coolflux firmware soft mute control */ + TFA9894_BF_VOL = 0x5187, /*!< CF firmware volume control */ + TFA9894_BF_CLIPCTRL = 0x5202, /*!< Clip control setting */ + TFA9894_BF_SLOPEE = 0x5230, /*!< Enables slope control */ + TFA9894_BF_SLOPESET = 0x5240, /*!< Slope speed setting (binary coded) */ + TFA9894_BF_AMPGAIN = 0x5287, /*!< Amplifier gain */ + TFA9894_BF_TDMDCG = 0x5703, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ + TFA9894_BF_TDMSPKG = 0x5743, /*!< Total gain depending on INPLEV setting (channel 0) */ + TFA9894_BF_DCINSEL = 0x5781, /*!< VAMP_OUT2 input selection */ + TFA9894_BF_LNMODE = 0x5881, /*!< Low noise gain mode control */ + TFA9894_BF_LPM1MODE = 0x5ac1, /*!< Low power mode control */ + TFA9894_BF_TDMSRCMAP = 0x5d02, /*!< TDM source mapping */ + TFA9894_BF_TDMSRCAS = 0x5d31, /*!< Sensed value A */ + TFA9894_BF_TDMSRCBS = 0x5d51, /*!< Sensed value B */ + TFA9894_BF_TDMSRCACLIP = 0x5d71, /*!< Clip information (analog /digital) for source0 */ + TFA9894_BF_TDMSRCBCLIP = 0x5d91, /*!< Clip information (analog /digital) for source1 */ + TFA9894_BF_DELCURCOMP = 0x6102, /*!< Delay to allign compensation signal with current sense signal */ + TFA9894_BF_SIGCURCOMP = 0x6130, /*!< Polarity of compensation for current sense */ + TFA9894_BF_ENCURCOMP = 0x6140, /*!< Enable current sense compensation */ + TFA9894_BF_LVLCLPPWM = 0x6152, /*!< Set the amount of pwm pulse that may be skipped before clip-flag is triggered */ + TFA9894_BF_DCVOF = 0x7005, /*!< First Boost Voltage Level */ + TFA9894_BF_DCVOS = 0x7065, /*!< Second Boost Voltage Level */ + TFA9894_BF_DCMCC = 0x70c3, /*!< Max Coil Current */ + TFA9894_BF_DCCV = 0x7101, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9894_BF_DCIE = 0x7120, /*!< Adaptive boost mode */ + TFA9894_BF_DCSR = 0x7130, /*!< Soft ramp up/down */ + TFA9894_BF_DCDIS = 0x7140, /*!< DCDC on/off */ + TFA9894_BF_DCPWM = 0x7150, /*!< DCDC PWM only mode */ + TFA9894_BF_DCTRACK = 0x7160, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_DCENVSEL = 0x7170, /*!< Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_DCTRIP = 0x7204, /*!< 1st adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9894_BF_DCTRIP2 = 0x7254, /*!< 2nd adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9894_BF_DCTRIPT = 0x72a4, /*!< Track adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_DCTRIPHYSTE = 0x72f0, /*!< Enable hysteresis on booster trip levels */ + TFA9894_BF_DCHOLD = 0x7304, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_RST = 0x9000, /*!< Reset for Coolflux DSP */ + TFA9894_BF_DMEM = 0x9011, /*!< Target memory for CFMA using I2C interface */ + TFA9894_BF_AIF = 0x9030, /*!< Auto increment */ + TFA9894_BF_CFINT = 0x9040, /*!< Coolflux Interrupt - auto clear */ + TFA9894_BF_CFCGATE = 0x9050, /*!< Coolflux clock gating disabling control */ + TFA9894_BF_REQCMD = 0x9080, /*!< Firmware event request rpc command */ + TFA9894_BF_REQRST = 0x9090, /*!< Firmware event request reset restart */ + TFA9894_BF_REQMIPS = 0x90a0, /*!< Firmware event request short on mips */ + TFA9894_BF_REQMUTED = 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA9894_BF_REQVOL = 0x90c0, /*!< Firmware event request volume ready */ + TFA9894_BF_REQDMG = 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA9894_BF_REQCAL = 0x90e0, /*!< Firmware event request calibration completed */ + TFA9894_BF_REQRSV = 0x90f0, /*!< Firmware event request reserved */ + TFA9894_BF_MADD = 0x910f, /*!< CF memory address */ + TFA9894_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA9894_BF_ERR = 0x9307, /*!< CF error flags */ + TFA9894_BF_ACKCMD = 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA9894_BF_ACKRST = 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA9894_BF_ACKMIPS = 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA9894_BF_ACKMUTED = 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA9894_BF_ACKVOL = 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA9894_BF_ACKDMG = 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA9894_BF_ACKCAL = 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA9894_BF_ACKRSV = 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA9894_BF_MTPK = 0xa107, /*!< KEY2 to access KEY2 protected registers, customer key */ + TFA9894_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ + TFA9894_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ + TFA9894_BF_CMTPI = 0xa350, /*!< Start copying all the data from mtp to I2C mtp registers - auto clear */ + TFA9894_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp - auto clear */ + TFA9894_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9894_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9894_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9894_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9894_BF_SWPROFIL = 0xe00f, /*!< Software profile data */ + TFA9894_BF_SWVSTEP = 0xe10f, /*!< Software vstep information */ + TFA9894_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ + TFA9894_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9894_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ + TFA9894_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9894_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9894_BF_CUSTINFO = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9894_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9894BfEnumList_t; +#define TFA9894_NAMETABLE static tfaBfName_t Tfa9894DatasheetNames[] = {\ + { 0x0, "PWDN"}, /* Powerdown control , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux DSP , */\ + { 0x30, "AMPE"}, /* Enable Amplifier , */\ + { 0x40, "DCA"}, /* Enable DCDC Boost converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux control over amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x90, "FSSSEL"}, /* Audio sample reference , */\ + { 0xa0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xb0, "TSTOCP"}, /* OCP testing control , */\ + { 0xc0, "BSSS"}, /* Vbat protection steepness , */\ + { 0xd0, "HPFBYP"}, /* Bypass High Pass Filter , */\ + { 0xe0, "DPSA"}, /* Enable DPSA , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* Device I2C settings configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x150, "BODE"}, /* Enable BOD (only in direct control mode) , */\ + { 0x160, "BODHYS"}, /* Enable Hysteresis of BOD , */\ + { 0x171, "BODFILT"}, /* BOD filter , */\ + { 0x191, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1b0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1c0, "MANWDE"}, /* Watchdog enable , */\ + { 0x1e0, "OPENMTP"}, /* Control for FAIM protection , */\ + { 0x1f0, "FAIMVBGOVRRL"}, /* Overrule the enabling of VBG for faim erase/write access, */\ + { 0x203, "AUDFS"}, /* Audio sample rate Fs , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* Current sense fractional delay , */\ + { 0x2b1, "TDMPRES"}, /* Control for HW manager , */\ + { 0x2d2, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external reference clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal reference clock , */\ + { 0x432, "MCLKSEL"}, /* Master Clock Selection , */\ + { 0x460, "MANAOOSC"}, /* Internal OSC1M off at PWDN , */\ + { 0x470, "ACKCLDDIS"}, /* Automatic PLL reference clock selection for cold start, */\ + { 0x510, "SPKSSEN"}, /* Enable speaker sub-system , */\ + { 0x520, "MTPSSEN"}, /* Enable FAIM sub-system , */\ + { 0x530, "WDTCLKEN"}, /* Enable Coolflux watchdog clock , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL Lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "OCDS"}, /* OCP amplifier (sticky register, clear on read) , */\ + { 0x1060, "CLKS"}, /* Clocks stable , */\ + { 0x1070, "MTPB"}, /* MTP busy , */\ + { 0x1080, "NOCLK"}, /* Lost clock , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "WDS"}, /* Watchdog , */\ + { 0x10b0, "SWS"}, /* Amplifier engage , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD Flag - VDD NOT OK , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active (sticky register, clear on read) , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos (sticky register, clear on read) , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "SPKS"}, /* Speaker status , */\ + { 0x1180, "CLKOOR"}, /* External clock status , */\ + { 0x1190, "MANALARM"}, /* Alarm state , */\ + { 0x11a0, "TDMERR"}, /* TDM error , */\ + { 0x11b0, "TDMLUTER"}, /* TDM lookup table error , */\ + { 0x1200, "OCPOAP"}, /* OCPOK pmos A , */\ + { 0x1210, "OCPOAN"}, /* OCPOK nmos A , */\ + { 0x1220, "OCPOBP"}, /* OCPOK pmos B , */\ + { 0x1230, "OCPOBN"}, /* OCPOK nmos B , */\ + { 0x1240, "CLIPS"}, /* Amplifier clipping , */\ + { 0x1250, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x1260, "MANOPER"}, /* Device in Operating state , */\ + { 0x1270, "LP1"}, /* Low power MODE1 detection , */\ + { 0x1280, "LA"}, /* Low amplitude detection , */\ + { 0x1290, "VDDPH"}, /* VDDP greater than VBAT flag , */\ + { 0x1402, "TDMSTAT"}, /* TDM Status bits , */\ + { 0x1433, "MANSTATE"}, /* Device Manager status , */\ + { 0x14b1, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage (1023*VDDP/13V) , */\ + { 0x2000, "TDME"}, /* Enable interface , */\ + { 0x2010, "TDMSPKE"}, /* Control audio tdm channel in sink0 , */\ + { 0x2020, "TDMDCE"}, /* Control audio tdm channel in sink1 , */\ + { 0x2030, "TDMCSE"}, /* Source 0 enable , */\ + { 0x2040, "TDMVSE"}, /* Source 1 enable , */\ + { 0x2050, "TDMCFE"}, /* Source 2 enable , */\ + { 0x2060, "TDMCF2E"}, /* Source 3 enable , */\ + { 0x2070, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2080, "TDMFSPOL"}, /* FS polarity , */\ + { 0x2090, "TDMDEL"}, /* Data delay to FS , */\ + { 0x20a0, "TDMADJ"}, /* Data adjustment , */\ + { 0x20b1, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2103, "TDMNBCK"}, /* TDM NBCK - Bit clock to FS ratio , */\ + { 0x2143, "TDMFSLN"}, /* FS length (master mode only) , */\ + { 0x2183, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x21c1, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x21e1, "TDMTXUS0"}, /* Format unused slots DATAO , */\ + { 0x2204, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2254, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x22a4, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2303, "TDMSPKS"}, /* TDM slot for sink 0 , */\ + { 0x2343, "TDMDCS"}, /* TDM slot for sink 1 , */\ + { 0x2381, "TDMCFSEL"}, /* TDM Source 2 data selection , */\ + { 0x23a1, "TDMCF2SEL"}, /* TDM Source 3 data selection , */\ + { 0x2403, "TDMCSS"}, /* Slot Position of source 0 data , */\ + { 0x2443, "TDMVSS"}, /* Slot Position of source 1 data , */\ + { 0x2483, "TDMCFS"}, /* Slot Position of source 2 data , */\ + { 0x24c3, "TDMCF2S"}, /* Slot Position of source 3 data , */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOCPR"}, /* Status OCP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTMANALARM"}, /* Status manager alarm state , */\ + { 0x4060, "ISTTDMER"}, /* Status TDM error , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTCFMER"}, /* Status cfma error , */\ + { 0x4090, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x40a0, "ISTSPKS"}, /* Status coolflux speaker error , */\ + { 0x40b0, "ISTACS"}, /* Status cold started , */\ + { 0x40c0, "ISTWDS"}, /* Status watchdog reset , */\ + { 0x40d0, "ISTBODNOK"}, /* Status brown out detect , */\ + { 0x40e0, "ISTLP1"}, /* Status low power mode1 detect , */\ + { 0x40f0, "ISTCLKOOR"}, /* Status clock out of range , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOCPR"}, /* Clear OCP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLMANALARM"}, /* Clear manager alarm state , */\ + { 0x4460, "ICLTDMER"}, /* Clear TDM error , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x4490, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x44a0, "ICLSPKS"}, /* Clear coolflux speaker error , */\ + { 0x44b0, "ICLACS"}, /* Clear cold started , */\ + { 0x44c0, "ICLWDS"}, /* Clear watchdog reset , */\ + { 0x44d0, "ICLBODNOK"}, /* Clear brown out detect , */\ + { 0x44e0, "ICLLP1"}, /* Clear low power mode1 detect , */\ + { 0x44f0, "ICLCLKOOR"}, /* Clear clock out of range , */\ + { 0x4800, "IEVDDS"}, /* Enable POR , */\ + { 0x4810, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOCPR"}, /* Enable OCP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IEMANALARM"}, /* Enable Manager Alarm state , */\ + { 0x4860, "IETDMER"}, /* Enable TDM error , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IECFMER"}, /* Enable cfma err , */\ + { 0x4890, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x48a0, "IESPKS"}, /* Enable coolflux speaker error , */\ + { 0x48b0, "IEACS"}, /* Enable cold started , */\ + { 0x48c0, "IEWDS"}, /* Enable watchdog reset , */\ + { 0x48d0, "IEBODNOK"}, /* Enable brown out detect , */\ + { 0x48e0, "IELP1"}, /* Enable low power mode1 detect , */\ + { 0x48f0, "IECLKOOR"}, /* Enable clock out of range , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity POR , */\ + { 0x4c10, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOMANALARM"}, /* Polarity manager alarm state , */\ + { 0x4c60, "IPOTDMER"}, /* Polarity TDM error , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4c90, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4ca0, "IPOSPKS"}, /* Polarity coolflux speaker error , */\ + { 0x4cb0, "IPOACS"}, /* Polarity cold started , */\ + { 0x4cc0, "IPOWDS"}, /* Polarity watchdog reset , */\ + { 0x4cd0, "IPOBODNOK"}, /* Polarity brown out detect , */\ + { 0x4ce0, "IPOLP1"}, /* Polarity low power mode1 detect , */\ + { 0x4cf0, "IPOCLKOOR"}, /* Polarity clock out of range , */\ + { 0x5001, "BSSCR"}, /* Battery safeguard attack time , */\ + { 0x5023, "BSST"}, /* Battery safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery safeguard maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery safeguard release time , */\ + { 0x50b1, "BSSHY"}, /* Battery Safeguard hysteresis , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5130, "CFSM"}, /* Coolflux firmware soft mute control , */\ + { 0x5187, "VOL"}, /* CF firmware volume control , */\ + { 0x5202, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5230, "SLOPEE"}, /* Enables slope control , */\ + { 0x5240, "SLOPESET"}, /* Slope speed setting (binary coded) , */\ + { 0x5287, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x5703, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5743, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x5781, "DCINSEL"}, /* VAMP_OUT2 input selection , */\ + { 0x5881, "LNMODE"}, /* Low noise gain mode control , */\ + { 0x5ac1, "LPM1MODE"}, /* Low power mode control , */\ + { 0x5d02, "TDMSRCMAP"}, /* TDM source mapping , */\ + { 0x5d31, "TDMSRCAS"}, /* Sensed value A , */\ + { 0x5d51, "TDMSRCBS"}, /* Sensed value B , */\ + { 0x5d71, "TDMSRCACLIP"}, /* Clip information (analog /digital) for source0 , */\ + { 0x5d91, "TDMSRCBCLIP"}, /* Clip information (analog /digital) for source1 , */\ + { 0x6102, "DELCURCOMP"}, /* Delay to allign compensation signal with current sense signal, */\ + { 0x6130, "SIGCURCOMP"}, /* Polarity of compensation for current sense , */\ + { 0x6140, "ENCURCOMP"}, /* Enable current sense compensation , */\ + { 0x6152, "LVLCLPPWM"}, /* Set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7005, "DCVOF"}, /* First Boost Voltage Level , */\ + { 0x7065, "DCVOS"}, /* Second Boost Voltage Level , */\ + { 0x70c3, "DCMCC"}, /* Max Coil Current , */\ + { 0x7101, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7120, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7130, "DCSR"}, /* Soft ramp up/down , */\ + { 0x7140, "DCDIS"}, /* DCDC on/off , */\ + { 0x7150, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7160, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7170, "DCENVSEL"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7204, "DCTRIP"}, /* 1st adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7254, "DCTRIP2"}, /* 2nd adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x72a4, "DCTRIPT"}, /* Track adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x72f0, "DCTRIPHYSTE"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7304, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x9000, "RST"}, /* Reset for Coolflux DSP , */\ + { 0x9011, "DMEM"}, /* Target memory for CFMA using I2C interface , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Coolflux Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* CF memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* CF error flags , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* KEY2 to access KEY2 protected registers, customer key, */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa350, "CMTPI"}, /* Start copying all the data from mtp to I2C mtp registers - auto clear, */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp - auto clear, */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xe00f, "SWPROFIL"}, /* Software profile data , */\ + { 0xe10f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9894_BITNAMETABLE static tfaBfName_t Tfa9894BitNames[] = {\ + { 0x0, "powerdown"}, /* Powerdown control , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux DSP , */\ + { 0x30, "enbl_amplifier"}, /* Enable Amplifier , */\ + { 0x40, "enbl_boost"}, /* Enable DCDC Boost converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux control over amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x90, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xa0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xb0, "test_ocp"}, /* OCP testing control , */\ + { 0xc0, "batsense_steepness"}, /* Vbat protection steepness , */\ + { 0xd0, "bypass_hp"}, /* Bypass High Pass Filter , */\ + { 0xe0, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0xf0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ + { 0x101, "vamp_sel1"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* Device I2C settings configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x150, "bod_enbl"}, /* Enable BOD (only in direct control mode) , */\ + { 0x160, "bod_hyst_enbl"}, /* Enable Hysteresis of BOD , */\ + { 0x171, "bod_delay_set"}, /* BOD filter , */\ + { 0x191, "bod_lvl_set"}, /* BOD threshold , */\ + { 0x1b0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1c0, "man_enbl_watchdog"}, /* Watchdog enable , */\ + { 0x1d0, "disable_engage"}, /* Disable Engage , */\ + { 0x1e0, "unprotect_faim"}, /* Control for FAIM protection , */\ + { 0x1f0, "faim_enable_vbg"}, /* Overrule the enabling of VBG for faim erase/write access, */\ + { 0x203, "audio_fs"}, /* Audio sample rate Fs , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* Current sense fractional delay , */\ + { 0x2b1, "use_tdm_presence"}, /* Control for HW manager , */\ + { 0x2d2, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external reference clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal reference clock , */\ + { 0x432, "mclk_sel"}, /* Master Clock Selection , */\ + { 0x460, "enbl_osc1m_auto_off"}, /* Internal OSC1M off at PWDN , */\ + { 0x470, "disable_auto_sel_refclk"}, /* Automatic PLL reference clock selection for cold start, */\ + { 0x510, "enbl_spkr_ss"}, /* Enable speaker sub-system , */\ + { 0x520, "enbl_faim_ss"}, /* Enable FAIM sub-system , */\ + { 0x530, "enbl_wdt_clk"}, /* Enable Coolflux watchdog clock , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* Hidden code to enable access to hidden register. (0x5A6B/23147 default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL Lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_ocp_alarm"}, /* OCP amplifier (sticky register, clear on read) , */\ + { 0x1060, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1070, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1080, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10b0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD Flag - VDD NOT OK , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active (sticky register, clear on read) , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos (sticky register, clear on read) , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_cf_speakererror"}, /* Speaker status , */\ + { 0x1180, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1190, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x11a0, "flag_tdm_error"}, /* TDM error , */\ + { 0x11b0, "flag_tdm_lut_error"}, /* TDM lookup table error , */\ + { 0x1200, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1210, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1220, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1230, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1240, "flag_clip"}, /* Amplifier clipping , */\ + { 0x1250, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x1260, "flag_man_operating_state"}, /* Device in Operating state , */\ + { 0x1270, "flag_lp_detect_mode1"}, /* Low power MODE1 detection , */\ + { 0x1280, "flag_low_amplitude"}, /* Low amplitude detection , */\ + { 0x1290, "flag_vddp_gt_vbat"}, /* VDDP greater than VBAT flag , */\ + { 0x1402, "tdm_status"}, /* TDM Status bits , */\ + { 0x1433, "man_state"}, /* Device Manager status , */\ + { 0x1473, "amp_ctrl_state"}, /* Amplifier control status , */\ + { 0x14b1, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage (1023*VDDP/13V) , */\ + { 0x2000, "tdm_enable"}, /* Enable interface , */\ + { 0x2010, "tdm_sink0_enable"}, /* Control audio tdm channel in sink0 , */\ + { 0x2020, "tdm_sink1_enable"}, /* Control audio tdm channel in sink1 , */\ + { 0x2030, "tdm_source0_enable"}, /* Source 0 enable , */\ + { 0x2040, "tdm_source1_enable"}, /* Source 1 enable , */\ + { 0x2050, "tdm_source2_enable"}, /* Source 2 enable , */\ + { 0x2060, "tdm_source3_enable"}, /* Source 3 enable , */\ + { 0x2070, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2080, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x2090, "tdm_data_delay"}, /* Data delay to FS , */\ + { 0x20a0, "tdm_data_adjustment"}, /* Data adjustment , */\ + { 0x20b1, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2103, "tdm_nbck"}, /* TDM NBCK - Bit clock to FS ratio , */\ + { 0x2143, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ + { 0x2183, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x21c1, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x21e1, "tdm_txdata_format_unused_slot"}, /* Format unused slots DATAO , */\ + { 0x2204, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2254, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x22a4, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2303, "tdm_sink0_slot"}, /* TDM slot for sink 0 , */\ + { 0x2343, "tdm_sink1_slot"}, /* TDM slot for sink 1 , */\ + { 0x2381, "tdm_source2_sel"}, /* TDM Source 2 data selection , */\ + { 0x23a1, "tdm_source3_sel"}, /* TDM Source 3 data selection , */\ + { 0x2403, "tdm_source0_slot"}, /* Slot Position of source 0 data , */\ + { 0x2443, "tdm_source1_slot"}, /* Slot Position of source 1 data , */\ + { 0x2483, "tdm_source2_slot"}, /* Slot Position of source 2 data , */\ + { 0x24c3, "tdm_source3_slot"}, /* Slot Position of source 3 data , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ocp_alarm"}, /* Status OCP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_man_alarm_state"}, /* Status manager alarm state , */\ + { 0x4060, "int_out_flag_tdm_error"}, /* Status TDM error , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x4090, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x40a0, "int_out_flag_cf_speakererror"}, /* Status coolflux speaker error , */\ + { 0x40b0, "int_out_flag_cold_started"}, /* Status cold started , */\ + { 0x40c0, "int_out_flag_watchdog_reset"}, /* Status watchdog reset , */\ + { 0x40d0, "int_out_flag_bod_vddd_nok"}, /* Status brown out detect , */\ + { 0x40e0, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 detect , */\ + { 0x40f0, "int_out_flag_clk_out_of_range"}, /* Status clock out of range , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ocp_alarm"}, /* Clear OCP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_man_alarm_state"}, /* Clear manager alarm state , */\ + { 0x4460, "int_in_flag_tdm_error"}, /* Clear TDM error , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x4490, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x44a0, "int_in_flag_cf_speakererror"}, /* Clear coolflux speaker error , */\ + { 0x44b0, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44c0, "int_in_flag_watchdog_reset"}, /* Clear watchdog reset , */\ + { 0x44d0, "int_in_flag_bod_vddd_nok"}, /* Clear brown out detect , */\ + { 0x44e0, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 detect , */\ + { 0x44f0, "int_in_flag_clk_out_of_range"}, /* Clear clock out of range , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable POR , */\ + { 0x4810, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ocp_alarm"}, /* Enable OCP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_man_alarm_state"}, /* Enable Manager Alarm state , */\ + { 0x4860, "int_enable_flag_tdm_error"}, /* Enable TDM error , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x4890, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x48a0, "int_enable_flag_cf_speakererror"}, /* Enable coolflux speaker error , */\ + { 0x48b0, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48c0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog reset , */\ + { 0x48d0, "int_enable_flag_bod_vddd_nok"}, /* Enable brown out detect , */\ + { 0x48e0, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 detect , */\ + { 0x48f0, "int_enable_flag_clk_out_of_range"}, /* Enable clock out of range , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity POR , */\ + { 0x4c10, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_man_alarm_state"}, /* Polarity manager alarm state , */\ + { 0x4c60, "int_polarity_flag_tdm_error"}, /* Polarity TDM error , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4c90, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4ca0, "int_polarity_flag_cf_speakererror"}, /* Polarity coolflux speaker error , */\ + { 0x4cb0, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4cc0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog reset , */\ + { 0x4cd0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity brown out detect , */\ + { 0x4ce0, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 detect , */\ + { 0x4cf0, "int_polarity_flag_clk_out_of_range"}, /* Polarity clock out of range , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery safeguard attack time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery safeguard maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery safeguard release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5130, "cf_mute"}, /* Coolflux firmware soft mute control , */\ + { 0x5187, "cf_volume"}, /* CF firmware volume control , */\ + { 0x5202, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5230, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x5240, "ctrl_slope"}, /* Slope speed setting (binary coded) , */\ + { 0x5287, "gain"}, /* Amplifier gain , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for battery safeguard, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5370, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5380, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5390, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x53a3, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5400, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5413, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5452, "dpsa_drive"}, /* Drive setting (binary coded) , */\ + { 0x550a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ + { 0x55b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ + { 0x55c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5600, "pwm_shape"}, /* PWM shape , */\ + { 0x5614, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5660, "reclock_pwm"}, /* Reclock the PWM signal inside analog , */\ + { 0x5670, "reclock_voltsense"}, /* Reclock the voltage sense PWM signal , */\ + { 0x5680, "enbl_pwm_phase_shift"}, /* Control for PWM phase shift , */\ + { 0x5690, "sel_pwm_delay_src"}, /* Control for selection for PWM delay line source , */\ + { 0x56a1, "enbl_odd_up_even_down"}, /* Control for PWM reference sawtooth generartion , */\ + { 0x5703, "ctrl_att_dcdc"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5743, "ctrl_att_spkr"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x5781, "vamp_sel2"}, /* VAMP_OUT2 input selection , */\ + { 0x5805, "zero_lvl"}, /* Low noise gain switch zero trigger level , */\ + { 0x5861, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x5881, "lownoisegain_mode"}, /* Low noise gain mode control , */\ + { 0x5905, "threshold_lvl"}, /* Low noise gain switch trigger level , */\ + { 0x5965, "hold_time"}, /* Low noise mode hold time before entering into low noise mode, */\ + { 0x5a05, "lpm1_cal_offset"}, /* Low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x5a65, "lpm1_zero_lvl"}, /* Low power mode1 zero crossing detection level , */\ + { 0x5ac1, "lpm1_mode"}, /* Low power mode control , */\ + { 0x5b05, "lpm1_threshold_lvl"}, /* Low power mode1 amplitude trigger level , */\ + { 0x5b65, "lpm1_hold_time"}, /* Low power mode hold time before entering into low power mode, */\ + { 0x5bc0, "disable_low_power_mode"}, /* Low power mode1 detector control , */\ + { 0x5c00, "enbl_minion"}, /* Enables minion (small) power stage , */\ + { 0x5c13, "vth_vddpvbat"}, /* Select vddp-vbat threshold signal , */\ + { 0x5c50, "lpen_vddpvbat"}, /* Select vddp-vbat filtred vs unfiltered compare , */\ + { 0x5c61, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x5d02, "tdm_source_mapping"}, /* TDM source mapping , */\ + { 0x5d31, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ + { 0x5d51, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ + { 0x5d71, "tdm_source0_clip_sel"}, /* Clip information (analog /digital) for source0 , */\ + { 0x5d91, "tdm_source1_clip_sel"}, /* Clip information (analog /digital) for source1 , */\ + { 0x5e02, "rst_min_vbat_delay"}, /* Delay for reseting the min_vbat value inside HW Clipper (number of Fs pulses), */\ + { 0x5e30, "rst_min_vbat_sel"}, /* Control for selecting reset signal for min_bat , */\ + { 0x5f00, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5f12, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x5f42, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x5f78, "spare_out"}, /* Spare out register , */\ + { 0x600f, "spare_in"}, /* Spare IN , */\ + { 0x6102, "cursense_comp_delay"}, /* Delay to allign compensation signal with current sense signal, */\ + { 0x6130, "cursense_comp_sign"}, /* Polarity of compensation for current sense , */\ + { 0x6140, "enbl_cursense_comp"}, /* Enable current sense compensation , */\ + { 0x6152, "pwms_clip_lvl"}, /* Set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7005, "frst_boost_voltage"}, /* First Boost Voltage Level , */\ + { 0x7065, "scnd_boost_voltage"}, /* Second Boost Voltage Level , */\ + { 0x70c3, "boost_cur"}, /* Max Coil Current , */\ + { 0x7101, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7120, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7130, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x7140, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x7150, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7160, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7170, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7180, "ignore_flag_voutcomp86"}, /* Determines the maximum PWM frequency be the most efficient in relation to the Booster inductor value, */\ + { 0x7204, "boost_trip_lvl_1st"}, /* 1st adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7254, "boost_trip_lvl_2nd"}, /* 2nd adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x72a4, "boost_trip_lvl_track"}, /* Track adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x72f0, "enbl_trip_hyst"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7304, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x7350, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x7361, "dcdc_ctrl_maxzercnt"}, /* Number of zero current flags to count before going to pfm mode, */\ + { 0x7386, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x73f0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x7404, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7451, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7474, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x74c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x74e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x74f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7500, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7510, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7520, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7530, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7540, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7550, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7560, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7570, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7580, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x7595, "bst_windac"}, /* For testing direct control windac , */\ + { 0x7600, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7611, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7631, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7650, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7660, "bst_use_new_zercur_detect"}, /* Enable new zero current detection for boost control, */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8040, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8050, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8060, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8105, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP) * signal, */\ + { 0x8164, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x81b0, "enbl_cs_adc"}, /* Enable current sense ADC , */\ + { 0x81c0, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ + { 0x81d0, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ + { 0x81e0, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x81f0, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ + { 0x8200, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ + { 0x8210, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ + { 0x8220, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8231, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8250, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8263, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x82a0, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x82b4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8300, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8310, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8320, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8330, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8340, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8350, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if enbl_cs_ldo is high, */\ + { 0x8364, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8800, "ctrl_vs_igen_supply"}, /* Control for selecting supply for VS current generator, */\ + { 0x8810, "ctrl_vs_force_div2"}, /* Select input resistive divider gain , */\ + { 0x8820, "enbl_dc_filter"}, /* Control for enabling the DC blocking filter for voltage and current sense, */\ + { 0x8901, "volsense_pwm_sel"}, /* Voltage sense source selection control , */\ + { 0x8920, "vs_gain_control"}, /* Voltage sense gain control , */\ + { 0x8930, "vs_bypass_gc"}, /* Bypasses the VS gain correction , */\ + { 0x8940, "vs_adc_bsoinv"}, /* Bitstream inversion for voltage sense ADC , */\ + { 0x8950, "vs_adc_nortz"}, /* Return to zero for voltage sense ADC , */\ + { 0x8960, "vs_adc_slowdel"}, /* Select delay for voltage sense ADC (internal decision circuitry), */\ + { 0x8970, "vs_classd_tran_skip"}, /* Skip voltage sense connection during a classD amplifier transition, */\ + { 0x8987, "vs_gain"}, /* Voltage sense gain , */\ + { 0x8a00, "vs_inn_short"}, /* Short voltage sense negative to common mode , */\ + { 0x8a10, "vs_inp_short"}, /* Short voltage sense positive to common mode , */\ + { 0x8a20, "vs_ldo_bypass"}, /* Bypass voltage sense LDO , */\ + { 0x8a30, "vs_ldo_pulldown"}, /* Pull down voltage sense LDO, only valid if enbl_cs_ldo is high, */\ + { 0x8a44, "vs_ldo_voset"}, /* Voltage sense LDO voltage level setting (two's complement), */\ + { 0x8a90, "enbl_vs_adc"}, /* Enable voltage sense ADC , */\ + { 0x8aa0, "enbl_vs_inn1"}, /* Enable connection of voltage sense negative1 , */\ + { 0x8ab0, "enbl_vs_inn2"}, /* Enable connection of voltage sense negative2 , */\ + { 0x8ac0, "enbl_vs_inp1"}, /* Enable connection of voltage sense positive1 , */\ + { 0x8ad0, "enbl_vs_inp2"}, /* Enable connection of voltage sense positive2 , */\ + { 0x8ae0, "enbl_vs_ldo"}, /* Enable voltage sense LDO , */\ + { 0x8af0, "enbl_vs_vbatldo"}, /* Enable of voltage sense LDO , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset for Coolflux DSP , */\ + { 0x9011, "cf_dmem"}, /* Target memory for CFMA using I2C interface , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Coolflux Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* CF memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* CF error flags , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0xa007, "mtpkey1"}, /* KEY1 To access KEY1 protected registers 0x5A/90d (default for engineering), */\ + { 0xa107, "mtpkey2"}, /* KEY2 to access KEY2 protected registers, customer key, */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from MTP to I2C mtp register - auto clear, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp - auto clear, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers - auto clear, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp - auto clear, */\ + { 0xa400, "faim_set_clkws"}, /* Sets the FaIM controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the FaIM are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the FaIM are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb000, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb010, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb020, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb030, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb040, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb050, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb060, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb070, "disable_main_ctrl_change_prot"}, /* Disable main control change protection , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0c0, "use_direct_vs_ctrls"}, /* Voltage sense direct control to overrule several functions for testing, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3d0, "test_abistfft_enbl"}, /* Enable ABIST with FFT on Coolflux DSP , */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc530, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc540, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc550, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc560, "test_enbl_vs"}, /* Enable for digimux mode of voltage sense , */\ + { 0xc570, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc583, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc5c0, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc607, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO , */\ + { 0xc687, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT , */\ + { 0xc707, "digimuxc_sel"}, /* DigimuxC input selection control routed to ADS1 , */\ + { 0xc800, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xc810, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xc820, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xc830, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xc844, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xc894, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xc903, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xc943, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xca05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ + { 0xca64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ + { 0xcab3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ + { 0xcaf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xcb09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcba0, "pll_mdec_msb"}, /* MSB of PLL_mdec - I2C direct PLL control mode only, */\ + { 0xcbb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcbc0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ + { 0xcbd0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcbe0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcbf0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcc0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xcd06, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xce0f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xcf02, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xcf33, "tsig_gain"}, /* Test signal gain , */\ + { 0xd000, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd011, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd032, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd064, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd0b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd0c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd109, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd201, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ + { 0xd221, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ + { 0xd241, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ + { 0xd301, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO datasheet), */\ + { 0xd321, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO datasheet), */\ + { 0xd340, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xd407, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd480, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xd491, "sel_wdt_clk"}, /* Watch dog clock divider settings , */\ + { 0xd4b0, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd500, "source_in_testmode"}, /* TDM source in test mode (return only current and voltage sense), */\ + { 0xd510, "gainatt_feedback"}, /* Gainatt feedback to tdm , */\ + { 0xd522, "test_parametric_io"}, /* Test IO parametric , */\ + { 0xd550, "ctrl_bst_clk_lp1"}, /* Boost clock control in low power mode1 , */\ + { 0xd561, "test_spare_out1"}, /* Test spare out 1 , */\ + { 0xd580, "bst_dcmbst"}, /* DCM boost , */\ + { 0xd593, "test_spare_out2"}, /* Test spare out 2 , */\ + { 0xe00f, "sw_profile"}, /* Software profile data , */\ + { 0xe10f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf307, "calibr_gain_vs"}, /* Voltage sense gain , */\ + { 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf40f, "mtpdata4"}, /* MTP4 data , */\ + { 0xf50f, "calibr_R25C"}, /* Ron resistance of speaker coil , */\ + { 0xf60f, "mtpdata6"}, /* MTP6 data , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable functionality of dcdcoff_mode bit , */\ + { 0xf910, "mtp_lock_enbl_coolflux"}, /* Disable functionality of enbl_coolflux bit , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_enbl_pwm_delay_clock_gating"}, /* PWM delay clock auto gating , */\ + { 0xf940, "mtp_enbl_ocp_clock_gating"}, /* OCP clock auto gating , */\ + { 0xf950, "mtp_gate_cgu_clock_for_test"}, /* CGU test clock control , */\ + { 0xf987, "type_bits_fw"}, /* MTP control for firmware features - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE , */\ + { 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9894_irq { + tfa9894_irq_max = -1, + tfa9894_irq_all = -1 /* all irqs */}; + +#define TFA9894_IRQ_NAMETABLE static tfaIrqName_t Tfa9894IrqNames[] = {\ +}; +#endif /* _TFA9894_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa9894_tfafieldnames_N2.h b/sound/soc/codecs/tfa9894_tfafieldnames_N2.h new file mode 100644 index 0000000000000000000000000000000000000000..22ac3ae26c4f7fed6ca0b481b24f9fb715786c43 --- /dev/null +++ b/sound/soc/codecs/tfa9894_tfafieldnames_N2.h @@ -0,0 +1,1123 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9894_TFAFIELDNAMES_N2_H +#define _TFA9894_TFAFIELDNAMES_N2_H + + +#define TFA9894N2_I2CVERSION 25.0 + +typedef enum nxpTfa9894N2BfEnumList { + TFA9894N2_BF_PWDN = 0x0000, /*!< Powerdown control */ + TFA9894N2_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9894N2_BF_CFE = 0x0020, /*!< Enable CoolFlux DSP */ + TFA9894N2_BF_AMPE = 0x0030, /*!< Enable Amplifier */ + TFA9894N2_BF_DCA = 0x0040, /*!< Enable DCDC Boost converter */ + TFA9894N2_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA9894N2_BF_AMPC = 0x0060, /*!< CoolFlux control over amplifier */ + TFA9894N2_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9894N2_BF_FSSSEL = 0x0090, /*!< Audio sample reference */ + TFA9894N2_BF_BYPOCP = 0x00a0, /*!< Bypass OCP */ + TFA9894N2_BF_TSTOCP = 0x00b0, /*!< OCP testing control */ + TFA9894N2_BF_BSSS = 0x00c0, /*!< Vbat protection steepness */ + TFA9894N2_BF_HPFBYP = 0x00d0, /*!< Bypass High Pass Filter */ + TFA9894N2_BF_DPSA = 0x00e0, /*!< Enable DPSA */ + TFA9894N2_BF_AMPINSEL = 0x0101, /*!< Amplifier input selection */ + TFA9894N2_BF_MANSCONF = 0x0120, /*!< Device I2C settings configured */ + TFA9894N2_BF_MANCOLD = 0x0130, /*!< Execute cold start */ + TFA9894N2_BF_MANROBOD = 0x0140, /*!< Reaction on BOD */ + TFA9894N2_BF_BODE = 0x0150, /*!< Enable BOD (only in direct control mode) */ + TFA9894N2_BF_BODHYS = 0x0160, /*!< Enable Hysteresis of BOD */ + TFA9894N2_BF_BODFILT = 0x0171, /*!< BOD filter */ + TFA9894N2_BF_BODTHLVL = 0x0191, /*!< BOD threshold */ + TFA9894N2_BF_MUTETO = 0x01b0, /*!< Time out SB mute sequence */ + TFA9894N2_BF_MANWDE = 0x01c0, /*!< Watchdog enable */ + TFA9894N2_BF_OPENMTP = 0x01e0, /*!< Control for FAIM protection */ + TFA9894N2_BF_FAIMVBGOVRRL = 0x01f0, /*!< Overrule the enabling of VBG for faim erase/write access */ + TFA9894N2_BF_AUDFS = 0x0203, /*!< Audio sample rate Fs */ + TFA9894N2_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ + TFA9894N2_BF_FRACTDEL = 0x0255, /*!< Current sense fractional delay */ + TFA9894N2_BF_TDMPRES = 0x02b1, /*!< Control for HW manager */ + TFA9894N2_BF_AMPOCRT = 0x02d2, /*!< Amplifier on-off criteria for shutdown */ + TFA9894N2_BF_REV = 0x030f, /*!< Revision info */ + TFA9894N2_BF_REFCKEXT = 0x0401, /*!< PLL external reference clock */ + TFA9894N2_BF_REFCKSEL = 0x0420, /*!< PLL internal reference clock */ + TFA9894N2_BF_MCLKSEL = 0x0432, /*!< Master Clock Selection */ + TFA9894N2_BF_MANAOOSC = 0x0460, /*!< Internal OSC1M off at PWDN */ + TFA9894N2_BF_ACKCLDDIS = 0x0470, /*!< Automatic PLL reference clock selection for cold start */ + TFA9894N2_BF_FSSYNCEN = 0x0480, /*!< Enable FS synchronisation for clock divider */ + TFA9894N2_BF_CLKREFSYNCEN = 0x0490, /*!< Enable PLL reference clock synchronisation for clock divider */ + TFA9894N2_BF_PLLSTUP = 0x04a0, /*!< PLL startup time configuration */ + TFA9894N2_BF_CGUSYNCDCG = 0x0500, /*!< Clock gating control for CGU synchronisation module */ + TFA9894N2_BF_SPKSSEN = 0x0510, /*!< Enable speaker sub-system */ + TFA9894N2_BF_MTPSSEN = 0x0520, /*!< Enable FAIM sub-system */ + TFA9894N2_BF_WDTCLKEN = 0x0530, /*!< Enable Coolflux watchdog clock */ + TFA9894N2_BF_VDDS = 0x1000, /*!< POR */ + TFA9894N2_BF_PLLS = 0x1010, /*!< PLL Lock */ + TFA9894N2_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA9894N2_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA9894N2_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA9894N2_BF_OCDS = 0x1050, /*!< OCP amplifier (sticky register, clear on read) */ + TFA9894N2_BF_CLKS = 0x1060, /*!< Clocks stable */ + TFA9894N2_BF_MTPB = 0x1070, /*!< MTP busy */ + TFA9894N2_BF_NOCLK = 0x1080, /*!< Lost clock */ + TFA9894N2_BF_ACS = 0x1090, /*!< Cold Start */ + TFA9894N2_BF_WDS = 0x10a0, /*!< Watchdog */ + TFA9894N2_BF_SWS = 0x10b0, /*!< Amplifier engage */ + TFA9894N2_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA9894N2_BF_AREFS = 0x10d0, /*!< References enable */ + TFA9894N2_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA9894N2_BF_BODNOK = 0x10f0, /*!< BOD Flag - VDD NOT OK */ + TFA9894N2_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9894N2_BF_DCDCA = 0x1110, /*!< DCDC active (sticky register, clear on read) */ + TFA9894N2_BF_DCOCPOK = 0x1120, /*!< DCDC OCP nmos (sticky register, clear on read) */ + TFA9894N2_BF_DCHVBAT = 0x1140, /*!< DCDC level 1x */ + TFA9894N2_BF_DCH114 = 0x1150, /*!< DCDC level 1.14x */ + TFA9894N2_BF_DCH107 = 0x1160, /*!< DCDC level 1.07x */ + TFA9894N2_BF_SPKS = 0x1170, /*!< Speaker status */ + TFA9894N2_BF_CLKOOR = 0x1180, /*!< External clock status */ + TFA9894N2_BF_MANALARM = 0x1190, /*!< Alarm state */ + TFA9894N2_BF_TDMERR = 0x11a0, /*!< TDM error */ + TFA9894N2_BF_TDMLUTER = 0x11b0, /*!< TDM lookup table error */ + TFA9894N2_BF_NOAUDCLK = 0x11c0, /*!< Lost Audio clock */ + TFA9894N2_BF_OCPOAP = 0x1200, /*!< OCPOK pmos A */ + TFA9894N2_BF_OCPOAN = 0x1210, /*!< OCPOK nmos A */ + TFA9894N2_BF_OCPOBP = 0x1220, /*!< OCPOK pmos B */ + TFA9894N2_BF_OCPOBN = 0x1230, /*!< OCPOK nmos B */ + TFA9894N2_BF_CLIPS = 0x1240, /*!< Amplifier clipping */ + TFA9894N2_BF_MANMUTE = 0x1250, /*!< Audio mute sequence */ + TFA9894N2_BF_MANOPER = 0x1260, /*!< Device in Operating state */ + TFA9894N2_BF_LP1 = 0x1270, /*!< Low power MODE1 detection */ + TFA9894N2_BF_LA = 0x1280, /*!< Low amplitude detection */ + TFA9894N2_BF_VDDPH = 0x1290, /*!< VDDP greater than VBAT flag */ + TFA9894N2_BF_TDMSTAT = 0x1302, /*!< TDM Status bits */ + TFA9894N2_BF_MANSTATE = 0x1333, /*!< Device Manager status */ + TFA9894N2_BF_DCMODE = 0x13b1, /*!< DCDC mode status bits */ + TFA9894N2_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9894N2_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9894N2_BF_VDDPS = 0x1709, /*!< IC VDDP voltage (1023*VDDP/13V) */ + TFA9894N2_BF_TDME = 0x2000, /*!< Enable interface */ + TFA9894N2_BF_TDMSPKE = 0x2010, /*!< Control audio tdm channel in sink0 */ + TFA9894N2_BF_TDMDCE = 0x2020, /*!< Control audio tdm channel in sink1 */ + TFA9894N2_BF_TDMCSE = 0x2030, /*!< Source 0 enable */ + TFA9894N2_BF_TDMVSE = 0x2040, /*!< Source 1 enable */ + TFA9894N2_BF_TDMCFE = 0x2050, /*!< Source 2 enable */ + TFA9894N2_BF_TDMCF2E = 0x2060, /*!< Source 3 enable */ + TFA9894N2_BF_TDMCLINV = 0x2070, /*!< Reception data to BCK clock */ + TFA9894N2_BF_TDMFSPOL = 0x2080, /*!< FS polarity */ + TFA9894N2_BF_TDMDEL = 0x2090, /*!< Data delay to FS */ + TFA9894N2_BF_TDMADJ = 0x20a0, /*!< Data adjustment */ + TFA9894N2_BF_TDMOOMP = 0x20b1, /*!< Received audio compression */ + TFA9894N2_BF_TDMNBCK = 0x2103, /*!< TDM NBCK - Bit clock to FS ratio */ + TFA9894N2_BF_TDMFSLN = 0x2143, /*!< FS length (master mode only) */ + TFA9894N2_BF_TDMSLOTS = 0x2183, /*!< N-slots in Frame */ + TFA9894N2_BF_TDMTXDFO = 0x21c1, /*!< Format unused bits */ + TFA9894N2_BF_TDMTXUS0 = 0x21e1, /*!< Format unused slots DATAO */ + TFA9894N2_BF_TDMSLLN = 0x2204, /*!< N-bits in slot */ + TFA9894N2_BF_TDMBRMG = 0x2254, /*!< N-bits remaining */ + TFA9894N2_BF_TDMSSIZE = 0x22a4, /*!< Sample size per slot */ + TFA9894N2_BF_TDMSPKS = 0x2303, /*!< TDM slot for sink 0 */ + TFA9894N2_BF_TDMDCS = 0x2343, /*!< TDM slot for sink 1 */ + TFA9894N2_BF_TDMCFSEL = 0x2381, /*!< TDM Source 2 data selection */ + TFA9894N2_BF_TDMCF2SEL = 0x23a1, /*!< TDM Source 3 data selection */ + TFA9894N2_BF_TDMCSS = 0x2403, /*!< Slot position of source 0 data */ + TFA9894N2_BF_TDMVSS = 0x2443, /*!< Slot position of source 1 data */ + TFA9894N2_BF_TDMCFS = 0x2483, /*!< Slot position of source 2 data */ + TFA9894N2_BF_TDMCF2S = 0x24c3, /*!< Slot position of source 3 data */ + TFA9894N2_BF_ISTVDDS = 0x4000, /*!< Status POR */ + TFA9894N2_BF_ISTBSTOC = 0x4010, /*!< Status DCDC OCP */ + TFA9894N2_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ + TFA9894N2_BF_ISTOCPR = 0x4030, /*!< Status OCP alarm */ + TFA9894N2_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ + TFA9894N2_BF_ISTMANALARM = 0x4050, /*!< Status manager alarm state */ + TFA9894N2_BF_ISTTDMER = 0x4060, /*!< Status TDM error */ + TFA9894N2_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ + TFA9894N2_BF_ISTCFMER = 0x4080, /*!< Status cfma error */ + TFA9894N2_BF_ISTCFMAC = 0x4090, /*!< Status cfma ack */ + TFA9894N2_BF_ISTSPKS = 0x40a0, /*!< Status coolflux speaker error */ + TFA9894N2_BF_ISTACS = 0x40b0, /*!< Status cold started */ + TFA9894N2_BF_ISTWDS = 0x40c0, /*!< Status watchdog reset */ + TFA9894N2_BF_ISTBODNOK = 0x40d0, /*!< Status brown out detect */ + TFA9894N2_BF_ISTLP1 = 0x40e0, /*!< Status low power mode1 detect */ + TFA9894N2_BF_ISTCLKOOR = 0x40f0, /*!< Status clock out of range */ + TFA9894N2_BF_ICLVDDS = 0x4400, /*!< Clear POR */ + TFA9894N2_BF_ICLBSTOC = 0x4410, /*!< Clear DCDC OCP */ + TFA9894N2_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ + TFA9894N2_BF_ICLOCPR = 0x4430, /*!< Clear OCP alarm */ + TFA9894N2_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ + TFA9894N2_BF_ICLMANALARM = 0x4450, /*!< Clear manager alarm state */ + TFA9894N2_BF_ICLTDMER = 0x4460, /*!< Clear TDM error */ + TFA9894N2_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ + TFA9894N2_BF_ICLCFMER = 0x4480, /*!< Clear cfma err */ + TFA9894N2_BF_ICLCFMAC = 0x4490, /*!< Clear cfma ack */ + TFA9894N2_BF_ICLSPKS = 0x44a0, /*!< Clear coolflux speaker error */ + TFA9894N2_BF_ICLACS = 0x44b0, /*!< Clear cold started */ + TFA9894N2_BF_ICLWDS = 0x44c0, /*!< Clear watchdog reset */ + TFA9894N2_BF_ICLBODNOK = 0x44d0, /*!< Clear brown out detect */ + TFA9894N2_BF_ICLLP1 = 0x44e0, /*!< Clear low power mode1 detect */ + TFA9894N2_BF_ICLCLKOOR = 0x44f0, /*!< Clear clock out of range */ + TFA9894N2_BF_IEVDDS = 0x4800, /*!< Enable POR */ + TFA9894N2_BF_IEBSTOC = 0x4810, /*!< Enable DCDC OCP */ + TFA9894N2_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ + TFA9894N2_BF_IEOCPR = 0x4830, /*!< Enable OCP alarm */ + TFA9894N2_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ + TFA9894N2_BF_IEMANALARM = 0x4850, /*!< Enable Manager Alarm state */ + TFA9894N2_BF_IETDMER = 0x4860, /*!< Enable TDM error */ + TFA9894N2_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ + TFA9894N2_BF_IECFMER = 0x4880, /*!< Enable cfma err */ + TFA9894N2_BF_IECFMAC = 0x4890, /*!< Enable cfma ack */ + TFA9894N2_BF_IESPKS = 0x48a0, /*!< Enable coolflux speaker error */ + TFA9894N2_BF_IEACS = 0x48b0, /*!< Enable cold started */ + TFA9894N2_BF_IEWDS = 0x48c0, /*!< Enable watchdog reset */ + TFA9894N2_BF_IEBODNOK = 0x48d0, /*!< Enable brown out detect */ + TFA9894N2_BF_IELP1 = 0x48e0, /*!< Enable low power mode1 detect */ + TFA9894N2_BF_IECLKOOR = 0x48f0, /*!< Enable clock out of range */ + TFA9894N2_BF_IPOVDDS = 0x4c00, /*!< Polarity POR */ + TFA9894N2_BF_IPOBSTOC = 0x4c10, /*!< Polarity DCDC OCP */ + TFA9894N2_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ + TFA9894N2_BF_IPOOCPR = 0x4c30, /*!< Polarity ocp alarm */ + TFA9894N2_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ + TFA9894N2_BF_IPOMANALARM = 0x4c50, /*!< Polarity manager alarm state */ + TFA9894N2_BF_IPOTDMER = 0x4c60, /*!< Polarity TDM error */ + TFA9894N2_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ + TFA9894N2_BF_IPOCFMER = 0x4c80, /*!< Polarity cfma err */ + TFA9894N2_BF_IPOCFMAC = 0x4c90, /*!< Polarity cfma ack */ + TFA9894N2_BF_IPOSPKS = 0x4ca0, /*!< Polarity coolflux speaker error */ + TFA9894N2_BF_IPOACS = 0x4cb0, /*!< Polarity cold started */ + TFA9894N2_BF_IPOWDS = 0x4cc0, /*!< Polarity watchdog reset */ + TFA9894N2_BF_IPOBODNOK = 0x4cd0, /*!< Polarity brown out detect */ + TFA9894N2_BF_IPOLP1 = 0x4ce0, /*!< Polarity low power mode1 detect */ + TFA9894N2_BF_IPOCLKOOR = 0x4cf0, /*!< Polarity clock out of range */ + TFA9894N2_BF_BSSCR = 0x5001, /*!< Battery safeguard attack time */ + TFA9894N2_BF_BSST = 0x5023, /*!< Battery safeguard threshold voltage level */ + TFA9894N2_BF_BSSRL = 0x5061, /*!< Battery safeguard maximum reduction */ + TFA9894N2_BF_BSSRR = 0x5082, /*!< Battery safeguard release time */ + TFA9894N2_BF_BSSHY = 0x50b1, /*!< Battery Safeguard hysteresis */ + TFA9894N2_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9894N2_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA9894N2_BF_CFSM = 0x5130, /*!< Coolflux firmware soft mute control */ + TFA9894N2_BF_VOL = 0x5187, /*!< CF firmware volume control */ + TFA9894N2_BF_CLIPCTRL = 0x5202, /*!< Clip control setting */ + TFA9894N2_BF_SLOPEE = 0x5230, /*!< Enables slope control */ + TFA9894N2_BF_SLOPESET = 0x5240, /*!< Slope speed setting (binary coded) */ + TFA9894N2_BF_BYPDLYLINE = 0x5250, /*!< Bypass the interpolator delay line */ + TFA9894N2_BF_AMPGAIN = 0x5287, /*!< Amplifier gain */ + TFA9894N2_BF_TDMDCG = 0x5703, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ + TFA9894N2_BF_TDMSPKG = 0x5743, /*!< Total gain depending on INPLEV setting (channel 0) */ + TFA9894N2_BF_DCINSEL = 0x5781, /*!< VAMP_OUT2 input selection */ + TFA9894N2_BF_LNMODE = 0x5881, /*!< Low noise gain mode control */ + TFA9894N2_BF_LPM1MODE = 0x5ac1, /*!< Low power mode control */ + TFA9894N2_BF_TDMSRCMAP = 0x5d02, /*!< TDM source mapping */ + TFA9894N2_BF_TDMSRCAS = 0x5d31, /*!< Sensed value A */ + TFA9894N2_BF_TDMSRCBS = 0x5d51, /*!< Sensed value B */ + TFA9894N2_BF_TDMSRCACLIP = 0x5d71, /*!< Clip information (analog /digital) for source0 */ + TFA9894N2_BF_TDMSRCBCLIP = 0x5d91, /*!< Clip information (analog /digital) for source1 */ + TFA9894N2_BF_DELCURCOMP = 0x6102, /*!< Delay to allign compensation signal with current sense signal */ + TFA9894N2_BF_SIGCURCOMP = 0x6130, /*!< Polarity of compensation for current sense */ + TFA9894N2_BF_ENCURCOMP = 0x6140, /*!< Enable current sense compensation */ + TFA9894N2_BF_LVLCLPPWM = 0x6152, /*!< Set the amount of pwm pulse that may be skipped before clip-flag is triggered */ + TFA9894N2_BF_DCVOF = 0x7005, /*!< First Boost Voltage Level */ + TFA9894N2_BF_DCVOS = 0x7065, /*!< Second Boost Voltage Level */ + TFA9894N2_BF_DCMCC = 0x70c3, /*!< Max Coil Current */ + TFA9894N2_BF_DCCV = 0x7101, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9894N2_BF_DCIE = 0x7120, /*!< Adaptive boost mode */ + TFA9894N2_BF_DCSR = 0x7130, /*!< Soft ramp up/down */ + TFA9894N2_BF_DCDIS = 0x7140, /*!< DCDC on/off */ + TFA9894N2_BF_DCPWM = 0x7150, /*!< DCDC PWM only mode */ + TFA9894N2_BF_DCTRACK = 0x7160, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ + TFA9894N2_BF_DCENVSEL = 0x7170, /*!< Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1 */ + TFA9894N2_BF_OVSCTLVL = 0x7195, /*!< Threshold level to activate active overshoot control */ + TFA9894N2_BF_DCTRIP = 0x7204, /*!< 1st adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9894N2_BF_DCTRIP2 = 0x7254, /*!< 2nd adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9894N2_BF_DCTRIPT = 0x72a4, /*!< Track adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9894N2_BF_DCTRIPHYSTE = 0x72f0, /*!< Enable hysteresis on booster trip levels */ + TFA9894N2_BF_DCHOLD = 0x7304, /*!< Hold time / Hysteresis for DCDC booster, effective only when boost_intelligent is set to 1 */ + TFA9894N2_BF_RST = 0x9000, /*!< Reset for Coolflux DSP */ + TFA9894N2_BF_DMEM = 0x9011, /*!< Target memory for CFMA using I2C interface */ + TFA9894N2_BF_AIF = 0x9030, /*!< Auto increment */ + TFA9894N2_BF_CFINT = 0x9040, /*!< Coolflux Interrupt - auto clear */ + TFA9894N2_BF_CFCGATE = 0x9050, /*!< Coolflux clock gating disabling control */ + TFA9894N2_BF_REQCMD = 0x9080, /*!< Firmware event request rpc command */ + TFA9894N2_BF_REQRST = 0x9090, /*!< Firmware event request reset restart */ + TFA9894N2_BF_REQMIPS = 0x90a0, /*!< Firmware event request short on mips */ + TFA9894N2_BF_REQMUTED = 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA9894N2_BF_REQVOL = 0x90c0, /*!< Firmware event request volume ready */ + TFA9894N2_BF_REQDMG = 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA9894N2_BF_REQCAL = 0x90e0, /*!< Firmware event request calibration completed */ + TFA9894N2_BF_REQRSV = 0x90f0, /*!< Firmware event request reserved */ + TFA9894N2_BF_MADD = 0x910f, /*!< CF memory address */ + TFA9894N2_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA9894N2_BF_ERR = 0x9307, /*!< CF error flags */ + TFA9894N2_BF_ACKCMD = 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA9894N2_BF_ACKRST = 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA9894N2_BF_ACKMIPS = 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA9894N2_BF_ACKMUTED = 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA9894N2_BF_ACKVOL = 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA9894N2_BF_ACKDMG = 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA9894N2_BF_ACKCAL = 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA9894N2_BF_ACKRSV = 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA9894N2_BF_MTPK = 0xa107, /*!< KEY2 to access KEY2 protected registers, customer key */ + TFA9894N2_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ + TFA9894N2_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ + TFA9894N2_BF_CMTPI = 0xa350, /*!< Start copying all the data from mtp to I2C mtp registers - auto clear */ + TFA9894N2_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp - auto clear */ + TFA9894N2_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9894N2_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9894N2_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9894N2_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9894N2_BF_PLLINSELI = 0xca05, /*!< PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9894N2_BF_PLLINSELP = 0xca64, /*!< PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9894N2_BF_PLLINSELR = 0xcab3, /*!< PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9894N2_BF_PLLNDEC = 0xcb09, /*!< PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLMDECMSB = 0xcba0, /*!< MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLBYPASS = 0xcbb0, /*!< PLL bypass control during functional mode */ + TFA9894N2_BF_PLLDIRECTI = 0xcbc0, /*!< PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLDIRECTO = 0xcbd0, /*!< PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLFRMSTBL = 0xcbe0, /*!< PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLFRM = 0xcbf0, /*!< PLL free running mode control in functional mode */ + TFA9894N2_BF_PLLMDECLSB = 0xcc0f, /*!< Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLPDEC = 0xcd06, /*!< PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_DIRECTPLL = 0xcd70, /*!< Enabled PLL direct control mode, overrules the PLL LUT with I2C register values */ + TFA9894N2_BF_DIRECTCLK = 0xcd80, /*!< Enabled CGU clock divider direct control mode */ + TFA9894N2_BF_PLLLIM = 0xcd90, /*!< PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1 */ + TFA9894N2_BF_SWPROFIL = 0xe00f, /*!< Software profile data */ + TFA9894N2_BF_SWVSTEP = 0xe10f, /*!< Software vstep information */ + TFA9894N2_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ + TFA9894N2_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9894N2_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ + TFA9894N2_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9894N2_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9894N2_BF_CUSTINFO = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9894N2_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9894N2BfEnumList_t; +#define TFA9894N2_NAMETABLE static tfaBfName_t Tfa9894N2DatasheetNames[] = {\ + { 0x0, "PWDN"}, /* Powerdown control , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux DSP , */\ + { 0x30, "AMPE"}, /* Enable Amplifier , */\ + { 0x40, "DCA"}, /* Enable DCDC Boost converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux control over amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x90, "FSSSEL"}, /* Audio sample reference , */\ + { 0xa0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xb0, "TSTOCP"}, /* OCP testing control , */\ + { 0xc0, "BSSS"}, /* Vbat protection steepness , */\ + { 0xd0, "HPFBYP"}, /* Bypass High Pass Filter , */\ + { 0xe0, "DPSA"}, /* Enable DPSA , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* Device I2C settings configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x150, "BODE"}, /* Enable BOD (only in direct control mode) , */\ + { 0x160, "BODHYS"}, /* Enable Hysteresis of BOD , */\ + { 0x171, "BODFILT"}, /* BOD filter , */\ + { 0x191, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1b0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1c0, "MANWDE"}, /* Watchdog enable , */\ + { 0x1e0, "OPENMTP"}, /* Control for FAIM protection , */\ + { 0x1f0, "FAIMVBGOVRRL"}, /* Overrule the enabling of VBG for faim erase/write access, */\ + { 0x203, "AUDFS"}, /* Audio sample rate Fs , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* Current sense fractional delay , */\ + { 0x2b1, "TDMPRES"}, /* Control for HW manager , */\ + { 0x2d2, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external reference clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal reference clock , */\ + { 0x432, "MCLKSEL"}, /* Master Clock Selection , */\ + { 0x460, "MANAOOSC"}, /* Internal OSC1M off at PWDN , */\ + { 0x470, "ACKCLDDIS"}, /* Automatic PLL reference clock selection for cold start, */\ + { 0x480, "FSSYNCEN"}, /* Enable FS synchronisation for clock divider , */\ + { 0x490, "CLKREFSYNCEN"}, /* Enable PLL reference clock synchronisation for clock divider, */\ + { 0x4a0, "PLLSTUP"}, /* PLL startup time configuration , */\ + { 0x500, "CGUSYNCDCG"}, /* Clock gating control for CGU synchronisation module, */\ + { 0x510, "SPKSSEN"}, /* Enable speaker sub-system , */\ + { 0x520, "MTPSSEN"}, /* Enable FAIM sub-system , */\ + { 0x530, "WDTCLKEN"}, /* Enable Coolflux watchdog clock , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL Lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "OCDS"}, /* OCP amplifier (sticky register, clear on read) , */\ + { 0x1060, "CLKS"}, /* Clocks stable , */\ + { 0x1070, "MTPB"}, /* MTP busy , */\ + { 0x1080, "NOCLK"}, /* Lost clock , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "WDS"}, /* Watchdog , */\ + { 0x10b0, "SWS"}, /* Amplifier engage , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD Flag - VDD NOT OK , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active (sticky register, clear on read) , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos (sticky register, clear on read) , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "SPKS"}, /* Speaker status , */\ + { 0x1180, "CLKOOR"}, /* External clock status , */\ + { 0x1190, "MANALARM"}, /* Alarm state , */\ + { 0x11a0, "TDMERR"}, /* TDM error , */\ + { 0x11b0, "TDMLUTER"}, /* TDM lookup table error , */\ + { 0x11c0, "NOAUDCLK"}, /* Lost Audio clock , */\ + { 0x1200, "OCPOAP"}, /* OCPOK pmos A , */\ + { 0x1210, "OCPOAN"}, /* OCPOK nmos A , */\ + { 0x1220, "OCPOBP"}, /* OCPOK pmos B , */\ + { 0x1230, "OCPOBN"}, /* OCPOK nmos B , */\ + { 0x1240, "CLIPS"}, /* Amplifier clipping , */\ + { 0x1250, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x1260, "MANOPER"}, /* Device in Operating state , */\ + { 0x1270, "LP1"}, /* Low power MODE1 detection , */\ + { 0x1280, "LA"}, /* Low amplitude detection , */\ + { 0x1290, "VDDPH"}, /* VDDP greater than VBAT flag , */\ + { 0x1302, "TDMSTAT"}, /* TDM Status bits , */\ + { 0x1333, "MANSTATE"}, /* Device Manager status , */\ + { 0x13b1, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage (1023*VDDP/13V) , */\ + { 0x2000, "TDME"}, /* Enable interface , */\ + { 0x2010, "TDMSPKE"}, /* Control audio tdm channel in sink0 , */\ + { 0x2020, "TDMDCE"}, /* Control audio tdm channel in sink1 , */\ + { 0x2030, "TDMCSE"}, /* Source 0 enable , */\ + { 0x2040, "TDMVSE"}, /* Source 1 enable , */\ + { 0x2050, "TDMCFE"}, /* Source 2 enable , */\ + { 0x2060, "TDMCF2E"}, /* Source 3 enable , */\ + { 0x2070, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2080, "TDMFSPOL"}, /* FS polarity , */\ + { 0x2090, "TDMDEL"}, /* Data delay to FS , */\ + { 0x20a0, "TDMADJ"}, /* Data adjustment , */\ + { 0x20b1, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2103, "TDMNBCK"}, /* TDM NBCK - Bit clock to FS ratio , */\ + { 0x2143, "TDMFSLN"}, /* FS length (master mode only) , */\ + { 0x2183, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x21c1, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x21e1, "TDMTXUS0"}, /* Format unused slots DATAO , */\ + { 0x2204, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2254, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x22a4, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2303, "TDMSPKS"}, /* TDM slot for sink 0 , */\ + { 0x2343, "TDMDCS"}, /* TDM slot for sink 1 , */\ + { 0x2381, "TDMCFSEL"}, /* TDM Source 2 data selection , */\ + { 0x23a1, "TDMCF2SEL"}, /* TDM Source 3 data selection , */\ + { 0x2403, "TDMCSS"}, /* Slot position of source 0 data , */\ + { 0x2443, "TDMVSS"}, /* Slot position of source 1 data , */\ + { 0x2483, "TDMCFS"}, /* Slot position of source 2 data , */\ + { 0x24c3, "TDMCF2S"}, /* Slot position of source 3 data , */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOCPR"}, /* Status OCP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTMANALARM"}, /* Status manager alarm state , */\ + { 0x4060, "ISTTDMER"}, /* Status TDM error , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTCFMER"}, /* Status cfma error , */\ + { 0x4090, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x40a0, "ISTSPKS"}, /* Status coolflux speaker error , */\ + { 0x40b0, "ISTACS"}, /* Status cold started , */\ + { 0x40c0, "ISTWDS"}, /* Status watchdog reset , */\ + { 0x40d0, "ISTBODNOK"}, /* Status brown out detect , */\ + { 0x40e0, "ISTLP1"}, /* Status low power mode1 detect , */\ + { 0x40f0, "ISTCLKOOR"}, /* Status clock out of range , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOCPR"}, /* Clear OCP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLMANALARM"}, /* Clear manager alarm state , */\ + { 0x4460, "ICLTDMER"}, /* Clear TDM error , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x4490, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x44a0, "ICLSPKS"}, /* Clear coolflux speaker error , */\ + { 0x44b0, "ICLACS"}, /* Clear cold started , */\ + { 0x44c0, "ICLWDS"}, /* Clear watchdog reset , */\ + { 0x44d0, "ICLBODNOK"}, /* Clear brown out detect , */\ + { 0x44e0, "ICLLP1"}, /* Clear low power mode1 detect , */\ + { 0x44f0, "ICLCLKOOR"}, /* Clear clock out of range , */\ + { 0x4800, "IEVDDS"}, /* Enable POR , */\ + { 0x4810, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOCPR"}, /* Enable OCP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IEMANALARM"}, /* Enable Manager Alarm state , */\ + { 0x4860, "IETDMER"}, /* Enable TDM error , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IECFMER"}, /* Enable cfma err , */\ + { 0x4890, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x48a0, "IESPKS"}, /* Enable coolflux speaker error , */\ + { 0x48b0, "IEACS"}, /* Enable cold started , */\ + { 0x48c0, "IEWDS"}, /* Enable watchdog reset , */\ + { 0x48d0, "IEBODNOK"}, /* Enable brown out detect , */\ + { 0x48e0, "IELP1"}, /* Enable low power mode1 detect , */\ + { 0x48f0, "IECLKOOR"}, /* Enable clock out of range , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity POR , */\ + { 0x4c10, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOMANALARM"}, /* Polarity manager alarm state , */\ + { 0x4c60, "IPOTDMER"}, /* Polarity TDM error , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4c90, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4ca0, "IPOSPKS"}, /* Polarity coolflux speaker error , */\ + { 0x4cb0, "IPOACS"}, /* Polarity cold started , */\ + { 0x4cc0, "IPOWDS"}, /* Polarity watchdog reset , */\ + { 0x4cd0, "IPOBODNOK"}, /* Polarity brown out detect , */\ + { 0x4ce0, "IPOLP1"}, /* Polarity low power mode1 detect , */\ + { 0x4cf0, "IPOCLKOOR"}, /* Polarity clock out of range , */\ + { 0x5001, "BSSCR"}, /* Battery safeguard attack time , */\ + { 0x5023, "BSST"}, /* Battery safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery safeguard maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery safeguard release time , */\ + { 0x50b1, "BSSHY"}, /* Battery Safeguard hysteresis , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5130, "CFSM"}, /* Coolflux firmware soft mute control , */\ + { 0x5187, "VOL"}, /* CF firmware volume control , */\ + { 0x5202, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5230, "SLOPEE"}, /* Enables slope control , */\ + { 0x5240, "SLOPESET"}, /* Slope speed setting (binary coded) , */\ + { 0x5250, "BYPDLYLINE"}, /* Bypass the interpolator delay line , */\ + { 0x5287, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x5703, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5743, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x5781, "DCINSEL"}, /* VAMP_OUT2 input selection , */\ + { 0x5881, "LNMODE"}, /* Low noise gain mode control , */\ + { 0x5ac1, "LPM1MODE"}, /* Low power mode control , */\ + { 0x5d02, "TDMSRCMAP"}, /* TDM source mapping , */\ + { 0x5d31, "TDMSRCAS"}, /* Sensed value A , */\ + { 0x5d51, "TDMSRCBS"}, /* Sensed value B , */\ + { 0x5d71, "TDMSRCACLIP"}, /* Clip information (analog /digital) for source0 , */\ + { 0x5d91, "TDMSRCBCLIP"}, /* Clip information (analog /digital) for source1 , */\ + { 0x6102, "DELCURCOMP"}, /* Delay to allign compensation signal with current sense signal, */\ + { 0x6130, "SIGCURCOMP"}, /* Polarity of compensation for current sense , */\ + { 0x6140, "ENCURCOMP"}, /* Enable current sense compensation , */\ + { 0x6152, "LVLCLPPWM"}, /* Set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7005, "DCVOF"}, /* First Boost Voltage Level , */\ + { 0x7065, "DCVOS"}, /* Second Boost Voltage Level , */\ + { 0x70c3, "DCMCC"}, /* Max Coil Current , */\ + { 0x7101, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7120, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7130, "DCSR"}, /* Soft ramp up/down , */\ + { 0x7140, "DCDIS"}, /* DCDC on/off , */\ + { 0x7150, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7160, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7170, "DCENVSEL"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7195, "OVSCTLVL"}, /* Threshold level to activate active overshoot control, */\ + { 0x7204, "DCTRIP"}, /* 1st adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7254, "DCTRIP2"}, /* 2nd adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x72a4, "DCTRIPT"}, /* Track adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x72f0, "DCTRIPHYSTE"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7304, "DCHOLD"}, /* Hold time / Hysteresis for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x9000, "RST"}, /* Reset for Coolflux DSP , */\ + { 0x9011, "DMEM"}, /* Target memory for CFMA using I2C interface , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Coolflux Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* CF memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* CF error flags , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* KEY2 to access KEY2 protected registers, customer key, */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa350, "CMTPI"}, /* Start copying all the data from mtp to I2C mtp registers - auto clear, */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp - auto clear, */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xca05, "PLLINSELI"}, /* PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xca64, "PLLINSELP"}, /* PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcab3, "PLLINSELR"}, /* PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcb09, "PLLNDEC"}, /* PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcba0, "PLLMDECMSB"}, /* MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbb0, "PLLBYPASS"}, /* PLL bypass control during functional mode , */\ + { 0xcbc0, "PLLDIRECTI"}, /* PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbd0, "PLLDIRECTO"}, /* PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbe0, "PLLFRMSTBL"}, /* PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbf0, "PLLFRM"}, /* PLL free running mode control in functional mode , */\ + { 0xcc0f, "PLLMDECLSB"}, /* Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcd06, "PLLPDEC"}, /* PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcd70, "DIRECTPLL"}, /* Enabled PLL direct control mode, overrules the PLL LUT with I2C register values, */\ + { 0xcd80, "DIRECTCLK"}, /* Enabled CGU clock divider direct control mode , */\ + { 0xcd90, "PLLLIM"}, /* PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1, */\ + { 0xe00f, "SWPROFIL"}, /* Software profile data , */\ + { 0xe10f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9894N2_BITNAMETABLE static tfaBfName_t Tfa9894N2BitNames[] = {\ + { 0x0, "powerdown"}, /* Powerdown control , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux DSP , */\ + { 0x30, "enbl_amplifier"}, /* Enable Amplifier , */\ + { 0x40, "enbl_boost"}, /* Enable DCDC Boost converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux control over amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x90, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xa0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xb0, "test_ocp"}, /* OCP testing control , */\ + { 0xc0, "batsense_steepness"}, /* Vbat protection steepness , */\ + { 0xd0, "bypass_hp"}, /* Bypass High Pass Filter , */\ + { 0xe0, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0xf0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ + { 0x101, "vamp_sel1"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* Device I2C settings configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x150, "bod_enbl"}, /* Enable BOD (only in direct control mode) , */\ + { 0x160, "bod_hyst_enbl"}, /* Enable Hysteresis of BOD , */\ + { 0x171, "bod_delay_set"}, /* BOD filter , */\ + { 0x191, "bod_lvl_set"}, /* BOD threshold , */\ + { 0x1b0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1c0, "man_enbl_watchdog"}, /* Watchdog enable , */\ + { 0x1d0, "disable_engage"}, /* Disable Engage , */\ + { 0x1e0, "unprotect_faim"}, /* Control for FAIM protection , */\ + { 0x1f0, "faim_enable_vbg"}, /* Overrule the enabling of VBG for faim erase/write access, */\ + { 0x203, "audio_fs"}, /* Audio sample rate Fs , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* Current sense fractional delay , */\ + { 0x2b1, "use_tdm_presence"}, /* Control for HW manager , */\ + { 0x2d2, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external reference clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal reference clock , */\ + { 0x432, "mclk_sel"}, /* Master Clock Selection , */\ + { 0x460, "enbl_osc1m_auto_off"}, /* Internal OSC1M off at PWDN , */\ + { 0x470, "disable_auto_sel_refclk"}, /* Automatic PLL reference clock selection for cold start, */\ + { 0x480, "enbl_fs_sync"}, /* Enable FS synchronisation for clock divider , */\ + { 0x490, "enbl_clkref_sync"}, /* Enable PLL reference clock synchronisation for clock divider, */\ + { 0x4a0, "pll_slow_startup"}, /* PLL startup time configuration , */\ + { 0x500, "disable_cgu_sync_cgate"}, /* Clock gating control for CGU synchronisation module, */\ + { 0x510, "enbl_spkr_ss"}, /* Enable speaker sub-system , */\ + { 0x520, "enbl_faim_ss"}, /* Enable FAIM sub-system , */\ + { 0x530, "enbl_wdt_clk"}, /* Enable Coolflux watchdog clock , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* Hidden code to enable access to hidden register. (0x5A6B/23147 default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL Lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_ocp_alarm"}, /* OCP amplifier (sticky register, clear on read) , */\ + { 0x1060, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1070, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1080, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10b0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD Flag - VDD NOT OK , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active (sticky register, clear on read) , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos (sticky register, clear on read) , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_cf_speakererror"}, /* Speaker status , */\ + { 0x1180, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1190, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x11a0, "flag_tdm_error"}, /* TDM error , */\ + { 0x11b0, "flag_tdm_lut_error"}, /* TDM lookup table error , */\ + { 0x11c0, "flag_lost_audio_clk"}, /* Lost Audio clock , */\ + { 0x1200, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1210, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1220, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1230, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1240, "flag_clip"}, /* Amplifier clipping , */\ + { 0x1250, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x1260, "flag_man_operating_state"}, /* Device in Operating state , */\ + { 0x1270, "flag_lp_detect_mode1"}, /* Low power MODE1 detection , */\ + { 0x1280, "flag_low_amplitude"}, /* Low amplitude detection , */\ + { 0x1290, "flag_vddp_gt_vbat"}, /* VDDP greater than VBAT flag , */\ + { 0x1302, "tdm_status"}, /* TDM Status bits , */\ + { 0x1333, "man_state"}, /* Device Manager status , */\ + { 0x1373, "amp_ctrl_state"}, /* Amplifier control status , */\ + { 0x13b1, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage (1023*VDDP/13V) , */\ + { 0x2000, "tdm_enable"}, /* Enable interface , */\ + { 0x2010, "tdm_sink0_enable"}, /* Control audio tdm channel in sink0 , */\ + { 0x2020, "tdm_sink1_enable"}, /* Control audio tdm channel in sink1 , */\ + { 0x2030, "tdm_source0_enable"}, /* Source 0 enable , */\ + { 0x2040, "tdm_source1_enable"}, /* Source 1 enable , */\ + { 0x2050, "tdm_source2_enable"}, /* Source 2 enable , */\ + { 0x2060, "tdm_source3_enable"}, /* Source 3 enable , */\ + { 0x2070, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2080, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x2090, "tdm_data_delay"}, /* Data delay to FS , */\ + { 0x20a0, "tdm_data_adjustment"}, /* Data adjustment , */\ + { 0x20b1, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2103, "tdm_nbck"}, /* TDM NBCK - Bit clock to FS ratio , */\ + { 0x2143, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ + { 0x2183, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x21c1, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x21e1, "tdm_txdata_format_unused_slot"}, /* Format unused slots DATAO , */\ + { 0x2204, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2254, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x22a4, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2303, "tdm_sink0_slot"}, /* TDM slot for sink 0 , */\ + { 0x2343, "tdm_sink1_slot"}, /* TDM slot for sink 1 , */\ + { 0x2381, "tdm_source2_sel"}, /* TDM Source 2 data selection , */\ + { 0x23a1, "tdm_source3_sel"}, /* TDM Source 3 data selection , */\ + { 0x2403, "tdm_source0_slot"}, /* Slot position of source 0 data , */\ + { 0x2443, "tdm_source1_slot"}, /* Slot position of source 1 data , */\ + { 0x2483, "tdm_source2_slot"}, /* Slot position of source 2 data , */\ + { 0x24c3, "tdm_source3_slot"}, /* Slot position of source 3 data , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ocp_alarm"}, /* Status OCP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_man_alarm_state"}, /* Status manager alarm state , */\ + { 0x4060, "int_out_flag_tdm_error"}, /* Status TDM error , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x4090, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x40a0, "int_out_flag_cf_speakererror"}, /* Status coolflux speaker error , */\ + { 0x40b0, "int_out_flag_cold_started"}, /* Status cold started , */\ + { 0x40c0, "int_out_flag_watchdog_reset"}, /* Status watchdog reset , */\ + { 0x40d0, "int_out_flag_bod_vddd_nok"}, /* Status brown out detect , */\ + { 0x40e0, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 detect , */\ + { 0x40f0, "int_out_flag_clk_out_of_range"}, /* Status clock out of range , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ocp_alarm"}, /* Clear OCP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_man_alarm_state"}, /* Clear manager alarm state , */\ + { 0x4460, "int_in_flag_tdm_error"}, /* Clear TDM error , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x4490, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x44a0, "int_in_flag_cf_speakererror"}, /* Clear coolflux speaker error , */\ + { 0x44b0, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44c0, "int_in_flag_watchdog_reset"}, /* Clear watchdog reset , */\ + { 0x44d0, "int_in_flag_bod_vddd_nok"}, /* Clear brown out detect , */\ + { 0x44e0, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 detect , */\ + { 0x44f0, "int_in_flag_clk_out_of_range"}, /* Clear clock out of range , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable POR , */\ + { 0x4810, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ocp_alarm"}, /* Enable OCP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_man_alarm_state"}, /* Enable Manager Alarm state , */\ + { 0x4860, "int_enable_flag_tdm_error"}, /* Enable TDM error , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x4890, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x48a0, "int_enable_flag_cf_speakererror"}, /* Enable coolflux speaker error , */\ + { 0x48b0, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48c0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog reset , */\ + { 0x48d0, "int_enable_flag_bod_vddd_nok"}, /* Enable brown out detect , */\ + { 0x48e0, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 detect , */\ + { 0x48f0, "int_enable_flag_clk_out_of_range"}, /* Enable clock out of range , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity POR , */\ + { 0x4c10, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_man_alarm_state"}, /* Polarity manager alarm state , */\ + { 0x4c60, "int_polarity_flag_tdm_error"}, /* Polarity TDM error , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4c90, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4ca0, "int_polarity_flag_cf_speakererror"}, /* Polarity coolflux speaker error , */\ + { 0x4cb0, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4cc0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog reset , */\ + { 0x4cd0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity brown out detect , */\ + { 0x4ce0, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 detect , */\ + { 0x4cf0, "int_polarity_flag_clk_out_of_range"}, /* Polarity clock out of range , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery safeguard attack time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery safeguard maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery safeguard release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5130, "cf_mute"}, /* Coolflux firmware soft mute control , */\ + { 0x5187, "cf_volume"}, /* CF firmware volume control , */\ + { 0x5202, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5230, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x5240, "ctrl_slope"}, /* Slope speed setting (binary coded) , */\ + { 0x5250, "bypass_dly_line"}, /* Bypass the interpolator delay line , */\ + { 0x5287, "gain"}, /* Amplifier gain , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for battery safeguard, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5370, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5380, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5390, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x53a3, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5400, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5413, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5452, "dpsa_drive"}, /* Drive setting (binary coded) , */\ + { 0x550a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ + { 0x55b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ + { 0x55c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5600, "pwm_shape"}, /* PWM shape , */\ + { 0x5614, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5660, "reclock_pwm"}, /* Reclock the PWM signal inside analog , */\ + { 0x5670, "reclock_voltsense"}, /* Reclock the voltage sense PWM signal , */\ + { 0x5680, "enbl_pwm_phase_shift"}, /* Control for PWM phase shift , */\ + { 0x5690, "sel_pwm_delay_src"}, /* Control for selection for PWM delay line source , */\ + { 0x56a1, "enbl_odd_up_even_down"}, /* Control for PWM reference sawtooth generartion , */\ + { 0x5703, "ctrl_att_dcdc"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5743, "ctrl_att_spkr"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x5781, "vamp_sel2"}, /* VAMP_OUT2 input selection , */\ + { 0x5805, "zero_lvl"}, /* Low noise gain switch zero trigger level , */\ + { 0x5861, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x5881, "lownoisegain_mode"}, /* Low noise gain mode control , */\ + { 0x5905, "threshold_lvl"}, /* Low noise gain switch trigger level , */\ + { 0x5965, "hold_time"}, /* Low noise mode hold time before entering into low noise mode, */\ + { 0x5a05, "lpm1_cal_offset"}, /* Low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x5a65, "lpm1_zero_lvl"}, /* Low power mode1 zero crossing detection level , */\ + { 0x5ac1, "lpm1_mode"}, /* Low power mode control , */\ + { 0x5b05, "lpm1_threshold_lvl"}, /* Low power mode1 amplitude trigger level , */\ + { 0x5b65, "lpm1_hold_time"}, /* Low power mode hold time before entering into low power mode, */\ + { 0x5bc0, "disable_low_power_mode"}, /* Low power mode1 detector control , */\ + { 0x5c00, "enbl_minion"}, /* Enables minion (small) power stage , */\ + { 0x5c13, "vth_vddpvbat"}, /* Select vddp-vbat threshold signal , */\ + { 0x5c50, "lpen_vddpvbat"}, /* Select vddp-vbat filtred vs unfiltered compare , */\ + { 0x5c61, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x5d02, "tdm_source_mapping"}, /* TDM source mapping , */\ + { 0x5d31, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ + { 0x5d51, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ + { 0x5d71, "tdm_source0_clip_sel"}, /* Clip information (analog /digital) for source0 , */\ + { 0x5d91, "tdm_source1_clip_sel"}, /* Clip information (analog /digital) for source1 , */\ + { 0x5e02, "rst_min_vbat_delay"}, /* Delay for reseting the min_vbat value inside HW Clipper (number of Fs pulses), */\ + { 0x5e30, "rst_min_vbat_sel"}, /* Control for selecting reset signal for min_bat , */\ + { 0x5f00, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5f12, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x5f42, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x5f78, "spare_out"}, /* Spare out register , */\ + { 0x600f, "spare_in"}, /* Spare IN , */\ + { 0x6102, "cursense_comp_delay"}, /* Delay to allign compensation signal with current sense signal, */\ + { 0x6130, "cursense_comp_sign"}, /* Polarity of compensation for current sense , */\ + { 0x6140, "enbl_cursense_comp"}, /* Enable current sense compensation , */\ + { 0x6152, "pwms_clip_lvl"}, /* Set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7005, "frst_boost_voltage"}, /* First Boost Voltage Level , */\ + { 0x7065, "scnd_boost_voltage"}, /* Second Boost Voltage Level , */\ + { 0x70c3, "boost_cur"}, /* Max Coil Current , */\ + { 0x7101, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7120, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7130, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x7140, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x7150, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7160, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7170, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7180, "ignore_flag_voutcomp86"}, /* Determines the maximum PWM frequency be the most efficient in relation to the Booster inductor value, */\ + { 0x7195, "overshoot_correction_lvl"}, /* Threshold level to activate active overshoot control, */\ + { 0x7204, "boost_trip_lvl_1st"}, /* 1st adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7254, "boost_trip_lvl_2nd"}, /* 2nd adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x72a4, "boost_trip_lvl_track"}, /* Track adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x72f0, "enbl_trip_hyst"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7304, "boost_hold_time"}, /* Hold time / Hysteresis for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x7350, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x7361, "dcdc_ctrl_maxzercnt"}, /* Number of zero current flags to count before going to pfm mode, */\ + { 0x7386, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x73f0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x7404, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7451, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7474, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x74c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x74e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x74f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7500, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7510, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7520, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7530, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7540, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7550, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7560, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7570, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7580, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x7595, "bst_windac"}, /* For testing direct control windac , */\ + { 0x7600, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7611, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7631, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7650, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7660, "bst_use_new_zercur_detect"}, /* Enable new zero current detection for boost control, */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8040, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8050, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8060, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8105, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP) * signal, */\ + { 0x8164, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x81b0, "enbl_cs_adc"}, /* Enable current sense ADC , */\ + { 0x81c0, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ + { 0x81d0, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ + { 0x81e0, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x81f0, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ + { 0x8200, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ + { 0x8210, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ + { 0x8220, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8231, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8250, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8263, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x82a0, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x82b4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8300, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8310, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8320, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8330, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8340, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8350, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if enbl_cs_ldo is high, */\ + { 0x8364, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8800, "ctrl_vs_igen_supply"}, /* Control for selecting supply for VS current generator, */\ + { 0x8810, "ctrl_vs_force_div2"}, /* Select input resistive divider gain , */\ + { 0x8820, "enbl_dc_filter"}, /* Control for enabling the DC blocking filter for voltage and current sense, */\ + { 0x8901, "volsense_pwm_sel"}, /* Voltage sense source selection control , */\ + { 0x8920, "vs_gain_control"}, /* Voltage sense gain control , */\ + { 0x8930, "vs_bypass_gc"}, /* Bypasses the VS gain correction , */\ + { 0x8940, "vs_adc_bsoinv"}, /* Bitstream inversion for voltage sense ADC , */\ + { 0x8950, "vs_adc_nortz"}, /* Return to zero for voltage sense ADC , */\ + { 0x8960, "vs_adc_slowdel"}, /* Select delay for voltage sense ADC (internal decision circuitry), */\ + { 0x8970, "vs_classd_tran_skip"}, /* Skip voltage sense connection during a classD amplifier transition, */\ + { 0x8987, "vs_gain"}, /* Voltage sense gain , */\ + { 0x8a00, "vs_inn_short"}, /* Short voltage sense negative to common mode , */\ + { 0x8a10, "vs_inp_short"}, /* Short voltage sense positive to common mode , */\ + { 0x8a20, "vs_ldo_bypass"}, /* Bypass voltage sense LDO , */\ + { 0x8a30, "vs_ldo_pulldown"}, /* Pull down voltage sense LDO, only valid if enbl_cs_ldo is high, */\ + { 0x8a44, "vs_ldo_voset"}, /* Voltage sense LDO voltage level setting (two's complement), */\ + { 0x8a90, "enbl_vs_adc"}, /* Enable voltage sense ADC , */\ + { 0x8aa0, "enbl_vs_inn1"}, /* Enable connection of voltage sense negative1 , */\ + { 0x8ab0, "enbl_vs_inn2"}, /* Enable connection of voltage sense negative2 , */\ + { 0x8ac0, "enbl_vs_inp1"}, /* Enable connection of voltage sense positive1 , */\ + { 0x8ad0, "enbl_vs_inp2"}, /* Enable connection of voltage sense positive2 , */\ + { 0x8ae0, "enbl_vs_ldo"}, /* Enable voltage sense LDO , */\ + { 0x8af0, "enbl_vs_vbatldo"}, /* Enable of voltage sense LDO , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset for Coolflux DSP , */\ + { 0x9011, "cf_dmem"}, /* Target memory for CFMA using I2C interface , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Coolflux Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* CF memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* CF error flags , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0xa007, "mtpkey1"}, /* KEY1 To access KEY1 protected registers 0x5A/90d (default for engineering), */\ + { 0xa107, "mtpkey2"}, /* KEY2 to access KEY2 protected registers, customer key, */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from MTP to I2C mtp register - auto clear, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp - auto clear, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers - auto clear, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp - auto clear, */\ + { 0xa400, "faim_set_clkws"}, /* Sets the FaIM controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the FaIM are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the FaIM are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb000, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb010, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb020, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb030, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb040, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb050, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb060, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb070, "disable_main_ctrl_change_prot"}, /* Disable main control change protection , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0c0, "use_direct_vs_ctrls"}, /* Voltage sense direct control to overrule several functions for testing, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "enbl_pll"}, /* Enables PLL in I2C direct control mode only , */\ + { 0xc0f0, "enbl_osc"}, /* Enables OSC in I2C direct control mode only , */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3d0, "test_abistfft_enbl"}, /* Enable ABIST with FFT on Coolflux DSP , */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost Converter Over Current Protection , */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc530, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc540, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc550, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc560, "test_enbl_vs"}, /* Enable for digimux mode of voltage sense , */\ + { 0xc570, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc583, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc5c0, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc607, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO , */\ + { 0xc687, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT , */\ + { 0xc707, "digimuxc_sel"}, /* DigimuxC input selection control routed to ADS1 , */\ + { 0xc800, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xc810, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xc820, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xc830, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xc844, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xc894, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xc903, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xc943, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xca05, "pll_inseli"}, /* PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xca64, "pll_inselp"}, /* PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcab3, "pll_inselr"}, /* PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcaf0, "pll_bandsel"}, /* PLL bandwidth selection control, USE WITH CAUTION , */\ + { 0xcb09, "pll_ndec"}, /* PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcba0, "pll_mdec_msb"}, /* MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbb0, "pll_bypass"}, /* PLL bypass control during functional mode , */\ + { 0xcbc0, "pll_directi"}, /* PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbd0, "pll_directo"}, /* PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbe0, "pll_frm_clockstable"}, /* PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbf0, "pll_frm"}, /* PLL free running mode control in functional mode , */\ + { 0xcc0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcd06, "pll_pdec"}, /* PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcd70, "use_direct_pll_ctrl"}, /* Enabled PLL direct control mode, overrules the PLL LUT with I2C register values, */\ + { 0xcd80, "use_direct_clk_ctrl"}, /* Enabled CGU clock divider direct control mode , */\ + { 0xcd90, "pll_limup_off"}, /* PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1, */\ + { 0xce0f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xcf02, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xcf33, "tsig_gain"}, /* Test signal gain , */\ + { 0xd000, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd011, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd032, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd064, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd0b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd0c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd109, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd201, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ + { 0xd301, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO datasheet), */\ + { 0xd321, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO datasheet), */\ + { 0xd340, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xd407, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd480, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xd491, "sel_wdt_clk"}, /* Watch dog clock divider settings , */\ + { 0xd4b0, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd500, "source_in_testmode"}, /* TDM source in test mode (return only current and voltage sense), */\ + { 0xd510, "gainatt_feedback"}, /* Gainatt feedback to tdm , */\ + { 0xd522, "test_parametric_io"}, /* Test IO parametric , */\ + { 0xd550, "ctrl_bst_clk_lp1"}, /* Boost clock control in low power mode1 , */\ + { 0xd561, "test_spare_out1"}, /* Test spare out 1 , */\ + { 0xd580, "bst_dcmbst"}, /* DCM boost , */\ + { 0xd593, "test_spare_out2"}, /* Test spare out 2 , */\ + { 0xe00f, "sw_profile"}, /* Software profile data , */\ + { 0xe10f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf307, "calibr_gain_vs"}, /* Voltage sense gain , */\ + { 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf40f, "mtpdata4"}, /* MTP4 data , */\ + { 0xf50f, "calibr_R25C"}, /* Ron resistance of speaker coil , */\ + { 0xf60f, "mtpdata6"}, /* MTP6 data , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable functionality of dcdcoff_mode bit , */\ + { 0xf910, "mtp_lock_enbl_coolflux"}, /* Disable functionality of enbl_coolflux bit , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_enbl_pwm_delay_clock_gating"}, /* PWM delay clock auto gating , */\ + { 0xf940, "mtp_enbl_ocp_clock_gating"}, /* OCP clock auto gating , */\ + { 0xf987, "type_bits_fw"}, /* MTP control for firmware features - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE , */\ + { 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; +#if 0 +enum tfa9894_irq { + tfa9894_irq_max = -1, + tfa9894_irq_all = -1 /* all irqs */}; +#endif// +#define TFA9894_IRQ_NAMETABLE static tfaIrqName_t Tfa9894IrqNames[] = {\ +}; +#endif /* _TFA9894_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa9896_tfafieldnames.h b/sound/soc/codecs/tfa9896_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..db708b4e5f6263a8986596227892314c3df73764 --- /dev/null +++ b/sound/soc/codecs/tfa9896_tfafieldnames.h @@ -0,0 +1,923 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9896_TFAFIELDNAMES_H +#define _TFA9896_TFAFIELDNAMES_H + + +#define TFA9896_I2CVERSION 16 + +typedef enum nxpTFA9896BfEnumList { + TFA9896_BF_VDDS = 0x0000, /*!< Power-on-reset flag (auto clear by reading) */ + TFA9896_BF_PLLS = 0x0010, /*!< PLL lock to programmed frequency */ + TFA9896_BF_OTDS = 0x0020, /*!< Over Temperature Protection alarm */ + TFA9896_BF_OVDS = 0x0030, /*!< Over Voltage Protection alarm */ + TFA9896_BF_UVDS = 0x0040, /*!< Under Voltage Protection alarm */ + TFA9896_BF_OCDS = 0x0050, /*!< Over Current Protection alarm */ + TFA9896_BF_CLKS = 0x0060, /*!< Clocks stable flag */ + TFA9896_BF_CLIPS = 0x0070, /*!< Amplifier clipping */ + TFA9896_BF_MTPB = 0x0080, /*!< MTP busy copying data to/from I2C registers */ + TFA9896_BF_NOCLK = 0x0090, /*!< lost clock detection (reference input clock) */ + TFA9896_BF_SPKS = 0x00a0, /*!< Speaker error */ + TFA9896_BF_ACS = 0x00b0, /*!< Cold Start required */ + TFA9896_BF_SWS = 0x00c0, /*!< Amplifier engage (Amp Switching) */ + TFA9896_BF_WDS = 0x00d0, /*!< watchdog reset (activates reset) */ + TFA9896_BF_AMPS = 0x00e0, /*!< Amplifier is enabled by manager */ + TFA9896_BF_AREFS = 0x00f0, /*!< References are enabled by manager */ + TFA9896_BF_BATS = 0x0109, /*!< Battery voltage from ADC readout */ + TFA9896_BF_TEMPS = 0x0208, /*!< Temperature readout from the temperature sensor ( C) */ + TFA9896_BF_REV = 0x030f, /*!< Device revision information */ + TFA9896_BF_RCV = 0x0420, /*!< Enable receiver mode */ + TFA9896_BF_CHS12 = 0x0431, /*!< Channel Selection TDM input for Coolflux */ + TFA9896_BF_INPLVL = 0x0450, /*!< Input level selection attenuator ( */ + TFA9896_BF_CHSA = 0x0461, /*!< Input selection for amplifier */ + TFA9896_BF_AUDFS = 0x04c3, /*!< Audio sample rate setting */ + TFA9896_BF_BSSCR = 0x0501, /*!< Batteery protection attack time */ + TFA9896_BF_BSST = 0x0523, /*!< Battery protection threshold level */ + TFA9896_BF_BSSRL = 0x0561, /*!< Battery protection maximum reduction */ + TFA9896_BF_BSSRR = 0x0582, /*!< Battery protection release time */ + TFA9896_BF_BSSHY = 0x05b1, /*!< Battery Protection Hysteresis */ + TFA9896_BF_BSSR = 0x05e0, /*!< Battery voltage value for read out (only) */ + TFA9896_BF_BSSBY = 0x05f0, /*!< Bypass clipper battery protection */ + TFA9896_BF_DPSA = 0x0600, /*!< Enable dynamic powerstage activation (DPSA) */ + TFA9896_BF_ATTEN = 0x0613, /*!< Gain attenuation setting */ + TFA9896_BF_CFSM = 0x0650, /*!< Soft mute in CoolFlux */ + TFA9896_BF_BSSS = 0x0670, /*!< Battery sense steepness */ + TFA9896_BF_VOL = 0x0687, /*!< Coolflux volume control */ + TFA9896_BF_DCVO2 = 0x0702, /*!< Second Boost Voltage */ + TFA9896_BF_DCMCC = 0x0733, /*!< Max boost coil current - step of 175 mA */ + TFA9896_BF_DCVO1 = 0x0772, /*!< First Boost Voltage */ + TFA9896_BF_DCIE = 0x07a0, /*!< Adaptive boost mode */ + TFA9896_BF_DCSR = 0x07b0, /*!< Soft Rampup/down mode for DCDC controller */ + TFA9896_BF_DCPAVG = 0x07c0, /*!< ctrl_peak2avg for analog part of DCDC */ + TFA9896_BF_DCPWM = 0x07d0, /*!< DCDC PWM only mode */ + TFA9896_BF_TROS = 0x0800, /*!< Selection ambient temperature for speaker calibration */ + TFA9896_BF_EXTTS = 0x0818, /*!< External temperature for speaker calibration (C) */ + TFA9896_BF_PWDN = 0x0900, /*!< powerdown selection */ + TFA9896_BF_I2CR = 0x0910, /*!< All I2C registers reset to default */ + TFA9896_BF_CFE = 0x0920, /*!< Enable CoolFlux */ + TFA9896_BF_AMPE = 0x0930, /*!< Enable Amplifier */ + TFA9896_BF_DCA = 0x0940, /*!< Enable DCDC Boost converter */ + TFA9896_BF_SBSL = 0x0950, /*!< Coolflux configured */ + TFA9896_BF_AMPC = 0x0960, /*!< Selection if Coolflux enables amplifier */ + TFA9896_BF_DCDIS = 0x0970, /*!< DCDC boost converter not connected */ + TFA9896_BF_PSDR = 0x0980, /*!< IDDQ amplifier test selection */ + TFA9896_BF_INTPAD = 0x09c1, /*!< INT pad (interrupt bump output) configuration */ + TFA9896_BF_IPLL = 0x09e0, /*!< PLL input reference clock selection */ + TFA9896_BF_DCTRIP = 0x0a04, /*!< Adaptive boost trip levels (effective only when boost_intel is set to 1) */ + TFA9896_BF_DCHOLD = 0x0a54, /*!< Hold time for DCDC booster (effective only when boost_intel is set to 1) */ + TFA9896_BF_MTPK = 0x0b07, /*!< KEY2 to access key2 protected registers (default for engineering) */ + TFA9896_BF_CVFDLY = 0x0c25, /*!< Fractional delay adjustment between current and voltage sense */ + TFA9896_BF_OPENMTP = 0x0ec0, /*!< Enable programming of the MTP memory */ + TFA9896_BF_TDMPRF = 0x1011, /*!< TDM usecase selection control */ + TFA9896_BF_TDMEN = 0x1030, /*!< TDM interface enable */ + TFA9896_BF_TDMCKINV = 0x1040, /*!< TDM clock inversion, receive on */ + TFA9896_BF_TDMFSLN = 0x1053, /*!< TDM FS length */ + TFA9896_BF_TDMFSPOL = 0x1090, /*!< TDM FS polarity (start frame) */ + TFA9896_BF_TDMSAMSZ = 0x10a4, /*!< TDM sample size for all TDM sinks and sources */ + TFA9896_BF_TDMSLOTS = 0x1103, /*!< TDM number of slots */ + TFA9896_BF_TDMSLLN = 0x1144, /*!< TDM slot length */ + TFA9896_BF_TDMBRMG = 0x1194, /*!< TDM bits remaining after the last slot */ + TFA9896_BF_TDMDDEL = 0x11e0, /*!< TDM data delay */ + TFA9896_BF_TDMDADJ = 0x11f0, /*!< TDM data adjustment */ + TFA9896_BF_TDMTXFRM = 0x1201, /*!< TDM TXDATA format */ + TFA9896_BF_TDMUUS0 = 0x1221, /*!< TDM TXDATA format unused slot SD0 */ + TFA9896_BF_TDMUUS1 = 0x1241, /*!< TDM TXDATA format unused slot SD1 */ + TFA9896_BF_TDMSI0EN = 0x1270, /*!< TDM sink0 enable */ + TFA9896_BF_TDMSI1EN = 0x1280, /*!< TDM sink1 enable */ + TFA9896_BF_TDMSI2EN = 0x1290, /*!< TDM sink2 enable */ + TFA9896_BF_TDMSO0EN = 0x12a0, /*!< TDM source0 enable */ + TFA9896_BF_TDMSO1EN = 0x12b0, /*!< TDM source1 enable */ + TFA9896_BF_TDMSO2EN = 0x12c0, /*!< TDM source2 enable */ + TFA9896_BF_TDMSI0IO = 0x12d0, /*!< TDM sink0 IO selection */ + TFA9896_BF_TDMSI1IO = 0x12e0, /*!< TDM sink1 IO selection */ + TFA9896_BF_TDMSI2IO = 0x12f0, /*!< TDM sink2 IO selection */ + TFA9896_BF_TDMSO0IO = 0x1300, /*!< TDM source0 IO selection */ + TFA9896_BF_TDMSO1IO = 0x1310, /*!< TDM source1 IO selection */ + TFA9896_BF_TDMSO2IO = 0x1320, /*!< TDM source2 IO selection */ + TFA9896_BF_TDMSI0SL = 0x1333, /*!< TDM sink0 slot position [GAIN IN] */ + TFA9896_BF_TDMSI1SL = 0x1373, /*!< TDM sink1 slot position [CH1 IN] */ + TFA9896_BF_TDMSI2SL = 0x13b3, /*!< TDM sink2 slot position [CH2 IN] */ + TFA9896_BF_TDMSO0SL = 0x1403, /*!< TDM source0 slot position [GAIN OUT] */ + TFA9896_BF_TDMSO1SL = 0x1443, /*!< TDM source1 slot position [Voltage Sense] */ + TFA9896_BF_TDMSO2SL = 0x1483, /*!< TDM source2 slot position [Current Sense] */ + TFA9896_BF_NBCK = 0x14c3, /*!< TDM NBCK bit clock ratio */ + TFA9896_BF_INTOVDDS = 0x2000, /*!< flag_por_int_out */ + TFA9896_BF_INTOPLLS = 0x2010, /*!< flag_pll_lock_int_out */ + TFA9896_BF_INTOOTDS = 0x2020, /*!< flag_otpok_int_out */ + TFA9896_BF_INTOOVDS = 0x2030, /*!< flag_ovpok_int_out */ + TFA9896_BF_INTOUVDS = 0x2040, /*!< flag_uvpok_int_out */ + TFA9896_BF_INTOOCDS = 0x2050, /*!< flag_ocp_alarm_int_out */ + TFA9896_BF_INTOCLKS = 0x2060, /*!< flag_clocks_stable_int_out */ + TFA9896_BF_INTOCLIPS = 0x2070, /*!< flag_clip_int_out */ + TFA9896_BF_INTOMTPB = 0x2080, /*!< mtp_busy_int_out */ + TFA9896_BF_INTONOCLK = 0x2090, /*!< flag_lost_clk_int_out */ + TFA9896_BF_INTOSPKS = 0x20a0, /*!< flag_cf_speakererror_int_out */ + TFA9896_BF_INTOACS = 0x20b0, /*!< flag_cold_started_int_out */ + TFA9896_BF_INTOSWS = 0x20c0, /*!< flag_engage_int_out */ + TFA9896_BF_INTOWDS = 0x20d0, /*!< flag_watchdog_reset_int_out */ + TFA9896_BF_INTOAMPS = 0x20e0, /*!< flag_enbl_amp_int_out */ + TFA9896_BF_INTOAREFS = 0x20f0, /*!< flag_enbl_ref_int_out */ + TFA9896_BF_INTOERR = 0x2200, /*!< flag_cfma_err_int_out */ + TFA9896_BF_INTOACK = 0x2210, /*!< flag_cfma_ack_int_out */ + TFA9896_BF_INTIVDDS = 0x2300, /*!< flag_por_int_in */ + TFA9896_BF_INTIPLLS = 0x2310, /*!< flag_pll_lock_int_in */ + TFA9896_BF_INTIOTDS = 0x2320, /*!< flag_otpok_int_in */ + TFA9896_BF_INTIOVDS = 0x2330, /*!< flag_ovpok_int_in */ + TFA9896_BF_INTIUVDS = 0x2340, /*!< flag_uvpok_int_in */ + TFA9896_BF_INTIOCDS = 0x2350, /*!< flag_ocp_alarm_int_in */ + TFA9896_BF_INTICLKS = 0x2360, /*!< flag_clocks_stable_int_in */ + TFA9896_BF_INTICLIPS = 0x2370, /*!< flag_clip_int_in */ + TFA9896_BF_INTIMTPB = 0x2380, /*!< mtp_busy_int_in */ + TFA9896_BF_INTINOCLK = 0x2390, /*!< flag_lost_clk_int_in */ + TFA9896_BF_INTISPKS = 0x23a0, /*!< flag_cf_speakererror_int_in */ + TFA9896_BF_INTIACS = 0x23b0, /*!< flag_cold_started_int_in */ + TFA9896_BF_INTISWS = 0x23c0, /*!< flag_engage_int_in */ + TFA9896_BF_INTIWDS = 0x23d0, /*!< flag_watchdog_reset_int_in */ + TFA9896_BF_INTIAMPS = 0x23e0, /*!< flag_enbl_amp_int_in */ + TFA9896_BF_INTIAREFS = 0x23f0, /*!< flag_enbl_ref_int_in */ + TFA9896_BF_INTIERR = 0x2500, /*!< flag_cfma_err_int_in */ + TFA9896_BF_INTIACK = 0x2510, /*!< flag_cfma_ack_int_in */ + TFA9896_BF_INTENVDDS = 0x2600, /*!< flag_por_int_enable */ + TFA9896_BF_INTENPLLS = 0x2610, /*!< flag_pll_lock_int_enable */ + TFA9896_BF_INTENOTDS = 0x2620, /*!< flag_otpok_int_enable */ + TFA9896_BF_INTENOVDS = 0x2630, /*!< flag_ovpok_int_enable */ + TFA9896_BF_INTENUVDS = 0x2640, /*!< flag_uvpok_int_enable */ + TFA9896_BF_INTENOCDS = 0x2650, /*!< flag_ocp_alarm_int_enable */ + TFA9896_BF_INTENCLKS = 0x2660, /*!< flag_clocks_stable_int_enable */ + TFA9896_BF_INTENCLIPS = 0x2670, /*!< flag_clip_int_enable */ + TFA9896_BF_INTENMTPB = 0x2680, /*!< mtp_busy_int_enable */ + TFA9896_BF_INTENNOCLK = 0x2690, /*!< flag_lost_clk_int_enable */ + TFA9896_BF_INTENSPKS = 0x26a0, /*!< flag_cf_speakererror_int_enable */ + TFA9896_BF_INTENACS = 0x26b0, /*!< flag_cold_started_int_enable */ + TFA9896_BF_INTENSWS = 0x26c0, /*!< flag_engage_int_enable */ + TFA9896_BF_INTENWDS = 0x26d0, /*!< flag_watchdog_reset_int_enable */ + TFA9896_BF_INTENAMPS = 0x26e0, /*!< flag_enbl_amp_int_enable */ + TFA9896_BF_INTENAREFS = 0x26f0, /*!< flag_enbl_ref_int_enable */ + TFA9896_BF_INTENERR = 0x2800, /*!< flag_cfma_err_int_enable */ + TFA9896_BF_INTENACK = 0x2810, /*!< flag_cfma_ack_int_enable */ + TFA9896_BF_INTPOLVDDS = 0x2900, /*!< flag_por_int_pol */ + TFA9896_BF_INTPOLPLLS = 0x2910, /*!< flag_pll_lock_int_pol */ + TFA9896_BF_INTPOLOTDS = 0x2920, /*!< flag_otpok_int_pol */ + TFA9896_BF_INTPOLOVDS = 0x2930, /*!< flag_ovpok_int_pol */ + TFA9896_BF_INTPOLUVDS = 0x2940, /*!< flag_uvpok_int_pol */ + TFA9896_BF_INTPOLOCDS = 0x2950, /*!< flag_ocp_alarm_int_pol */ + TFA9896_BF_INTPOLCLKS = 0x2960, /*!< flag_clocks_stable_int_pol */ + TFA9896_BF_INTPOLCLIPS = 0x2970, /*!< flag_clip_int_pol */ + TFA9896_BF_INTPOLMTPB = 0x2980, /*!< mtp_busy_int_pol */ + TFA9896_BF_INTPOLNOCLK = 0x2990, /*!< flag_lost_clk_int_pol */ + TFA9896_BF_INTPOLSPKS = 0x29a0, /*!< flag_cf_speakererror_int_pol */ + TFA9896_BF_INTPOLACS = 0x29b0, /*!< flag_cold_started_int_pol */ + TFA9896_BF_INTPOLSWS = 0x29c0, /*!< flag_engage_int_pol */ + TFA9896_BF_INTPOLWDS = 0x29d0, /*!< flag_watchdog_reset_int_pol */ + TFA9896_BF_INTPOLAMPS = 0x29e0, /*!< flag_enbl_amp_int_pol */ + TFA9896_BF_INTPOLAREFS = 0x29f0, /*!< flag_enbl_ref_int_pol */ + TFA9896_BF_INTPOLERR = 0x2b00, /*!< flag_cfma_err_int_pol */ + TFA9896_BF_INTPOLACK = 0x2b10, /*!< flag_cfma_ack_int_pol */ + TFA9896_BF_CLIP = 0x4900, /*!< Bypass clip control */ + TFA9896_BF_CIMTP = 0x62b0, /*!< Start copying data from I2C mtp registers to mtp */ + TFA9896_BF_RST = 0x7000, /*!< Reset CoolFlux DSP */ + TFA9896_BF_DMEM = 0x7011, /*!< Target memory for access */ + TFA9896_BF_AIF = 0x7030, /*!< Auto increment flag for memory-address */ + TFA9896_BF_CFINT = 0x7040, /*!< CF Interrupt - auto clear */ + TFA9896_BF_REQ = 0x7087, /*!< CF request for accessing the 8 channels */ + TFA9896_BF_MADD = 0x710f, /*!< Memory address */ + TFA9896_BF_MEMA = 0x720f, /*!< Activate memory access */ + TFA9896_BF_ERR = 0x7307, /*!< CF error flags */ + TFA9896_BF_ACK = 0x7387, /*!< CF acknowledgement of the requests channels */ + TFA9896_BF_MTPOTC = 0x8000, /*!< Calibration schedule selection */ + TFA9896_BF_MTPEX = 0x8010, /*!< Calibration of RON status bit */ +} nxpTFA9896BfEnumList_t; +#define TFA9896_NAMETABLE static tfaBfName_t Tfa9896DatasheetNames[] = {\ + { 0x0, "VDDS"}, /* Power-on-reset flag (auto clear by reading) , */\ + { 0x10, "PLLS"}, /* PLL lock to programmed frequency , */\ + { 0x20, "OTDS"}, /* Over Temperature Protection alarm , */\ + { 0x30, "OVDS"}, /* Over Voltage Protection alarm , */\ + { 0x40, "UVDS"}, /* Under Voltage Protection alarm , */\ + { 0x50, "OCDS"}, /* Over Current Protection alarm , */\ + { 0x60, "CLKS"}, /* Clocks stable flag , */\ + { 0x70, "CLIPS"}, /* Amplifier clipping , */\ + { 0x80, "MTPB"}, /* MTP busy copying data to/from I2C registers , */\ + { 0x90, "NOCLK"}, /* lost clock detection (reference input clock) , */\ + { 0xa0, "SPKS"}, /* Speaker error , */\ + { 0xb0, "ACS"}, /* Cold Start required , */\ + { 0xc0, "SWS"}, /* Amplifier engage (Amp Switching) , */\ + { 0xd0, "WDS"}, /* watchdog reset (activates reset) , */\ + { 0xe0, "AMPS"}, /* Amplifier is enabled by manager , */\ + { 0xf0, "AREFS"}, /* References are enabled by manager , */\ + { 0x109, "BATS"}, /* Battery voltage from ADC readout , */\ + { 0x208, "TEMPS"}, /* Temperature readout from the temperature sensor ( C), */\ + { 0x30f, "REV"}, /* Device revision information , */\ + { 0x420, "RCV"}, /* Enable receiver mode , */\ + { 0x431, "CHS12"}, /* Channel Selection TDM input for Coolflux , */\ + { 0x450, "INPLVL"}, /* Input level selection attenuator ( , */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x4c3, "AUDFS"}, /* Audio sample rate setting , */\ + { 0x501, "BSSCR"}, /* Batteery protection attack time , */\ + { 0x523, "BSST"}, /* Battery protection threshold level , */\ + { 0x561, "BSSRL"}, /* Battery protection maximum reduction , */\ + { 0x582, "BSSRR"}, /* Battery protection release time , */\ + { 0x5b1, "BSSHY"}, /* Battery Protection Hysteresis , */\ + { 0x5e0, "BSSR"}, /* Battery voltage value for read out (only) , */\ + { 0x5f0, "BSSBY"}, /* Bypass clipper battery protection , */\ + { 0x600, "DPSA"}, /* Enable dynamic powerstage activation (DPSA) , */\ + { 0x613, "ATTEN"}, /* Gain attenuation setting , */\ + { 0x650, "CFSM"}, /* Soft mute in CoolFlux , */\ + { 0x670, "BSSS"}, /* Battery sense steepness , */\ + { 0x687, "VOL"}, /* Coolflux volume control , */\ + { 0x702, "DCVO2"}, /* Second Boost Voltage , */\ + { 0x733, "DCMCC"}, /* Max boost coil current - step of 175 mA , */\ + { 0x772, "DCVO1"}, /* First Boost Voltage , */\ + { 0x7a0, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7b0, "DCSR"}, /* Soft Rampup/down mode for DCDC controller , */\ + { 0x7c0, "DCPAVG"}, /* ctrl_peak2avg for analog part of DCDC , */\ + { 0x7d0, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x800, "TROS"}, /* Selection ambient temperature for speaker calibration , */\ + { 0x818, "EXTTS"}, /* External temperature for speaker calibration (C) , */\ + { 0x900, "PWDN"}, /* powerdown selection , */\ + { 0x910, "I2CR"}, /* All I2C registers reset to default , */\ + { 0x920, "CFE"}, /* Enable CoolFlux , */\ + { 0x930, "AMPE"}, /* Enable Amplifier , */\ + { 0x940, "DCA"}, /* Enable DCDC Boost converter , */\ + { 0x950, "SBSL"}, /* Coolflux configured , */\ + { 0x960, "AMPC"}, /* Selection if Coolflux enables amplifier , */\ + { 0x970, "DCDIS"}, /* DCDC boost converter not connected , */\ + { 0x980, "PSDR"}, /* IDDQ amplifier test selection , */\ + { 0x9c1, "INTPAD"}, /* INT pad (interrupt bump output) configuration , */\ + { 0x9e0, "IPLL"}, /* PLL input reference clock selection , */\ + { 0xa04, "DCTRIP"}, /* Adaptive boost trip levels (effective only when boost_intel is set to 1), */\ + { 0xa54, "DCHOLD"}, /* Hold time for DCDC booster (effective only when boost_intel is set to 1), */\ + { 0xb07, "MTPK"}, /* KEY2 to access key2 protected registers (default for engineering), */\ + { 0xc25, "CVFDLY"}, /* Fractional delay adjustment between current and voltage sense, */\ + { 0xec0, "OPENMTP"}, /* Enable programming of the MTP memory , */\ + { 0x1011, "TDMPRF"}, /* TDM usecase selection control , */\ + { 0x1030, "TDMEN"}, /* TDM interface enable , */\ + { 0x1040, "TDMCKINV"}, /* TDM clock inversion, receive on , */\ + { 0x1053, "TDMFSLN"}, /* TDM FS length , */\ + { 0x1090, "TDMFSPOL"}, /* TDM FS polarity (start frame) , */\ + { 0x10a4, "TDMSAMSZ"}, /* TDM sample size for all TDM sinks and sources , */\ + { 0x1103, "TDMSLOTS"}, /* TDM number of slots , */\ + { 0x1144, "TDMSLLN"}, /* TDM slot length , */\ + { 0x1194, "TDMBRMG"}, /* TDM bits remaining after the last slot , */\ + { 0x11e0, "TDMDDEL"}, /* TDM data delay , */\ + { 0x11f0, "TDMDADJ"}, /* TDM data adjustment , */\ + { 0x1201, "TDMTXFRM"}, /* TDM TXDATA format , */\ + { 0x1221, "TDMUUS0"}, /* TDM TXDATA format unused slot SD0 , */\ + { 0x1241, "TDMUUS1"}, /* TDM TXDATA format unused slot SD1 , */\ + { 0x1270, "TDMSI0EN"}, /* TDM sink0 enable , */\ + { 0x1280, "TDMSI1EN"}, /* TDM sink1 enable , */\ + { 0x1290, "TDMSI2EN"}, /* TDM sink2 enable , */\ + { 0x12a0, "TDMSO0EN"}, /* TDM source0 enable , */\ + { 0x12b0, "TDMSO1EN"}, /* TDM source1 enable , */\ + { 0x12c0, "TDMSO2EN"}, /* TDM source2 enable , */\ + { 0x12d0, "TDMSI0IO"}, /* TDM sink0 IO selection , */\ + { 0x12e0, "TDMSI1IO"}, /* TDM sink1 IO selection , */\ + { 0x12f0, "TDMSI2IO"}, /* TDM sink2 IO selection , */\ + { 0x1300, "TDMSO0IO"}, /* TDM source0 IO selection , */\ + { 0x1310, "TDMSO1IO"}, /* TDM source1 IO selection , */\ + { 0x1320, "TDMSO2IO"}, /* TDM source2 IO selection , */\ + { 0x1333, "TDMSI0SL"}, /* TDM sink0 slot position [GAIN IN] , */\ + { 0x1373, "TDMSI1SL"}, /* TDM sink1 slot position [CH1 IN] , */\ + { 0x13b3, "TDMSI2SL"}, /* TDM sink2 slot position [CH2 IN] , */\ + { 0x1403, "TDMSO0SL"}, /* TDM source0 slot position [GAIN OUT] , */\ + { 0x1443, "TDMSO1SL"}, /* TDM source1 slot position [Voltage Sense] , */\ + { 0x1483, "TDMSO2SL"}, /* TDM source2 slot position [Current Sense] , */\ + { 0x14c3, "NBCK"}, /* TDM NBCK bit clock ratio , */\ + { 0x2000, "INTOVDDS"}, /* flag_por_int_out , */\ + { 0x2010, "INTOPLLS"}, /* flag_pll_lock_int_out , */\ + { 0x2020, "INTOOTDS"}, /* flag_otpok_int_out , */\ + { 0x2030, "INTOOVDS"}, /* flag_ovpok_int_out , */\ + { 0x2040, "INTOUVDS"}, /* flag_uvpok_int_out , */\ + { 0x2050, "INTOOCDS"}, /* flag_ocp_alarm_int_out , */\ + { 0x2060, "INTOCLKS"}, /* flag_clocks_stable_int_out , */\ + { 0x2070, "INTOCLIPS"}, /* flag_clip_int_out , */\ + { 0x2080, "INTOMTPB"}, /* mtp_busy_int_out , */\ + { 0x2090, "INTONOCLK"}, /* flag_lost_clk_int_out , */\ + { 0x20a0, "INTOSPKS"}, /* flag_cf_speakererror_int_out , */\ + { 0x20b0, "INTOACS"}, /* flag_cold_started_int_out , */\ + { 0x20c0, "INTOSWS"}, /* flag_engage_int_out , */\ + { 0x20d0, "INTOWDS"}, /* flag_watchdog_reset_int_out , */\ + { 0x20e0, "INTOAMPS"}, /* flag_enbl_amp_int_out , */\ + { 0x20f0, "INTOAREFS"}, /* flag_enbl_ref_int_out , */\ + { 0x2200, "INTOERR"}, /* flag_cfma_err_int_out , */\ + { 0x2210, "INTOACK"}, /* flag_cfma_ack_int_out , */\ + { 0x2300, "INTIVDDS"}, /* flag_por_int_in , */\ + { 0x2310, "INTIPLLS"}, /* flag_pll_lock_int_in , */\ + { 0x2320, "INTIOTDS"}, /* flag_otpok_int_in , */\ + { 0x2330, "INTIOVDS"}, /* flag_ovpok_int_in , */\ + { 0x2340, "INTIUVDS"}, /* flag_uvpok_int_in , */\ + { 0x2350, "INTIOCDS"}, /* flag_ocp_alarm_int_in , */\ + { 0x2360, "INTICLKS"}, /* flag_clocks_stable_int_in , */\ + { 0x2370, "INTICLIPS"}, /* flag_clip_int_in , */\ + { 0x2380, "INTIMTPB"}, /* mtp_busy_int_in , */\ + { 0x2390, "INTINOCLK"}, /* flag_lost_clk_int_in , */\ + { 0x23a0, "INTISPKS"}, /* flag_cf_speakererror_int_in , */\ + { 0x23b0, "INTIACS"}, /* flag_cold_started_int_in , */\ + { 0x23c0, "INTISWS"}, /* flag_engage_int_in , */\ + { 0x23d0, "INTIWDS"}, /* flag_watchdog_reset_int_in , */\ + { 0x23e0, "INTIAMPS"}, /* flag_enbl_amp_int_in , */\ + { 0x23f0, "INTIAREFS"}, /* flag_enbl_ref_int_in , */\ + { 0x2500, "INTIERR"}, /* flag_cfma_err_int_in , */\ + { 0x2510, "INTIACK"}, /* flag_cfma_ack_int_in , */\ + { 0x2600, "INTENVDDS"}, /* flag_por_int_enable , */\ + { 0x2610, "INTENPLLS"}, /* flag_pll_lock_int_enable , */\ + { 0x2620, "INTENOTDS"}, /* flag_otpok_int_enable , */\ + { 0x2630, "INTENOVDS"}, /* flag_ovpok_int_enable , */\ + { 0x2640, "INTENUVDS"}, /* flag_uvpok_int_enable , */\ + { 0x2650, "INTENOCDS"}, /* flag_ocp_alarm_int_enable , */\ + { 0x2660, "INTENCLKS"}, /* flag_clocks_stable_int_enable , */\ + { 0x2670, "INTENCLIPS"}, /* flag_clip_int_enable , */\ + { 0x2680, "INTENMTPB"}, /* mtp_busy_int_enable , */\ + { 0x2690, "INTENNOCLK"}, /* flag_lost_clk_int_enable , */\ + { 0x26a0, "INTENSPKS"}, /* flag_cf_speakererror_int_enable , */\ + { 0x26b0, "INTENACS"}, /* flag_cold_started_int_enable , */\ + { 0x26c0, "INTENSWS"}, /* flag_engage_int_enable , */\ + { 0x26d0, "INTENWDS"}, /* flag_watchdog_reset_int_enable , */\ + { 0x26e0, "INTENAMPS"}, /* flag_enbl_amp_int_enable , */\ + { 0x26f0, "INTENAREFS"}, /* flag_enbl_ref_int_enable , */\ + { 0x2800, "INTENERR"}, /* flag_cfma_err_int_enable , */\ + { 0x2810, "INTENACK"}, /* flag_cfma_ack_int_enable , */\ + { 0x2900, "INTPOLVDDS"}, /* flag_por_int_pol , */\ + { 0x2910, "INTPOLPLLS"}, /* flag_pll_lock_int_pol , */\ + { 0x2920, "INTPOLOTDS"}, /* flag_otpok_int_pol , */\ + { 0x2930, "INTPOLOVDS"}, /* flag_ovpok_int_pol , */\ + { 0x2940, "INTPOLUVDS"}, /* flag_uvpok_int_pol , */\ + { 0x2950, "INTPOLOCDS"}, /* flag_ocp_alarm_int_pol , */\ + { 0x2960, "INTPOLCLKS"}, /* flag_clocks_stable_int_pol , */\ + { 0x2970, "INTPOLCLIPS"}, /* flag_clip_int_pol , */\ + { 0x2980, "INTPOLMTPB"}, /* mtp_busy_int_pol , */\ + { 0x2990, "INTPOLNOCLK"}, /* flag_lost_clk_int_pol , */\ + { 0x29a0, "INTPOLSPKS"}, /* flag_cf_speakererror_int_pol , */\ + { 0x29b0, "INTPOLACS"}, /* flag_cold_started_int_pol , */\ + { 0x29c0, "INTPOLSWS"}, /* flag_engage_int_pol , */\ + { 0x29d0, "INTPOLWDS"}, /* flag_watchdog_reset_int_pol , */\ + { 0x29e0, "INTPOLAMPS"}, /* flag_enbl_amp_int_pol , */\ + { 0x29f0, "INTPOLAREFS"}, /* flag_enbl_ref_int_pol , */\ + { 0x2b00, "INTPOLERR"}, /* flag_cfma_err_int_pol , */\ + { 0x2b10, "INTPOLACK"}, /* flag_cfma_ack_int_pol , */\ + { 0x4900, "CLIP"}, /* Bypass clip control , */\ + { 0x62b0, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0x7000, "RST"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "DMEM"}, /* Target memory for access , */\ + { 0x7030, "AIF"}, /* Auto increment flag for memory-address , */\ + { 0x7040, "CFINT"}, /* CF Interrupt - auto clear , */\ + { 0x7087, "REQ"}, /* CF request for accessing the 8 channels , */\ + { 0x710f, "MADD"}, /* Memory address , */\ + { 0x720f, "MEMA"}, /* Activate memory access , */\ + { 0x7307, "ERR"}, /* CF error flags , */\ + { 0x7387, "ACK"}, /* CF acknowledgement of the requests channels , */\ + { 0x8000, "MTPOTC"}, /* Calibration schedule selection , */\ + { 0x8010, "MTPEX"}, /* Calibration of RON status bit , */\ + { 0x8045, "SWPROFIL" },\ + { 0x80a5, "SWVSTEP" },\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9896_BITNAMETABLE static tfaBfName_t Tfa9896BitNames[] = {\ + { 0x0, "flag_por"}, /* Power-on-reset flag (auto clear by reading) , */\ + { 0x10, "flag_pll_lock"}, /* PLL lock to programmed frequency , */\ + { 0x20, "flag_otpok"}, /* Over Temperature Protection alarm , */\ + { 0x30, "flag_ovpok"}, /* Over Voltage Protection alarm , */\ + { 0x40, "flag_uvpok"}, /* Under Voltage Protection alarm , */\ + { 0x50, "flag_ocp_alarm"}, /* Over Current Protection alarm , */\ + { 0x60, "flag_clocks_stable"}, /* Clocks stable flag , */\ + { 0x70, "flag_clip"}, /* Amplifier clipping , */\ + { 0x80, "mtp_busy"}, /* MTP busy copying data to/from I2C registers , */\ + { 0x90, "flag_lost_clk"}, /* lost clock detection (reference input clock) , */\ + { 0xa0, "flag_cf_speakererror"}, /* Speaker error , */\ + { 0xb0, "flag_cold_started"}, /* Cold Start required , */\ + { 0xc0, "flag_engage"}, /* Amplifier engage (Amp Switching) , */\ + { 0xd0, "flag_watchdog_reset"}, /* watchdog reset (activates reset) , */\ + { 0xe0, "flag_enbl_amp"}, /* Amplifier is enabled by manager , */\ + { 0xf0, "flag_enbl_ref"}, /* References are enabled by manager , */\ + { 0x109, "bat_adc"}, /* Battery voltage from ADC readout , */\ + { 0x208, "temp_adc"}, /* Temperature readout from the temperature sensor ( C), */\ + { 0x30f, "device_rev"}, /* Device revision information , */\ + { 0x420, "ctrl_rcv"}, /* Enable receiver mode , */\ + { 0x431, "chan_sel"}, /* Channel Selection TDM input for Coolflux , */\ + { 0x450, "input_level"}, /* Input level selection attenuator ( , */\ + { 0x461, "vamp_sel"}, /* Input selection for amplifier , */\ + { 0x4c3, "audio_fs"}, /* Audio sample rate setting , */\ + { 0x501, "vbat_prot_attacktime"}, /* Batteery protection attack time , */\ + { 0x523, "vbat_prot_thlevel"}, /* Battery protection threshold level , */\ + { 0x561, "vbat_prot_max_reduct"}, /* Battery protection maximum reduction , */\ + { 0x582, "vbat_prot_release_t"}, /* Battery protection release time , */\ + { 0x5b1, "vbat_prot_hysterese"}, /* Battery Protection Hysteresis , */\ + { 0x5d0, "reset_min_vbat"}, /* Battery supply safeguard clipper reset ( if CF_DSP is bypassed), */\ + { 0x5e0, "sel_vbat"}, /* Battery voltage value for read out (only) , */\ + { 0x5f0, "bypass_clipper"}, /* Bypass clipper battery protection , */\ + { 0x600, "dpsa"}, /* Enable dynamic powerstage activation (DPSA) , */\ + { 0x613, "ctrl_att"}, /* Gain attenuation setting , */\ + { 0x650, "cf_mute"}, /* Soft mute in CoolFlux , */\ + { 0x670, "batsense_steepness"}, /* Battery sense steepness , */\ + { 0x687, "vol"}, /* Coolflux volume control , */\ + { 0x702, "scnd_boost_voltage"}, /* Second Boost Voltage , */\ + { 0x733, "boost_cur"}, /* Max boost coil current - step of 175 mA , */\ + { 0x772, "frst_boost_voltage"}, /* First Boost Voltage , */\ + { 0x7a0, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7b0, "boost_speed"}, /* Soft Rampup/down mode for DCDC controller , */\ + { 0x7c0, "boost_peak2avg"}, /* ctrl_peak2avg for analog part of DCDC , */\ + { 0x7d0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7e0, "ignore_flag_voutcomp86"}, /* Ignore flag_voutcomp86 (flag from analog) , */\ + { 0x800, "ext_temp_sel"}, /* Selection ambient temperature for speaker calibration , */\ + { 0x818, "ext_temp"}, /* External temperature for speaker calibration (C) , */\ + { 0x900, "powerdown"}, /* powerdown selection , */\ + { 0x910, "reset"}, /* All I2C registers reset to default , */\ + { 0x920, "enbl_coolflux"}, /* Enable CoolFlux , */\ + { 0x930, "enbl_amplifier"}, /* Enable Amplifier , */\ + { 0x940, "enbl_boost"}, /* Enable DCDC Boost converter , */\ + { 0x950, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x960, "sel_enbl_amplifier"}, /* Selection if Coolflux enables amplifier , */\ + { 0x970, "dcdcoff_mode"}, /* DCDC boost converter not connected , */\ + { 0x980, "iddqtest"}, /* IDDQ amplifier test selection , */\ + { 0x9c1, "int_pad_io"}, /* INT pad (interrupt bump output) configuration , */\ + { 0x9e0, "sel_fs_bck"}, /* PLL input reference clock selection , */\ + { 0x9f0, "sel_scl_cf_clock"}, /* Coolflux sub-system clock selection , */\ + { 0xa04, "boost_trip_lvl"}, /* Adaptive boost trip levels (effective only when boost_intel is set to 1), */\ + { 0xa54, "boost_hold_time"}, /* Hold time for DCDC booster (effective only when boost_intel is set to 1), */\ + { 0xaa1, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0xb07, "mtpkey2"}, /* KEY2 to access key2 protected registers (default for engineering), */\ + { 0xc00, "enbl_volt_sense"}, /* Voltage sense enabling control bit , */\ + { 0xc10, "vsense_pwm_sel"}, /* Voltage sense source selection , */\ + { 0xc25, "vi_frac_delay"}, /* Fractional delay adjustment between current and voltage sense, */\ + { 0xc80, "sel_voltsense_out"}, /* TDM output data selection for AEC , */\ + { 0xc90, "vsense_bypass_avg"}, /* Voltage sense average block bypass , */\ + { 0xd05, "cf_frac_delay"}, /* Fractional delay adjustment between current and voltage sense by firmware, */\ + { 0xe00, "bypass_dcdc_curr_prot"}, /* Control to switch off dcdc current reduction with bat protection, */\ + { 0xe10, "bypass_ocp"}, /* Bypass OCP (digital IP block) , */\ + { 0xe20, "ocptest"}, /* ocptest (analog IP block) enable , */\ + { 0xe80, "disable_clock_sh_prot"}, /* Disable clock_sh protection , */\ + { 0xe92, "reserve_reg_15_09"}, /* Spare control bits for future usage , */\ + { 0xec0, "unprotect_mtp"}, /* Enable programming of the MTP memory , */\ + { 0xed2, "reserve_reg_15_13"}, /* Spare control bits for future usage , */\ + { 0xf00, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode forcing each 50us a pwm pulse , */\ + { 0xf11, "dcdc_ctrl_maxzercnt"}, /* DCDC number of zero current flags required to go to pfm mode, */\ + { 0xf36, "dcdc_vbat_delta_detect"}, /* DCDC threshold required on a delta Vbat (in PFM mode) switching to PWM mode, */\ + { 0xfa0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x1011, "tdm_usecase"}, /* TDM usecase selection control , */\ + { 0x1030, "tdm_enable"}, /* TDM interface enable , */\ + { 0x1040, "tdm_clk_inversion"}, /* TDM clock inversion, receive on , */\ + { 0x1053, "tdm_fs_ws_length"}, /* TDM FS length , */\ + { 0x1090, "tdm_fs_ws_polarity"}, /* TDM FS polarity (start frame) , */\ + { 0x10a4, "tdm_sample_size"}, /* TDM sample size for all TDM sinks and sources , */\ + { 0x1103, "tdm_nb_of_slots"}, /* TDM number of slots , */\ + { 0x1144, "tdm_slot_length"}, /* TDM slot length , */\ + { 0x1194, "tdm_bits_remaining"}, /* TDM bits remaining after the last slot , */\ + { 0x11e0, "tdm_data_delay"}, /* TDM data delay , */\ + { 0x11f0, "tdm_data_adjustment"}, /* TDM data adjustment , */\ + { 0x1201, "tdm_txdata_format"}, /* TDM TXDATA format , */\ + { 0x1221, "tdm_txdata_format_unused_slot_sd0"}, /* TDM TXDATA format unused slot SD0 , */\ + { 0x1241, "tdm_txdata_format_unused_slot_sd1"}, /* TDM TXDATA format unused slot SD1 , */\ + { 0x1270, "tdm_sink0_enable"}, /* TDM sink0 enable , */\ + { 0x1280, "tdm_sink1_enable"}, /* TDM sink1 enable , */\ + { 0x1290, "tdm_sink2_enable"}, /* TDM sink2 enable , */\ + { 0x12a0, "tdm_source0_enable"}, /* TDM source0 enable , */\ + { 0x12b0, "tdm_source1_enable"}, /* TDM source1 enable , */\ + { 0x12c0, "tdm_source2_enable"}, /* TDM source2 enable , */\ + { 0x12d0, "tdm_sink0_io"}, /* TDM sink0 IO selection , */\ + { 0x12e0, "tdm_sink1_io"}, /* TDM sink1 IO selection , */\ + { 0x12f0, "tdm_sink2_io"}, /* TDM sink2 IO selection , */\ + { 0x1300, "tdm_source0_io"}, /* TDM source0 IO selection , */\ + { 0x1310, "tdm_source1_io"}, /* TDM source1 IO selection , */\ + { 0x1320, "tdm_source2_io"}, /* TDM source2 IO selection , */\ + { 0x1333, "tdm_sink0_slot"}, /* TDM sink0 slot position [GAIN IN] , */\ + { 0x1373, "tdm_sink1_slot"}, /* TDM sink1 slot position [CH1 IN] , */\ + { 0x13b3, "tdm_sink2_slot"}, /* TDM sink2 slot position [CH2 IN] , */\ + { 0x1403, "tdm_source0_slot"}, /* TDM source0 slot position [GAIN OUT] , */\ + { 0x1443, "tdm_source1_slot"}, /* TDM source1 slot position [Voltage Sense] , */\ + { 0x1483, "tdm_source2_slot"}, /* TDM source2 slot position [Current Sense] , */\ + { 0x14c3, "tdm_nbck"}, /* TDM NBCK bit clock ratio , */\ + { 0x1500, "flag_tdm_lut_error"}, /* TDM LUT error flag , */\ + { 0x1512, "flag_tdm_status"}, /* TDM interface status bits , */\ + { 0x1540, "flag_tdm_error"}, /* TDM interface error indicator , */\ + { 0x1551, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x2000, "flag_por_int_out"}, /* flag_por_int_out , */\ + { 0x2010, "flag_pll_lock_int_out"}, /* flag_pll_lock_int_out , */\ + { 0x2020, "flag_otpok_int_out"}, /* flag_otpok_int_out , */\ + { 0x2030, "flag_ovpok_int_out"}, /* flag_ovpok_int_out , */\ + { 0x2040, "flag_uvpok_int_out"}, /* flag_uvpok_int_out , */\ + { 0x2050, "flag_ocp_alarm_int_out"}, /* flag_ocp_alarm_int_out , */\ + { 0x2060, "flag_clocks_stable_int_out"}, /* flag_clocks_stable_int_out , */\ + { 0x2070, "flag_clip_int_out"}, /* flag_clip_int_out , */\ + { 0x2080, "mtp_busy_int_out"}, /* mtp_busy_int_out , */\ + { 0x2090, "flag_lost_clk_int_out"}, /* flag_lost_clk_int_out , */\ + { 0x20a0, "flag_cf_speakererror_int_out"}, /* flag_cf_speakererror_int_out , */\ + { 0x20b0, "flag_cold_started_int_out"}, /* flag_cold_started_int_out , */\ + { 0x20c0, "flag_engage_int_out"}, /* flag_engage_int_out , */\ + { 0x20d0, "flag_watchdog_reset_int_out"}, /* flag_watchdog_reset_int_out , */\ + { 0x20e0, "flag_enbl_amp_int_out"}, /* flag_enbl_amp_int_out , */\ + { 0x20f0, "flag_enbl_ref_int_out"}, /* flag_enbl_ref_int_out , */\ + { 0x2100, "flag_voutcomp_int_out"}, /* flag_voutcomp_int_out , */\ + { 0x2110, "flag_voutcomp93_int_out"}, /* flag_voutcomp93_int_out , */\ + { 0x2120, "flag_voutcomp86_int_out"}, /* flag_voutcomp86_int_out , */\ + { 0x2130, "flag_hiz_int_out"}, /* flag_hiz_int_out , */\ + { 0x2140, "flag_ocpokbst_int_out"}, /* flag_ocpokbst_int_out , */\ + { 0x2150, "flag_peakcur_int_out"}, /* flag_peakcur_int_out , */\ + { 0x2160, "flag_ocpokap_int_out"}, /* flag_ocpokap_int_out , */\ + { 0x2170, "flag_ocpokan_int_out"}, /* flag_ocpokan_int_out , */\ + { 0x2180, "flag_ocpokbp_int_out"}, /* flag_ocpokbp_int_out , */\ + { 0x2190, "flag_ocpokbn_int_out"}, /* flag_ocpokbn_int_out , */\ + { 0x21a0, "flag_adc10_ready_int_out"}, /* flag_adc10_ready_int_out , */\ + { 0x21b0, "flag_clipa_high_int_out"}, /* flag_clipa_high_int_out , */\ + { 0x21c0, "flag_clipa_low_int_out"}, /* flag_clipa_low_int_out , */\ + { 0x21d0, "flag_clipb_high_int_out"}, /* flag_clipb_high_int_out , */\ + { 0x21e0, "flag_clipb_low_int_out"}, /* flag_clipb_low_int_out , */\ + { 0x21f0, "flag_tdm_error_int_out"}, /* flag_tdm_error_int_out , */\ + { 0x2200, "flag_cfma_err_int_out"}, /* flag_cfma_err_int_out , */\ + { 0x2210, "flag_cfma_ack_int_out"}, /* flag_cfma_ack_int_out , */\ + { 0x2300, "flag_por_int_in"}, /* flag_por_int_in , */\ + { 0x2310, "flag_pll_lock_int_in"}, /* flag_pll_lock_int_in , */\ + { 0x2320, "flag_otpok_int_in"}, /* flag_otpok_int_in , */\ + { 0x2330, "flag_ovpok_int_in"}, /* flag_ovpok_int_in , */\ + { 0x2340, "flag_uvpok_int_in"}, /* flag_uvpok_int_in , */\ + { 0x2350, "flag_ocp_alarm_int_in"}, /* flag_ocp_alarm_int_in , */\ + { 0x2360, "flag_clocks_stable_int_in"}, /* flag_clocks_stable_int_in , */\ + { 0x2370, "flag_clip_int_in"}, /* flag_clip_int_in , */\ + { 0x2380, "mtp_busy_int_in"}, /* mtp_busy_int_in , */\ + { 0x2390, "flag_lost_clk_int_in"}, /* flag_lost_clk_int_in , */\ + { 0x23a0, "flag_cf_speakererror_int_in"}, /* flag_cf_speakererror_int_in , */\ + { 0x23b0, "flag_cold_started_int_in"}, /* flag_cold_started_int_in , */\ + { 0x23c0, "flag_engage_int_in"}, /* flag_engage_int_in , */\ + { 0x23d0, "flag_watchdog_reset_int_in"}, /* flag_watchdog_reset_int_in , */\ + { 0x23e0, "flag_enbl_amp_int_in"}, /* flag_enbl_amp_int_in , */\ + { 0x23f0, "flag_enbl_ref_int_in"}, /* flag_enbl_ref_int_in , */\ + { 0x2400, "flag_voutcomp_int_in"}, /* flag_voutcomp_int_in , */\ + { 0x2410, "flag_voutcomp93_int_in"}, /* flag_voutcomp93_int_in , */\ + { 0x2420, "flag_voutcomp86_int_in"}, /* flag_voutcomp86_int_in , */\ + { 0x2430, "flag_hiz_int_in"}, /* flag_hiz_int_in , */\ + { 0x2440, "flag_ocpokbst_int_in"}, /* flag_ocpokbst_int_in , */\ + { 0x2450, "flag_peakcur_int_in"}, /* flag_peakcur_int_in , */\ + { 0x2460, "flag_ocpokap_int_in"}, /* flag_ocpokap_int_in , */\ + { 0x2470, "flag_ocpokan_int_in"}, /* flag_ocpokan_int_in , */\ + { 0x2480, "flag_ocpokbp_int_in"}, /* flag_ocpokbp_int_in , */\ + { 0x2490, "flag_ocpokbn_int_in"}, /* flag_ocpokbn_int_in , */\ + { 0x24a0, "flag_adc10_ready_int_in"}, /* flag_adc10_ready_int_in , */\ + { 0x24b0, "flag_clipa_high_int_in"}, /* flag_clipa_high_int_in , */\ + { 0x24c0, "flag_clipa_low_int_in"}, /* flag_clipa_low_int_in , */\ + { 0x24d0, "flag_clipb_high_int_in"}, /* flag_clipb_high_int_in , */\ + { 0x24e0, "flag_clipb_low_int_in"}, /* flag_clipb_low_int_in , */\ + { 0x24f0, "flag_tdm_error_int_in"}, /* flag_tdm_error_int_in , */\ + { 0x2500, "flag_cfma_err_int_in"}, /* flag_cfma_err_int_in , */\ + { 0x2510, "flag_cfma_ack_int_in"}, /* flag_cfma_ack_int_in , */\ + { 0x2600, "flag_por_int_enable"}, /* flag_por_int_enable , */\ + { 0x2610, "flag_pll_lock_int_enable"}, /* flag_pll_lock_int_enable , */\ + { 0x2620, "flag_otpok_int_enable"}, /* flag_otpok_int_enable , */\ + { 0x2630, "flag_ovpok_int_enable"}, /* flag_ovpok_int_enable , */\ + { 0x2640, "flag_uvpok_int_enable"}, /* flag_uvpok_int_enable , */\ + { 0x2650, "flag_ocp_alarm_int_enable"}, /* flag_ocp_alarm_int_enable , */\ + { 0x2660, "flag_clocks_stable_int_enable"}, /* flag_clocks_stable_int_enable , */\ + { 0x2670, "flag_clip_int_enable"}, /* flag_clip_int_enable , */\ + { 0x2680, "mtp_busy_int_enable"}, /* mtp_busy_int_enable , */\ + { 0x2690, "flag_lost_clk_int_enable"}, /* flag_lost_clk_int_enable , */\ + { 0x26a0, "flag_cf_speakererror_int_enable"}, /* flag_cf_speakererror_int_enable , */\ + { 0x26b0, "flag_cold_started_int_enable"}, /* flag_cold_started_int_enable , */\ + { 0x26c0, "flag_engage_int_enable"}, /* flag_engage_int_enable , */\ + { 0x26d0, "flag_watchdog_reset_int_enable"}, /* flag_watchdog_reset_int_enable , */\ + { 0x26e0, "flag_enbl_amp_int_enable"}, /* flag_enbl_amp_int_enable , */\ + { 0x26f0, "flag_enbl_ref_int_enable"}, /* flag_enbl_ref_int_enable , */\ + { 0x2700, "flag_voutcomp_int_enable"}, /* flag_voutcomp_int_enable , */\ + { 0x2710, "flag_voutcomp93_int_enable"}, /* flag_voutcomp93_int_enable , */\ + { 0x2720, "flag_voutcomp86_int_enable"}, /* flag_voutcomp86_int_enable , */\ + { 0x2730, "flag_hiz_int_enable"}, /* flag_hiz_int_enable , */\ + { 0x2740, "flag_ocpokbst_int_enable"}, /* flag_ocpokbst_int_enable , */\ + { 0x2750, "flag_peakcur_int_enable"}, /* flag_peakcur_int_enable , */\ + { 0x2760, "flag_ocpokap_int_enable"}, /* flag_ocpokap_int_enable , */\ + { 0x2770, "flag_ocpokan_int_enable"}, /* flag_ocpokan_int_enable , */\ + { 0x2780, "flag_ocpokbp_int_enable"}, /* flag_ocpokbp_int_enable , */\ + { 0x2790, "flag_ocpokbn_int_enable"}, /* flag_ocpokbn_int_enable , */\ + { 0x27a0, "flag_adc10_ready_int_enable"}, /* flag_adc10_ready_int_enable , */\ + { 0x27b0, "flag_clipa_high_int_enable"}, /* flag_clipa_high_int_enable , */\ + { 0x27c0, "flag_clipa_low_int_enable"}, /* flag_clipa_low_int_enable , */\ + { 0x27d0, "flag_clipb_high_int_enable"}, /* flag_clipb_high_int_enable , */\ + { 0x27e0, "flag_clipb_low_int_enable"}, /* flag_clipb_low_int_enable , */\ + { 0x27f0, "flag_tdm_error_int_enable"}, /* flag_tdm_error_int_enable , */\ + { 0x2800, "flag_cfma_err_int_enable"}, /* flag_cfma_err_int_enable , */\ + { 0x2810, "flag_cfma_ack_int_enable"}, /* flag_cfma_ack_int_enable , */\ + { 0x2900, "flag_por_int_pol"}, /* flag_por_int_pol , */\ + { 0x2910, "flag_pll_lock_int_pol"}, /* flag_pll_lock_int_pol , */\ + { 0x2920, "flag_otpok_int_pol"}, /* flag_otpok_int_pol , */\ + { 0x2930, "flag_ovpok_int_pol"}, /* flag_ovpok_int_pol , */\ + { 0x2940, "flag_uvpok_int_pol"}, /* flag_uvpok_int_pol , */\ + { 0x2950, "flag_ocp_alarm_int_pol"}, /* flag_ocp_alarm_int_pol , */\ + { 0x2960, "flag_clocks_stable_int_pol"}, /* flag_clocks_stable_int_pol , */\ + { 0x2970, "flag_clip_int_pol"}, /* flag_clip_int_pol , */\ + { 0x2980, "mtp_busy_int_pol"}, /* mtp_busy_int_pol , */\ + { 0x2990, "flag_lost_clk_int_pol"}, /* flag_lost_clk_int_pol , */\ + { 0x29a0, "flag_cf_speakererror_int_pol"}, /* flag_cf_speakererror_int_pol , */\ + { 0x29b0, "flag_cold_started_int_pol"}, /* flag_cold_started_int_pol , */\ + { 0x29c0, "flag_engage_int_pol"}, /* flag_engage_int_pol , */\ + { 0x29d0, "flag_watchdog_reset_int_pol"}, /* flag_watchdog_reset_int_pol , */\ + { 0x29e0, "flag_enbl_amp_int_pol"}, /* flag_enbl_amp_int_pol , */\ + { 0x29f0, "flag_enbl_ref_int_pol"}, /* flag_enbl_ref_int_pol , */\ + { 0x2a00, "flag_voutcomp_int_pol"}, /* flag_voutcomp_int_pol , */\ + { 0x2a10, "flag_voutcomp93_int_pol"}, /* flag_voutcomp93_int_pol , */\ + { 0x2a20, "flag_voutcomp86_int_pol"}, /* flag_voutcomp86_int_pol , */\ + { 0x2a30, "flag_hiz_int_pol"}, /* flag_hiz_int_pol , */\ + { 0x2a40, "flag_ocpokbst_int_pol"}, /* flag_ocpokbst_int_pol , */\ + { 0x2a50, "flag_peakcur_int_pol"}, /* flag_peakcur_int_pol , */\ + { 0x2a60, "flag_ocpokap_int_pol"}, /* flag_ocpokap_int_pol , */\ + { 0x2a70, "flag_ocpokan_int_pol"}, /* flag_ocpokan_int_pol , */\ + { 0x2a80, "flag_ocpokbp_int_pol"}, /* flag_ocpokbp_int_pol , */\ + { 0x2a90, "flag_ocpokbn_int_pol"}, /* flag_ocpokbn_int_pol , */\ + { 0x2aa0, "flag_adc10_ready_int_pol"}, /* flag_adc10_ready_int_pol , */\ + { 0x2ab0, "flag_clipa_high_int_pol"}, /* flag_clipa_high_int_pol , */\ + { 0x2ac0, "flag_clipa_low_int_pol"}, /* flag_clipa_low_int_pol , */\ + { 0x2ad0, "flag_clipb_high_int_pol"}, /* flag_clipb_high_int_pol , */\ + { 0x2ae0, "flag_clipb_low_int_pol"}, /* flag_clipb_low_int_pol , */\ + { 0x2af0, "flag_tdm_error_int_pol"}, /* flag_tdm_error_int_pol , */\ + { 0x2b00, "flag_cfma_err_int_pol"}, /* flag_cfma_err_int_pol , */\ + { 0x2b10, "flag_cfma_ack_int_pol"}, /* flag_cfma_ack_int_pol , */\ + { 0x3000, "flag_voutcomp"}, /* Status flag_voutcomp, indication Vset is larger than Vbat, */\ + { 0x3010, "flag_voutcomp93"}, /* Status flag_voutcomp93, indication Vset is larger than 1.07 x Vbat, */\ + { 0x3020, "flag_voutcomp86"}, /* Status flag voutcomp86, indication Vset is larger than 1.14 x Vbat, */\ + { 0x3030, "flag_hiz"}, /* Status flag_hiz, indication Vbst is larger than Vbat, */\ + { 0x3040, "flag_ocpokbst"}, /* Status flag_ocpokbst, indication no over current in boost converter PMOS switch, */\ + { 0x3050, "flag_peakcur"}, /* Status flag_peakcur, indication current is max in dcdc converter, */\ + { 0x3060, "flag_ocpokap"}, /* Status flag_ocpokap, indication no over current in amplifier A PMOS output stage, */\ + { 0x3070, "flag_ocpokan"}, /* Status flag_ocpokan, indication no over current in amplifier A NMOS output stage, */\ + { 0x3080, "flag_ocpokbp"}, /* Status flag_ocpokbp, indication no over current in amplifier B PMOS output stage, */\ + { 0x3090, "flag_ocpokbn"}, /* Status flag_ocpokbn, indication no over current in amplifier B NMOS output stage, */\ + { 0x30a0, "flag_adc10_ready"}, /* Status flag_adc10_ready, indication adc10 is ready, */\ + { 0x30b0, "flag_clipa_high"}, /* Status flag_clipa_high, indication pmos amplifier A is clipping, */\ + { 0x30c0, "flag_clipa_low"}, /* Status flag_clipa_low, indication nmos amplifier A is clipping, */\ + { 0x30d0, "flag_clipb_high"}, /* Status flag_clipb_high, indication pmos amplifier B is clipping, */\ + { 0x30e0, "flag_clipb_low"}, /* Status flag_clipb_low, indication nmos amplifier B is clipping, */\ + { 0x310f, "mtp_man_data_out"}, /* MTP manual read out data , */\ + { 0x3200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0x3210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0x3225, "mtp_ecc_tcout"}, /* MTP error correction test data out , */\ + { 0x3280, "mtpctrl_valid_test_rd"}, /* MTP test readout for read , */\ + { 0x3290, "mtpctrl_valid_test_wr"}, /* MTP test readout for write , */\ + { 0x32a0, "flag_in_alarm_state"}, /* Flag alarm state , */\ + { 0x32b0, "mtp_ecc_err2"}, /* Two or more bit errors detected in MTP, can not reconstruct value, */\ + { 0x32c0, "mtp_ecc_err1"}, /* One bit error detected in MTP, reconstructed value, */\ + { 0x32d0, "mtp_mtp_hvf"}, /* High voltage ready flag for MTP , */\ + { 0x32f0, "mtp_zero_check_fail"}, /* Zero check failed for MTP , */\ + { 0x3309, "data_adc10_tempbat"}, /* ADC10 data output for testing battery voltage and temperature, */\ + { 0x400f, "hid_code"}, /* 5A6Bh, 23147d to access hidden registers (default for engineering), */\ + { 0x4100, "bypass_hp"}, /* Bypass High Pass Filter , */\ + { 0x4110, "hard_mute"}, /* Hard Mute , */\ + { 0x4120, "soft_mute"}, /* Soft Mute , */\ + { 0x4134, "pwm_delay"}, /* PWM delay setting , */\ + { 0x4180, "pwm_shape"}, /* PWM Shape , */\ + { 0x4190, "pwm_bitlength"}, /* PWM Bitlength in noise shaper , */\ + { 0x4203, "drive"}, /* Drive bits to select number of amplifier power stages, */\ + { 0x4240, "reclock_pwm"}, /* Control for enabling reclocking of PWM signal , */\ + { 0x4250, "reclock_voltsense"}, /* Control for enabling reclocking of voltage sense signal, */\ + { 0x4281, "dpsalevel"}, /* DPSA threshold level , */\ + { 0x42a1, "dpsa_release"}, /* DPSA release time , */\ + { 0x42c0, "coincidence"}, /* Prevent simultaneously switching of output stage , */\ + { 0x42d0, "kickback"}, /* Prevent double pulses of output stage , */\ + { 0x4306, "drivebst"}, /* Drive bits to select the power transistor sections boost converter, */\ + { 0x4370, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x4381, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x43a0, "ocptestbst"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0); For new ocp (ctrl_reversebst is 1), */\ + { 0x43d0, "test_abistfft_enbl"}, /* FFT Coolflux , */\ + { 0x43e0, "bst_dcmbst"}, /* DCM mode control for DCDC during I2C direct control mode, */\ + { 0x43f0, "test_bcontrol"}, /* test_bcontrol , */\ + { 0x4400, "reversebst"}, /* OverCurrent Protection selection of power stage boost converter, */\ + { 0x4410, "sensetest"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0x4420, "enbl_engagebst"}, /* Enable power stage of dcdc controller , */\ + { 0x4470, "enbl_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x4480, "enbl_voutcomp"}, /* Enable vout comparators , */\ + { 0x4490, "enbl_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x44a0, "enbl_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x44b0, "enbl_hizcom"}, /* Enable hiz comparator , */\ + { 0x44c0, "enbl_peakcur"}, /* Enable peak current , */\ + { 0x44d0, "bypass_ovpglitch"}, /* Bypass OVP Glitch Filter , */\ + { 0x44e0, "enbl_windac"}, /* Enable window dac , */\ + { 0x44f0, "enbl_powerbst"}, /* Enable line of the powerstage , */\ + { 0x4507, "ocp_thr"}, /* OCP threshold level , */\ + { 0x4580, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0x4590, "bypass_ovp"}, /* Bypass OVP , */\ + { 0x45a0, "bypass_uvp"}, /* Bypass UVP , */\ + { 0x45b0, "bypass_otp"}, /* Bypass OTP , */\ + { 0x45d0, "bypass_ocpcounter"}, /* Bypass OCP counter , */\ + { 0x45e0, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0x45f0, "vpalarm"}, /* vpalarm (UVP/OUP handling) , */\ + { 0x4600, "bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x4610, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x4627, "cs_gain"}, /* Current sense gain , */\ + { 0x46a0, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x46b0, "bypass_pwmcounter"}, /* Bypass PWM Counter , */\ + { 0x46c0, "cs_negfixed"}, /* Current sense does not switch to neg , */\ + { 0x46d2, "cs_neghyst"}, /* Current sense switches to neg depending on hyseteris level, */\ + { 0x4700, "switch_fb"}, /* Current sense control switch_fb , */\ + { 0x4713, "se_hyst"}, /* Current sense control se_hyst , */\ + { 0x4754, "se_level"}, /* Current sense control se_level , */\ + { 0x47a5, "ktemp"}, /* Current sense control temperature compensation trimming, */\ + { 0x4800, "cs_negin"}, /* Current sense control negin , */\ + { 0x4810, "cs_sein"}, /* Current sense control cs_sein , */\ + { 0x4820, "cs_coincidence"}, /* Coincidence current sense , */\ + { 0x4830, "iddqtestbst"}, /* IDDQ testing in powerstage of DCDC boost converter, */\ + { 0x4840, "coincidencebst"}, /* Switch protection on to prevent simultaneously switching power stages bst and amp, */\ + { 0x4876, "delay_se_neg"}, /* delay of se and neg , */\ + { 0x48e1, "cs_ttrack"}, /* Sample and hold track time , */\ + { 0x4900, "bypass_clip"}, /* Bypass clip control , */\ + { 0x4920, "cf_cgate_off"}, /* Disable clock gating in the coolflux , */\ + { 0x4940, "clipfast"}, /* Clock selection for HW clipper for battery safeguard, */\ + { 0x4950, "cs_8ohm"}, /* 8 ohm mode for current sense (gain mode) , */\ + { 0x4974, "delay_clock_sh"}, /* delay_sh, tunes S7H delay , */\ + { 0x49c0, "inv_clksh"}, /* Invert the sample/hold clock for current sense ADC, */\ + { 0x49d0, "inv_neg"}, /* Invert neg signal , */\ + { 0x49e0, "inv_se"}, /* Invert se signal , */\ + { 0x49f0, "setse"}, /* Switches between Single Ended and differential mode; 1 is single ended, */\ + { 0x4a12, "adc10_sel"}, /* Select the input to convert the 10b ADC , */\ + { 0x4a60, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0x4a81, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0x4aa0, "bypass_lp_vbat"}, /* LP filter in batt sensor , */\ + { 0x4ae0, "dc_offset"}, /* Current sense decimator offset control , */\ + { 0x4af0, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0x4b00, "adc13_iset"}, /* MICADC setting of current consumption (debug use only), */\ + { 0x4b14, "adc13_gain"}, /* MICADC gain setting (two's complement format) , */\ + { 0x4b61, "adc13_slowdel"}, /* MICADC delay setting for internal clock (debug use only), */\ + { 0x4b83, "adc13_offset"}, /* MICADC offset setting , */\ + { 0x4bc0, "adc13_bsoinv"}, /* MICADC bit stream output invert mode for test , */\ + { 0x4bd0, "adc13_resonator_enable"}, /* MICADC give extra SNR with less stability (debug use only), */\ + { 0x4be0, "testmicadc"}, /* Mux at input of MICADC for test purpose , */\ + { 0x4c0f, "abist_offset"}, /* Offset control for ABIST testing , */\ + { 0x4d05, "windac"}, /* For testing direct control windac , */\ + { 0x4dc3, "pwm_dcc_cnt"}, /* control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0x4e04, "slopecur"}, /* For testing direct control slopecur , */\ + { 0x4e50, "ctrl_dem"}, /* Dynamic element matching control, rest of codes are optional, */\ + { 0x4ed0, "enbl_pwm_dcc"}, /* Enable direct control of pwm duty cycle , */\ + { 0x4f00, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x4f10, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x4f20, "bst_ctrl_azbst"}, /* Control of auto-zeroing of zero current comparator, */\ + { 0x5007, "gain"}, /* Gain setting of the gain multiplier , */\ + { 0x5081, "sourceb"}, /* PWM OUTB selection control , */\ + { 0x50a1, "sourcea"}, /* PWM OUTA selection control , */\ + { 0x50c1, "sourcebst"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0x50e0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0x5104, "pulselengthbst"}, /* Pulse length setting test input for boost converter, */\ + { 0x5150, "bypasslatchbst"}, /* Bypass latch in boost converter , */\ + { 0x5160, "invertbst"}, /* Invert pwmbst test signal , */\ + { 0x5174, "pulselength"}, /* Pulse length setting test input for amplifier , */\ + { 0x51c0, "bypasslatch"}, /* Bypass latch in PWM source selection module , */\ + { 0x51d0, "invertb"}, /* invert pwmb test signal , */\ + { 0x51e0, "inverta"}, /* invert pwma test signal , */\ + { 0x51f0, "bypass_ctrlloop"}, /* bypass_ctrlloop bypasses the control loop of the amplifier, */\ + { 0x5210, "test_rdsona"}, /* tbd for rdson testing , */\ + { 0x5220, "test_rdsonb"}, /* tbd for rdson testing , */\ + { 0x5230, "test_rdsonbst"}, /* tbd for rdson testing , */\ + { 0x5240, "test_cvia"}, /* tbd for rdson testing , */\ + { 0x5250, "test_cvib"}, /* tbd for rdson testing , */\ + { 0x5260, "test_cvibst"}, /* tbd for rdson testing , */\ + { 0x5306, "digimuxa_sel"}, /* DigimuxA input selection control (see Digimux list for details), */\ + { 0x5376, "digimuxb_sel"}, /* DigimuxB input selection control (see Digimux list for details), */\ + { 0x5400, "hs_mode"}, /* I2C high speed mode selection control , */\ + { 0x5412, "test_parametric_io"}, /* Control for parametric tests of IO cells , */\ + { 0x5440, "enbl_ringo"}, /* Enable ring oscillator control, for test purpose to check with ringo, */\ + { 0x5456, "digimuxc_sel"}, /* DigimuxC input selection control (see Digimux list for details), */\ + { 0x54c0, "dio_ehs"}, /* Slew control for DIO in output mode , */\ + { 0x54d0, "gainio_ehs"}, /* Slew control for GAINIO in output mode , */\ + { 0x550d, "enbl_amp"}, /* enbl_amp for testing to enable all analoge blocks in amplifier, */\ + { 0x5600, "use_direct_ctrls"}, /* Use direct controls to overrule several functions for testing - I2C direct control mode, */\ + { 0x5610, "rst_datapath"}, /* Reset datapath during direct control mode , */\ + { 0x5620, "rst_cgu"}, /* Reset CGU during durect control mode , */\ + { 0x5637, "enbl_ref"}, /* For testing to enable all analoge blocks in references, */\ + { 0x56b0, "enbl_engage"}, /* Enable output stage amplifier , */\ + { 0x56c0, "use_direct_clk_ctrl"}, /* use_direct_clk_ctrl, to overrule several functions direct for testing, */\ + { 0x56d0, "use_direct_pll_ctrl"}, /* use_direct_pll_ctrl, to overrule several functions direct for testing, */\ + { 0x5707, "anamux"}, /* Anamux control , */\ + { 0x57e0, "otptest"}, /* otptest, test mode otp amplifier , */\ + { 0x57f0, "reverse"}, /* 1b = Normal mode, slope is controlled , */\ + { 0x5813, "pll_selr"}, /* PLL pll_selr , */\ + { 0x5854, "pll_selp"}, /* PLL pll_selp , */\ + { 0x58a5, "pll_seli"}, /* PLL pll_seli , */\ + { 0x5950, "pll_mdec_msb"}, /* Most significant bits of pll_mdec[16] , */\ + { 0x5960, "pll_ndec_msb"}, /* Most significant bits of pll_ndec[9] , */\ + { 0x5970, "pll_frm"}, /* PLL pll_frm , */\ + { 0x5980, "pll_directi"}, /* PLL pll_directi , */\ + { 0x5990, "pll_directo"}, /* PLL pll_directo , */\ + { 0x59a0, "enbl_pll"}, /* PLL enbl_pll , */\ + { 0x59f0, "pll_bypass"}, /* PLL bypass , */\ + { 0x5a0f, "tsig_freq"}, /* Internal sinus test generator frequency control LSB bits, */\ + { 0x5b02, "tsig_freq_msb"}, /* Select internal sine wave generator, frequency control MSB bits, */\ + { 0x5b30, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0x5b44, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0x5c0f, "pll_mdec"}, /* PLL MDEC - I2C direct PLL control mode only , */\ + { 0x5d06, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0x5d78, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0x6007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0x6185, "mtp_ecc_tcin"}, /* MTP ECC TCIN data , */\ + { 0x6203, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0x6260, "mtp_ecc_eeb"}, /* Enable code bit generation (active low!) , */\ + { 0x6270, "mtp_ecc_ecb"}, /* Enable correction signal (active low!) , */\ + { 0x6280, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0x6290, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0x62a0, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0x62b0, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0x62d2, "mtp_speed_mode"}, /* MTP speed mode , */\ + { 0x6340, "mtp_direct_enable"}, /* mtp_direct_enable , */\ + { 0x6350, "mtp_direct_wr"}, /* mtp_direct_wr , */\ + { 0x6360, "mtp_direct_rd"}, /* mtp_direct_rd , */\ + { 0x6370, "mtp_direct_rst"}, /* mtp_direct_rst , */\ + { 0x6380, "mtp_direct_ers"}, /* mtp_direct_ers , */\ + { 0x6390, "mtp_direct_prg"}, /* mtp_direct_prg , */\ + { 0x63a0, "mtp_direct_epp"}, /* mtp_direct_epp , */\ + { 0x63b4, "mtp_direct_test"}, /* mtp_direct_test , */\ + { 0x640f, "mtp_man_data_in"}, /* Write data for MTP manual write , */\ + { 0x7000, "cf_rst_dsp"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "cf_dmem"}, /* Target memory for access , */\ + { 0x7030, "cf_aif"}, /* Auto increment flag for memory-address , */\ + { 0x7040, "cf_int"}, /* CF Interrupt - auto clear , */\ + { 0x7087, "cf_req"}, /* CF request for accessing the 8 channels , */\ + { 0x710f, "cf_madd"}, /* Memory address , */\ + { 0x720f, "cf_mema"}, /* Activate memory access , */\ + { 0x7307, "cf_err"}, /* CF error flags , */\ + { 0x7387, "cf_ack"}, /* CF acknowledgement of the requests channels , */\ + { 0x8000, "calibration_onetime"}, /* Calibration schedule selection , */\ + { 0x8010, "calibr_ron_done"}, /* Calibration of RON status bit , */\ + { 0x8105, "calibr_vout_offset"}, /* calibr_vout_offset (DCDCoffset) 2's compliment (key1 protected), */\ + { 0x8163, "calibr_delta_gain"}, /* delta gain for vamp (alpha) 2's compliment (key1 protected), */\ + { 0x81a5, "calibr_offs_amp"}, /* offset for vamp (Ampoffset) 2's compliment (key1 protected), */\ + { 0x8207, "calibr_gain_cs"}, /* gain current sense (Imeasalpha) 2's compliment (key1 protected), */\ + { 0x8284, "calibr_temp_offset"}, /* temperature offset 2's compliment (key1 protected), */\ + { 0x82d2, "calibr_temp_gain"}, /* temperature gain 2's compliment (key1 protected) , */\ + { 0x830f, "calibr_ron"}, /* calibration value of the RON resistance of the coil, */\ + { 0x8505, "type_bits_hw"}, /* bit0 = disable function dcdcoff_mode ($09[7]) , */\ + { 0x8601, "type_bits_1_0_sw"}, /* MTP control SW , */\ + { 0x8681, "type_bits_9_8_sw"}, /* MTP control SW , */\ + { 0x870f, "type_bits2_sw"}, /* MTP-control SW2 , */\ + { 0x8806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0x8870, "htol_iic_addr_en"}, /* HTOL I2C_Address_Enable , */\ + { 0x8881, "ctrl_ovp_response"}, /* OVP response control , */\ + { 0x88a0, "disable_ovp_alarm_state"}, /* OVP alarm state control , */\ + { 0x88b0, "enbl_stretch_ovp"}, /* OVP alram strech control , */\ + { 0x88c0, "cf_debug_mode"}, /* Coolflux debug mode , */\ + { 0x8a0f, "production_data1"}, /* production_data1 , */\ + { 0x8b0f, "production_data2"}, /* production_data2 , */\ + { 0x8c0f, "production_data3"}, /* production_data3 , */\ + { 0x8d0f, "production_data4"}, /* production_data4 , */\ + { 0x8e0f, "production_data5"}, /* production_data5 , */\ + { 0x8f0f, "production_data6"}, /* production_data6 , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum TFA9896_irq { + TFA9896_irq_vdds = 0, + TFA9896_irq_plls = 1, + TFA9896_irq_ds = 2, + TFA9896_irq_vds = 3, + TFA9896_irq_uvds = 4, + TFA9896_irq_cds = 5, + TFA9896_irq_clks = 6, + TFA9896_irq_clips = 7, + TFA9896_irq_mtpb = 8, + TFA9896_irq_clk = 9, + TFA9896_irq_spks = 10, + TFA9896_irq_acs = 11, + TFA9896_irq_sws = 12, + TFA9896_irq_wds = 13, + TFA9896_irq_amps = 14, + TFA9896_irq_arefs = 15, + TFA9896_irq_err = 32, + TFA9896_irq_ack = 33, + TFA9896_irq_max = 34, + TFA9896_irq_all = -1 /* all irqs */}; + +#define TFA9896_IRQ_NAMETABLE static tfaIrqName_t TFA9896IrqNames[] = {\ + { 0, "VDDS"},\ + { 1, "PLLS"},\ + { 2, "DS"},\ + { 3, "VDS"},\ + { 4, "UVDS"},\ + { 5, "CDS"},\ + { 6, "CLKS"},\ + { 7, "CLIPS"},\ + { 8, "MTPB"},\ + { 9, "CLK"},\ + { 10, "SPKS"},\ + { 11, "ACS"},\ + { 12, "SWS"},\ + { 13, "WDS"},\ + { 14, "AMPS"},\ + { 15, "AREFS"},\ + { 16, "16"},\ + { 17, "17"},\ + { 18, "18"},\ + { 19, "19"},\ + { 20, "20"},\ + { 21, "21"},\ + { 22, "22"},\ + { 23, "23"},\ + { 24, "24"},\ + { 25, "25"},\ + { 26, "26"},\ + { 27, "27"},\ + { 28, "28"},\ + { 29, "29"},\ + { 30, "30"},\ + { 31, "31"},\ + { 32, "ERR"},\ + { 33, "ACK"},\ + { 34, "34"},\ +}; +#endif /* _TFA9896_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa98xx.c b/sound/soc/codecs/tfa98xx.c new file mode 100644 index 0000000000000000000000000000000000000000..15e9a0c6cf5e3a9a1b4ba847c5f2b7e2768de93e --- /dev/null +++ b/sound/soc/codecs/tfa98xx.c @@ -0,0 +1,3278 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ +#define pr_fmt(fmt) "%s(): " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "tfa98xx.h" +#include "tfa.h" + + /* required for enum tfa9912_irq */ +#include "tfa98xx_tfafieldnames.h" + +#define TFA98XX_VERSION TFA98XX_API_REV_STR + +#define I2C_RETRIES 50 +#define I2C_RETRY_DELAY 5 /* ms */ +#define ERR -1 + +/* Change volume selection behavior: + * Uncomment following line to generate a profile change when updating + * a volume control (also changes to the profile of the modified volume + * control) + */ + /*#define TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL 1 + */ + + /* Supported rates and data formats */ +#define TFA98XX_RATES SNDRV_PCM_RATE_8000_48000 +#define TFA98XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define TF98XX_MAX_DSP_START_TRY_COUNT 10 + +/* data accessible by all instances */ +/* Memory pool used for DSP messages */ +static struct kmem_cache *tfa98xx_cache; +/* Mutex protected data */ +static DEFINE_MUTEX(tfa98xx_mutex); +static LIST_HEAD(tfa98xx_device_list); +static int tfa98xx_device_count; +static int tfa98xx_sync_count; +static LIST_HEAD(profile_list); /* list of user selectable profiles */ +static int tfa98xx_mixer_profiles; /* number of user selectable profiles */ +static int tfa98xx_mixer_profile; /* current mixer profile */ +static struct snd_kcontrol_new *tfa98xx_controls; +static nxpTfaContainer_t *tfa98xx_container; + +static int tfa98xx_kmsg_regs; +static int tfa98xx_ftrace_regs; + +static char *fw_name = "tfa98xx.cnt"; +module_param(fw_name, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(fw_name, "TFA98xx DSP firmware (container file) name."); + +static int trace_level; +module_param(trace_level, int, S_IRUGO); +MODULE_PARM_DESC(trace_level, "TFA98xx debug trace level (0=off, bits:1=verbose,2=regdmesg,3=regftrace,4=timing)."); + +static char *dflt_prof_name = ""; +module_param(dflt_prof_name, charp, S_IRUGO); + +static int no_start; +module_param(no_start, int, S_IRUGO); +MODULE_PARM_DESC(no_start, "do not start the work queue; for debugging via user\n"); + +static int no_reset; +module_param(no_reset, int, S_IRUGO); +MODULE_PARM_DESC(no_reset, "do not use the reset line; for debugging via user\n"); + +static int pcm_sample_format; +module_param(pcm_sample_format, int, S_IRUGO); +MODULE_PARM_DESC(pcm_sample_format, "PCM sample format: 0=S16_LE, 1=S24_LE, 2=S32_LE\n"); + +static int pcm_no_constraint; +module_param(pcm_no_constraint, int, S_IRUGO); +MODULE_PARM_DESC(pcm_no_constraint, "do not use constraints for PCM parameters\n"); + +static void tfa98xx_tapdet_check_update(struct tfa98xx *tfa98xx); +static int tfa98xx_get_fssel(unsigned int rate); +static void tfa98xx_interrupt_enable(struct tfa98xx *tfa98xx, bool enable); + +static int get_profile_from_list(char *buf, int id); +static int get_profile_id_for_sr(int id, unsigned int rate); + +struct tfa98xx_rate { + unsigned int rate; + unsigned int fssel; +}; + +static const struct tfa98xx_rate rate_to_fssel[] = { + { 8000, 0 }, + { 11025, 1 }, + { 12000, 2 }, + { 16000, 3 }, + { 22050, 4 }, + { 24000, 5 }, + { 32000, 6 }, + { 44100, 7 }, + { 48000, 8 }, +}; + + +static inline char *tfa_cont_profile_name(struct tfa98xx *tfa98xx, + int prof_idx) +{ + if (tfa98xx->tfa->cnt == NULL) + return NULL; + return tfaContProfileName(tfa98xx->tfa->cnt, + tfa98xx->tfa->dev_idx, prof_idx); +} + +static enum tfa_error tfa98xx_write_re25(struct tfa_device *tfa, int value) +{ + enum tfa_error err; + + /* clear MTPEX */ + err = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 0); + if (err == tfa_error_ok) { + /* set RE25 in shadow regiser */ + err = tfa_dev_mtp_set(tfa, TFA_MTP_RE25_PRIM, value); + } + if (err == tfa_error_ok) { + /* set MTPEX to copy RE25 into MTP */ + err = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 2); + } + + return err; +} + +/* Wrapper for tfa start */ +static enum tfa_error tfa98xx_tfa_start(struct tfa98xx *tfa98xx, + int next_profile, int vstep) +{ + enum tfa_error err; + ktime_t start_time, stop_time; + u64 delta_time; + + if (trace_level & 8) + start_time = ktime_get_boottime(); + + err = tfa_dev_start(tfa98xx->tfa, next_profile, vstep); + + if (trace_level & 8) { + stop_time = ktime_get_boottime(); + delta_time = ktime_to_ns(ktime_sub(stop_time, start_time)); + do_div(delta_time, 1000); + dev_dbg(&tfa98xx->i2c->dev, "tfa_dev_start(%d,%d) time = %lld us\n", + next_profile, vstep, delta_time); + } + + if ((err == tfa_error_ok) && (tfa98xx->set_mtp_cal)) { + enum tfa_error err_cal; + + err_cal = tfa98xx_write_re25(tfa98xx->tfa, tfa98xx->cal_data); + if (err_cal != tfa_error_ok) { + pr_err("Error, setting calibration value in mtp, err=%d\n", + err_cal); + } else { + tfa98xx->set_mtp_cal = false; + pr_info("Calibration value (%d) set in mtp\n", + tfa98xx->cal_data); + } + } + + /* Check and update tap-detection state (in case of profile change) */ + tfa98xx_tapdet_check_update(tfa98xx); + + /* Remove sticky bit by reading it once */ + tfa_get_noclk(tfa98xx->tfa); + + /* A cold start erases the configuration, including interrupts setting. + * Restore it if required + */ + tfa98xx_interrupt_enable(tfa98xx, true); + + return err; +} + +static int tfa98xx_input_open(struct input_dev *dev) +{ + struct tfa98xx *tfa98xx = input_get_drvdata(dev); + + dev_dbg(tfa98xx->codec->dev, "opening device file\n"); + + /* note: open function is called only once by the framework. + * No need to count number of open file instances. + */ + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { + dev_dbg(&tfa98xx->i2c->dev, + "DSP not loaded, cannot start tap-detection\n"); + return -EIO; + } + + /* enable tap-detection service */ + tfa98xx->tapdet_open = true; + tfa98xx_tapdet_check_update(tfa98xx); + + return 0; +} + +static void tfa98xx_input_close(struct input_dev *dev) +{ + struct tfa98xx *tfa98xx = input_get_drvdata(dev); + + dev_dbg(tfa98xx->codec->dev, "closing device file\n"); + + /* Note: close function is called if the device is unregistered */ + + /* disable tap-detection service */ + tfa98xx->tapdet_open = false; + tfa98xx_tapdet_check_update(tfa98xx); +} + +static int tfa98xx_register_inputdev(struct tfa98xx *tfa98xx) +{ + int err; + struct input_dev *input; + input = input_allocate_device(); + + if (!input) { + dev_err(tfa98xx->codec->dev, "Unable to allocate input device\n"); + return -ENOMEM; + } + + input->evbit[0] = BIT_MASK(EV_KEY); + input->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); + input->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); + input->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); + input->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); + input->keybit[BIT_WORD(BTN_4)] |= BIT_MASK(BTN_4); + input->keybit[BIT_WORD(BTN_5)] |= BIT_MASK(BTN_5); + input->keybit[BIT_WORD(BTN_6)] |= BIT_MASK(BTN_6); + input->keybit[BIT_WORD(BTN_7)] |= BIT_MASK(BTN_7); + input->keybit[BIT_WORD(BTN_8)] |= BIT_MASK(BTN_8); + input->keybit[BIT_WORD(BTN_9)] |= BIT_MASK(BTN_9); + + input->open = tfa98xx_input_open; + input->close = tfa98xx_input_close; + + input->name = "tfa98xx-tapdetect"; + + input->id.bustype = BUS_I2C; + input_set_drvdata(input, tfa98xx); + + err = input_register_device(input); + if (err) { + dev_err(tfa98xx->codec->dev, "Unable to register input device\n"); + goto err_free_dev; + } + + dev_dbg(tfa98xx->codec->dev, "Input device for tap-detection registered: %s\n", + input->name); + tfa98xx->input = input; + return 0; + +err_free_dev: + input_free_device(input); + return err; +} + +/* + * Check if an input device for tap-detection can and shall be registered. + * Register it if appropriate. + * If already registered, check if still relevant and remove it if necessary. + * unregister: true to request inputdev unregistration. + */ +static void __tfa98xx_inputdev_check_register(struct tfa98xx *tfa98xx, bool unregister) +{ + bool tap_profile = false; + unsigned int i; + for (i = 0; i < tfa_cnt_get_dev_nprof(tfa98xx->tfa); i++) { + if (strstr(tfa_cont_profile_name(tfa98xx, i), ".tap")) { + tap_profile = true; + tfa98xx->tapdet_profiles |= 1 << i; + dev_info(tfa98xx->codec->dev, + "found a tap-detection profile (%d - %s)\n", + i, tfa_cont_profile_name(tfa98xx, i)); + } + } + + /* Check for device support: + * - at device level + * - at container (profile) level + */ + if (!(tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) || + !tap_profile || + unregister) { + /* No input device supported or required */ + if (tfa98xx->input) { + input_unregister_device(tfa98xx->input); + tfa98xx->input = NULL; + } + return; + } + + /* input device required */ + if (tfa98xx->input) + dev_info(tfa98xx->codec->dev, "Input device already registered, skipping\n"); + else + tfa98xx_register_inputdev(tfa98xx); +} + +static void tfa98xx_inputdev_check_register(struct tfa98xx *tfa98xx) +{ + __tfa98xx_inputdev_check_register(tfa98xx, false); +} + +static void tfa98xx_inputdev_unregister(struct tfa98xx *tfa98xx) +{ + __tfa98xx_inputdev_check_register(tfa98xx, true); +} + +#ifdef CONFIG_DEBUG_FS +/* OTC reporting + * Returns the MTP0 OTC bit value + */ +static int tfa98xx_dbgfs_otc_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int value; + + mutex_lock(&tfa98xx->dsp_lock); + value = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_OTC); + mutex_unlock(&tfa98xx->dsp_lock); + + if (value < 0) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, value); + return -EIO; + } + + *val = value; + pr_debug("[0x%x] OTC : %d\n", tfa98xx->i2c->addr, value); + + return 0; +} + +static int tfa98xx_dbgfs_otc_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error err; + + if (val != 0 && val != 1) { + pr_err("[0x%x] Unexpected value %llu\n", tfa98xx->i2c->addr, val); + return -EINVAL; + } + + mutex_lock(&tfa98xx->dsp_lock); + err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_OTC, val); + mutex_unlock(&tfa98xx->dsp_lock); + + if (err != tfa_error_ok) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, err); + return -EIO; + } + + pr_debug("[0x%x] OTC < %llu\n", tfa98xx->i2c->addr, val); + + return 0; +} + +static int tfa98xx_dbgfs_mtpex_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int value; + + mutex_lock(&tfa98xx->dsp_lock); + value = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_EX); + mutex_unlock(&tfa98xx->dsp_lock); + + if (value < 0) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, value); + return -EIO; + } + + + *val = value; + pr_debug("[0x%x] MTPEX : %d\n", tfa98xx->i2c->addr, value); + + return 0; +} + +static int tfa98xx_dbgfs_mtpex_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error err; + + if (val != 0) { + pr_err("[0x%x] Can only clear MTPEX (0 value expected)\n", tfa98xx->i2c->addr); + return -EINVAL; + } + + mutex_lock(&tfa98xx->dsp_lock); + err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_EX, val); + mutex_unlock(&tfa98xx->dsp_lock); + + if (err != tfa_error_ok) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, err); + return -EIO; + } + + pr_debug("[0x%x] MTPEX < 0\n", tfa98xx->i2c->addr); + + return 0; +} + +static int tfa98xx_dbgfs_temp_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + + mutex_lock(&tfa98xx->dsp_lock); + *val = tfa98xx_get_exttemp(tfa98xx->tfa); + mutex_unlock(&tfa98xx->dsp_lock); + + pr_debug("[0x%x] TEMP : %llu\n", tfa98xx->i2c->addr, *val); + + return 0; +} + +static int tfa98xx_dbgfs_temp_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + + mutex_lock(&tfa98xx->dsp_lock); + tfa98xx_set_exttemp(tfa98xx->tfa, (short)val); + mutex_unlock(&tfa98xx->dsp_lock); + + pr_debug("[0x%x] TEMP < %llu\n", tfa98xx->i2c->addr, val); + + return 0; +} + +static ssize_t tfa98xx_dbgfs_start_set(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error ret; + char buf[32]; + const char ref[] = "please calibrate now"; + int buf_size, cal_profile = 0; + + /* check string length, and account for eol */ + if (count > sizeof(ref) + 1 || count < (sizeof(ref) - 1)) + return -EINVAL; + + buf_size = min(count, (size_t)(sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + /* Compare string, excluding the trailing \0 and the potentials eol */ + if (strncmp(buf, ref, sizeof(ref) - 1)) + return -EINVAL; + + mutex_lock(&tfa98xx->dsp_lock); + ret = (enum tfa_error)tfa_calibrate(tfa98xx->tfa); + if (ret == tfa_error_ok) { + cal_profile = tfaContGetCalProfile(tfa98xx->tfa); + if (cal_profile < 0) { + pr_warn("[0x%x] Calibration profile not found\n", + tfa98xx->i2c->addr); + } + + ret = tfa98xx_tfa_start(tfa98xx, cal_profile, tfa98xx->vstep); + } + if (ret == tfa_error_ok) + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); + mutex_unlock(&tfa98xx->dsp_lock); + + if (ret) { + pr_info("[0x%x] Calibration start failed (%d)\n", tfa98xx->i2c->addr, ret); + return -EIO; + } else { + pr_info("[0x%x] Calibration started\n", tfa98xx->i2c->addr); + } + + return count; +} + +static ssize_t tfa98xx_dbgfs_r_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + char *str; + uint16_t status; + int ret; + + mutex_lock(&tfa98xx->dsp_lock); + + /* Need to ensure DSP is access-able, use mtp read access for this + * purpose + */ + ret = tfa98xx_get_mtp(tfa98xx->tfa, &status); + if (ret) { + ret = -EIO; + pr_err("[0x%x] MTP read failed\n", tfa98xx->i2c->addr); + goto r_c_err; + } + + ret = tfaRunSpeakerCalibration(tfa98xx->tfa); + if (ret) { + ret = -EIO; + pr_err("[0x%x] calibration failed\n", tfa98xx->i2c->addr); + goto r_c_err; + } + + str = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!str) { + ret = -ENOMEM; + pr_err("[0x%x] memory allocation failed\n", tfa98xx->i2c->addr); + goto r_c_err; + } + + if (tfa98xx->tfa->spkr_count > 1) { + ret = snprintf(str, PAGE_SIZE, + "Prim:%d mOhms, Sec:%d mOhms\n", + tfa98xx->tfa->mohm[0], + tfa98xx->tfa->mohm[1]); + } else { + ret = snprintf(str, PAGE_SIZE, + "Prim:%d mOhms\n", + tfa98xx->tfa->mohm[0]); + } + + pr_debug("[0x%x] calib_done: %s", tfa98xx->i2c->addr, str); + + if (ret < 0) + goto r_err; + + ret = simple_read_from_buffer(user_buf, count, ppos, str, ret); + +r_err: + kfree(str); +r_c_err: + mutex_unlock(&tfa98xx->dsp_lock); + return ret; +} + +static ssize_t tfa98xx_dbgfs_version_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + char str[] = TFA98XX_VERSION "\n"; + int ret; + + ret = simple_read_from_buffer(user_buf, count, ppos, str, sizeof(str)); + + return ret; +} + +static ssize_t tfa98xx_dbgfs_dsp_state_get(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int ret = 0; + char *str; + + switch (tfa98xx->dsp_init) { + case TFA98XX_DSP_INIT_STOPPED: + str = "Stopped\n"; + break; + case TFA98XX_DSP_INIT_RECOVER: + str = "Recover requested\n"; + break; + case TFA98XX_DSP_INIT_FAIL: + str = "Failed init\n"; + break; + case TFA98XX_DSP_INIT_PENDING: + str = "Pending init\n"; + break; + case TFA98XX_DSP_INIT_DONE: + str = "Init complete\n"; + break; + default: + str = "Invalid\n"; + } + + pr_debug("[0x%x] dsp_state : %s\n", tfa98xx->i2c->addr, str); + + ret = simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); + return ret; +} + +static ssize_t tfa98xx_dbgfs_dsp_state_set(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error ret; + char buf[32]; + const char start_cmd[] = "start"; + const char stop_cmd[] = "stop"; + const char mon_start_cmd[] = "monitor start"; + const char mon_stop_cmd[] = "monitor stop"; + int buf_size; + + buf_size = min(count, (size_t)(sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + /* Compare strings, excluding the trailing \0 */ + if (!strncmp(buf, start_cmd, sizeof(start_cmd) - 1)) { + pr_info("[0x%x] Manual triggering of dsp start...\n", tfa98xx->i2c->addr); + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + mutex_unlock(&tfa98xx->dsp_lock); + pr_debug("[0x%x] tfa_dev_start complete: %d\n", tfa98xx->i2c->addr, ret); + } else if (!strncmp(buf, stop_cmd, sizeof(stop_cmd) - 1)) { + pr_info("[0x%x] Manual triggering of dsp stop...\n", tfa98xx->i2c->addr); + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa_dev_stop(tfa98xx->tfa); + mutex_unlock(&tfa98xx->dsp_lock); + pr_debug("[0x%x] tfa_dev_stop complete: %d\n", tfa98xx->i2c->addr, ret); + } else if (!strncmp(buf, mon_start_cmd, sizeof(mon_start_cmd) - 1)) { + pr_info("[0x%x] Manual start of monitor thread...\n", tfa98xx->i2c->addr); + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->monitor_work, HZ); + } else if (!strncmp(buf, mon_stop_cmd, sizeof(mon_stop_cmd) - 1)) { + pr_info("[0x%x] Manual stop of monitor thread...\n", tfa98xx->i2c->addr); + cancel_delayed_work_sync(&tfa98xx->monitor_work); + } else { + return -EINVAL; + } + + return count; +} + +static ssize_t tfa98xx_dbgfs_fw_state_get(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + char *str; + + switch (tfa98xx->dsp_fw_state) { + case TFA98XX_DSP_FW_NONE: + str = "None\n"; + break; + case TFA98XX_DSP_FW_PENDING: + str = "Pending\n"; + break; + case TFA98XX_DSP_FW_FAIL: + str = "Fail\n"; + break; + case TFA98XX_DSP_FW_OK: + str = "Ok\n"; + break; + default: + str = "Invalid\n"; + } + + pr_debug("[0x%x] fw_state : %s", tfa98xx->i2c->addr, str); + + return simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); +} + +static ssize_t tfa98xx_dbgfs_rpc_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int ret = 0; + uint8_t *buffer; + enum Tfa98xx_Error error; + + if (tfa98xx->tfa == NULL) { + pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); + return -ENODEV; + } + + if (count == 0) + return 0; + + buffer = kmalloc(count, GFP_KERNEL); + if (buffer == NULL) { + pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); + return -ENOMEM; + } + + mutex_lock(&tfa98xx->dsp_lock); + error = dsp_msg_read(tfa98xx->tfa, count, buffer); + mutex_unlock(&tfa98xx->dsp_lock); + if (error != Tfa98xx_Error_Ok) { + pr_debug("[0x%x] dsp_msg_read error: %d\n", tfa98xx->i2c->addr, error); + kfree(buffer); + return -EFAULT; + } + + ret = copy_to_user(user_buf, buffer, count); + kfree(buffer); + if (ret) + return -EFAULT; + + *ppos += count; + return count; +} + +static ssize_t tfa98xx_dbgfs_rpc_send(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + nxpTfaFileDsc_t *msg_file; + enum Tfa98xx_Error error; + int err = 0; + + if (tfa98xx->tfa == NULL) { + pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); + return -ENODEV; + } + + if (count == 0) + return 0; + + /* msg_file.name is not used */ + msg_file = kmalloc(count + sizeof(nxpTfaFileDsc_t), GFP_KERNEL); + if (msg_file == NULL) { + pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); + return -ENOMEM; + } + msg_file->size = count; + + if (copy_from_user(msg_file->data, user_buf, count)) + return -EFAULT; + + mutex_lock(&tfa98xx->dsp_lock); + if ((msg_file->data[0] == 'M') && (msg_file->data[1] == 'G')) { + /* int vstep_idx, int vstep_msg_idx both 0 */ + error = tfaContWriteFile(tfa98xx->tfa, msg_file, 0, 0); + if (error != Tfa98xx_Error_Ok) { + pr_debug("[0x%x] tfaContWriteFile error: %d\n", + tfa98xx->i2c->addr, error); + err = -EIO; + } + } else { + error = dsp_msg(tfa98xx->tfa, msg_file->size, msg_file->data); + if (error != Tfa98xx_Error_Ok) { + pr_debug("[0x%x] dsp_msg error: %d\n", tfa98xx->i2c->addr, error); + err = -EIO; + } + } + mutex_unlock(&tfa98xx->dsp_lock); + + kfree(msg_file); + + if (err) + return err; + return count; +} +/* -- RPC */ + +static int tfa98xx_dbgfs_pga_gain_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + unsigned int value; + + value = tfa_get_pga_gain(tfa98xx->tfa); + if (value < 0) + return -EINVAL; + + *val = value; + return 0; +} + +static int tfa98xx_dbgfs_pga_gain_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + uint16_t value; + int err; + + value = val & 0xffff; + if (value > 7) + return -EINVAL; + + err = tfa_set_pga_gain(tfa98xx->tfa, value); + if (err < 0) + return -EINVAL; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_otc_fops, tfa98xx_dbgfs_otc_get, + tfa98xx_dbgfs_otc_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_mtpex_fops, tfa98xx_dbgfs_mtpex_get, + tfa98xx_dbgfs_mtpex_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_temp_fops, tfa98xx_dbgfs_temp_get, + tfa98xx_dbgfs_temp_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_pga_gain_fops, tfa98xx_dbgfs_pga_gain_get, + tfa98xx_dbgfs_pga_gain_set, "%llu\n"); + +static const struct file_operations tfa98xx_dbgfs_calib_start_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = tfa98xx_dbgfs_start_set, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_r_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = tfa98xx_dbgfs_r_read, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_version_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = tfa98xx_dbgfs_version_read, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_dsp_state_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = tfa98xx_dbgfs_dsp_state_get, + .write = tfa98xx_dbgfs_dsp_state_set, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_fw_state_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = tfa98xx_dbgfs_fw_state_get, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_rpc_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = tfa98xx_dbgfs_rpc_read, + .write = tfa98xx_dbgfs_rpc_send, + .llseek = default_llseek, +}; + +static void tfa98xx_debug_init(struct tfa98xx *tfa98xx, + struct i2c_client *i2c) +{ + char name[50]; + + scnprintf(name, MAX_CONTROL_NAME, "%s-%x", i2c->name, i2c->addr); + tfa98xx->dbg_dir = debugfs_create_dir(name, NULL); + debugfs_create_file("OTC", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_otc_fops); + debugfs_create_file("MTPEX", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_mtpex_fops); + debugfs_create_file("TEMP", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_temp_fops); + debugfs_create_file("calibrate", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_start_fops); + debugfs_create_file("R", S_IRUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_r_fops); + debugfs_create_file("version", S_IRUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_version_fops); + debugfs_create_file("dsp-state", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_dsp_state_fops); + debugfs_create_file("fw-state", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_fw_state_fops); + debugfs_create_file("rpc", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_rpc_fops); + + if (tfa98xx->flags & TFA98XX_FLAG_SAAM_AVAILABLE) { + dev_dbg(tfa98xx->dev, "Adding pga_gain debug interface\n"); + debugfs_create_file("pga_gain", S_IRUGO, tfa98xx->dbg_dir, + tfa98xx->i2c, + &tfa98xx_dbgfs_pga_gain_fops); + } +} + +static void tfa98xx_debug_remove(struct tfa98xx *tfa98xx) +{ + if (tfa98xx->dbg_dir) + debugfs_remove_recursive(tfa98xx->dbg_dir); +} +#endif + + +/* copies the profile basename (i.e. part until .) into buf */ +static void get_profile_basename(char *buf, char *profile) +{ + int cp_len = 0, idx = 0; + char *pch; + + pch = strchr(profile, '.'); + idx = pch - profile; + cp_len = (pch != NULL) ? idx : (int)strlen(profile); + memcpy(buf, profile, cp_len); + buf[cp_len] = 0; +} + +/* return the profile name accociated with id from the profile list */ +static int get_profile_from_list(char *buf, int id) +{ + struct tfa98xx_baseprofile *bprof; + + list_for_each_entry(bprof, &profile_list, list) { + if (bprof->item_id == id) { + strcpy(buf, bprof->basename); + return 0; + } + } + + return ERR; +} + +/* search for the profile in the profile list */ +static int is_profile_in_list(char *profile, int len) +{ + struct tfa98xx_baseprofile *bprof; + + list_for_each_entry(bprof, &profile_list, list) { + + if ((len == bprof->len) && (0 == strncmp(bprof->basename, + profile, len))) + return 1; + } + + return 0; +} + +/* + * for the profile with id, look if the requested samplerate is + * supported, if found return the (container)profile for this + * samplerate, on error or if not found return -1 + */ +static int get_profile_id_for_sr(int id, unsigned int rate) +{ + int idx = 0; + struct tfa98xx_baseprofile *bprof; + + list_for_each_entry(bprof, &profile_list, list) { + if (id == bprof->item_id) { + idx = tfa98xx_get_fssel(rate); + if (idx < 0) { + /* samplerate not supported */ + return ERR; + } + + return bprof->sr_rate_sup[idx]; + } + } + + /* profile not found */ + return ERR; +} + +/* check if this profile is a calibration profile */ +static int is_calibration_profile(char *profile) +{ + if (strstr(profile, ".cal") != NULL) + return 1; + return 0; +} + +/* + * adds the (container)profile index of the samplerate found in + * the (container)profile to a fixed samplerate table in the (mixer)profile + */ +static int add_sr_to_profile(struct tfa98xx *tfa98xx, char *basename, + int len, int profile) +{ + struct tfa98xx_baseprofile *bprof; + int idx = 0; + unsigned int sr = 0; + + list_for_each_entry(bprof, &profile_list, list) { + if ((len == bprof->len) && (0 == strncmp(bprof->basename, + basename, len))) { + /* add supported samplerate for this profile */ + sr = tfa98xx_get_profile_sr(tfa98xx->tfa, profile); + if (!sr) { + pr_err("unable to identify supported sample rate for %s\n", + bprof->basename); + return ERR; + } + + /* get the index for this samplerate */ + idx = tfa98xx_get_fssel(sr); + if (idx < 0 || idx >= TFA98XX_NUM_RATES) { + pr_err("invalid index for samplerate %d\n", idx); + return ERR; + } + + /* enter the (container)profile for this samplerate + * at the corresponding index + */ + bprof->sr_rate_sup[idx] = profile; + + pr_debug("added profile:samplerate = [%d:%d]\ + for mixer profile: %s\n", profile, sr, bprof->basename); + } + } + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) +static struct snd_soc_codec *snd_soc_kcontrol_codec( + struct snd_kcontrol *kcontrol) +{ + return snd_kcontrol_chip(kcontrol); +} +#endif + +static int tfa98xx_get_vstep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int mixer_profile = kcontrol->private_value; + int ret = 0; + int profile; + + profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); + if (profile < 0) { + pr_err("tfa98xx: tfa98xx_get_vstep: invalid profile %d\ + (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); + return -EINVAL; + } + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int vstep = tfa98xx->prof_vsteps[profile]; + + ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = + tfacont_get_max_vstep(tfa98xx->tfa, profile) + - vstep - 1; + } + mutex_unlock(&tfa98xx_mutex); + + return ret; +} + +static int tfa98xx_set_vstep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int mixer_profile = kcontrol->private_value; + int profile; + int err = 0; + int change = 0; + + if (no_start != 0) + return 0; + + profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); + if (profile < 0) { + pr_err("tfa98xx: tfa98xx_set_vstep: invalid profile %d\ + (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); + return -EINVAL; + } + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int vstep, vsteps; + int ready = 0; + int new_vstep; + int value = ucontrol->value.integer.value[tfa98xx->tfa->dev_idx]; + + vstep = tfa98xx->prof_vsteps[profile]; + vsteps = tfacont_get_max_vstep(tfa98xx->tfa, profile); + + if (vstep == vsteps - value - 1) + continue; + + new_vstep = vsteps - value - 1; + + if (new_vstep < 0) + new_vstep = 0; + + tfa98xx->prof_vsteps[profile] = new_vstep; + +#ifndef TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL + if (profile == tfa98xx->profile) { +#endif + /* this is the active profile, program the new vstep */ + tfa98xx->vstep = new_vstep; + mutex_lock(&tfa98xx->dsp_lock); + tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); + + if (ready) { + err = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, + tfa98xx->vstep); + if (err) { + pr_err("Write vstep error: %d\n", err); + } else { + pr_debug("Succesfully changed vstep index!\n"); + change = 1; + } + } + + mutex_unlock(&tfa98xx->dsp_lock); +#ifndef TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL + } +#endif + pr_debug("%d: vstep:%d, (control value: %d) - profile %d\n", + tfa98xx->tfa->dev_idx, new_vstep, value, profile); + } + + if (change) { + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); + mutex_unlock(&tfa98xx->dsp_lock); + } + } + + mutex_unlock(&tfa98xx_mutex); + + return change; +} + +static int tfa98xx_info_vstep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + + int mixer_profile = tfa98xx_mixer_profile; + int profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); + if (profile < 0) { + pr_err("tfa98xx: tfa98xx_info_vstep: invalid profile %d\ + (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); + return -EINVAL; + } + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + mutex_lock(&tfa98xx_mutex); + uinfo->count = tfa98xx_device_count; + mutex_unlock(&tfa98xx_mutex); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = max(0, + tfacont_get_max_vstep(tfa98xx->tfa, profile) - 1); + pr_debug("vsteps count: %d [prof=%d]\n", + tfacont_get_max_vstep(tfa98xx->tfa, profile), + profile); + return 0; +} + +static int tfa98xx_get_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + mutex_lock(&tfa98xx_mutex); + ucontrol->value.integer.value[0] = tfa98xx_mixer_profile; + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_set_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int change = 0; + int new_profile; + int prof_idx; + int profile_count = tfa98xx_mixer_profiles; + int profile = tfa98xx_mixer_profile; + + if (no_start != 0) + return 0; + + new_profile = ucontrol->value.integer.value[0]; + if (new_profile == profile) + return 0; + + if ((new_profile < 0) || (new_profile >= profile_count)) { + pr_err("not existing profile (%d)\n", new_profile); + return -EINVAL; + } + + /* get the container profile for the requested sample rate */ + prof_idx = get_profile_id_for_sr(new_profile, tfa98xx->rate); + if (prof_idx < 0) { + pr_err("tfa98xx: sample rate [%d] not supported for this \ + mixer profile [%d].\n", tfa98xx->rate, new_profile); + return 0; + } + pr_debug("selected container profile [%d]\n", prof_idx); + + /* update mixer profile */ + tfa98xx_mixer_profile = new_profile; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int err; + int ready = 0; + + /* update 'real' profile (container profile) */ + tfa98xx->profile = prof_idx; + tfa98xx->vstep = tfa98xx->prof_vsteps[prof_idx]; + + /* Don't call tfa_dev_start() if there is no clock. */ + mutex_lock(&tfa98xx->dsp_lock); + tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); + if (ready) { + /* Also re-enables the interrupts */ + err = tfa98xx_tfa_start(tfa98xx, prof_idx, tfa98xx->vstep); + if (err) { + pr_info("Write profile error: %d\n", err); + } else { + pr_debug("Changed to profile %d (vstep = %d)\n", + prof_idx, tfa98xx->vstep); + change = 1; + } + } + mutex_unlock(&tfa98xx->dsp_lock); + + /* Flag DSP as invalidated as the profile change may invalidate the + * current DSP configuration. That way, further stream start can + * trigger a tfa_dev_start. + */ + tfa98xx->dsp_init = TFA98XX_DSP_INIT_INVALIDATED; + } + + if (change) { + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); + mutex_unlock(&tfa98xx->dsp_lock); + } + } + + mutex_unlock(&tfa98xx_mutex); + + return change; +} + +static int tfa98xx_info_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + char profile_name[MAX_CONTROL_NAME] = { 0 }; + int count = tfa98xx_mixer_profiles, err = -1; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + err = get_profile_from_list(profile_name, uinfo->value.enumerated.item); + if (err != 0) + return -EINVAL; + + strcpy(uinfo->value.enumerated.name, profile_name); + + return 0; +} + +static int tfa98xx_info_stop_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + mutex_lock(&tfa98xx_mutex); + uinfo->count = tfa98xx_device_count; + mutex_unlock(&tfa98xx_mutex); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int tfa98xx_get_stop_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = 0; + } + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_set_stop_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int ready = 0; + int i = tfa98xx->tfa->dev_idx; + + pr_debug("%d: %ld\n", i, ucontrol->value.integer.value[i]); + + tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); + + if ((ucontrol->value.integer.value[i] != 0) && ready) { + cancel_delayed_work_sync(&tfa98xx->monitor_work); + + cancel_delayed_work_sync(&tfa98xx->init_work); + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) + continue; + + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_stop(tfa98xx->tfa); + tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; + mutex_unlock(&tfa98xx->dsp_lock); + } + + ucontrol->value.integer.value[i] = 0; + } + mutex_unlock(&tfa98xx_mutex); + + return 1; +} + +static int tfa98xx_info_cal_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + mutex_lock(&tfa98xx_mutex); + uinfo->count = tfa98xx_device_count; + mutex_unlock(&tfa98xx_mutex); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xffff; /* 16 bit value */ + + return 0; +} + +static int tfa98xx_set_cal_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + enum tfa_error err; + int i = tfa98xx->tfa->dev_idx; + + tfa98xx->cal_data = (uint16_t)ucontrol->value.integer.value[i]; + + mutex_lock(&tfa98xx->dsp_lock); + err = tfa98xx_write_re25(tfa98xx->tfa, tfa98xx->cal_data); + tfa98xx->set_mtp_cal = (err != tfa_error_ok); + if (tfa98xx->set_mtp_cal == false) { + pr_info("Calibration value (%d) set in mtp\n", + tfa98xx->cal_data); + } + mutex_unlock(&tfa98xx->dsp_lock); + } + mutex_unlock(&tfa98xx_mutex); + + return 1; +} + +static int tfa98xx_get_cal_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = + tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_RE25_PRIM); + mutex_unlock(&tfa98xx->dsp_lock); + } + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_create_controls(struct tfa98xx *tfa98xx) +{ + int prof, nprof, mix_index = 0; + int nr_controls = 0, id = 0; + char *name; + struct tfa98xx_baseprofile *bprofile; + + /* Create the following controls: + * - enum control to select the active profile + * - one volume control for each profile hosting a vstep + * - Stop control on TFA1 devices + */ + + nr_controls = 2; /* Profile and stop control */ + + if (tfa98xx->flags & TFA98XX_FLAG_CALIBRATION_CTL) + nr_controls += 1; /* calibration */ + + /* allocate the tfa98xx_controls base on the nr of profiles */ + nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); + for (prof = 0; prof < nprof; prof++) { + if (tfacont_get_max_vstep(tfa98xx->tfa, prof)) + nr_controls++; /* Playback Volume control */ + } + + tfa98xx_controls = devm_kzalloc(tfa98xx->codec->dev, + nr_controls * sizeof(tfa98xx_controls[0]), GFP_KERNEL); + if (!tfa98xx_controls) + return -ENOMEM; + + /* Create a mixer item for selecting the active profile */ + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + if (!name) + return -ENOMEM; + scnprintf(name, MAX_CONTROL_NAME, "%s Profile", tfa98xx->fw.name); + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_profile; + tfa98xx_controls[mix_index].get = tfa98xx_get_profile; + tfa98xx_controls[mix_index].put = tfa98xx_set_profile; + /* save number of profiles */ + // tfa98xx_controls[mix_index].private_value = profs; + mix_index++; + + /* create mixer items for each profile that has volume */ + for (prof = 0; prof < nprof; prof++) { + /* create an new empty profile */ + bprofile = devm_kzalloc(tfa98xx->codec->dev, + sizeof(*bprofile), GFP_KERNEL); + if (!bprofile) + return -ENOMEM; + + bprofile->len = 0; + bprofile->item_id = -1; + INIT_LIST_HEAD(&bprofile->list); + + /* copy profile name into basename until the . */ + get_profile_basename(bprofile->basename, + tfa_cont_profile_name(tfa98xx, prof)); + bprofile->len = strlen(bprofile->basename); + + /* + * search the profile list for a profile with basename, if it is not + * found then add it to the list and add a new mixer control + * (if it has vsteps)also, if it is a calibration profile, + * do not add it to the list + */ + if ((is_profile_in_list(bprofile->basename, bprofile->len) == 0) && + is_calibration_profile( + tfa_cont_profile_name(tfa98xx, prof)) == 0) { + /* the profile is not present, add it to the list */ + list_add(&bprofile->list, &profile_list); + bprofile->item_id = id++; + + pr_debug("profile added [%d]: %s\n", + bprofile->item_id, bprofile->basename); + + if (tfacont_get_max_vstep(tfa98xx->tfa, prof)) { + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, + GFP_KERNEL); + if (!name) + return -ENOMEM; + + scnprintf(name, MAX_CONTROL_NAME, "%s %s Playback Volume", + tfa98xx->fw.name, bprofile->basename); + + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_vstep; + tfa98xx_controls[mix_index].get = tfa98xx_get_vstep; + tfa98xx_controls[mix_index].put = tfa98xx_set_vstep; + /* save profile index */ + tfa98xx_controls[mix_index].private_value = bprofile->item_id; + mix_index++; + } + } + + /* look for the basename profile in the list of mixer profiles and + * add the container profile index to the supported samplerates + * of this mixer profile */ + add_sr_to_profile(tfa98xx, bprofile->basename, bprofile->len, prof); + } + + /* set the number of user selectable profiles in the mixer */ + tfa98xx_mixer_profiles = id; + + /* Create a mixer item for stop control on TFA1 */ + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + if (!name) + return -ENOMEM; + + scnprintf(name, MAX_CONTROL_NAME, "%s Stop", tfa98xx->fw.name); + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_stop_ctl; + tfa98xx_controls[mix_index].get = tfa98xx_get_stop_ctl; + tfa98xx_controls[mix_index].put = tfa98xx_set_stop_ctl; + mix_index++; + + if (tfa98xx->flags & TFA98XX_FLAG_CALIBRATION_CTL) { + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + if (!name) + return -ENOMEM; + + scnprintf(name, MAX_CONTROL_NAME, "%s Calibration", tfa98xx->fw.name); + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_cal_ctl; + tfa98xx_controls[mix_index].get = tfa98xx_get_cal_ctl; + tfa98xx_controls[mix_index].put = tfa98xx_set_cal_ctl; + mix_index++; + } + + return snd_soc_add_codec_controls(tfa98xx->codec, + tfa98xx_controls, mix_index); +} + +static void *tfa98xx_devm_kstrdup(struct device *dev, char *buf) +{ + char *str = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); + if (!str) + return str; + memcpy(str, buf, strlen(buf)); + return str; +} + +static int tfa98xx_append_i2c_address(struct device *dev, + struct i2c_client *i2c, + struct snd_soc_dapm_widget *widgets, + int num_widgets, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + char buf[50]; + int i; + int i2cbus = i2c->adapter->nr; + int addr = i2c->addr; + if (dai_drv && num_dai > 0) + for (i = 0; i < num_dai; i++) { + snprintf(buf, 50, "%s-%x-%x", dai_drv[i].name, i2cbus, + addr); + dai_drv[i].name = tfa98xx_devm_kstrdup(dev, buf); + + snprintf(buf, 50, "%s-%x-%x", + dai_drv[i].playback.stream_name, + i2cbus, addr); + dai_drv[i].playback.stream_name = tfa98xx_devm_kstrdup(dev, buf); + + snprintf(buf, 50, "%s-%x-%x", + dai_drv[i].capture.stream_name, + i2cbus, addr); + dai_drv[i].capture.stream_name = tfa98xx_devm_kstrdup(dev, buf); + } + + /* the idea behind this is convert: + * SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), + * into: + * SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback-2-36", + * 0, SND_SOC_NOPM, 0, 0), + */ + if (widgets && num_widgets > 0) + for (i = 0; i < num_widgets; i++) { + if (!widgets[i].sname) + continue; + if ((widgets[i].id == snd_soc_dapm_aif_in) + || (widgets[i].id == snd_soc_dapm_aif_out)) { + snprintf(buf, 50, "%s-%x-%x", widgets[i].sname, + i2cbus, addr); + widgets[i].sname = tfa98xx_devm_kstrdup(dev, buf); + } + } + + return 0; +} + +static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_common[] = { + /* Stream widgets */ + SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF OUT", "AIF Capture", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("OUTL"), + SND_SOC_DAPM_INPUT("AEC Loopback"), +}; + +static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_stereo[] = { + SND_SOC_DAPM_OUTPUT("OUTR"), +}; + +static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_saam[] = { + SND_SOC_DAPM_INPUT("SAAM MIC"), +}; + +static struct snd_soc_dapm_widget tfa9888_dapm_inputs[] = { + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_INPUT("DMIC3"), + SND_SOC_DAPM_INPUT("DMIC4"), +}; + +static const struct snd_soc_dapm_route tfa98xx_dapm_routes_common[] = { + { "OUTL", NULL, "AIF IN" }, + { "AIF OUT", NULL, "AEC Loopback" }, +}; + +static const struct snd_soc_dapm_route tfa98xx_dapm_routes_saam[] = { + { "AIF OUT", NULL, "SAAM MIC" }, +}; + +static const struct snd_soc_dapm_route tfa98xx_dapm_routes_stereo[] = { + { "OUTR", NULL, "AIF IN" }, +}; + +static const struct snd_soc_dapm_route tfa9888_input_dapm_routes[] = { + { "AIF OUT", NULL, "DMIC1" }, + { "AIF OUT", NULL, "DMIC2" }, + { "AIF OUT", NULL, "DMIC3" }, + { "AIF OUT", NULL, "DMIC4" }, +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) +static struct snd_soc_dapm_context *snd_soc_codec_get_dapm( + struct snd_soc_codec *codec) +{ + return &codec->dapm; +} +#endif + +static void tfa98xx_add_widgets(struct tfa98xx *tfa98xx) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(tfa98xx->codec); + struct snd_soc_dapm_widget *widgets; + unsigned int num_dapm_widgets = ARRAY_SIZE(tfa98xx_dapm_widgets_common); + + widgets = devm_kzalloc(&tfa98xx->i2c->dev, + sizeof(struct snd_soc_dapm_widget) * + ARRAY_SIZE(tfa98xx_dapm_widgets_common), + GFP_KERNEL); + if (!widgets) + return; + memcpy(widgets, tfa98xx_dapm_widgets_common, + sizeof(struct snd_soc_dapm_widget) * + ARRAY_SIZE(tfa98xx_dapm_widgets_common)); + + tfa98xx_append_i2c_address(&tfa98xx->i2c->dev, + tfa98xx->i2c, + widgets, + num_dapm_widgets, + NULL, + 0); + + snd_soc_dapm_new_controls(dapm, widgets, + ARRAY_SIZE(tfa98xx_dapm_widgets_common)); + snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_common, + ARRAY_SIZE(tfa98xx_dapm_routes_common)); + + if (tfa98xx->flags & TFA98XX_FLAG_STEREO_DEVICE) { + snd_soc_dapm_new_controls(dapm, tfa98xx_dapm_widgets_stereo, + ARRAY_SIZE(tfa98xx_dapm_widgets_stereo)); + snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_stereo, + ARRAY_SIZE(tfa98xx_dapm_routes_stereo)); + } + + if (tfa98xx->flags & TFA98XX_FLAG_MULTI_MIC_INPUTS) { + snd_soc_dapm_new_controls(dapm, tfa9888_dapm_inputs, + ARRAY_SIZE(tfa9888_dapm_inputs)); + snd_soc_dapm_add_routes(dapm, tfa9888_input_dapm_routes, + ARRAY_SIZE(tfa9888_input_dapm_routes)); + } + + if (tfa98xx->flags & TFA98XX_FLAG_SAAM_AVAILABLE) { + snd_soc_dapm_new_controls(dapm, tfa98xx_dapm_widgets_saam, + ARRAY_SIZE(tfa98xx_dapm_widgets_saam)); + snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_saam, + ARRAY_SIZE(tfa98xx_dapm_routes_saam)); + } +} + +/* I2C wrapper functions */ +enum Tfa98xx_Error tfa98xx_write_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short value) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + int ret; + int retries = I2C_RETRIES; + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + if (!tfa98xx || !tfa98xx->regmap) { + pr_err("No tfa98xx regmap available\n"); + return Tfa98xx_Error_Bad_Parameter; + } +retry: + ret = regmap_write(tfa98xx->regmap, subaddress, value); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + return Tfa98xx_Error_Fail; + } + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx->i2c->dev, " WR reg=0x%02x, val=0x%04x %s\n", + subaddress, value, + ret < 0 ? "Error!!" : ""); + + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\tWR reg=0x%02x, val=0x%04x %s\n", + subaddress, value, + ret < 0 ? "Error!!" : ""); + return error; +} + +enum Tfa98xx_Error tfa98xx_read_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short *val) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + unsigned int value; + int retries = I2C_RETRIES; + int ret; + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + if (!tfa98xx || !tfa98xx->regmap) { + pr_err("No tfa98xx regmap available\n"); + return Tfa98xx_Error_Bad_Parameter; + } +retry: + ret = regmap_read(tfa98xx->regmap, subaddress, &value); + if (ret < 0) { + pr_warn("i2c error at subaddress 0x%x, retries left: %d\n", + subaddress, retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + return Tfa98xx_Error_Fail; + } + *val = value & 0xffff; + + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx->i2c->dev, "RD reg=0x%02x, val=0x%04x %s\n", + subaddress, *val, + ret < 0 ? "Error!!" : ""); + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\tRD reg=0x%02x, val=0x%04x %s\n", + subaddress, *val, + ret < 0 ? "Error!!" : ""); + + return error; +} + + +/* + * init external dsp + */ +enum Tfa98xx_Error + tfa98xx_init_dsp(struct tfa_device *tfa) +{ + return Tfa98xx_Error_Not_Supported; +} + +int tfa98xx_get_dsp_status(struct tfa_device *tfa) +{ + return 0; +} + +/* + * write external dsp message + */ +enum Tfa98xx_Error + tfa98xx_write_dsp(struct tfa_device *tfa, int num_bytes, + const char *command_buffer) +{ + return Tfa98xx_Error_Not_Supported; +} + +/* + * read external dsp message + */ +enum Tfa98xx_Error + tfa98xx_read_dsp(struct tfa_device *tfa, int num_bytes, + unsigned char *result_buffer) +{ + return Tfa98xx_Error_Not_Supported; +} +/* + * write/read external dsp message + */ +enum Tfa98xx_Error + tfa98xx_writeread_dsp(struct tfa_device *tfa, int command_length, + void *command_buffer, int result_length, void *result_buffer) +{ + return Tfa98xx_Error_Not_Supported; +} + +enum Tfa98xx_Error tfa98xx_read_data(struct tfa_device *tfa, + unsigned char reg, + int len, unsigned char value[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + struct i2c_client *tfa98xx_client; + int err; + int tries = 0; + unsigned char *reg_buf = NULL; + struct i2c_msg msgs[] = { + { + .flags = 0, + .len = 1, + .buf = NULL, + }, { + .flags = I2C_M_RD, + .len = len, + .buf = value, + }, + }; + //GRP_KERNEL also works, + reg_buf = (unsigned char *)kmalloc(sizeof(reg), GFP_DMA); + if (!reg_buf) { + return -ENOMEM;; + } + + *reg_buf = reg; + msgs[0].buf = reg_buf; + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + if (tfa98xx->i2c) { + tfa98xx_client = tfa98xx->i2c; + msgs[0].addr = tfa98xx_client->addr; + msgs[1].addr = tfa98xx_client->addr; + + do { + err = i2c_transfer(tfa98xx_client->adapter, msgs, + ARRAY_SIZE(msgs)); + if (err != ARRAY_SIZE(msgs)) + msleep_interruptible(I2C_RETRY_DELAY); + } while ((err != ARRAY_SIZE(msgs)) && (++tries < I2C_RETRIES)); + + if (err != ARRAY_SIZE(msgs)) { + dev_err(&tfa98xx_client->dev, "read transfer error %d\n", + err); + error = Tfa98xx_Error_Fail; + } + + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx_client->dev, "RD-DAT reg=0x%02x, len=%d\n", + reg, len); + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\t\tRD-DAT reg=0x%02x, len=%d\n", + reg, len); + } else { + pr_err("No device available\n"); + error = Tfa98xx_Error_Fail; + } + kfree(reg_buf); + return error; +} + +enum Tfa98xx_Error tfa98xx_write_raw(struct tfa_device *tfa, + int len, + const unsigned char data[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + int ret; + int retries = I2C_RETRIES; + + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + +retry: + ret = i2c_master_send(tfa98xx->i2c, data, len); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + } + + if (ret == len) { + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx->i2c->dev, " WR-RAW len=%d\n", len); + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\t\tWR-RAW len=%d\n", len); + return Tfa98xx_Error_Ok; + } + pr_err(" WR-RAW (len=%d) Error I2C send size mismatch %d\n", len, ret); + error = Tfa98xx_Error_Fail; + + return error; +} + +/* Interrupts management */ + +static void tfa98xx_interrupt_enable_tfa2(struct tfa98xx *tfa98xx, bool enable) +{ + /* Only for 0x72 we need to enable NOCLK interrupts */ + if (tfa98xx->flags & TFA98XX_FLAG_REMOVE_PLOP_NOISE) + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_stnoclk, enable); + + if (tfa98xx->flags & TFA98XX_FLAG_LP_MODES) { + /* FIXME: IELP0 does not excist for 9912 */ + tfa_irq_ena(tfa98xx->tfa, 36, enable); + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_stclpr, enable); + } +} + +/* Check if tap-detection can and shall be enabled. + * Configure SPK interrupt accordingly or setup polling mode + * Tap-detection shall be active if: + * - the service is enabled (tapdet_open), AND + * - the current profile is a tap-detection profile + * On TFA1 familiy of devices, activating tap-detection means enabling the SPK + * interrupt if available. + * We also update the tapdet_enabled and tapdet_poll variables. + */ +static void tfa98xx_tapdet_check_update(struct tfa98xx *tfa98xx) +{ + unsigned int enable = false; + + /* Support tap-detection on TFA1 family of devices */ + if ((tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) == 0) + return; + + if (tfa98xx->tapdet_open && + (tfa98xx->tapdet_profiles & (1 << tfa98xx->profile))) + enable = true; + + if (!gpio_is_valid(tfa98xx->irq_gpio)) { + /* interrupt not available, setup polling mode */ + tfa98xx->tapdet_poll = true; + if (enable) + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->tapdet_work, HZ / 10); + else + cancel_delayed_work_sync(&tfa98xx->tapdet_work); + dev_dbg(tfa98xx->codec->dev, + "Polling for tap-detection: %s (%d; 0x%x, %d)\n", + enable ? "enabled" : "disabled", + tfa98xx->tapdet_open, tfa98xx->tapdet_profiles, + tfa98xx->profile); + + } else { + dev_dbg(tfa98xx->codec->dev, + "Interrupt for tap-detection: %s (%d; 0x%x, %d)\n", + enable ? "enabled" : "disabled", + tfa98xx->tapdet_open, tfa98xx->tapdet_profiles, + tfa98xx->profile); + /* enabled interrupt */ + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_sttapdet, enable); + } + + /* check disabled => enabled transition to clear pending events */ + if (!tfa98xx->tapdet_enabled && enable) { + /* clear pending event if any */ + tfa_irq_clear(tfa98xx->tfa, tfa9912_irq_sttapdet); + } + + if (!tfa98xx->tapdet_poll) + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_sttapdet, 1); /* enable again */ +} + +/* global enable / disable interrupts */ +static void tfa98xx_interrupt_enable(struct tfa98xx *tfa98xx, bool enable) +{ + if (tfa98xx->flags & TFA98XX_FLAG_SKIP_INTERRUPTS) + return; + + if (tfa98xx->tfa->tfa_family == 2) + tfa98xx_interrupt_enable_tfa2(tfa98xx, enable); +} + +/* Firmware management */ +static void tfa98xx_container_loaded(const struct firmware *cont, + void *context) +{ + nxpTfaContainer_t *container; + struct tfa98xx *tfa98xx = context; + enum tfa_error tfa_err; + int container_size; + int ret; + + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; + + if (!cont) { + pr_err("Failed to read %s\n", fw_name); + return; + } + + pr_debug("loaded %s - size: %zu\n", fw_name, cont->size); + + mutex_lock(&tfa98xx_mutex); + if (tfa98xx_container == NULL) { + container = kzalloc(cont->size, GFP_KERNEL); + if (container == NULL) { + mutex_unlock(&tfa98xx_mutex); + release_firmware(cont); + pr_err("Error allocating memory\n"); + return; + } + + container_size = cont->size; + memcpy(container, cont->data, container_size); + release_firmware(cont); + + pr_debug("%.2s%.2s\n", container->version, container->subversion); + pr_debug("%.8s\n", container->customer); + pr_debug("%.8s\n", container->application); + pr_debug("%.8s\n", container->type); + pr_debug("%d ndev\n", container->ndev); + pr_debug("%d nprof\n", container->nprof); + + tfa_err = tfa_load_cnt(container, container_size); + if (tfa_err != tfa_error_ok) { + mutex_unlock(&tfa98xx_mutex); + kfree(container); + dev_err(tfa98xx->dev, "Cannot load container file, aborting\n"); + return; + } + + tfa98xx_container = container; + } else { + pr_debug("container file already loaded...\n"); + container = tfa98xx_container; + release_firmware(cont); + } + mutex_unlock(&tfa98xx_mutex); + + tfa98xx->tfa->cnt = container; + + /* + i2c transaction limited to 64k + (Documentation/i2c/writing-clients) + */ + tfa98xx->tfa->buffer_size = 65536; + + /* DSP messages via i2c */ + tfa98xx->tfa->has_msg = 0; + + if (tfa_dev_probe(tfa98xx->i2c->addr, tfa98xx->tfa) != 0) { + dev_err(tfa98xx->dev, "Failed to probe TFA98xx @ 0x%.2x\n", + tfa98xx->i2c->addr); + return; + } + + tfa98xx->tfa->dev_idx = tfa_cont_get_idx(tfa98xx->tfa); + if (tfa98xx->tfa->dev_idx < 0) { + dev_err(tfa98xx->dev, "Failed to find TFA98xx @ 0x%.2x in \ + container file\n", tfa98xx->i2c->addr); + return; + } + + /* Enable debug traces */ + tfa98xx->tfa->verbose = trace_level & 1; + + /* prefix is the application name from the cnt */ + tfa_cnt_get_app_name(tfa98xx->tfa, tfa98xx->fw.name); + + /* set default profile/vstep */ + tfa98xx->profile = 0; + tfa98xx->vstep = 0; + + /* Override default profile if requested */ + if (strcmp(dflt_prof_name, "")) { + unsigned int i; + int nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); + for (i = 0; i < nprof; i++) { + if (strcmp(tfa_cont_profile_name(tfa98xx, i), + dflt_prof_name) == 0) { + tfa98xx->profile = i; + dev_info(tfa98xx->dev, + "changing default profile to %s (%d)\n", + dflt_prof_name, tfa98xx->profile); + break; + } + } + if (i >= nprof) + dev_info(tfa98xx->dev, + "Default profile override failed (%s profile not found)\n", + dflt_prof_name); + } + + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_OK; + pr_debug("Firmware init complete\n"); + + if (no_start != 0) + return; + + /* Only controls for master device */ + if (tfa98xx->tfa->dev_idx == 0) + tfa98xx_create_controls(tfa98xx); + + tfa98xx_inputdev_check_register(tfa98xx); + + if (tfa_is_cold(tfa98xx->tfa) == 0) { + pr_debug("Warning: device 0x%.2x is still warm\n", tfa98xx->i2c->addr); + tfa_reset(tfa98xx->tfa); + } + + /* Preload settings using internal clock on TFA2 */ + if (tfa98xx->tfa->tfa_family == 2) { + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + if (ret == Tfa98xx_Error_Not_Supported) + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; + mutex_unlock(&tfa98xx->dsp_lock); + } + + tfa98xx_interrupt_enable(tfa98xx, true); +} + +static int tfa98xx_load_container(struct tfa98xx *tfa98xx) +{ + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_PENDING; + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + fw_name, tfa98xx->dev, GFP_KERNEL, + tfa98xx, tfa98xx_container_loaded); +} + + +static void tfa98xx_tapdet(struct tfa98xx *tfa98xx) +{ + unsigned int tap_pattern; + int btn; + + /* check tap pattern (BTN_0 is "error" wrong tap indication */ + tap_pattern = tfa_get_tap_pattern(tfa98xx->tfa); + switch (tap_pattern) { + case 0xffffffff: + pr_info("More than 4 taps detected! (flagTapPattern = -1)\n"); + btn = BTN_0; + break; + case 0xfffffffe: + case 0xfe: + pr_info("Illegal tap detected!\n"); + btn = BTN_0; + break; + case 0: + pr_info("Unrecognized pattern! (flagTapPattern = 0)\n"); + btn = BTN_0; + break; + default: + pr_info("Detected pattern: %d\n", tap_pattern); + btn = BTN_0 + tap_pattern; + break; + } + + input_report_key(tfa98xx->input, btn, 1); + input_report_key(tfa98xx->input, btn, 0); + input_sync(tfa98xx->input); + + /* acknowledge event done by clearing interrupt */ + +} + +static void tfa98xx_tapdet_work(struct work_struct *work) +{ + struct tfa98xx *tfa98xx; + + //TODO check is this is still needed for tap polling + tfa98xx = container_of(work, struct tfa98xx, tapdet_work.work); + + if (tfa_irq_get(tfa98xx->tfa, tfa9912_irq_sttapdet)) + tfa98xx_tapdet(tfa98xx); + + queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->tapdet_work, HZ / 10); +} + +static void tfa98xx_monitor(struct work_struct *work) +{ + struct tfa98xx *tfa98xx; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + tfa98xx = container_of(work, struct tfa98xx, monitor_work.work); + + /* Check for tap-detection - bypass monitor if it is active */ + if (!tfa98xx->input) { + mutex_lock(&tfa98xx->dsp_lock); + error = tfa_status(tfa98xx->tfa); + mutex_unlock(&tfa98xx->dsp_lock); + if (error == Tfa98xx_Error_DSP_not_running) { + if (tfa98xx->dsp_init == TFA98XX_DSP_INIT_DONE) { + tfa98xx->dsp_init = TFA98XX_DSP_INIT_RECOVER; + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->init_work, 0); + } + } + } + + /* reschedule */ + queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->monitor_work, 5 * HZ); +} + +static void tfa98xx_dsp_init(struct tfa98xx *tfa98xx) +{ + int ret; + bool failed = false; + bool reschedule = false; + bool sync = false; + + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { + pr_debug("Skipping tfa_dev_start (no FW: %d)\n", tfa98xx->dsp_fw_state); + return; + } + + if (tfa98xx->dsp_init == TFA98XX_DSP_INIT_DONE) { + pr_debug("Stream already started, skipping DSP power-on\n"); + return; + } + mutex_lock(&tfa98xx->dsp_lock); + + tfa98xx->dsp_init = TFA98XX_DSP_INIT_PENDING; + + if (tfa98xx->init_count < TF98XX_MAX_DSP_START_TRY_COUNT) { + /* directly try to start DSP */ + ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + if (ret == Tfa98xx_Error_Not_Supported) { + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; + dev_err(&tfa98xx->i2c->dev, "Failed starting device\n"); + failed = true; + } else if (ret != Tfa98xx_Error_Ok) { + /* It may fail as we may not have a valid clock at that + * time, so re-schedule and re-try later. + */ + dev_err(&tfa98xx->i2c->dev, + "tfa_dev_start failed! (err %d) - %d\n", + ret, tfa98xx->init_count); + reschedule = true; + } else { + sync = true; + + /* Subsystem ready, tfa init complete */ + tfa98xx->dsp_init = TFA98XX_DSP_INIT_DONE; + dev_dbg(&tfa98xx->i2c->dev, + "tfa_dev_start success (%d)\n", + tfa98xx->init_count); + /* cancel other pending init works */ + cancel_delayed_work(&tfa98xx->init_work); + tfa98xx->init_count = 0; + } + } else { + /* exceeded max number ot start tentatives, cancel start */ + dev_err(&tfa98xx->i2c->dev, + "Failed starting device (%d)\n", + tfa98xx->init_count); + failed = true; + } + + if (reschedule) { + /* reschedule this init work for later */ + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->init_work, + msecs_to_jiffies(5)); + tfa98xx->init_count++; + } + if (failed) { + tfa98xx->dsp_init = TFA98XX_DSP_INIT_FAIL; + /* cancel other pending init works */ + cancel_delayed_work(&tfa98xx->init_work); + tfa98xx->init_count = 0; + } + mutex_unlock(&tfa98xx->dsp_lock); + + if (sync) { + /* check if all devices have started */ + bool do_sync; + mutex_lock(&tfa98xx_mutex); + + if (tfa98xx_sync_count < tfa98xx_device_count) + tfa98xx_sync_count++; + + do_sync = (tfa98xx_sync_count >= tfa98xx_device_count); + mutex_unlock(&tfa98xx_mutex); + + /* when all devices have started then unmute */ + if (do_sync) { + tfa98xx_sync_count = 0; + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); + + /* + * start monitor thread to check IC status bit + * periodically, and re-init IC to recover if + * needed. + */ + if (tfa98xx->tfa->tfa_family == 1) + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->monitor_work, + 1 * HZ); + mutex_unlock(&tfa98xx->dsp_lock); + } + + } + } +} + + +static void tfa98xx_dsp_init_work(struct work_struct *work) +{ + struct tfa98xx *tfa98xx = container_of(work, struct tfa98xx, + init_work.work); + + tfa98xx_dsp_init(tfa98xx); +} + +static void tfa98xx_interrupt(struct work_struct *work) +{ + struct tfa98xx *tfa98xx = container_of(work, struct tfa98xx, + interrupt_work.work); + + pr_info("\n"); + + if (tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) { + /* check for tap interrupt */ + if (tfa_irq_get(tfa98xx->tfa, tfa9912_irq_sttapdet)) { + tfa98xx_tapdet(tfa98xx); + + /* clear interrupt */ + tfa_irq_clear(tfa98xx->tfa, tfa9912_irq_sttapdet); + } + } /* TFA98XX_FLAG_TAPDET_AVAILABLE */ + + if (tfa98xx->flags & TFA98XX_FLAG_REMOVE_PLOP_NOISE) { + int start_triggered; + + mutex_lock(&tfa98xx->dsp_lock); + start_triggered = tfa_plop_noise_interrupt(tfa98xx->tfa, + tfa98xx->profile, tfa98xx->vstep); + /* Only enable when the return value is 1, + * otherwise the interrupt is triggered twice + */ + if (start_triggered) + tfa98xx_interrupt_enable(tfa98xx, true); + mutex_unlock(&tfa98xx->dsp_lock); + } /* TFA98XX_FLAG_REMOVE_PLOP_NOISE */ + + if (tfa98xx->flags & TFA98XX_FLAG_LP_MODES) + tfa_lp_mode_interrupt(tfa98xx->tfa); + /* TFA98XX_FLAG_LP_MODES */ + + /* unmask interrupts masked in IRQ handler */ + tfa_irq_unmask(tfa98xx->tfa); +} + +static int tfa98xx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + unsigned int sr; + int len, prof, nprof, idx = 0; + char *basename; + u64 formats; + int err; + + /* + * Support CODEC to CODEC links, + * these are called with a NULL runtime pointer. + */ + if (!substream->runtime) + return 0; + + if (pcm_no_constraint != 0) + return 0; + + switch (pcm_sample_format) { + case 1: + formats = SNDRV_PCM_FMTBIT_S24_LE; + break; + case 2: + formats = SNDRV_PCM_FMTBIT_S32_LE; + break; + default: + formats = SNDRV_PCM_FMTBIT_S16_LE; + break; + } + + err = snd_pcm_hw_constraint_mask64(substream->runtime, + SNDRV_PCM_HW_PARAM_FORMAT, formats); + if (err < 0) + return err; + + if (no_start != 0) + return 0; + + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { + dev_info(codec->dev, "Container file not loaded\n"); + return -EINVAL; + } + + basename = kzalloc(MAX_CONTROL_NAME, GFP_KERNEL); + if (!basename) + return -ENOMEM; + + /* copy profile name into basename until the . */ + get_profile_basename(basename, + tfa_cont_profile_name(tfa98xx, tfa98xx->profile)); + len = strlen(basename); + + /* loop over all profiles and get the supported samples rate(s) from + * the profiles with the same basename + */ + nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); + tfa98xx->rate_constraint.list = &tfa98xx->rate_constraint_list[0]; + tfa98xx->rate_constraint.count = 0; + for (prof = 0; prof < nprof; prof++) { + if (0 == strncmp(basename, tfa_cont_profile_name(tfa98xx, prof), + len)) { + /* Check which sample rate is supported with current profile, + * and enforce this. + */ + sr = tfa98xx_get_profile_sr(tfa98xx->tfa, prof); + if (!sr) + dev_info(codec->dev, "Unable to identify \ + supported sample rate\n"); + + if (tfa98xx->rate_constraint.count >= TFA98XX_NUM_RATES) { + dev_err(codec->dev, "too many sample rates\n"); + } else { + tfa98xx->rate_constraint_list[idx++] = sr; + tfa98xx->rate_constraint.count += 1; + } + } + } + + kfree(basename); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &tfa98xx->rate_constraint); +} + +static int tfa98xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec_dai->codec); + + tfa98xx->sysclk = freq; + return 0; +} + +static int tfa98xx_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + pr_debug("\n"); + return 0; +} + +static int tfa98xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(dai->codec); + struct snd_soc_codec *codec = dai->codec; + + pr_debug("fmt=0x%x\n", fmt); + + /* Supported mode: regular I2S, slave, or PDM */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + dev_err(codec->dev, "Invalid Codec master mode\n"); + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_PDM: + break; + default: + dev_err(codec->dev, "Unsupported DAI format %d\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + tfa98xx->audio_mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + + return 0; +} + +static int tfa98xx_get_fssel(unsigned int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rate_to_fssel); i++) { + if (rate_to_fssel[i].rate == rate) + return rate_to_fssel[i].fssel; + } + return -EINVAL; +} + +static int tfa98xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + unsigned int rate; + int prof_idx; + + /* Supported */ + rate = params_rate(params); + pr_debug("Requested rate: %d, sample size: %d, physical size: %d\n", + rate, snd_pcm_format_width(params_format(params)), + snd_pcm_format_physical_width(params_format(params))); + + if (no_start != 0) + return 0; + + /* check if samplerate is supported for this mixer profile */ + prof_idx = get_profile_id_for_sr(tfa98xx_mixer_profile, rate); + if (prof_idx < 0) { + pr_err("tfa98xx: invalid sample rate %d.\n", rate); + return -EINVAL; + } + pr_debug("mixer profile:container profile = [%d:%d]\n", + tfa98xx_mixer_profile, prof_idx); + + + /* update 'real' profile (container profile) */ + tfa98xx->profile = prof_idx; + + /* update to new rate */ + tfa98xx->rate = rate; + + return 0; +} + +static int tfa98xx_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + + dev_dbg(&tfa98xx->i2c->dev, "%s: state: %d\n", __func__, mute); + + if (no_start) { + pr_debug("no_start parameter set no tfa_dev_start or tfa_dev_stop, returning\n"); + return 0; + } + + if (mute) { + /* stop DSP only when both playback and capture streams + * are deactivated + */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + tfa98xx->pstream = 0; + else + tfa98xx->cstream = 0; + if (tfa98xx->pstream != 0 || tfa98xx->cstream != 0) + return 0; + + mutex_lock(&tfa98xx_mutex); + tfa98xx_sync_count = 0; + mutex_unlock(&tfa98xx_mutex); + + cancel_delayed_work_sync(&tfa98xx->monitor_work); + + cancel_delayed_work_sync(&tfa98xx->init_work); + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) + return 0; + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_stop(tfa98xx->tfa); + tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; + mutex_unlock(&tfa98xx->dsp_lock); + } else { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + tfa98xx->pstream = 1; + else + tfa98xx->cstream = 1; + + /* Start DSP */ +#if 1 + if (tfa98xx->dsp_init != TFA98XX_DSP_INIT_PENDING) + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->init_work, 0); +#else + tfa98xx_dsp_init(tfa98xx); +#endif// + } + + return 0; +} + +static const struct snd_soc_dai_ops tfa98xx_dai_ops = { + .startup = tfa98xx_startup, + .set_fmt = tfa98xx_set_fmt, + .set_sysclk = tfa98xx_set_dai_sysclk, + .set_tdm_slot = tfa98xx_set_tdm_slot, + .hw_params = tfa98xx_hw_params, + .mute_stream = tfa98xx_mute, +}; + +static struct snd_soc_dai_driver tfa98xx_dai[] = { + { + .name = "tfa98xx-aif", + .id = 1, + .playback = { + .stream_name = "AIF Playback", + .channels_min = 1, + .channels_max = 4, + .rates = TFA98XX_RATES, + .formats = TFA98XX_FORMATS, + }, + .capture = { + .stream_name = "AIF Capture", + .channels_min = 1, + .channels_max = 4, + .rates = TFA98XX_RATES, + .formats = TFA98XX_FORMATS, + }, + .ops = &tfa98xx_dai_ops, + .symmetric_rates = 1, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) + .symmetric_channels = 1, + .symmetric_samplebits = 1, +#endif + }, +}; + +static int tfa98xx_probe(struct snd_soc_codec *codec) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int ret; + + pr_debug("\n"); + + /* setup work queue, will be used to initial DSP on first boot up */ + tfa98xx->tfa98xx_wq = create_singlethread_workqueue("tfa98xx"); + if (!tfa98xx->tfa98xx_wq) + return -ENOMEM; + + INIT_DELAYED_WORK(&tfa98xx->init_work, tfa98xx_dsp_init_work); + INIT_DELAYED_WORK(&tfa98xx->monitor_work, tfa98xx_monitor); + INIT_DELAYED_WORK(&tfa98xx->interrupt_work, tfa98xx_interrupt); + INIT_DELAYED_WORK(&tfa98xx->tapdet_work, tfa98xx_tapdet_work); + + tfa98xx->codec = codec; + + ret = tfa98xx_load_container(tfa98xx); + pr_debug("Container loading requested: %d\n", ret); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) + codec->control_data = tfa98xx->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } +#endif + tfa98xx_add_widgets(tfa98xx); + + dev_info(codec->dev, "tfa98xx codec registered (%s)", + tfa98xx->fw.name); + + return ret; +} + +static int tfa98xx_remove(struct snd_soc_codec *codec) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + pr_debug("\n"); + + tfa98xx_interrupt_enable(tfa98xx, false); + + tfa98xx_inputdev_unregister(tfa98xx); + + cancel_delayed_work_sync(&tfa98xx->interrupt_work); + cancel_delayed_work_sync(&tfa98xx->monitor_work); + cancel_delayed_work_sync(&tfa98xx->init_work); + cancel_delayed_work_sync(&tfa98xx->tapdet_work); + + if (tfa98xx->tfa98xx_wq) + destroy_workqueue(tfa98xx->tfa98xx_wq); + + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) +static struct regmap *tfa98xx_get_regmap(struct device *dev) +{ + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + + return tfa98xx->regmap; +} +#endif +static struct snd_soc_codec_driver soc_codec_dev_tfa98xx = { + .probe = tfa98xx_probe, + .remove = tfa98xx_remove, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) + .get_regmap = tfa98xx_get_regmap, +#endif +}; + + +static bool tfa98xx_writeable_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +static bool tfa98xx_readable_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +static bool tfa98xx_volatile_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +static const struct regmap_config tfa98xx_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .max_register = TFA98XX_MAX_REGISTER, + .writeable_reg = tfa98xx_writeable_register, + .readable_reg = tfa98xx_readable_register, + .volatile_reg = tfa98xx_volatile_register, + .cache_type = REGCACHE_NONE, +}; + +static void tfa98xx_irq_tfa2(struct tfa98xx *tfa98xx) +{ + pr_info("\n"); + + /* + * mask interrupts + * will be unmasked after handling interrupts in workqueue + */ + tfa_irq_mask(tfa98xx->tfa); + queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->interrupt_work, 0); +} + + +static irqreturn_t tfa98xx_irq(int irq, void *data) +{ + struct tfa98xx *tfa98xx = data; + + if (tfa98xx->tfa->tfa_family == 2) + tfa98xx_irq_tfa2(tfa98xx); + + return IRQ_HANDLED; +} + +static int tfa98xx_ext_reset(struct tfa98xx *tfa98xx) +{ + if (tfa98xx && gpio_is_valid(tfa98xx->reset_gpio)) { + int reset = tfa98xx->reset_polarity; + + gpio_set_value_cansleep(tfa98xx->reset_gpio, reset); + mdelay(1); + gpio_set_value_cansleep(tfa98xx->reset_gpio, !reset); + mdelay(1); + } + return 0; +} + +static int tfa98xx_parse_dt(struct device *dev, struct tfa98xx *tfa98xx, + struct device_node *np) { + u32 value; + int ret; + + tfa98xx->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (tfa98xx->reset_gpio < 0) + dev_dbg(dev, "No reset GPIO provided, will not HW reset device\n"); + + tfa98xx->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (tfa98xx->irq_gpio < 0) + dev_dbg(dev, "No IRQ GPIO provided.\n"); + ret = of_property_read_u32(np, "reset-polarity", &value); + if (ret < 0) + tfa98xx->reset_polarity = HIGH; + else + tfa98xx->reset_polarity = (value == 0) ? LOW : HIGH; + + dev_dbg(dev, "reset-polarity:%d\n", tfa98xx->reset_polarity); + return 0; +} + +static ssize_t tfa98xx_reg_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + + if (count != 1) { + pr_debug("invalid register address"); + return -EINVAL; + } + + tfa98xx->reg = buf[0]; + + return 1; +} + +static ssize_t tfa98xx_rw_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + u8 *data; + int ret; + int retries = I2C_RETRIES; + + data = kmalloc(count + 1, GFP_KERNEL); + if (!data) { + pr_debug("can not allocate memory\n"); + return -ENOMEM; + } + + data[0] = tfa98xx->reg; + memcpy(&data[1], buf, count); + +retry: + ret = i2c_master_send(tfa98xx->i2c, data, count + 1); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + } + + kfree(data); + + /* the number of data bytes written without the register address */ + return ((ret > 1) ? count : -EIO); +} + +static ssize_t tfa98xx_rw_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + struct i2c_msg msgs[] = { + { + .addr = tfa98xx->i2c->addr, + .flags = 0, + .len = 1, + .buf = &tfa98xx->reg, + }, + { + .addr = tfa98xx->i2c->addr, + .flags = I2C_M_RD, + .len = count, + .buf = buf, + }, + }; + int ret; + int retries = I2C_RETRIES; +retry: + ret = i2c_transfer(tfa98xx->i2c->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + return ret; + } + /* ret contains the number of i2c transaction */ + /* return the number of bytes read */ + return ((ret > 1) ? count : -EIO); +} + +static struct bin_attribute dev_attr_rw = { + .attr = { + .name = "rw", + .mode = S_IRUSR | S_IWUSR, + }, + .size = 0, + .read = tfa98xx_rw_read, + .write = tfa98xx_rw_write, +}; + +static struct bin_attribute dev_attr_reg = { + .attr = { + .name = "reg", + .mode = S_IWUSR, + }, + .size = 0, + .read = NULL, + .write = tfa98xx_reg_write, +}; + +static int tfa98xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct snd_soc_dai_driver *dai; + struct tfa98xx *tfa98xx; + struct device_node *np = i2c->dev.of_node; + int irq_flags; + unsigned int reg; + int ret; + + pr_info("addr=0x%x\n", i2c->addr); + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_err(&i2c->dev, "check_functionality failed\n"); + return -EIO; + } + + tfa98xx = devm_kzalloc(&i2c->dev, sizeof(struct tfa98xx), GFP_KERNEL); + if (tfa98xx == NULL) + return -ENOMEM; + + tfa98xx->dev = &i2c->dev; + tfa98xx->i2c = i2c; + tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; + tfa98xx->rate = 48000; /* init to the default sample rate (48kHz) */ + tfa98xx->tfa = NULL; + + tfa98xx->regmap = devm_regmap_init_i2c(i2c, &tfa98xx_regmap); + if (IS_ERR(tfa98xx->regmap)) { + ret = PTR_ERR(tfa98xx->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + i2c_set_clientdata(i2c, tfa98xx); + mutex_init(&tfa98xx->dsp_lock); + init_waitqueue_head(&tfa98xx->wq); + + if (np) { + ret = tfa98xx_parse_dt(&i2c->dev, tfa98xx, np); + if (ret) { + dev_err(&i2c->dev, "Failed to parse DT node\n"); + return ret; + } + if (no_start) + tfa98xx->irq_gpio = -1; + if (no_reset) + tfa98xx->reset_gpio = -1; + } else { + tfa98xx->reset_gpio = -1; + tfa98xx->irq_gpio = -1; + } + + if (gpio_is_valid(tfa98xx->reset_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, tfa98xx->reset_gpio, + GPIOF_OUT_INIT_LOW, "TFA98XX_RST"); + if (ret) + return ret; + } + + if (gpio_is_valid(tfa98xx->irq_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, tfa98xx->irq_gpio, + GPIOF_DIR_IN, "TFA98XX_INT"); + if (ret) + return ret; + } + + /* Power up! */ + tfa98xx_ext_reset(tfa98xx); + + if ((no_start == 0) && (no_reset == 0)) { + ret = regmap_read(tfa98xx->regmap, 0x03, ®); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read Revision register: %d\n", + ret); + return -EIO; + } + switch (reg & 0xff) { + case 0x72: /* tfa9872 */ + pr_info("TFA9872 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; + tfa98xx->flags |= TFA98XX_FLAG_REMOVE_PLOP_NOISE; + /* tfa98xx->flags |= TFA98XX_FLAG_LP_MODES; */ + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x74: /* tfa9874 */ + pr_info("TFA9874 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x78: /* tfa9878 */ + pr_info("TFA9878 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x88: /* tfa9888 */ + pr_info("TFA9888 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_STEREO_DEVICE; + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x13: /* tfa9912 */ + pr_info("TFA9912 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + /* tfa98xx->flags |= TFA98XX_FLAG_TAPDET_AVAILABLE; */ + break; + case 0x94: /* tfa9894 */ + pr_info("TFA9894 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x80: /* tfa9890 */ + case 0x81: /* tfa9890 */ + pr_info("TFA9890 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + break; + case 0x92: /* tfa9891 */ + pr_info("TFA9891 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SAAM_AVAILABLE; + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + break; + case 0x12: /* tfa9895 */ + pr_info("TFA9895 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + break; + case 0x97: + pr_info("TFA9897 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x96: + pr_info("TFA9896 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + default: + pr_info("Unsupported device revision (0x%x)\n", reg & 0xff); + return -EINVAL; + } + } + + tfa98xx->tfa = devm_kzalloc(&i2c->dev, sizeof(struct tfa_device), + GFP_KERNEL); + if (tfa98xx->tfa == NULL) + return -ENOMEM; + + tfa98xx->tfa->data = (void *)tfa98xx; + tfa98xx->tfa->cachep = tfa98xx_cache; + + /* Modify the stream names, by appending the i2c device address. + * This is used with multicodec, in order to discriminate the devices. + * Stream names appear in the dai definition and in the stream. + * We create copies of original structures because each device will + * have its own instance of this structure, with its own address. + */ + dai = devm_kzalloc(&i2c->dev, sizeof(tfa98xx_dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + memcpy(dai, tfa98xx_dai, sizeof(tfa98xx_dai)); + + tfa98xx_append_i2c_address(&i2c->dev, + i2c, + NULL, + 0, + dai, + ARRAY_SIZE(tfa98xx_dai)); + + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_tfa98xx, dai, + ARRAY_SIZE(tfa98xx_dai)); + + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register TFA98xx: %d\n", ret); + return ret; + } + + if (gpio_is_valid(tfa98xx->irq_gpio) && + !(tfa98xx->flags & TFA98XX_FLAG_SKIP_INTERRUPTS)) { + /* register irq handler */ + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(tfa98xx->irq_gpio), + NULL, tfa98xx_irq, irq_flags, + "tfa98xx", tfa98xx); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", + gpio_to_irq(tfa98xx->irq_gpio), ret); + return ret; + } + } else { + dev_info(&i2c->dev, "Skipping IRQ registration\n"); + /* disable feature support if gpio was invalid */ + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + } + +#ifdef CONFIG_DEBUG_FS + if (no_start == 0) + tfa98xx_debug_init(tfa98xx, i2c); +#endif + /* Register the sysfs files for climax backdoor access */ + ret = device_create_bin_file(&i2c->dev, &dev_attr_rw); + if (ret) + dev_info(&i2c->dev, "error creating sysfs files\n"); + ret = device_create_bin_file(&i2c->dev, &dev_attr_reg); + if (ret) + dev_info(&i2c->dev, "error creating sysfs files\n"); + + pr_info("%s Probe completed successfully!\n", __func__); + + INIT_LIST_HEAD(&tfa98xx->list); + + mutex_lock(&tfa98xx_mutex); + tfa98xx_device_count++; + list_add(&tfa98xx->list, &tfa98xx_device_list); + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_i2c_remove(struct i2c_client *i2c) +{ + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + + pr_debug("addr=0x%x\n", i2c->addr); + + tfa98xx_interrupt_enable(tfa98xx, false); + + cancel_delayed_work_sync(&tfa98xx->interrupt_work); + cancel_delayed_work_sync(&tfa98xx->monitor_work); + cancel_delayed_work_sync(&tfa98xx->init_work); + cancel_delayed_work_sync(&tfa98xx->tapdet_work); + + device_remove_bin_file(&i2c->dev, &dev_attr_reg); + device_remove_bin_file(&i2c->dev, &dev_attr_rw); +#ifdef CONFIG_DEBUG_FS + tfa98xx_debug_remove(tfa98xx); +#endif + + snd_soc_unregister_codec(&i2c->dev); + + if (gpio_is_valid(tfa98xx->irq_gpio)) + devm_gpio_free(&i2c->dev, tfa98xx->irq_gpio); + if (gpio_is_valid(tfa98xx->reset_gpio)) + devm_gpio_free(&i2c->dev, tfa98xx->reset_gpio); + + mutex_lock(&tfa98xx_mutex); + list_del(&tfa98xx->list); + tfa98xx_device_count--; + if (tfa98xx_device_count == 0) { + kfree(tfa98xx_container); + tfa98xx_container = NULL; + } + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static const struct i2c_device_id tfa98xx_i2c_id[] = { + { "tfa98xx", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tfa98xx_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id tfa98xx_dt_match[] = { + {.compatible = "nxp,tfa98xx" }, + {.compatible = "nxp,tfa9872" }, + {.compatible = "nxp,tfa9874" }, + {.compatible = "nxp,tfa9878" }, + {.compatible = "nxp,tfa9888" }, + {.compatible = "nxp,tfa9890" }, + {.compatible = "nxp,tfa9891" }, + {.compatible = "nxp,tfa9894" }, + {.compatible = "nxp,tfa9895" }, + {.compatible = "nxp,tfa9896" }, + {.compatible = "nxp,tfa9897" }, + {.compatible = "nxp,tfa9912" }, + { }, +}; +#endif + +static struct i2c_driver tfa98xx_i2c_driver = { + .driver = { + .name = "tfa98xx", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tfa98xx_dt_match), + }, + .probe = tfa98xx_i2c_probe, + .remove = tfa98xx_i2c_remove, + .id_table = tfa98xx_i2c_id, +}; + +static int __init tfa98xx_i2c_init(void) +{ + int ret = 0; + + pr_info("TFA98XX driver version %s\n", TFA98XX_VERSION); + + /* Enable debug traces */ + tfa98xx_kmsg_regs = trace_level & 2; + tfa98xx_ftrace_regs = trace_level & 4; + + /* Initialize kmem_cache */ + /* Cache name /proc/slabinfo */ + tfa98xx_cache = kmem_cache_create("tfa98xx_cache", + PAGE_SIZE, /* Structure size, we should fit in single page */ + 0, /* Structure alignment */ + (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | + SLAB_MEM_SPREAD), /* Cache property */ + NULL); /* Object constructor */ + if (!tfa98xx_cache) { + pr_err("tfa98xx can't create memory pool\n"); + ret = -ENOMEM; + } + + ret = i2c_add_driver(&tfa98xx_i2c_driver); + + return ret; +} +module_init(tfa98xx_i2c_init); + +static void __exit tfa98xx_i2c_exit(void) +{ + i2c_del_driver(&tfa98xx_i2c_driver); + kmem_cache_destroy(tfa98xx_cache); +} +module_exit(tfa98xx_i2c_exit); + +MODULE_DESCRIPTION("ASoC TFA98XX driver"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/codecs/tfa98xx.h b/sound/soc/codecs/tfa98xx.h new file mode 100644 index 0000000000000000000000000000000000000000..3ba367ad867960f9bd3d4aa400aaa903d99e5613 --- /dev/null +++ b/sound/soc/codecs/tfa98xx.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef __TFA98XX_INC__ +#define __TFA98XX_INC__ + +#include +#include +#include + +#include "tfa_device.h" +#include "tfa_container.h" +#include "config.h" + +/* max. length of a alsa mixer control name */ +#define MAX_CONTROL_NAME 48 + +#define TFA98XX_MAX_REGISTER 0xff + +#define TFA98XX_FLAG_SKIP_INTERRUPTS (1 << 0) +#define TFA98XX_FLAG_SAAM_AVAILABLE (1 << 1) +#define TFA98XX_FLAG_STEREO_DEVICE (1 << 2) +#define TFA98XX_FLAG_MULTI_MIC_INPUTS (1 << 3) +#define TFA98XX_FLAG_TAPDET_AVAILABLE (1 << 4) +#define TFA98XX_FLAG_CALIBRATION_CTL (1 << 5) +#define TFA98XX_FLAG_REMOVE_PLOP_NOISE (1 << 6) +#define TFA98XX_FLAG_LP_MODES (1 << 7) +#define TFA98XX_FLAG_TDM_DEVICE (1 << 8) + +#define TFA98XX_NUM_RATES 9 + +/* DSP init status */ +enum tfa98xx_dsp_init_state { + TFA98XX_DSP_INIT_STOPPED, /* DSP not running */ + TFA98XX_DSP_INIT_RECOVER, /* DSP error detected at runtime */ + TFA98XX_DSP_INIT_FAIL, /* DSP init failed */ + TFA98XX_DSP_INIT_PENDING, /* DSP start requested */ + TFA98XX_DSP_INIT_DONE, /* DSP running */ + TFA98XX_DSP_INIT_INVALIDATED, /* DSP was running, requires re-init */ +}; + +enum tfa98xx_dsp_fw_state { + TFA98XX_DSP_FW_NONE = 0, + TFA98XX_DSP_FW_PENDING, + TFA98XX_DSP_FW_FAIL, + TFA98XX_DSP_FW_OK, +}; + +struct tfa98xx_firmware { + void *base; + struct tfa98xx_device *dev; + char name[9]; //TODO get length from tfa parameter defs +}; + +struct tfa98xx_baseprofile { + char basename[MAX_CONTROL_NAME]; /* profile basename */ + int len; /* profile length */ + int item_id; /* profile id */ + int sr_rate_sup[TFA98XX_NUM_RATES]; /* sample rates supported by this profile */ + struct list_head list; /* list of all profiles */ +}; +enum tfa_reset_polarity{ + LOW = 0, + HIGH = 1 +}; +struct tfa98xx { + struct regmap *regmap; + struct i2c_client *i2c; + struct regulator *vdd; + struct snd_soc_codec *codec; + struct workqueue_struct *tfa98xx_wq; + struct delayed_work init_work; + struct delayed_work monitor_work; + struct delayed_work interrupt_work; + struct delayed_work tapdet_work; + struct mutex dsp_lock; + int dsp_init; + int dsp_fw_state; + int sysclk; + int rst_gpio; + u16 rev; + int audio_mode; + struct tfa98xx_firmware fw; + char *fw_name; + int rate; + wait_queue_head_t wq; + struct device *dev; + unsigned int init_count; + int pstream; + int cstream; + struct input_dev *input; + bool tapdet_enabled; /* service enabled */ + bool tapdet_open; /* device file opened */ + unsigned int tapdet_profiles; /* tapdet profile bitfield */ + bool tapdet_poll; /* tapdet running on polling mode */ + + unsigned int rate_constraint_list[TFA98XX_NUM_RATES]; + struct snd_pcm_hw_constraint_list rate_constraint; + + int reset_gpio; + int power_gpio; + int irq_gpio; + enum tfa_reset_polarity reset_polarity; + struct list_head list; + struct tfa_device *tfa; + int vstep; + int profile; + int prof_vsteps[TFACONT_MAXPROFS]; /* store vstep per profile (single device) */ + +#ifdef CONFIG_DEBUG_FS + struct dentry *dbg_dir; +#endif + u8 reg; + unsigned int flags; + bool set_mtp_cal; + uint16_t cal_data; +}; + + +#endif /* __TFA98XX_INC__ */ + diff --git a/sound/soc/codecs/tfa98xx_genregs_N1C.h b/sound/soc/codecs/tfa98xx_genregs_N1C.h new file mode 100644 index 0000000000000000000000000000000000000000..eb1e1ad581b4158291d375630f8b15328eab4212 --- /dev/null +++ b/sound/soc/codecs/tfa98xx_genregs_N1C.h @@ -0,0 +1,3857 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA2_GENREGS_H +#define TFA2_GENREGS_H + + +#define TFA98XX_SYS_CONTROL0 0x00 +#define TFA98XX_SYS_CONTROL1 0x01 +#define TFA98XX_SYS_CONTROL2 0x02 +#define TFA98XX_DEVICE_REVISION 0x03 +#define TFA98XX_CLOCK_CONTROL 0x04 +#define TFA98XX_CLOCK_GATING_CONTROL 0x05 +#define TFA98XX_SIDE_TONE_CONFIG 0x0d +#define TFA98XX_CTRL_DIGTOANA_REG 0x0e +#define TFA98XX_STATUS_FLAGS0 0x10 +#define TFA98XX_STATUS_FLAGS1 0x11 +#define TFA98XX_STATUS_FLAGS2 0x12 +#define TFA98XX_STATUS_FLAGS3 0x13 +#define TFA98XX_STATUS_FLAGS4 0x14 +#define TFA98XX_BATTERY_VOLTAGE 0x15 +#define TFA98XX_TEMPERATURE 0x16 +#define TFA98XX_TDM_CONFIG0 0x20 +#define TFA98XX_TDM_CONFIG1 0x21 +#define TFA98XX_TDM_CONFIG2 0x22 +#define TFA98XX_TDM_CONFIG3 0x23 +#define TFA98XX_TDM_CONFIG4 0x24 +#define TFA98XX_TDM_CONFIG5 0x25 +#define TFA98XX_TDM_CONFIG6 0x26 +#define TFA98XX_TDM_CONFIG7 0x27 +#define TFA98XX_TDM_CONFIG8 0x28 +#define TFA98XX_TDM_CONFIG9 0x29 +#define TFA98XX_PDM_CONFIG0 0x31 +#define TFA98XX_PDM_CONFIG1 0x32 +#define TFA98XX_HAPTIC_DRIVER_CONFIG 0x33 +#define TFA98XX_GPIO_DATAIN_REG 0x34 +#define TFA98XX_GPIO_CONFIG 0x35 +#define TFA98XX_INTERRUPT_OUT_REG1 0x40 +#define TFA98XX_INTERRUPT_OUT_REG2 0x41 +#define TFA98XX_INTERRUPT_OUT_REG3 0x42 +#define TFA98XX_INTERRUPT_IN_REG1 0x44 +#define TFA98XX_INTERRUPT_IN_REG2 0x45 +#define TFA98XX_INTERRUPT_IN_REG3 0x46 +#define TFA98XX_INTERRUPT_ENABLE_REG1 0x48 +#define TFA98XX_INTERRUPT_ENABLE_REG2 0x49 +#define TFA98XX_INTERRUPT_ENABLE_REG3 0x4a +#define TFA98XX_STATUS_POLARITY_REG1 0x4c +#define TFA98XX_STATUS_POLARITY_REG2 0x4d +#define TFA98XX_STATUS_POLARITY_REG3 0x4e +#define TFA98XX_BAT_PROT_CONFIG 0x50 +#define TFA98XX_AUDIO_CONTROL 0x51 +#define TFA98XX_AMPLIFIER_CONFIG 0x52 +#define TFA98XX_AUDIO_CONTROL2 0x5a +#define TFA98XX_DCDC_CONTROL0 0x70 +#define TFA98XX_CF_CONTROLS 0x90 +#define TFA98XX_CF_MAD 0x91 +#define TFA98XX_CF_MEM 0x92 +#define TFA98XX_CF_STATUS 0x93 +#define TFA98XX_MTPKEY2_REG 0xa1 +#define TFA98XX_MTP_STATUS 0xa2 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL 0xa3 +#define TFA98XX_MTP_DATA_OUT_MSB 0xa5 +#define TFA98XX_MTP_DATA_OUT_LSB 0xa6 +#define TFA98XX_TEMP_SENSOR_CONFIG 0xb1 +#define TFA98XX_KEY2_PROTECTED_MTP0 0xf0 +#define TFA98XX_KEY1_PROTECTED_MTP4 0xf4 +#define TFA98XX_KEY1_PROTECTED_MTP5 0xf5 + +/* + * (0x00)-sys_control0 + */ + +/* + * powerdown + */ +#define TFA98XX_SYS_CONTROL0_PWDN (0x1<<0) +#define TFA98XX_SYS_CONTROL0_PWDN_POS 0 +#define TFA98XX_SYS_CONTROL0_PWDN_LEN 1 +#define TFA98XX_SYS_CONTROL0_PWDN_MAX 1 +#define TFA98XX_SYS_CONTROL0_PWDN_MSK 0x1 + +/* + * reset + */ +#define TFA98XX_SYS_CONTROL0_I2CR (0x1<<1) +#define TFA98XX_SYS_CONTROL0_I2CR_POS 1 +#define TFA98XX_SYS_CONTROL0_I2CR_LEN 1 +#define TFA98XX_SYS_CONTROL0_I2CR_MAX 1 +#define TFA98XX_SYS_CONTROL0_I2CR_MSK 0x2 + +/* + * enbl_coolflux + */ +#define TFA98XX_SYS_CONTROL0_CFE (0x1<<2) +#define TFA98XX_SYS_CONTROL0_CFE_POS 2 +#define TFA98XX_SYS_CONTROL0_CFE_LEN 1 +#define TFA98XX_SYS_CONTROL0_CFE_MAX 1 +#define TFA98XX_SYS_CONTROL0_CFE_MSK 0x4 + +/* + * enbl_amplifier + */ +#define TFA98XX_SYS_CONTROL0_AMPE (0x1<<3) +#define TFA98XX_SYS_CONTROL0_AMPE_POS 3 +#define TFA98XX_SYS_CONTROL0_AMPE_LEN 1 +#define TFA98XX_SYS_CONTROL0_AMPE_MAX 1 +#define TFA98XX_SYS_CONTROL0_AMPE_MSK 0x8 + +/* + * enbl_boost + */ +#define TFA98XX_SYS_CONTROL0_DCA (0x1<<4) +#define TFA98XX_SYS_CONTROL0_DCA_POS 4 +#define TFA98XX_SYS_CONTROL0_DCA_LEN 1 +#define TFA98XX_SYS_CONTROL0_DCA_MAX 1 +#define TFA98XX_SYS_CONTROL0_DCA_MSK 0x10 + +/* + * coolflux_configured + */ +#define TFA98XX_SYS_CONTROL0_SBSL (0x1<<5) +#define TFA98XX_SYS_CONTROL0_SBSL_POS 5 +#define TFA98XX_SYS_CONTROL0_SBSL_LEN 1 +#define TFA98XX_SYS_CONTROL0_SBSL_MAX 1 +#define TFA98XX_SYS_CONTROL0_SBSL_MSK 0x20 + +/* + * sel_enbl_amplifier + */ +#define TFA98XX_SYS_CONTROL0_AMPC (0x1<<6) +#define TFA98XX_SYS_CONTROL0_AMPC_POS 6 +#define TFA98XX_SYS_CONTROL0_AMPC_LEN 1 +#define TFA98XX_SYS_CONTROL0_AMPC_MAX 1 +#define TFA98XX_SYS_CONTROL0_AMPC_MSK 0x40 + +/* + * int_pad_io + */ +#define TFA98XX_SYS_CONTROL0_INTP (0x3<<7) +#define TFA98XX_SYS_CONTROL0_INTP_POS 7 +#define TFA98XX_SYS_CONTROL0_INTP_LEN 2 +#define TFA98XX_SYS_CONTROL0_INTP_MAX 3 +#define TFA98XX_SYS_CONTROL0_INTP_MSK 0x180 + +/* + * fs_pulse_sel + */ +#define TFA98XX_SYS_CONTROL0_FSSSEL (0x3<<9) +#define TFA98XX_SYS_CONTROL0_FSSSEL_POS 9 +#define TFA98XX_SYS_CONTROL0_FSSSEL_LEN 2 +#define TFA98XX_SYS_CONTROL0_FSSSEL_MAX 3 +#define TFA98XX_SYS_CONTROL0_FSSSEL_MSK 0x600 + +/* + * bypass_ocp + */ +#define TFA98XX_SYS_CONTROL0_BYPOCP (0x1<<11) +#define TFA98XX_SYS_CONTROL0_BYPOCP_POS 11 +#define TFA98XX_SYS_CONTROL0_BYPOCP_LEN 1 +#define TFA98XX_SYS_CONTROL0_BYPOCP_MAX 1 +#define TFA98XX_SYS_CONTROL0_BYPOCP_MSK 0x800 + +/* + * test_ocp + */ +#define TFA98XX_SYS_CONTROL0_TSTOCP (0x1<<12) +#define TFA98XX_SYS_CONTROL0_TSTOCP_POS 12 +#define TFA98XX_SYS_CONTROL0_TSTOCP_LEN 1 +#define TFA98XX_SYS_CONTROL0_TSTOCP_MAX 1 +#define TFA98XX_SYS_CONTROL0_TSTOCP_MSK 0x1000 + + +/* + * (0x01)-sys_control1 + */ + +/* + * vamp_sel + */ +#define TFA98XX_SYS_CONTROL1_AMPINSEL (0x3<<0) +#define TFA98XX_SYS_CONTROL1_AMPINSEL_POS 0 +#define TFA98XX_SYS_CONTROL1_AMPINSEL_LEN 2 +#define TFA98XX_SYS_CONTROL1_AMPINSEL_MAX 3 +#define TFA98XX_SYS_CONTROL1_AMPINSEL_MSK 0x3 + +/* + * src_set_configured + */ +#define TFA98XX_SYS_CONTROL1_MANSCONF (0x1<<2) +#define TFA98XX_SYS_CONTROL1_MANSCONF_POS 2 +#define TFA98XX_SYS_CONTROL1_MANSCONF_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANSCONF_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANSCONF_MSK 0x4 + +/* + * execute_cold_start + */ +#define TFA98XX_SYS_CONTROL1_MANCOLD (0x1<<3) +#define TFA98XX_SYS_CONTROL1_MANCOLD_POS 3 +#define TFA98XX_SYS_CONTROL1_MANCOLD_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANCOLD_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANCOLD_MSK 0x8 + +/* + * enbl_osc1m_auto_off + */ +#define TFA98XX_SYS_CONTROL1_MANAOOSC (0x1<<4) +#define TFA98XX_SYS_CONTROL1_MANAOOSC_POS 4 +#define TFA98XX_SYS_CONTROL1_MANAOOSC_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANAOOSC_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANAOOSC_MSK 0x10 + +/* + * man_enbl_brown_out + */ +#define TFA98XX_SYS_CONTROL1_MANROBOD (0x1<<5) +#define TFA98XX_SYS_CONTROL1_MANROBOD_POS 5 +#define TFA98XX_SYS_CONTROL1_MANROBOD_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANROBOD_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANROBOD_MSK 0x20 + +/* + * enbl_bod + */ +#define TFA98XX_SYS_CONTROL1_BODE (0x1<<6) +#define TFA98XX_SYS_CONTROL1_BODE_POS 6 +#define TFA98XX_SYS_CONTROL1_BODE_LEN 1 +#define TFA98XX_SYS_CONTROL1_BODE_MAX 1 +#define TFA98XX_SYS_CONTROL1_BODE_MSK 0x40 + +/* + * enbl_bod_hyst + */ +#define TFA98XX_SYS_CONTROL1_BODHYS (0x1<<7) +#define TFA98XX_SYS_CONTROL1_BODHYS_POS 7 +#define TFA98XX_SYS_CONTROL1_BODHYS_LEN 1 +#define TFA98XX_SYS_CONTROL1_BODHYS_MAX 1 +#define TFA98XX_SYS_CONTROL1_BODHYS_MSK 0x80 + +/* + * bod_delay + */ +#define TFA98XX_SYS_CONTROL1_BODFILT (0x3<<8) +#define TFA98XX_SYS_CONTROL1_BODFILT_POS 8 +#define TFA98XX_SYS_CONTROL1_BODFILT_LEN 2 +#define TFA98XX_SYS_CONTROL1_BODFILT_MAX 3 +#define TFA98XX_SYS_CONTROL1_BODFILT_MSK 0x300 + +/* + * bod_lvlsel + */ +#define TFA98XX_SYS_CONTROL1_BODTHLVL (0x3<<10) +#define TFA98XX_SYS_CONTROL1_BODTHLVL_POS 10 +#define TFA98XX_SYS_CONTROL1_BODTHLVL_LEN 2 +#define TFA98XX_SYS_CONTROL1_BODTHLVL_MAX 3 +#define TFA98XX_SYS_CONTROL1_BODTHLVL_MSK 0xc00 + +/* + * disable_mute_time_out + */ +#define TFA98XX_SYS_CONTROL1_MUTETO (0x1<<13) +#define TFA98XX_SYS_CONTROL1_MUTETO_POS 13 +#define TFA98XX_SYS_CONTROL1_MUTETO_LEN 1 +#define TFA98XX_SYS_CONTROL1_MUTETO_MAX 1 +#define TFA98XX_SYS_CONTROL1_MUTETO_MSK 0x2000 + +/* + * pwm_sel_rcv_ns + */ +#define TFA98XX_SYS_CONTROL1_RCVNS (0x1<<14) +#define TFA98XX_SYS_CONTROL1_RCVNS_POS 14 +#define TFA98XX_SYS_CONTROL1_RCVNS_LEN 1 +#define TFA98XX_SYS_CONTROL1_RCVNS_MAX 1 +#define TFA98XX_SYS_CONTROL1_RCVNS_MSK 0x4000 + +/* + * man_enbl_watchdog + */ +#define TFA98XX_SYS_CONTROL1_MANWDE (0x1<<15) +#define TFA98XX_SYS_CONTROL1_MANWDE_POS 15 +#define TFA98XX_SYS_CONTROL1_MANWDE_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANWDE_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANWDE_MSK 0x8000 + + +/* + * (0x02)-sys_control2 + */ + +/* + * audio_fs + */ +#define TFA98XX_SYS_CONTROL2_AUDFS (0xf<<0) +#define TFA98XX_SYS_CONTROL2_AUDFS_POS 0 +#define TFA98XX_SYS_CONTROL2_AUDFS_LEN 4 +#define TFA98XX_SYS_CONTROL2_AUDFS_MAX 15 +#define TFA98XX_SYS_CONTROL2_AUDFS_MSK 0xf + +/* + * input_level + */ +#define TFA98XX_SYS_CONTROL2_INPLEV (0x1<<4) +#define TFA98XX_SYS_CONTROL2_INPLEV_POS 4 +#define TFA98XX_SYS_CONTROL2_INPLEV_LEN 1 +#define TFA98XX_SYS_CONTROL2_INPLEV_MAX 1 +#define TFA98XX_SYS_CONTROL2_INPLEV_MSK 0x10 + +/* + * cs_frac_delay + */ +#define TFA98XX_SYS_CONTROL2_FRACTDEL (0x3f<<5) +#define TFA98XX_SYS_CONTROL2_FRACTDEL_POS 5 +#define TFA98XX_SYS_CONTROL2_FRACTDEL_LEN 6 +#define TFA98XX_SYS_CONTROL2_FRACTDEL_MAX 63 +#define TFA98XX_SYS_CONTROL2_FRACTDEL_MSK 0x7e0 + +/* + * bypass_hvbat_filter + */ +#define TFA98XX_SYS_CONTROL2_BYPHVBF (0x1<<11) +#define TFA98XX_SYS_CONTROL2_BYPHVBF_POS 11 +#define TFA98XX_SYS_CONTROL2_BYPHVBF_LEN 1 +#define TFA98XX_SYS_CONTROL2_BYPHVBF_MAX 1 +#define TFA98XX_SYS_CONTROL2_BYPHVBF_MSK 0x800 + +/* + * ctrl_rcvldop_bypass + */ +#define TFA98XX_SYS_CONTROL2_LDOBYP (0x1<<12) +#define TFA98XX_SYS_CONTROL2_LDOBYP_POS 12 +#define TFA98XX_SYS_CONTROL2_LDOBYP_LEN 1 +#define TFA98XX_SYS_CONTROL2_LDOBYP_MAX 1 +#define TFA98XX_SYS_CONTROL2_LDOBYP_MSK 0x1000 + + +/* + * (0x03)-device_revision + */ + +/* + * device_rev + */ +#define TFA98XX_DEVICE_REVISION_REV (0xffff<<0) +#define TFA98XX_DEVICE_REVISION_REV_POS 0 +#define TFA98XX_DEVICE_REVISION_REV_LEN 16 +#define TFA98XX_DEVICE_REVISION_REV_MAX 65535 +#define TFA98XX_DEVICE_REVISION_REV_MSK 0xffff + + +/* + * (0x04)-clock_control + */ + +/* + * pll_clkin_sel + */ +#define TFA98XX_CLOCK_CONTROL_REFCKEXT (0x3<<0) +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_POS 0 +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_LEN 2 +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_MAX 3 +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_MSK 0x3 + +/* + * pll_clkin_sel_osc + */ +#define TFA98XX_CLOCK_CONTROL_REFCKSEL (0x1<<2) +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_POS 2 +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_LEN 1 +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_MAX 1 +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_MSK 0x4 + + +/* + * (0x05)-clock_gating_control + */ + +/* + * enbl_spkr_ss_left + */ +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE (0x1<<0) +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_POS 0 +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_MSK 0x1 + +/* + * enbl_spkr_ss_right + */ +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE (0x1<<1) +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_POS 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_MSK 0x2 + +/* + * enbl_volsense_left + */ +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE (0x1<<2) +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_POS 2 +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_MSK 0x4 + +/* + * enbl_volsense_right + */ +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE (0x1<<3) +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_POS 3 +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_MSK 0x8 + +/* + * enbl_cursense_left + */ +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE (0x1<<4) +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_POS 4 +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_MSK 0x10 + +/* + * enbl_cursense_right + */ +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE (0x1<<5) +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_POS 5 +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_MSK 0x20 + +/* + * enbl_pdm_ss + */ +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME (0x1<<6) +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_POS 6 +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_MSK 0x40 + + +/* + * (0x0d)-side_tone_config + */ + +/* + * side_tone_gain + */ +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN (0x1ff<<1) +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_POS 1 +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_LEN 9 +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_MAX 511 +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_MSK 0x3fe + +/* + * mute_side_tone + */ +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE (0x1<<10) +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_POS 10 +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_LEN 1 +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_MAX 1 +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_MSK 0x400 + + +/* + * (0x0e)-ctrl_digtoana_reg + */ + +/* + * ctrl_digtoana + */ +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP (0x7f<<0) +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_POS 0 +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_LEN 7 +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_MAX 127 +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_MSK 0x7f + + +/* + * (0x10)-status_flags0 + */ + +/* + * flag_por + */ +#define TFA98XX_STATUS_FLAGS0_VDDS (0x1<<0) +#define TFA98XX_STATUS_FLAGS0_VDDS_POS 0 +#define TFA98XX_STATUS_FLAGS0_VDDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_VDDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_VDDS_MSK 0x1 + +/* + * flag_pll_lock + */ +#define TFA98XX_STATUS_FLAGS0_PLLS (0x1<<1) +#define TFA98XX_STATUS_FLAGS0_PLLS_POS 1 +#define TFA98XX_STATUS_FLAGS0_PLLS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_PLLS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_PLLS_MSK 0x2 + +/* + * flag_otpok + */ +#define TFA98XX_STATUS_FLAGS0_OTDS (0x1<<2) +#define TFA98XX_STATUS_FLAGS0_OTDS_POS 2 +#define TFA98XX_STATUS_FLAGS0_OTDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_OTDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_OTDS_MSK 0x4 + +/* + * flag_ovpok + */ +#define TFA98XX_STATUS_FLAGS0_OVDS (0x1<<3) +#define TFA98XX_STATUS_FLAGS0_OVDS_POS 3 +#define TFA98XX_STATUS_FLAGS0_OVDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_OVDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_OVDS_MSK 0x8 + +/* + * flag_uvpok + */ +#define TFA98XX_STATUS_FLAGS0_UVDS (0x1<<4) +#define TFA98XX_STATUS_FLAGS0_UVDS_POS 4 +#define TFA98XX_STATUS_FLAGS0_UVDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_UVDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_UVDS_MSK 0x10 + +/* + * flag_clocks_stable + */ +#define TFA98XX_STATUS_FLAGS0_CLKS (0x1<<6) +#define TFA98XX_STATUS_FLAGS0_CLKS_POS 5 +#define TFA98XX_STATUS_FLAGS0_CLKS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_CLKS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_CLKS_MSK 0x20 + +/* + * flag_mtp_busy + */ +#define TFA98XX_STATUS_FLAGS0_MTPB (0x1<<6) +#define TFA98XX_STATUS_FLAGS0_MTPB_POS 6 +#define TFA98XX_STATUS_FLAGS0_MTPB_LEN 1 +#define TFA98XX_STATUS_FLAGS0_MTPB_MAX 1 +#define TFA98XX_STATUS_FLAGS0_MTPB_MSK 0x40 + +/* + * flag_lost_clk + */ +#define TFA98XX_STATUS_FLAGS0_NOCLK (0x1<<7) +#define TFA98XX_STATUS_FLAGS0_NOCLK_POS 7 +#define TFA98XX_STATUS_FLAGS0_NOCLK_LEN 1 +#define TFA98XX_STATUS_FLAGS0_NOCLK_MAX 1 +#define TFA98XX_STATUS_FLAGS0_NOCLK_MSK 0x80 + +/* + * flag_cf_speakererror + */ +#define TFA98XX_STATUS_FLAGS0_SPKS (0x1<<8) +#define TFA98XX_STATUS_FLAGS0_SPKS_POS 8 +#define TFA98XX_STATUS_FLAGS0_SPKS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_SPKS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_SPKS_MSK 0x100 + +/* + * flag_cold_started + */ +#define TFA98XX_STATUS_FLAGS0_ACS (0x1<<9) +#define TFA98XX_STATUS_FLAGS0_ACS_POS 9 +#define TFA98XX_STATUS_FLAGS0_ACS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_ACS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_ACS_MSK 0x200 + +/* + * flag_engage + */ +#define TFA98XX_STATUS_FLAGS0_SWS (0x1<<10) +#define TFA98XX_STATUS_FLAGS0_SWS_POS 10 +#define TFA98XX_STATUS_FLAGS0_SWS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_SWS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_SWS_MSK 0x400 + +/* + * flag_watchdog_reset + */ +#define TFA98XX_STATUS_FLAGS0_WDS (0x1<<11) +#define TFA98XX_STATUS_FLAGS0_WDS_POS 11 +#define TFA98XX_STATUS_FLAGS0_WDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_WDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_WDS_MSK 0x800 + +/* + * flag_enbl_amp + */ +#define TFA98XX_STATUS_FLAGS0_AMPS (0x1<<12) +#define TFA98XX_STATUS_FLAGS0_AMPS_POS 12 +#define TFA98XX_STATUS_FLAGS0_AMPS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_AMPS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_AMPS_MSK 0x1000 + +/* + * flag_enbl_ref + */ +#define TFA98XX_STATUS_FLAGS0_AREFS (0x1<<13) +#define TFA98XX_STATUS_FLAGS0_AREFS_POS 13 +#define TFA98XX_STATUS_FLAGS0_AREFS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_AREFS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_AREFS_MSK 0x2000 + +/* + * flag_adc10_ready + */ +#define TFA98XX_STATUS_FLAGS0_ADCCR (0x1<<14) +#define TFA98XX_STATUS_FLAGS0_ADCCR_POS 14 +#define TFA98XX_STATUS_FLAGS0_ADCCR_LEN 1 +#define TFA98XX_STATUS_FLAGS0_ADCCR_MAX 1 +#define TFA98XX_STATUS_FLAGS0_ADCCR_MSK 0x4000 + +/* + * flag_bod_vddd_nok + */ +#define TFA98XX_STATUS_FLAGS0_BODNOK (0x1<<15) +#define TFA98XX_STATUS_FLAGS0_BODNOK_POS 15 +#define TFA98XX_STATUS_FLAGS0_BODNOK_LEN 1 +#define TFA98XX_STATUS_FLAGS0_BODNOK_MAX 1 +#define TFA98XX_STATUS_FLAGS0_BODNOK_MSK 0x8000 + + +/* + * (0x11)-status_flags1 + */ + +/* + * flag_bst_bstcur + */ +#define TFA98XX_STATUS_FLAGS1_DCIL (0x1<<0) +#define TFA98XX_STATUS_FLAGS1_DCIL_POS 0 +#define TFA98XX_STATUS_FLAGS1_DCIL_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCIL_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCIL_MSK 0x1 + +/* + * flag_bst_hiz + */ +#define TFA98XX_STATUS_FLAGS1_DCDCA (0x1<<1) +#define TFA98XX_STATUS_FLAGS1_DCDCA_POS 1 +#define TFA98XX_STATUS_FLAGS1_DCDCA_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCDCA_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCDCA_MSK 0x2 + +/* + * flag_bst_ocpok + */ +#define TFA98XX_STATUS_FLAGS1_DCOCPOK (0x1<<2) +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_POS 2 +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_MSK 0x4 + +/* + * flag_bst_voutcomp + */ +#define TFA98XX_STATUS_FLAGS1_DCHVBAT (0x1<<4) +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_POS 4 +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_MSK 0x10 + +/* + * flag_bst_voutcomp86 + */ +#define TFA98XX_STATUS_FLAGS1_DCH114 (0x1<<5) +#define TFA98XX_STATUS_FLAGS1_DCH114_POS 5 +#define TFA98XX_STATUS_FLAGS1_DCH114_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCH114_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCH114_MSK 0x20 + +/* + * flag_bst_voutcomp93 + */ +#define TFA98XX_STATUS_FLAGS1_DCH107 (0x1<<6) +#define TFA98XX_STATUS_FLAGS1_DCH107_POS 6 +#define TFA98XX_STATUS_FLAGS1_DCH107_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCH107_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCH107_MSK 0x40 + +/* + * flag_soft_mute_busy + */ +#define TFA98XX_STATUS_FLAGS1_STMUTEB (0x1<<7) +#define TFA98XX_STATUS_FLAGS1_STMUTEB_POS 7 +#define TFA98XX_STATUS_FLAGS1_STMUTEB_LEN 1 +#define TFA98XX_STATUS_FLAGS1_STMUTEB_MAX 1 +#define TFA98XX_STATUS_FLAGS1_STMUTEB_MSK 0x80 + +/* + * flag_soft_mute_state + */ +#define TFA98XX_STATUS_FLAGS1_STMUTE (0x1<<8) +#define TFA98XX_STATUS_FLAGS1_STMUTE_POS 8 +#define TFA98XX_STATUS_FLAGS1_STMUTE_LEN 1 +#define TFA98XX_STATUS_FLAGS1_STMUTE_MAX 1 +#define TFA98XX_STATUS_FLAGS1_STMUTE_MSK 0x100 + +/* + * flag_tdm_lut_error + */ +#define TFA98XX_STATUS_FLAGS1_TDMLUTER (0x1<<9) +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_POS 9 +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_LEN 1 +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_MAX 1 +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_MSK 0x200 + +/* + * flag_tdm_status + */ +#define TFA98XX_STATUS_FLAGS1_TDMSTAT (0x7<<10) +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_POS 10 +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_LEN 3 +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_MAX 7 +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_MSK 0x1c00 + +/* + * flag_tdm_error + */ +#define TFA98XX_STATUS_FLAGS1_TDMERR (0x1<<13) +#define TFA98XX_STATUS_FLAGS1_TDMERR_POS 13 +#define TFA98XX_STATUS_FLAGS1_TDMERR_LEN 1 +#define TFA98XX_STATUS_FLAGS1_TDMERR_MAX 1 +#define TFA98XX_STATUS_FLAGS1_TDMERR_MSK 0x2000 + +/* + * flag_haptic_busy + */ +#define TFA98XX_STATUS_FLAGS1_HAPTIC (0x1<<14) +#define TFA98XX_STATUS_FLAGS1_HAPTIC_POS 14 +#define TFA98XX_STATUS_FLAGS1_HAPTIC_LEN 1 +#define TFA98XX_STATUS_FLAGS1_HAPTIC_MAX 1 +#define TFA98XX_STATUS_FLAGS1_HAPTIC_MSK 0x4000 + + +/* + * (0x12)-status_flags2 + */ + +/* + * flag_ocpokap_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOAPL (0x1<<0) +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_POS 0 +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_MSK 0x1 + +/* + * flag_ocpokan_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOANL (0x1<<1) +#define TFA98XX_STATUS_FLAGS2_OCPOANL_POS 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANL_MSK 0x2 + +/* + * flag_ocpokbp_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBPL (0x1<<2) +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_POS 2 +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_MSK 0x4 + +/* + * flag_ocpokbn_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBNL (0x1<<3) +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_POS 3 +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_MSK 0x8 + +/* + * flag_clipa_high_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPAHL (0x1<<4) +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_POS 4 +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_MSK 0x10 + +/* + * flag_clipa_low_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPALL (0x1<<5) +#define TFA98XX_STATUS_FLAGS2_CLIPALL_POS 5 +#define TFA98XX_STATUS_FLAGS2_CLIPALL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPALL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPALL_MSK 0x20 + +/* + * flag_clipb_high_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPBHL (0x1<<6) +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_POS 6 +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_MSK 0x40 + +/* + * flag_clipb_low_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPBLL (0x1<<7) +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_POS 7 +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_MSK 0x80 + +/* + * flag_ocpokap_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC (0x1<<8) +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_POS 8 +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_MSK 0x100 + +/* + * flag_ocpokan_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOANRC (0x1<<9) +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_POS 9 +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_MSK 0x200 + +/* + * flag_ocpokbp_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC (0x1<<10) +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_POS 10 +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_MSK 0x400 + +/* + * flag_ocpokbn_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC (0x1<<11) +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_POS 11 +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_MSK 0x800 + +/* + * flag_rcvldop_ready + */ +#define TFA98XX_STATUS_FLAGS2_RCVLDOR (0x1<<12) +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_POS 12 +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_LEN 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_MAX 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_MSK 0x1000 + +/* + * flag_rcvldop_bypassready + */ +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR (0x1<<13) +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_POS 13 +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_LEN 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_MAX 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_MSK 0x2000 + +/* + * flag_ocp_alarm_left + */ +#define TFA98XX_STATUS_FLAGS2_OCDSL (0x1<<14) +#define TFA98XX_STATUS_FLAGS2_OCDSL_POS 14 +#define TFA98XX_STATUS_FLAGS2_OCDSL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCDSL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCDSL_MSK 0x4000 + +/* + * flag_clip_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPSL (0x1<<15) +#define TFA98XX_STATUS_FLAGS2_CLIPSL_POS 15 +#define TFA98XX_STATUS_FLAGS2_CLIPSL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPSL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPSL_MSK 0x8000 + + +/* + * (0x13)-status_flags3 + */ + +/* + * flag_ocpokap_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOAPR (0x1<<0) +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_POS 0 +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_MSK 0x1 + +/* + * flag_ocpokan_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOANR (0x1<<1) +#define TFA98XX_STATUS_FLAGS3_OCPOANR_POS 1 +#define TFA98XX_STATUS_FLAGS3_OCPOANR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOANR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOANR_MSK 0x2 + +/* + * flag_ocpokbp_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOBPR (0x1<<2) +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_POS 2 +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_MSK 0x4 + +/* + * flag_ocpokbn_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOBNR (0x1<<3) +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_POS 3 +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_MSK 0x8 + +/* + * flag_clipa_high_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPAHR (0x1<<4) +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_POS 4 +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_MSK 0x10 + +/* + * flag_clipa_low_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPALR (0x1<<5) +#define TFA98XX_STATUS_FLAGS3_CLIPALR_POS 5 +#define TFA98XX_STATUS_FLAGS3_CLIPALR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPALR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPALR_MSK 0x20 + +/* + * flag_clipb_high_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPBHR (0x1<<6) +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_POS 6 +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_MSK 0x40 + +/* + * flag_clipb_low_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPBLR (0x1<<7) +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_POS 7 +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_MSK 0x80 + +/* + * flag_ocp_alarm_right + */ +#define TFA98XX_STATUS_FLAGS3_OCDSR (0x1<<8) +#define TFA98XX_STATUS_FLAGS3_OCDSR_POS 8 +#define TFA98XX_STATUS_FLAGS3_OCDSR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCDSR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCDSR_MSK 0x100 + +/* + * flag_clip_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPSR (0x1<<9) +#define TFA98XX_STATUS_FLAGS3_CLIPSR_POS 9 +#define TFA98XX_STATUS_FLAGS3_CLIPSR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPSR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPSR_MSK 0x200 + +/* + * flag_mic_ocpok + */ +#define TFA98XX_STATUS_FLAGS3_OCPOKMC (0x1<<10) +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_POS 10 +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_MSK 0x400 + +/* + * flag_man_alarm_state + */ +#define TFA98XX_STATUS_FLAGS3_MANALARM (0x1<<11) +#define TFA98XX_STATUS_FLAGS3_MANALARM_POS 11 +#define TFA98XX_STATUS_FLAGS3_MANALARM_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANALARM_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANALARM_MSK 0x800 + +/* + * flag_man_wait_src_settings + */ +#define TFA98XX_STATUS_FLAGS3_MANWAIT1 (0x1<<12) +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_POS 12 +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_MSK 0x1000 + +/* + * flag_man_wait_cf_config + */ +#define TFA98XX_STATUS_FLAGS3_MANWAIT2 (0x1<<13) +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_POS 13 +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_MSK 0x2000 + +/* + * flag_man_start_mute_audio + */ +#define TFA98XX_STATUS_FLAGS3_MANMUTE (0x1<<14) +#define TFA98XX_STATUS_FLAGS3_MANMUTE_POS 14 +#define TFA98XX_STATUS_FLAGS3_MANMUTE_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANMUTE_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANMUTE_MSK 0x4000 + +/* + * flag_man_operating_state + */ +#define TFA98XX_STATUS_FLAGS3_MANOPER (0x1<<15) +#define TFA98XX_STATUS_FLAGS3_MANOPER_POS 15 +#define TFA98XX_STATUS_FLAGS3_MANOPER_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANOPER_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANOPER_MSK 0x8000 + + +/* + * (0x14)-status_flags4 + */ + +/* + * flag_cf_speakererror_left + */ +#define TFA98XX_STATUS_FLAGS4_SPKSL (0x1<<0) +#define TFA98XX_STATUS_FLAGS4_SPKSL_POS 0 +#define TFA98XX_STATUS_FLAGS4_SPKSL_LEN 1 +#define TFA98XX_STATUS_FLAGS4_SPKSL_MAX 1 +#define TFA98XX_STATUS_FLAGS4_SPKSL_MSK 0x1 + +/* + * flag_cf_speakererror_right + */ +#define TFA98XX_STATUS_FLAGS4_SPKSR (0x1<<1) +#define TFA98XX_STATUS_FLAGS4_SPKSR_POS 1 +#define TFA98XX_STATUS_FLAGS4_SPKSR_LEN 1 +#define TFA98XX_STATUS_FLAGS4_SPKSR_MAX 1 +#define TFA98XX_STATUS_FLAGS4_SPKSR_MSK 0x2 + +/* + * flag_clk_out_of_range + */ +#define TFA98XX_STATUS_FLAGS4_CLKOOR (0x1<<2) +#define TFA98XX_STATUS_FLAGS4_CLKOOR_POS 2 +#define TFA98XX_STATUS_FLAGS4_CLKOOR_LEN 1 +#define TFA98XX_STATUS_FLAGS4_CLKOOR_MAX 1 +#define TFA98XX_STATUS_FLAGS4_CLKOOR_MSK 0x4 + +/* + * man_state + */ +#define TFA98XX_STATUS_FLAGS4_MANSTATE (0xf<<3) +#define TFA98XX_STATUS_FLAGS4_MANSTATE_POS 3 +#define TFA98XX_STATUS_FLAGS4_MANSTATE_LEN 4 +#define TFA98XX_STATUS_FLAGS4_MANSTATE_MAX 15 +#define TFA98XX_STATUS_FLAGS4_MANSTATE_MSK 0x78 + + +/* + * (0x15)-battery_voltage + */ + +/* + * bat_adc + */ +#define TFA98XX_BATTERY_VOLTAGE_BATS (0x3ff<<0) +#define TFA98XX_BATTERY_VOLTAGE_BATS_POS 0 +#define TFA98XX_BATTERY_VOLTAGE_BATS_LEN 10 +#define TFA98XX_BATTERY_VOLTAGE_BATS_MAX 1023 +#define TFA98XX_BATTERY_VOLTAGE_BATS_MSK 0x3ff + + +/* + * (0x16)-temperature + */ + +/* + * temp_adc + */ +#define TFA98XX_TEMPERATURE_TEMPS (0x1ff<<0) +#define TFA98XX_TEMPERATURE_TEMPS_POS 0 +#define TFA98XX_TEMPERATURE_TEMPS_LEN 9 +#define TFA98XX_TEMPERATURE_TEMPS_MAX 511 +#define TFA98XX_TEMPERATURE_TEMPS_MSK 0x1ff + + +/* + * (0x20)-tdm_config0 + */ + +/* + * tdm_usecase + */ +#define TFA98XX_TDM_CONFIG0_TDMUC (0xf<<0) +#define TFA98XX_TDM_CONFIG0_TDMUC_POS 0 +#define TFA98XX_TDM_CONFIG0_TDMUC_LEN 4 +#define TFA98XX_TDM_CONFIG0_TDMUC_MAX 15 +#define TFA98XX_TDM_CONFIG0_TDMUC_MSK 0xf + +/* + * tdm_enable + */ +#define TFA98XX_TDM_CONFIG0_TDME (0x1<<4) +#define TFA98XX_TDM_CONFIG0_TDME_POS 4 +#define TFA98XX_TDM_CONFIG0_TDME_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDME_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDME_MSK 0x10 + +/* + * tdm_mode + */ +#define TFA98XX_TDM_CONFIG0_TDMMODE (0x1<<5) +#define TFA98XX_TDM_CONFIG0_TDMMODE_POS 5 +#define TFA98XX_TDM_CONFIG0_TDMMODE_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDMMODE_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDMMODE_MSK 0x20 + +/* + * tdm_clk_inversion + */ +#define TFA98XX_TDM_CONFIG0_TDMCLINV (0x1<<6) +#define TFA98XX_TDM_CONFIG0_TDMCLINV_POS 6 +#define TFA98XX_TDM_CONFIG0_TDMCLINV_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDMCLINV_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDMCLINV_MSK 0x40 + +/* + * tdm_fs_ws_length + */ +#define TFA98XX_TDM_CONFIG0_TDMFSLN (0xf<<7) +#define TFA98XX_TDM_CONFIG0_TDMFSLN_POS 7 +#define TFA98XX_TDM_CONFIG0_TDMFSLN_LEN 4 +#define TFA98XX_TDM_CONFIG0_TDMFSLN_MAX 15 +#define TFA98XX_TDM_CONFIG0_TDMFSLN_MSK 0x780 + +/* + * tdm_fs_ws_polarity + */ +#define TFA98XX_TDM_CONFIG0_TDMFSPOL (0x1<<11) +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_POS 11 +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_MSK 0x800 + +/* + * tdm_nbck + */ +#define TFA98XX_TDM_CONFIG0_TDMNBCK (0xf<<12) +#define TFA98XX_TDM_CONFIG0_TDMNBCK_POS 12 +#define TFA98XX_TDM_CONFIG0_TDMNBCK_LEN 4 +#define TFA98XX_TDM_CONFIG0_TDMNBCK_MAX 15 +#define TFA98XX_TDM_CONFIG0_TDMNBCK_MSK 0xf000 + + +/* + * (0x21)-tdm_config1 + */ + +/* + * tdm_nb_of_slots + */ +#define TFA98XX_TDM_CONFIG1_TDMSLOTS (0xf<<0) +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_POS 0 +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_LEN 4 +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_MAX 15 +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_MSK 0xf + +/* + * tdm_slot_length + */ +#define TFA98XX_TDM_CONFIG1_TDMSLLN (0x1f<<4) +#define TFA98XX_TDM_CONFIG1_TDMSLLN_POS 4 +#define TFA98XX_TDM_CONFIG1_TDMSLLN_LEN 5 +#define TFA98XX_TDM_CONFIG1_TDMSLLN_MAX 31 +#define TFA98XX_TDM_CONFIG1_TDMSLLN_MSK 0x1f0 + +/* + * tdm_bits_remaining + */ +#define TFA98XX_TDM_CONFIG1_TDMBRMG (0x1f<<9) +#define TFA98XX_TDM_CONFIG1_TDMBRMG_POS 9 +#define TFA98XX_TDM_CONFIG1_TDMBRMG_LEN 5 +#define TFA98XX_TDM_CONFIG1_TDMBRMG_MAX 31 +#define TFA98XX_TDM_CONFIG1_TDMBRMG_MSK 0x3e00 + +/* + * tdm_data_delay + */ +#define TFA98XX_TDM_CONFIG1_TDMDEL (0x1<<14) +#define TFA98XX_TDM_CONFIG1_TDMDEL_POS 14 +#define TFA98XX_TDM_CONFIG1_TDMDEL_LEN 1 +#define TFA98XX_TDM_CONFIG1_TDMDEL_MAX 1 +#define TFA98XX_TDM_CONFIG1_TDMDEL_MSK 0x4000 + +/* + * tdm_data_adjustment + */ +#define TFA98XX_TDM_CONFIG1_TDMADJ (0x1<<15) +#define TFA98XX_TDM_CONFIG1_TDMADJ_POS 15 +#define TFA98XX_TDM_CONFIG1_TDMADJ_LEN 1 +#define TFA98XX_TDM_CONFIG1_TDMADJ_MAX 1 +#define TFA98XX_TDM_CONFIG1_TDMADJ_MSK 0x8000 + + +/* + * (0x22)-tdm_config2 + */ + +/* + * tdm_audio_sample_compression + */ +#define TFA98XX_TDM_CONFIG2_TDMOOMP (0x3<<0) +#define TFA98XX_TDM_CONFIG2_TDMOOMP_POS 0 +#define TFA98XX_TDM_CONFIG2_TDMOOMP_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMOOMP_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMOOMP_MSK 0x3 + +/* + * tdm_sample_size + */ +#define TFA98XX_TDM_CONFIG2_TDMSSIZE (0x1f<<2) +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_POS 2 +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_LEN 5 +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_MAX 31 +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_MSK 0x7c + +/* + * tdm_txdata_format + */ +#define TFA98XX_TDM_CONFIG2_TDMTXDFO (0x3<<7) +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_POS 7 +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_MSK 0x180 + +/* + * tdm_txdata_format_unused_slot_sd0 + */ +#define TFA98XX_TDM_CONFIG2_TDMTXUS0 (0x3<<9) +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_POS 9 +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_MSK 0x600 + +/* + * tdm_txdata_format_unused_slot_sd1 + */ +#define TFA98XX_TDM_CONFIG2_TDMTXUS1 (0x3<<11) +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_POS 11 +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_MSK 0x1800 + +/* + * tdm_txdata_format_unused_slot_sd2 + */ +#define TFA98XX_TDM_CONFIG2_TDMTXUS2 (0x3<<13) +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_POS 13 +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_MSK 0x6000 + + +/* + * (0x23)-tdm_config3 + */ + +/* + * tdm_sink1_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMLE (0x1<<1) +#define TFA98XX_TDM_CONFIG3_TDMLE_POS 1 +#define TFA98XX_TDM_CONFIG3_TDMLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMLE_MSK 0x2 + +/* + * tdm_sink2_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMRE (0x1<<2) +#define TFA98XX_TDM_CONFIG3_TDMRE_POS 2 +#define TFA98XX_TDM_CONFIG3_TDMRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMRE_MSK 0x4 + +/* + * tdm_source1_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMVSRE (0x1<<4) +#define TFA98XX_TDM_CONFIG3_TDMVSRE_POS 4 +#define TFA98XX_TDM_CONFIG3_TDMVSRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMVSRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMVSRE_MSK 0x10 + +/* + * tdm_source2_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCSRE (0x1<<5) +#define TFA98XX_TDM_CONFIG3_TDMCSRE_POS 5 +#define TFA98XX_TDM_CONFIG3_TDMCSRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCSRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCSRE_MSK 0x20 + +/* + * tdm_source3_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMVSLE (0x1<<6) +#define TFA98XX_TDM_CONFIG3_TDMVSLE_POS 6 +#define TFA98XX_TDM_CONFIG3_TDMVSLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMVSLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMVSLE_MSK 0x40 + +/* + * tdm_source4_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCSLE (0x1<<7) +#define TFA98XX_TDM_CONFIG3_TDMCSLE_POS 7 +#define TFA98XX_TDM_CONFIG3_TDMCSLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCSLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCSLE_MSK 0x80 + +/* + * tdm_source5_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCFRE (0x1<<8) +#define TFA98XX_TDM_CONFIG3_TDMCFRE_POS 8 +#define TFA98XX_TDM_CONFIG3_TDMCFRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCFRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCFRE_MSK 0x100 + +/* + * tdm_source6_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCFLE (0x1<<9) +#define TFA98XX_TDM_CONFIG3_TDMCFLE_POS 9 +#define TFA98XX_TDM_CONFIG3_TDMCFLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCFLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCFLE_MSK 0x200 + +/* + * tdm_source7_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCF3E (0x1<<10) +#define TFA98XX_TDM_CONFIG3_TDMCF3E_POS 10 +#define TFA98XX_TDM_CONFIG3_TDMCF3E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCF3E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCF3E_MSK 0x400 + +/* + * tdm_source8_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCF4E (0x1<<11) +#define TFA98XX_TDM_CONFIG3_TDMCF4E_POS 11 +#define TFA98XX_TDM_CONFIG3_TDMCF4E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCF4E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCF4E_MSK 0x800 + +/* + * tdm_source9_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMPD1E (0x1<<12) +#define TFA98XX_TDM_CONFIG3_TDMPD1E_POS 12 +#define TFA98XX_TDM_CONFIG3_TDMPD1E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMPD1E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMPD1E_MSK 0x1000 + +/* + * tdm_source10_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMPD2E (0x1<<13) +#define TFA98XX_TDM_CONFIG3_TDMPD2E_POS 13 +#define TFA98XX_TDM_CONFIG3_TDMPD2E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMPD2E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMPD2E_MSK 0x2000 + + +/* + * (0x24)-tdm_config4 + */ + +/* + * tdm_sink1_io + */ +#define TFA98XX_TDM_CONFIG4_TDMLIO (0x3<<2) +#define TFA98XX_TDM_CONFIG4_TDMLIO_POS 2 +#define TFA98XX_TDM_CONFIG4_TDMLIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMLIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMLIO_MSK 0xc + +/* + * tdm_sink2_io + */ +#define TFA98XX_TDM_CONFIG4_TDMRIO (0x3<<4) +#define TFA98XX_TDM_CONFIG4_TDMRIO_POS 4 +#define TFA98XX_TDM_CONFIG4_TDMRIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMRIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMRIO_MSK 0x30 + +/* + * tdm_source1_io + */ +#define TFA98XX_TDM_CONFIG4_TDMVSRIO (0x3<<8) +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_POS 8 +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_MSK 0x300 + +/* + * tdm_source2_io + */ +#define TFA98XX_TDM_CONFIG4_TDMCSRIO (0x3<<10) +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_POS 10 +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_MSK 0xc00 + +/* + * tdm_source3_io + */ +#define TFA98XX_TDM_CONFIG4_TDMVSLIO (0x3<<12) +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_POS 12 +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_MSK 0x3000 + +/* + * tdm_source4_io + */ +#define TFA98XX_TDM_CONFIG4_TDMCSLIO (0x3<<14) +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_POS 14 +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_MSK 0xc000 + + +/* + * (0x25)-tdm_config5 + */ + +/* + * tdm_source5_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCFRIO (0x3<<0) +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_POS 0 +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_MSK 0x3 + +/* + * tdm_source6_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCFLIO (0x3<<2) +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_POS 2 +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_MSK 0xc + +/* + * tdm_source7_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCF3IO (0x3<<4) +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_POS 4 +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_MSK 0x30 + +/* + * tdm_source8_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCF4IO (0x3<<6) +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_POS 6 +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_MSK 0xc0 + +/* + * tdm_source9_io + */ +#define TFA98XX_TDM_CONFIG5_TDMPD1IO (0x3<<8) +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_POS 8 +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_MSK 0x300 + +/* + * tdm_source10_io + */ +#define TFA98XX_TDM_CONFIG5_TDMPD2IO (0x3<<10) +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_POS 10 +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_MSK 0xc00 + + +/* + * (0x26)-tdm_config6 + */ + +/* + * tdm_sink1_slot + */ +#define TFA98XX_TDM_CONFIG6_TDMLS (0xf<<4) +#define TFA98XX_TDM_CONFIG6_TDMLS_POS 4 +#define TFA98XX_TDM_CONFIG6_TDMLS_LEN 4 +#define TFA98XX_TDM_CONFIG6_TDMLS_MAX 15 +#define TFA98XX_TDM_CONFIG6_TDMLS_MSK 0xf0 + +/* + * tdm_sink2_slot + */ +#define TFA98XX_TDM_CONFIG6_TDMRS (0xf<<8) +#define TFA98XX_TDM_CONFIG6_TDMRS_POS 8 +#define TFA98XX_TDM_CONFIG6_TDMRS_LEN 4 +#define TFA98XX_TDM_CONFIG6_TDMRS_MAX 15 +#define TFA98XX_TDM_CONFIG6_TDMRS_MSK 0xf00 + + +/* + * (0x27)-tdm_config7 + */ + +/* + * tdm_source1_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMVSRS (0xf<<0) +#define TFA98XX_TDM_CONFIG7_TDMVSRS_POS 0 +#define TFA98XX_TDM_CONFIG7_TDMVSRS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMVSRS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMVSRS_MSK 0xf + +/* + * tdm_source2_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMCSRS (0xf<<4) +#define TFA98XX_TDM_CONFIG7_TDMCSRS_POS 4 +#define TFA98XX_TDM_CONFIG7_TDMCSRS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMCSRS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMCSRS_MSK 0xf0 + +/* + * tdm_source3_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMVSLS (0xf<<8) +#define TFA98XX_TDM_CONFIG7_TDMVSLS_POS 8 +#define TFA98XX_TDM_CONFIG7_TDMVSLS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMVSLS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMVSLS_MSK 0xf00 + +/* + * tdm_source4_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMCSLS (0xf<<12) +#define TFA98XX_TDM_CONFIG7_TDMCSLS_POS 12 +#define TFA98XX_TDM_CONFIG7_TDMCSLS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMCSLS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMCSLS_MSK 0xf000 + + +/* + * (0x28)-tdm_config8 + */ + +/* + * tdm_source5_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCFRS (0xf<<0) +#define TFA98XX_TDM_CONFIG8_TDMCFRS_POS 0 +#define TFA98XX_TDM_CONFIG8_TDMCFRS_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCFRS_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCFRS_MSK 0xf + +/* + * tdm_source6_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCFLS (0xf<<4) +#define TFA98XX_TDM_CONFIG8_TDMCFLS_POS 4 +#define TFA98XX_TDM_CONFIG8_TDMCFLS_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCFLS_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCFLS_MSK 0xf0 + +/* + * tdm_source7_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCF3S (0xf<<8) +#define TFA98XX_TDM_CONFIG8_TDMCF3S_POS 8 +#define TFA98XX_TDM_CONFIG8_TDMCF3S_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCF3S_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCF3S_MSK 0xf00 + +/* + * tdm_source8_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCF4S (0xf<<12) +#define TFA98XX_TDM_CONFIG8_TDMCF4S_POS 12 +#define TFA98XX_TDM_CONFIG8_TDMCF4S_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCF4S_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCF4S_MSK 0xf000 + + +/* + * (0x29)-tdm_config9 + */ + +/* + * tdm_source9_slot + */ +#define TFA98XX_TDM_CONFIG9_TDMPD1S (0xf<<0) +#define TFA98XX_TDM_CONFIG9_TDMPD1S_POS 0 +#define TFA98XX_TDM_CONFIG9_TDMPD1S_LEN 4 +#define TFA98XX_TDM_CONFIG9_TDMPD1S_MAX 15 +#define TFA98XX_TDM_CONFIG9_TDMPD1S_MSK 0xf + +/* + * tdm_source10_slot + */ +#define TFA98XX_TDM_CONFIG9_TDMPD2S (0xf<<4) +#define TFA98XX_TDM_CONFIG9_TDMPD2S_POS 4 +#define TFA98XX_TDM_CONFIG9_TDMPD2S_LEN 4 +#define TFA98XX_TDM_CONFIG9_TDMPD2S_MAX 15 +#define TFA98XX_TDM_CONFIG9_TDMPD2S_MSK 0xf0 + + +/* + * (0x31)-pdm_config0 + */ + +/* + * pdm_mode + */ +#define TFA98XX_PDM_CONFIG0_PDMSM (0x1<<0) +#define TFA98XX_PDM_CONFIG0_PDMSM_POS 0 +#define TFA98XX_PDM_CONFIG0_PDMSM_LEN 1 +#define TFA98XX_PDM_CONFIG0_PDMSM_MAX 1 +#define TFA98XX_PDM_CONFIG0_PDMSM_MSK 0x1 + +/* + * pdm_side_tone_sel + */ +#define TFA98XX_PDM_CONFIG0_PDMSTSEL (0x3<<1) +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_POS 1 +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_LEN 2 +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_MAX 3 +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_MSK 0x6 + +/* + * pdm_left_sel + */ +#define TFA98XX_PDM_CONFIG0_PDMLSEL (0x1<<3) +#define TFA98XX_PDM_CONFIG0_PDMLSEL_POS 3 +#define TFA98XX_PDM_CONFIG0_PDMLSEL_LEN 1 +#define TFA98XX_PDM_CONFIG0_PDMLSEL_MAX 1 +#define TFA98XX_PDM_CONFIG0_PDMLSEL_MSK 0x8 + +/* + * pdm_right_sel + */ +#define TFA98XX_PDM_CONFIG0_PDMRSEL (0x1<<4) +#define TFA98XX_PDM_CONFIG0_PDMRSEL_POS 4 +#define TFA98XX_PDM_CONFIG0_PDMRSEL_LEN 1 +#define TFA98XX_PDM_CONFIG0_PDMRSEL_MAX 1 +#define TFA98XX_PDM_CONFIG0_PDMRSEL_MSK 0x10 + +/* + * enbl_micvdd + */ +#define TFA98XX_PDM_CONFIG0_MICVDDE (0x1<<5) +#define TFA98XX_PDM_CONFIG0_MICVDDE_POS 5 +#define TFA98XX_PDM_CONFIG0_MICVDDE_LEN 1 +#define TFA98XX_PDM_CONFIG0_MICVDDE_MAX 1 +#define TFA98XX_PDM_CONFIG0_MICVDDE_MSK 0x20 + + +/* + * (0x32)-pdm_config1 + */ + +/* + * pdm_nbck + */ +#define TFA98XX_PDM_CONFIG1_PDMCLRAT (0x3<<0) +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_POS 0 +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_LEN 2 +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_MAX 3 +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_MSK 0x3 + +/* + * pdm_gain + */ +#define TFA98XX_PDM_CONFIG1_PDMGAIN (0xf<<2) +#define TFA98XX_PDM_CONFIG1_PDMGAIN_POS 2 +#define TFA98XX_PDM_CONFIG1_PDMGAIN_LEN 4 +#define TFA98XX_PDM_CONFIG1_PDMGAIN_MAX 15 +#define TFA98XX_PDM_CONFIG1_PDMGAIN_MSK 0x3c + +/* + * sel_pdm_out_data + */ +#define TFA98XX_PDM_CONFIG1_PDMOSEL (0xf<<6) +#define TFA98XX_PDM_CONFIG1_PDMOSEL_POS 6 +#define TFA98XX_PDM_CONFIG1_PDMOSEL_LEN 4 +#define TFA98XX_PDM_CONFIG1_PDMOSEL_MAX 15 +#define TFA98XX_PDM_CONFIG1_PDMOSEL_MSK 0x3c0 + +/* + * sel_cf_haptic_data + */ +#define TFA98XX_PDM_CONFIG1_SELCFHAPD (0x1<<10) +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_POS 10 +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_LEN 1 +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_MAX 1 +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_MSK 0x400 + + +/* + * (0x33)-haptic_driver_config + */ + +/* + * haptic_duration + */ +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME (0xff<<0) +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_POS 0 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_LEN 8 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_MAX 255 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_MSK 0xff + +/* + * haptic_data + */ +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL (0xff<<8) +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_POS 8 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_LEN 8 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_MAX 255 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_MSK 0xff00 + + +/* + * (0x34)-gpio_datain_reg + */ + +/* + * gpio_datain + */ +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN (0xf<<0) +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_POS 0 +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_LEN 4 +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_MAX 15 +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_MSK 0xf + + +/* + * (0x35)-gpio_config + */ + +/* + * gpio_ctrl + */ +#define TFA98XX_GPIO_CONFIG_GPIOCTRL (0x1<<0) +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_POS 0 +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_LEN 1 +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_MAX 1 +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_MSK 0x1 + +/* + * gpio_dir + */ +#define TFA98XX_GPIO_CONFIG_GPIOCONF (0xf<<1) +#define TFA98XX_GPIO_CONFIG_GPIOCONF_POS 1 +#define TFA98XX_GPIO_CONFIG_GPIOCONF_LEN 4 +#define TFA98XX_GPIO_CONFIG_GPIOCONF_MAX 15 +#define TFA98XX_GPIO_CONFIG_GPIOCONF_MSK 0x1e + +/* + * gpio_dataout + */ +#define TFA98XX_GPIO_CONFIG_GPIODOUT (0xf<<5) +#define TFA98XX_GPIO_CONFIG_GPIODOUT_POS 5 +#define TFA98XX_GPIO_CONFIG_GPIODOUT_LEN 4 +#define TFA98XX_GPIO_CONFIG_GPIODOUT_MAX 15 +#define TFA98XX_GPIO_CONFIG_GPIODOUT_MSK 0x1e0 + + +/* + * (0x40)-interrupt_out_reg1 + */ + +/* + * int_out_flag_por + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS (0x1<<0) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_POS 0 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_MSK 0x1 + +/* + * int_out_flag_pll_lock + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS (0x1<<1) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_POS 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_MSK 0x2 + +/* + * int_out_flag_otpok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS (0x1<<2) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_POS 2 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_MSK 0x4 + +/* + * int_out_flag_ovpok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS (0x1<<3) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_POS 3 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_MSK 0x8 + +/* + * int_out_flag_uvpok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS (0x1<<4) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_POS 4 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_MSK 0x10 + +/* + * int_out_flag_clocks_stable + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS (0x1<<5) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_POS 5 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_MSK 0x20 + +/* + * int_out_flag_mtp_busy + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB (0x1<<6) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_POS 6 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_MSK 0x40 + +/* + * int_out_flag_lost_clk + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK (0x1<<7) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_POS 7 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_MSK 0x80 + +/* + * int_out_flag_cf_speakererror + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS (0x1<<8) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_POS 8 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_MSK 0x100 + +/* + * int_out_flag_cold_started + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS (0x1<<9) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_POS 9 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_MSK 0x200 + +/* + * int_out_flag_engage + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS (0x1<<10) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_POS 10 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_MSK 0x400 + +/* + * int_out_flag_watchdog_reset + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS (0x1<<11) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_POS 11 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_MSK 0x800 + +/* + * int_out_flag_enbl_amp + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS (0x1<<12) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_POS 12 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_MSK 0x1000 + +/* + * int_out_flag_enbl_ref + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS (0x1<<13) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_POS 13 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_MSK 0x2000 + +/* + * int_out_flag_adc10_ready + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR (0x1<<14) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_POS 14 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_MSK 0x4000 + +/* + * int_out_flag_bod_vddd_nok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK (0x1<<15) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_POS 15 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_MSK 0x8000 + + +/* + * (0x41)-interrupt_out_reg2 + */ + +/* + * int_out_flag_bst_bstcur + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU (0x1<<0) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_POS 0 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_MSK 0x1 + +/* + * int_out_flag_bst_hiz + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI (0x1<<1) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_POS 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_MSK 0x2 + +/* + * int_out_flag_bst_ocpok + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC (0x1<<2) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_POS 2 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_MSK 0x4 + +/* + * int_out_flag_bst_peakcur + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR (0x1<<3) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_POS 3 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_MSK 0x8 + +/* + * int_out_flag_bst_voutcomp + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC (0x1<<4) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_POS 4 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_MSK 0x10 + +/* + * int_out_flag_bst_voutcomp86 + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86 (0x1<<5) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_POS 5 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_MSK 0x20 + +/* + * int_out_flag_bst_voutcomp93 + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93 (0x1<<6) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_POS 6 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_MSK 0x40 + +/* + * int_out_flag_rcvldop_ready + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD (0x1<<7) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_POS 7 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_MSK 0x80 + +/* + * int_out_flag_ocp_alarm_left + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL (0x1<<8) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_POS 8 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_MSK 0x100 + +/* + * int_out_flag_ocp_alarm_right + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR (0x1<<9) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_POS 9 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_MSK 0x200 + +/* + * int_out_flag_man_wait_src_settings + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC (0x1<<10) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_POS 10 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_MSK 0x400 + +/* + * int_out_flag_man_wait_cf_config + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC (0x1<<11) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_POS 11 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_MSK 0x800 + +/* + * int_out_flag_man_start_mute_audio + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU (0x1<<12) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_POS 12 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_MSK 0x1000 + +/* + * int_out_flag_cfma_err + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER (0x1<<13) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_POS 13 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_MSK 0x2000 + +/* + * int_out_flag_cfma_ack + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC (0x1<<14) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_POS 14 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_MSK 0x4000 + +/* + * int_out_flag_clk_out_of_range + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR (0x1<<15) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_POS 15 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_MSK 0x8000 + + +/* + * (0x42)-interrupt_out_reg3 + */ + +/* + * int_out_flag_tdm_error + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER (0x1<<0) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_POS 0 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_MSK 0x1 + +/* + * int_out_flag_clip_left + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL (0x1<<1) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_POS 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_MSK 0x2 + +/* + * int_out_flag_clip_right + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR (0x1<<2) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_POS 2 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_MSK 0x4 + +/* + * int_out_flag_mic_ocpok + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM (0x1<<3) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_POS 3 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_MSK 0x8 + + +/* + * (0x44)-interrupt_in_reg1 + */ + +/* + * int_in_flag_por + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS (0x1<<0) +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_POS 0 +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_MSK 0x1 + +/* + * int_in_flag_pll_lock + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS (0x1<<1) +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_POS 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_MSK 0x2 + +/* + * int_in_flag_otpok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS (0x1<<2) +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_POS 2 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_MSK 0x4 + +/* + * int_in_flag_ovpok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS (0x1<<3) +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_POS 3 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_MSK 0x8 + +/* + * int_in_flag_uvpok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS (0x1<<4) +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_POS 4 +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_MSK 0x10 + +/* + * int_in_flag_clocks_stable + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS (0x1<<5) +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_POS 5 +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_MSK 0x20 + +/* + * int_in_flag_mtp_busy + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB (0x1<<6) +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_POS 6 +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_MSK 0x40 + +/* + * int_in_flag_lost_clk + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK (0x1<<7) +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_POS 7 +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_MSK 0x80 + +/* + * int_in_flag_cf_speakererror + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS (0x1<<8) +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_POS 8 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_MSK 0x100 + +/* + * int_in_flag_cold_started + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS (0x1<<9) +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_POS 9 +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_MSK 0x200 + +/* + * int_in_flag_engage + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS (0x1<<10) +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_POS 10 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_MSK 0x400 + +/* + * int_in_flag_watchdog_reset + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS (0x1<<11) +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_POS 11 +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_MSK 0x800 + +/* + * int_in_flag_enbl_amp + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS (0x1<<12) +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_POS 12 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_MSK 0x1000 + +/* + * int_in_flag_enbl_ref + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS (0x1<<13) +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_POS 13 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_MSK 0x2000 + +/* + * int_in_flag_adc10_ready + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR (0x1<<14) +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_POS 14 +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_MSK 0x4000 + +/* + * int_in_flag_bod_vddd_nok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK (0x1<<15) +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_POS 15 +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_MSK 0x8000 + + +/* + * (0x45)-interrupt_in_reg2 + */ + +/* + * int_in_flag_bst_bstcur + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU (0x1<<0) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_POS 0 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_MSK 0x1 + +/* + * int_in_flag_bst_hiz + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI (0x1<<1) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_POS 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_MSK 0x2 + +/* + * int_in_flag_bst_ocpok + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC (0x1<<2) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_POS 2 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_MSK 0x4 + +/* + * int_in_flag_bst_peakcur + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC (0x1<<3) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_POS 3 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_MSK 0x8 + +/* + * int_in_flag_bst_voutcomp + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC (0x1<<4) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_POS 4 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_MSK 0x10 + +/* + * int_in_flag_bst_voutcomp86 + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86 (0x1<<5) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_POS 5 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_MSK 0x20 + +/* + * int_in_flag_bst_voutcomp93 + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93 (0x1<<6) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_POS 6 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_MSK 0x40 + +/* + * int_in_flag_rcvldop_ready + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD (0x1<<7) +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_POS 7 +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_MSK 0x80 + +/* + * int_in_flag_ocp_alarm_left + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL (0x1<<8) +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_POS 8 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_MSK 0x100 + +/* + * int_in_flag_ocp_alarm_right + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR (0x1<<9) +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_POS 9 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_MSK 0x200 + +/* + * int_in_flag_man_wait_src_settings + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC (0x1<<10) +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_POS 10 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_MSK 0x400 + +/* + * int_in_flag_man_wait_cf_config + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC (0x1<<11) +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_POS 11 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_MSK 0x800 + +/* + * int_in_flag_man_start_mute_audio + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU (0x1<<12) +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_POS 12 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_MSK 0x1000 + +/* + * int_in_flag_cfma_err + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER (0x1<<13) +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_POS 13 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_MSK 0x2000 + +/* + * int_in_flag_cfma_ack + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC (0x1<<14) +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_POS 14 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_MSK 0x4000 + +/* + * int_in_flag_clk_out_of_range + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR (0x1<<15) +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_POS 15 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_MSK 0x8000 + + +/* + * (0x46)-interrupt_in_reg3 + */ + +/* + * int_in_flag_tdm_error + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER (0x1<<0) +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_POS 0 +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_MSK 0x1 + +/* + * int_in_flag_clip_left + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL (0x1<<1) +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_POS 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_MSK 0x2 + +/* + * int_in_flag_clip_right + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR (0x1<<2) +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_POS 2 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_MSK 0x4 + +/* + * int_in_flag_mic_ocpok + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM (0x1<<3) +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_POS 3 +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_MSK 0x8 + + +/* + * (0x48)-interrupt_enable_reg1 + */ + +/* + * int_enable_flag_por + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS (0x1<<0) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_POS 0 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_MSK 0x1 + +/* + * int_enable_flag_pll_lock + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS (0x1<<1) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_POS 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_MSK 0x2 + +/* + * int_enable_flag_otpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS (0x1<<2) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_POS 2 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_MSK 0x4 + +/* + * int_enable_flag_ovpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS (0x1<<3) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_POS 3 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_MSK 0x8 + +/* + * int_enable_flag_uvpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS (0x1<<4) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_POS 4 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_MSK 0x10 + +/* + * int_enable_flag_clocks_stable + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS (0x1<<5) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_POS 5 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_MSK 0x20 + +/* + * int_enable_flag_mtp_busy + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB (0x1<<6) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_POS 6 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_MSK 0x40 + +/* + * int_enable_flag_lost_clk + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK (0x1<<7) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_POS 7 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_MSK 0x80 + +/* + * int_enable_flag_cf_speakererror + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS (0x1<<8) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_POS 8 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_MSK 0x100 + +/* + * int_enable_flag_cold_started + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS (0x1<<9) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_POS 9 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_MSK 0x200 + +/* + * int_enable_flag_engage + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS (0x1<<10) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_POS 10 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_MSK 0x400 + +/* + * int_enable_flag_watchdog_reset + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS (0x1<<11) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_POS 11 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_MSK 0x800 + +/* + * int_enable_flag_enbl_amp + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS (0x1<<12) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_POS 12 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_MSK 0x1000 + +/* + * int_enable_flag_enbl_ref + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS (0x1<<13) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_POS 13 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_MSK 0x2000 + +/* + * int_enable_flag_adc10_ready + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR (0x1<<14) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_POS 14 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_MSK 0x4000 + +/* + * int_enable_flag_bod_vddd_nok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK (0x1<<15) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_POS 15 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_MSK 0x8000 + + +/* + * (0x49)-interrupt_enable_reg2 + */ + +/* + * int_enable_flag_bst_bstcur + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU (0x1<<0) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_POS 0 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_MSK 0x1 + +/* + * int_enable_flag_bst_hiz + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI (0x1<<1) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_POS 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_MSK 0x2 + +/* + * int_enable_flag_bst_ocpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC (0x1<<2) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_POS 2 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_MSK 0x4 + +/* + * int_enable_flag_bst_peakcur + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC (0x1<<3) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_POS 3 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_MSK 0x8 + +/* + * int_enable_flag_bst_voutcomp + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC (0x1<<4) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_POS 4 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_MSK 0x10 + +/* + * int_enable_flag_bst_voutcomp86 + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86 (0x1<<5) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_POS 5 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_MSK 0x20 + +/* + * int_enable_flag_bst_voutcomp93 + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93 (0x1<<6) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_POS 6 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_MSK 0x40 + +/* + * int_enable_flag_rcvldop_ready + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD (0x1<<7) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_POS 7 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_MSK 0x80 + +/* + * int_enable_flag_ocp_alarm_left + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL (0x1<<8) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_POS 8 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_MSK 0x100 + +/* + * int_enable_flag_ocp_alarm_right + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR (0x1<<9) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_POS 9 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_MSK 0x200 + +/* + * int_enable_flag_man_wait_src_settings + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC (0x1<<10) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_POS 10 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_MSK 0x400 + +/* + * int_enable_flag_man_wait_cf_config + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC (0x1<<11) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_POS 11 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_MSK 0x800 + +/* + * int_enable_flag_man_start_mute_audio + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU (0x1<<12) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_POS 12 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_MSK 0x1000 + +/* + * int_enable_flag_cfma_err + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER (0x1<<13) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_POS 13 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_MSK 0x2000 + +/* + * int_enable_flag_cfma_ack + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC (0x1<<14) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_POS 14 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_MSK 0x4000 + +/* + * int_enable_flag_clk_out_of_range + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR (0x1<<15) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_POS 15 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_MSK 0x8000 + + +/* + * (0x4a)-interrupt_enable_reg3 + */ + +/* + * int_enable_flag_tdm_error + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER (0x1<<0) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_POS 0 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_MSK 0x1 + +/* + * int_enable_flag_clip_left + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL (0x1<<1) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_POS 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_MSK 0x2 + +/* + * int_enable_flag_clip_right + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR (0x1<<2) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_POS 2 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_MSK 0x4 + +/* + * int_enable_flag_mic_ocpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1 (0x1<<3) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_POS 3 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_MSK 0x8 + + +/* + * (0x4c)-status_polarity_reg1 + */ + +/* + * int_polarity_flag_por + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS (0x1<<0) +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_POS 0 +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_MSK 0x1 + +/* + * int_polarity_flag_pll_lock + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS (0x1<<1) +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_POS 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_MSK 0x2 + +/* + * int_polarity_flag_otpok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS (0x1<<2) +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_POS 2 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_MSK 0x4 + +/* + * int_polarity_flag_ovpok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS (0x1<<3) +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_POS 3 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_MSK 0x8 + +/* + * int_polarity_flag_uvpok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS (0x1<<4) +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_POS 4 +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_MSK 0x10 + +/* + * int_polarity_flag_clocks_stable + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS (0x1<<5) +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_POS 5 +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_MSK 0x20 + +/* + * int_polarity_flag_mtp_busy + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB (0x1<<6) +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_POS 6 +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_MSK 0x40 + +/* + * int_polarity_flag_lost_clk + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK (0x1<<7) +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_POS 7 +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_MSK 0x80 + +/* + * int_polarity_flag_cf_speakererror + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS (0x1<<8) +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_POS 8 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_MSK 0x100 + +/* + * int_polarity_flag_cold_started + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS (0x1<<9) +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_POS 9 +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_MSK 0x200 + +/* + * int_polarity_flag_engage + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS (0x1<<10) +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_POS 10 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_MSK 0x400 + +/* + * int_polarity_flag_watchdog_reset + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS (0x1<<11) +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_POS 11 +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_MSK 0x800 + +/* + * int_polarity_flag_enbl_amp + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS (0x1<<12) +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_POS 12 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_MSK 0x1000 + +/* + * int_polarity_flag_enbl_ref + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS (0x1<<13) +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_POS 13 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_MSK 0x2000 + +/* + * int_polarity_flag_adc10_ready + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR (0x1<<14) +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_POS 14 +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_MSK 0x4000 + +/* + * int_polarity_flag_bod_vddd_nok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK (0x1<<15) +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_POS 15 +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_MSK 0x8000 + + +/* + * (0x4d)-status_polarity_reg2 + */ + +/* + * int_polarity_flag_bst_bstcur + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU (0x1<<0) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_POS 0 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_MSK 0x1 + +/* + * int_polarity_flag_bst_hiz + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI (0x1<<1) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_POS 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_MSK 0x2 + +/* + * int_polarity_flag_bst_ocpok + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC (0x1<<2) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_POS 2 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_MSK 0x4 + +/* + * int_polarity_flag_bst_peakcur + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC (0x1<<3) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_POS 3 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_MSK 0x8 + +/* + * int_polarity_flag_bst_voutcomp + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC (0x1<<4) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_POS 4 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_MSK 0x10 + +/* + * int_polarity_flag_bst_voutcomp86 + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86 (0x1<<5) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_POS 5 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_MSK 0x20 + +/* + * int_polarity_flag_bst_voutcomp93 + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93 (0x1<<6) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_POS 6 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_MSK 0x40 + +/* + * int_polarity_flag_rcvldop_ready + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD (0x1<<7) +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_POS 7 +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_MSK 0x80 + +/* + * int_polarity_flag_ocp_alarm_left + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL (0x1<<8) +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_POS 8 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_MSK 0x100 + +/* + * int_polarity_flag_ocp_alarm_right + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR (0x1<<9) +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_POS 9 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_MSK 0x200 + +/* + * int_polarity_flag_man_wait_src_settings + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC (0x1<<10) +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_POS 10 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_MSK 0x400 + +/* + * int_polarity_flag_man_wait_cf_config + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC (0x1<<11) +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_POS 11 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_MSK 0x800 + +/* + * int_polarity_flag_man_start_mute_audio + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU (0x1<<12) +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_POS 12 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_MSK 0x1000 + +/* + * int_polarity_flag_cfma_err + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER (0x1<<13) +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_POS 13 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_MSK 0x2000 + +/* + * int_polarity_flag_cfma_ack + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC (0x1<<14) +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_POS 14 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_MSK 0x4000 + +/* + * int_polarity_flag_clk_out_of_range + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR (0x1<<15) +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_POS 15 +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_MSK 0x8000 + + +/* + * (0x4e)-status_polarity_reg3 + */ + +/* + * int_polarity_flag_tdm_error + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER (0x1<<0) +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_POS 0 +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_MSK 0x1 + +/* + * int_polarity_flag_clip_left + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL (0x1<<1) +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_POS 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_MSK 0x2 + +/* + * int_polarity_flag_clip_right + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR (0x1<<2) +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_POS 2 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_MSK 0x4 + +/* + * int_polarity_flag_mic_ocpok + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM (0x1<<3) +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_POS 3 +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_MSK 0x8 + + +/* + * (0x50)-bat_prot_config + */ + +/* + * vbat_prot_attack_time + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSCR (0x3<<0) +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_POS 0 +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_LEN 2 +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_MAX 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_MSK 0x3 + +/* + * vbat_prot_thlevel + */ +#define TFA98XX_BAT_PROT_CONFIG_BSST (0xf<<2) +#define TFA98XX_BAT_PROT_CONFIG_BSST_POS 2 +#define TFA98XX_BAT_PROT_CONFIG_BSST_LEN 4 +#define TFA98XX_BAT_PROT_CONFIG_BSST_MAX 15 +#define TFA98XX_BAT_PROT_CONFIG_BSST_MSK 0x3c + +/* + * vbat_prot_max_reduct + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSRL (0x3<<6) +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_POS 6 +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_LEN 2 +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_MAX 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_MSK 0xc0 + +/* + * vbat_prot_release_time + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSRR (0x7<<8) +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_POS 8 +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_LEN 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_MAX 7 +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_MSK 0x700 + +/* + * vbat_prot_hysterese + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSHY (0x3<<11) +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_POS 11 +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_LEN 2 +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_MAX 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_MSK 0x1800 + +/* + * sel_vbat + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSR (0x1<<14) +#define TFA98XX_BAT_PROT_CONFIG_BSSR_POS 14 +#define TFA98XX_BAT_PROT_CONFIG_BSSR_LEN 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSR_MAX 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSR_MSK 0x4000 + +/* + * bypass_clipper + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSBY (0x1<<15) +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_POS 15 +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_LEN 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_MAX 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_MSK 0x8000 + + +/* + * (0x51)-audio_control + */ + +/* + * batsense_steepness + */ +#define TFA98XX_AUDIO_CONTROL_BSSS (0x1<<0) +#define TFA98XX_AUDIO_CONTROL_BSSS_POS 0 +#define TFA98XX_AUDIO_CONTROL_BSSS_LEN 1 +#define TFA98XX_AUDIO_CONTROL_BSSS_MAX 1 +#define TFA98XX_AUDIO_CONTROL_BSSS_MSK 0x1 + +/* + * soft_mute + */ +#define TFA98XX_AUDIO_CONTROL_INTSMUTE (0x1<<1) +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_POS 1 +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_LEN 1 +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_MAX 1 +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_MSK 0x2 + +/* + * cf_mute_left + */ +#define TFA98XX_AUDIO_CONTROL_CFSML (0x1<<2) +#define TFA98XX_AUDIO_CONTROL_CFSML_POS 2 +#define TFA98XX_AUDIO_CONTROL_CFSML_LEN 1 +#define TFA98XX_AUDIO_CONTROL_CFSML_MAX 1 +#define TFA98XX_AUDIO_CONTROL_CFSML_MSK 0x4 + +/* + * cf_mute_right + */ +#define TFA98XX_AUDIO_CONTROL_CFSMR (0x1<<3) +#define TFA98XX_AUDIO_CONTROL_CFSMR_POS 3 +#define TFA98XX_AUDIO_CONTROL_CFSMR_LEN 1 +#define TFA98XX_AUDIO_CONTROL_CFSMR_MAX 1 +#define TFA98XX_AUDIO_CONTROL_CFSMR_MSK 0x8 + +/* + * bypass_hp_left + */ +#define TFA98XX_AUDIO_CONTROL_HPFBYPL (0x1<<4) +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_POS 4 +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_LEN 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_MAX 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_MSK 0x10 + +/* + * bypass_hp_right + */ +#define TFA98XX_AUDIO_CONTROL_HPFBYPR (0x1<<5) +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_POS 5 +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_LEN 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_MAX 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_MSK 0x20 + +/* + * enbl_dpsa_left + */ +#define TFA98XX_AUDIO_CONTROL_DPSAL (0x1<<6) +#define TFA98XX_AUDIO_CONTROL_DPSAL_POS 6 +#define TFA98XX_AUDIO_CONTROL_DPSAL_LEN 1 +#define TFA98XX_AUDIO_CONTROL_DPSAL_MAX 1 +#define TFA98XX_AUDIO_CONTROL_DPSAL_MSK 0x40 + +/* + * enbl_dpsa_right + */ +#define TFA98XX_AUDIO_CONTROL_DPSAR (0x1<<7) +#define TFA98XX_AUDIO_CONTROL_DPSAR_POS 7 +#define TFA98XX_AUDIO_CONTROL_DPSAR_LEN 1 +#define TFA98XX_AUDIO_CONTROL_DPSAR_MAX 1 +#define TFA98XX_AUDIO_CONTROL_DPSAR_MSK 0x80 + +/* + * cf_volume + */ +#define TFA98XX_AUDIO_CONTROL_VOL (0xff<<8) +#define TFA98XX_AUDIO_CONTROL_VOL_POS 8 +#define TFA98XX_AUDIO_CONTROL_VOL_LEN 8 +#define TFA98XX_AUDIO_CONTROL_VOL_MAX 255 +#define TFA98XX_AUDIO_CONTROL_VOL_MSK 0xff00 + + +/* + * (0x52)-amplifier_config + */ + +/* + * ctrl_rcv + */ +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV (0x1<<0) +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_POS 0 +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_LEN 1 +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_MAX 1 +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_MSK 0x1 + +/* + * ctrl_cc + */ +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL (0x7<<2) +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_POS 2 +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_LEN 3 +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_MAX 7 +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_MSK 0x1c + +/* + * gain + */ +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN (0xff<<5) +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_POS 5 +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_LEN 8 +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_MAX 255 +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_MSK 0x1fe0 + +/* + * ctrl_slopectrl + */ +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE (0x1<<13) +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_POS 13 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_LEN 1 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_MAX 1 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_MSK 0x2000 + +/* + * ctrl_slope + */ +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET (0x3<<14) +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_POS 14 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_LEN 2 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_MAX 3 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_MSK 0xc000 + + +/* + * (0x5a)-audio_control2 + */ + +/* + * cf_volume_sec + */ +#define TFA98XX_AUDIO_CONTROL2_VOLSEC (0xff<<0) +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_POS 0 +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_LEN 8 +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_MAX 255 +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_MSK 0xff + +/* + * sw_profile + */ +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL (0xff<<8) +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_POS 8 +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_LEN 8 +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_MAX 255 +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_MSK 0xff00 + + +/* + * (0x70)-dcdc_control0 + */ + +/* + * boost_volt + */ +#define TFA98XX_DCDC_CONTROL0_DCVO (0x7<<0) +#define TFA98XX_DCDC_CONTROL0_DCVO_POS 0 +#define TFA98XX_DCDC_CONTROL0_DCVO_LEN 3 +#define TFA98XX_DCDC_CONTROL0_DCVO_MAX 7 +#define TFA98XX_DCDC_CONTROL0_DCVO_MSK 0x7 + +/* + * boost_cur + */ +#define TFA98XX_DCDC_CONTROL0_DCMCC (0xf<<3) +#define TFA98XX_DCDC_CONTROL0_DCMCC_POS 3 +#define TFA98XX_DCDC_CONTROL0_DCMCC_LEN 4 +#define TFA98XX_DCDC_CONTROL0_DCMCC_MAX 15 +#define TFA98XX_DCDC_CONTROL0_DCMCC_MSK 0x78 + +/* + * bst_coil_value + */ +#define TFA98XX_DCDC_CONTROL0_DCCV (0x3<<7) +#define TFA98XX_DCDC_CONTROL0_DCCV_POS 7 +#define TFA98XX_DCDC_CONTROL0_DCCV_LEN 2 +#define TFA98XX_DCDC_CONTROL0_DCCV_MAX 3 +#define TFA98XX_DCDC_CONTROL0_DCCV_MSK 0x180 + +/* + * boost_intel + */ +#define TFA98XX_DCDC_CONTROL0_DCIE (0x1<<9) +#define TFA98XX_DCDC_CONTROL0_DCIE_POS 9 +#define TFA98XX_DCDC_CONTROL0_DCIE_LEN 1 +#define TFA98XX_DCDC_CONTROL0_DCIE_MAX 1 +#define TFA98XX_DCDC_CONTROL0_DCIE_MSK 0x200 + +/* + * boost_speed + */ +#define TFA98XX_DCDC_CONTROL0_DCSR (0x1<<10) +#define TFA98XX_DCDC_CONTROL0_DCSR_POS 10 +#define TFA98XX_DCDC_CONTROL0_DCSR_LEN 1 +#define TFA98XX_DCDC_CONTROL0_DCSR_MAX 1 +#define TFA98XX_DCDC_CONTROL0_DCSR_MSK 0x400 + +/* + * dcdc_synchronisation + */ +#define TFA98XX_DCDC_CONTROL0_DCSYNCP (0x7<<11) +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_POS 11 +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_LEN 3 +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_MAX 7 +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_MSK 0x3800 + +/* + * dcdcoff_mode + */ +#define TFA98XX_DCDC_CONTROL0_DCDIS (0x1<<14) +#define TFA98XX_DCDC_CONTROL0_DCDIS_POS 14 +#define TFA98XX_DCDC_CONTROL0_DCDIS_LEN 1 +#define TFA98XX_DCDC_CONTROL0_DCDIS_MAX 1 +#define TFA98XX_DCDC_CONTROL0_DCDIS_MSK 0x4000 + + +/* + * (0x90)-cf_controls + */ + +/* + * cf_rst_dsp + */ +#define TFA98XX_CF_CONTROLS_RST (0x1<<0) +#define TFA98XX_CF_CONTROLS_RST_POS 0 +#define TFA98XX_CF_CONTROLS_RST_LEN 1 +#define TFA98XX_CF_CONTROLS_RST_MAX 1 +#define TFA98XX_CF_CONTROLS_RST_MSK 0x1 + +/* + * cf_dmem + */ +#define TFA98XX_CF_CONTROLS_DMEM (0x3<<1) +#define TFA98XX_CF_CONTROLS_DMEM_POS 1 +#define TFA98XX_CF_CONTROLS_DMEM_LEN 2 +#define TFA98XX_CF_CONTROLS_DMEM_MAX 3 +#define TFA98XX_CF_CONTROLS_DMEM_MSK 0x6 + +/* + * cf_aif + */ +#define TFA98XX_CF_CONTROLS_AIF (0x1<<3) +#define TFA98XX_CF_CONTROLS_AIF_POS 3 +#define TFA98XX_CF_CONTROLS_AIF_LEN 1 +#define TFA98XX_CF_CONTROLS_AIF_MAX 1 +#define TFA98XX_CF_CONTROLS_AIF_MSK 0x8 + +/* + * cf_int + */ +#define TFA98XX_CF_CONTROLS_CFINT (0x1<<4) +#define TFA98XX_CF_CONTROLS_CFINT_POS 4 +#define TFA98XX_CF_CONTROLS_CFINT_LEN 1 +#define TFA98XX_CF_CONTROLS_CFINT_MAX 1 +#define TFA98XX_CF_CONTROLS_CFINT_MSK 0x10 + +/* + * cf_cgate_off + */ +#define TFA98XX_CF_CONTROLS_CFCGATE (0x1<<5) +#define TFA98XX_CF_CONTROLS_CFCGATE_POS 5 +#define TFA98XX_CF_CONTROLS_CFCGATE_LEN 1 +#define TFA98XX_CF_CONTROLS_CFCGATE_MAX 1 +#define TFA98XX_CF_CONTROLS_CFCGATE_MSK 0x20 + +/* + * cf_req_cmd + */ +#define TFA98XX_CF_CONTROLS_REQCMD (0x1<<8) +#define TFA98XX_CF_CONTROLS_REQCMD_POS 8 +#define TFA98XX_CF_CONTROLS_REQCMD_LEN 1 +#define TFA98XX_CF_CONTROLS_REQCMD_MAX 1 +#define TFA98XX_CF_CONTROLS_REQCMD_MSK 0x100 + +/* + * cf_req_reset + */ +#define TFA98XX_CF_CONTROLS_REQRST (0x1<<9) +#define TFA98XX_CF_CONTROLS_REQRST_POS 9 +#define TFA98XX_CF_CONTROLS_REQRST_LEN 1 +#define TFA98XX_CF_CONTROLS_REQRST_MAX 1 +#define TFA98XX_CF_CONTROLS_REQRST_MSK 0x200 + +/* + * cf_req_mips + */ +#define TFA98XX_CF_CONTROLS_REQMIPS (0x1<<10) +#define TFA98XX_CF_CONTROLS_REQMIPS_POS 10 +#define TFA98XX_CF_CONTROLS_REQMIPS_LEN 1 +#define TFA98XX_CF_CONTROLS_REQMIPS_MAX 1 +#define TFA98XX_CF_CONTROLS_REQMIPS_MSK 0x400 + +/* + * cf_req_mute_ready + */ +#define TFA98XX_CF_CONTROLS_REQMUTED (0x1<<11) +#define TFA98XX_CF_CONTROLS_REQMUTED_POS 11 +#define TFA98XX_CF_CONTROLS_REQMUTED_LEN 1 +#define TFA98XX_CF_CONTROLS_REQMUTED_MAX 1 +#define TFA98XX_CF_CONTROLS_REQMUTED_MSK 0x800 + +/* + * cf_req_volume_ready + */ +#define TFA98XX_CF_CONTROLS_REQVOL (0x1<<12) +#define TFA98XX_CF_CONTROLS_REQVOL_POS 12 +#define TFA98XX_CF_CONTROLS_REQVOL_LEN 1 +#define TFA98XX_CF_CONTROLS_REQVOL_MAX 1 +#define TFA98XX_CF_CONTROLS_REQVOL_MSK 0x1000 + +/* + * cf_req_damage + */ +#define TFA98XX_CF_CONTROLS_REQDMG (0x1<<13) +#define TFA98XX_CF_CONTROLS_REQDMG_POS 13 +#define TFA98XX_CF_CONTROLS_REQDMG_LEN 1 +#define TFA98XX_CF_CONTROLS_REQDMG_MAX 1 +#define TFA98XX_CF_CONTROLS_REQDMG_MSK 0x2000 + +/* + * cf_req_calibrate_ready + */ +#define TFA98XX_CF_CONTROLS_REQCAL (0x1<<14) +#define TFA98XX_CF_CONTROLS_REQCAL_POS 14 +#define TFA98XX_CF_CONTROLS_REQCAL_LEN 1 +#define TFA98XX_CF_CONTROLS_REQCAL_MAX 1 +#define TFA98XX_CF_CONTROLS_REQCAL_MSK 0x4000 + +/* + * cf_req_reserved + */ +#define TFA98XX_CF_CONTROLS_REQRSV (0x1<<15) +#define TFA98XX_CF_CONTROLS_REQRSV_POS 15 +#define TFA98XX_CF_CONTROLS_REQRSV_LEN 1 +#define TFA98XX_CF_CONTROLS_REQRSV_MAX 1 +#define TFA98XX_CF_CONTROLS_REQRSV_MSK 0x8000 + + +/* + * (0x91)-cf_mad + */ + +/* + * cf_madd + */ +#define TFA98XX_CF_MAD_MADD (0xffff<<0) +#define TFA98XX_CF_MAD_MADD_POS 0 +#define TFA98XX_CF_MAD_MADD_LEN 16 +#define TFA98XX_CF_MAD_MADD_MAX 65535 +#define TFA98XX_CF_MAD_MADD_MSK 0xffff + + +/* + * (0x92)-cf_mem + */ + +/* + * cf_mema + */ +#define TFA98XX_CF_MEM_MEMA (0xffff<<0) +#define TFA98XX_CF_MEM_MEMA_POS 0 +#define TFA98XX_CF_MEM_MEMA_LEN 16 +#define TFA98XX_CF_MEM_MEMA_MAX 65535 +#define TFA98XX_CF_MEM_MEMA_MSK 0xffff + + +/* + * (0x93)-cf_status + */ + +/* + * cf_err + */ +#define TFA98XX_CF_STATUS_ERR (0xff<<0) +#define TFA98XX_CF_STATUS_ERR_POS 0 +#define TFA98XX_CF_STATUS_ERR_LEN 8 +#define TFA98XX_CF_STATUS_ERR_MAX 255 +#define TFA98XX_CF_STATUS_ERR_MSK 0xff + +/* + * cf_ack_cmd + */ +#define TFA98XX_CF_STATUS_ACKCMD (0x1<<8) +#define TFA98XX_CF_STATUS_ACKCMD_POS 8 +#define TFA98XX_CF_STATUS_ACKCMD_LEN 1 +#define TFA98XX_CF_STATUS_ACKCMD_MAX 1 +#define TFA98XX_CF_STATUS_ACKCMD_MSK 0x100 + +/* + * cf_ack_reset + */ +#define TFA98XX_CF_STATUS_ACKRST (0x1<<9) +#define TFA98XX_CF_STATUS_ACKRST_POS 9 +#define TFA98XX_CF_STATUS_ACKRST_LEN 1 +#define TFA98XX_CF_STATUS_ACKRST_MAX 1 +#define TFA98XX_CF_STATUS_ACKRST_MSK 0x200 + +/* + * cf_ack_mips + */ +#define TFA98XX_CF_STATUS_ACKMIPS (0x1<<10) +#define TFA98XX_CF_STATUS_ACKMIPS_POS 10 +#define TFA98XX_CF_STATUS_ACKMIPS_LEN 1 +#define TFA98XX_CF_STATUS_ACKMIPS_MAX 1 +#define TFA98XX_CF_STATUS_ACKMIPS_MSK 0x400 + +/* + * cf_ack_mute_ready + */ +#define TFA98XX_CF_STATUS_ACKMUTED (0x1<<11) +#define TFA98XX_CF_STATUS_ACKMUTED_POS 11 +#define TFA98XX_CF_STATUS_ACKMUTED_LEN 1 +#define TFA98XX_CF_STATUS_ACKMUTED_MAX 1 +#define TFA98XX_CF_STATUS_ACKMUTED_MSK 0x800 + +/* + * cf_ack_volume_ready + */ +#define TFA98XX_CF_STATUS_ACKVOL (0x1<<12) +#define TFA98XX_CF_STATUS_ACKVOL_POS 12 +#define TFA98XX_CF_STATUS_ACKVOL_LEN 1 +#define TFA98XX_CF_STATUS_ACKVOL_MAX 1 +#define TFA98XX_CF_STATUS_ACKVOL_MSK 0x1000 + +/* + * cf_ack_damage + */ +#define TFA98XX_CF_STATUS_ACKDMG (0x1<<13) +#define TFA98XX_CF_STATUS_ACKDMG_POS 13 +#define TFA98XX_CF_STATUS_ACKDMG_LEN 1 +#define TFA98XX_CF_STATUS_ACKDMG_MAX 1 +#define TFA98XX_CF_STATUS_ACKDMG_MSK 0x2000 + +/* + * cf_ack_calibrate_ready + */ +#define TFA98XX_CF_STATUS_ACKCAL (0x1<<14) +#define TFA98XX_CF_STATUS_ACKCAL_POS 14 +#define TFA98XX_CF_STATUS_ACKCAL_LEN 1 +#define TFA98XX_CF_STATUS_ACKCAL_MAX 1 +#define TFA98XX_CF_STATUS_ACKCAL_MSK 0x4000 + +/* + * cf_ack_reserved + */ +#define TFA98XX_CF_STATUS_ACKRSV (0x1<<15) +#define TFA98XX_CF_STATUS_ACKRSV_POS 15 +#define TFA98XX_CF_STATUS_ACKRSV_LEN 1 +#define TFA98XX_CF_STATUS_ACKRSV_MAX 1 +#define TFA98XX_CF_STATUS_ACKRSV_MSK 0x8000 + + +/* + * (0xa1)-mtpkey2_reg + */ + +/* + * mtpkey2 + */ +#define TFA98XX_MTPKEY2_REG_MTPK (0xff<<0) +#define TFA98XX_MTPKEY2_REG_MTPK_POS 0 +#define TFA98XX_MTPKEY2_REG_MTPK_LEN 8 +#define TFA98XX_MTPKEY2_REG_MTPK_MAX 255 +#define TFA98XX_MTPKEY2_REG_MTPK_MSK 0xff + + +/* + * (0xa2)-mtp_status + */ + +/* + * key01_locked + */ +#define TFA98XX_MTP_STATUS_KEY1LOCKED (0x1<<0) +#define TFA98XX_MTP_STATUS_KEY1LOCKED_POS 0 +#define TFA98XX_MTP_STATUS_KEY1LOCKED_LEN 1 +#define TFA98XX_MTP_STATUS_KEY1LOCKED_MAX 1 +#define TFA98XX_MTP_STATUS_KEY1LOCKED_MSK 0x1 + +/* + * key02_locked + */ +#define TFA98XX_MTP_STATUS_KEY2LOCKED (0x1<<1) +#define TFA98XX_MTP_STATUS_KEY2LOCKED_POS 1 +#define TFA98XX_MTP_STATUS_KEY2LOCKED_LEN 1 +#define TFA98XX_MTP_STATUS_KEY2LOCKED_MAX 1 +#define TFA98XX_MTP_STATUS_KEY2LOCKED_MSK 0x2 + + +/* + * (0xa3)-KEY_protected_mtp_control + */ + +/* + * auto_copy_iic_to_mtp + */ +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP (0x1<<6) +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_POS 6 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_LEN 1 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_MAX 1 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_MSK 0x40 + + +/* + * (0xa5)-mtp_data_out_msb + */ + +/* + * mtp_man_data_out_msb + */ +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB (0xffff<<0) +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_POS 0 +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_LEN 16 +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_MAX 65535 +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_MSK 0xffff + + +/* + * (0xa6)-mtp_data_out_lsb + */ + +/* + * mtp_man_data_out_lsb + */ +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB (0xffff<<0) +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_POS 0 +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_LEN 16 +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_MAX 65535 +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_MSK 0xffff + + +/* + * (0xb1)-temp_sensor_config + */ + +/* + * ext_temp + */ +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS (0x1ff<<0) +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_POS 0 +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_LEN 9 +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_MAX 511 +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_MSK 0x1ff + +/* + * ext_temp_sel + */ +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS (0x1<<9) +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_POS 9 +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_LEN 1 +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_MAX 1 +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_MSK 0x200 + + +/* + * (0xf0)-KEY2_protected_MTP0 + */ + +/* + * calibration_onetime + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC (0x1<<0) +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_POS 0 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK 0x1 + +/* + * calibr_ron_done + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX (0x1<<1) +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_POS 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK 0x2 + +/* + * calibr_dcdc_api_calibrate + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI (0x1<<2) +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_POS 2 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_MSK 0x4 + +/* + * calibr_dcdc_delta_sign + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB (0x1<<3) +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_POS 3 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_MSK 0x8 + +/* + * calibr_dcdc_delta + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF (0x7<<4) +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_POS 4 +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_LEN 3 +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_MAX 7 +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_MSK 0x70 + + +/* + * (0xf4)-KEY1_protected_MTP4 + */ + + +/* + * (0xf5)-KEY1_protected_MTP5 + */ + +#endif /* TFA98XX_GENREGS_H */ diff --git a/sound/soc/codecs/tfa98xx_parameters.h b/sound/soc/codecs/tfa98xx_parameters.h new file mode 100644 index 0000000000000000000000000000000000000000..d2d68f7e598c7e881561fa1f10208a3e03397a57 --- /dev/null +++ b/sound/soc/codecs/tfa98xx_parameters.h @@ -0,0 +1,724 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA98XXPARAMETERS_H_ +#define TFA98XXPARAMETERS_H_ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#include "tfa_service.h" + +#if (defined(WIN32) || defined(_X64)) +/* These warnings are disabled because it is only given by Windows and there is no easy fix */ +#pragma warning(disable:4200) +#pragma warning(disable:4214) +#endif + +/* + * profiles & volumesteps + * + */ +#define TFA_MAX_PROFILES (64) +#define TFA_MAX_VSTEPS (64) +#define TFA_MAX_VSTEP_MSG_MARKER (100) /* This marker is used to indicate if all msgs need to be written to the device */ +#define TFA_MAX_MSGS (10) + +// the pack pragma is required to make that the size in memory +// matches the actual variable lenghts +// This is to assure that the binary files can be transported between +// different platforms. +#pragma pack (push, 1) + +/* + * typedef for 24 bit value using 3 bytes + */ +typedef struct uint24 { + uint8_t b[3]; +} uint24_t; +/* + * the generic header + * all char types are in ASCII + */ +typedef struct nxpTfaHeader { + uint16_t id; + char version[2]; // "V_" : V=version, vv=subversion + char subversion[2]; // "vv" : vv=subversion + uint16_t size; // data size in bytes following CRC + uint32_t CRC; // 32-bits CRC for following data + char customer[8]; // “name of customer” + char application[8]; // “application name” + char type[8]; // “application type name” +} nxpTfaHeader_t; + +typedef enum nxpTfaSamplerate { + fs_8k, // 8kHz + fs_11k025, // 11.025kHz + fs_12k, // 12kHz + fs_16k, // 16kHz + fs_22k05, // 22.05kHz + fs_24k, // 24kHz + fs_32k, // 32kHz + fs_44k1, // 44.1kHz + fs_48k, // 48kHz + fs_96k, // 96kHz + fs_count // Should always be last item. +} nxpTfaSamplerate_t; + +// Keep in sync with nxpTfaSamplerate_t ! +static const int nxpTfaSamplerateHz[fs_count] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 96000 }; + + +/* + * coolflux direct memory access + */ +typedef struct nxpTfaDspMem { + uint8_t type; /* 0--3: p, x, y, iomem */ + uint16_t address; /* target address */ + uint8_t size; /* data size in words */ + int words[]; /* payload in signed 32bit integer (two's complement) */ +} nxpTfaDspMem_t; + +/* + * the biquad coefficients for the API together with index in filter + * the biquad_index is the actual index in the equalizer +1 + */ +#define BIQUAD_COEFF_SIZE 6 + +/* +* Output fixed point coeffs structure +*/ +typedef struct { + int a2; + int a1; + int b2; + int b1; + int b0; +} nxpTfaBiquad_t; + +typedef struct nxpTfaBiquadOld { + uint8_t bytes[BIQUAD_COEFF_SIZE*sizeof(uint24_t)]; +} nxpTfaBiquadOld_t; + +typedef struct nxpTfaBiquadFloat { + float headroom; + float b0; + float b1; + float b2; + float a1; + float a2; +} nxpTfaBiquadFloat_t; + +/* +* EQ filter definitions +* Note: This is not in line with smartstudio (JV: 12/12/2016) +*/ +typedef enum nxpTfaFilterType { + fCustom, //User defined biquad coefficients + fFlat, //Vary only gain + fLowpass, //2nd order Butterworth low pass + fHighpass, //2nd order Butterworth high pass + fLowshelf, + fHighshelf, + fNotch, + fPeak, + fBandpass, + f1stLP, + f1stHP, + fElliptic +} nxpTfaFilterType_t; + +/* + * filter parameters for biquad (re-)calculation + */ +typedef struct nxpTfaFilter { + nxpTfaBiquadOld_t biquad; + uint8_t enabled; + uint8_t type; // (== enum FilterTypes, assure 8bits length) + float frequency; + float Q; + float gain; +} nxpTfaFilter_t ; //8 * float + int32 + byte == 37 + +/* + * biquad params for calculation +*/ + +#define TFA_BQ_EQ_INDEX 0 +#define TFA_BQ_ANTI_ALIAS_INDEX 10 +#define TFA_BQ_INTEGRATOR_INDEX 13 + +/* +* Loudspeaker Compensation filter definitions +*/ +typedef struct nxpTfaLsCompensationFilter { + nxpTfaBiquad_t biquad; + uint8_t lsCompOn; // Loudspeaker compensation on/off; when 'off', the DSP code doesn't apply the bwExt => bwExtOn GUI flag should be gray to avoid confusion + uint8_t bwExtOn; // Bandwidth extension on/off + float fRes; // [Hz] speaker resonance frequency + float Qt; // Speaker resonance Q-factor + float fBwExt; // [Hz] Band width extension frequency + float samplingFreq;// [Hz] Sampling frequency +} nxpTfaLsCompensationFilter_t; + +/* +* Anti Aliasing Elliptic filter definitions +*/ +typedef struct nxpTfaAntiAliasFilter { + nxpTfaBiquad_t biquad; /**< Output results fixed point coeffs */ + uint8_t enabled; + float cutOffFreq; // cut off frequency + float samplingFreq; // sampling frequency + float rippleDb; // range: [0.1 3.0] + float rolloff; // range: [-1.0 1.0] +} nxpTfaAntiAliasFilter_t; + +/** +* Integrator filter input definitions +*/ +typedef struct nxpTfaIntegratorFilter { + nxpTfaBiquad_t biquad; /**< Output results fixed point coeffs */ + uint8_t type; /**< Butterworth filter type: high or low pass */ + float cutOffFreq; /**< cut off frequency in Hertz; range: [100.0 4000.0] */ + float samplingFreq; /**< sampling frequency in Hertz */ + float leakage; /**< leakage factor; range [0.0 1.0] */ +} nxpTfaIntegratorFilter_t; + + +typedef struct nxpTfaEqFilter { + nxpTfaBiquad_t biquad; + uint8_t enabled; + uint8_t type; // (== enum FilterTypes, assure 8bits length) + float cutOffFreq; // cut off frequency, // range: [100.0 4000.0] + float samplingFreq; // sampling frequency + float Q; // range: [0.5 5.0] + float gainDb; // range: [-10.0 10.0] +} nxpTfaEqFilter_t ; //8 * float + int32 + byte == 37 + +typedef struct nxpTfaContAntiAlias { + int8_t index; /**< index determines destination type; anti-alias, integrator,eq */ + uint8_t type; + float cutOffFreq; // cut off frequency + float samplingFreq; + float rippleDb; // integrator leakage + float rolloff; + uint8_t bytes[5*3]; // payload 5*24buts coeffs +} nxpTfaContAntiAlias_t; + +typedef struct nxpTfaContIntegrator { + int8_t index; /**< index determines destination type; anti-alias, integrator,eq */ + uint8_t type; + float cutOffFreq; // cut off frequency + float samplingFreq; + float leakage; // integrator leakage + float reserved; + uint8_t bytes[5*3]; // payload 5*24buts coeffs +} nxpTfaContIntegrator_t; + +typedef struct nxpTfaContEq { + int8_t index; + uint8_t type; // (== enum FilterTypes, assure 8bits length) + float cutOffFreq; // cut off frequency, // range: [100.0 4000.0] + float samplingFreq; // sampling frequency + float Q; // range: [0.5 5.0] + float gainDb; // range: [-10.0 10.0] + uint8_t bytes[5*3]; // payload 5*24buts coeffs +} nxpTfaContEq_t ; //8 * float + int32 + byte == 37 + +typedef union nxpTfaContBiquad { + nxpTfaContEq_t eq; + nxpTfaContAntiAlias_t aa; + nxpTfaContIntegrator_t in; +} nxpTfaContBiquad_t; + +#define TFA_BQ_EQ_INDEX 0 +#define TFA_BQ_ANTI_ALIAS_INDEX 10 +#define TFA_BQ_INTEGRATOR_INDEX 13 +#define TFA98XX_MAX_EQ 10 + +typedef struct nxpTfaEqualizer { + nxpTfaFilter_t filter[TFA98XX_MAX_EQ]; +} nxpTfaEqualizer_t; + +/* + * files + */ +#define HDR(c1, c2) (c2<<8|c1) // little endian +typedef enum nxpTfaHeaderType { + paramsHdr = HDR('P', 'M'), /* containter file */ + volstepHdr = HDR('V', 'P'), + patchHdr = HDR('P', 'A'), + speakerHdr = HDR('S', 'P'), + presetHdr = HDR('P', 'R'), + configHdr = HDR('C', 'O'), + equalizerHdr = HDR('E', 'Q'), + drcHdr = HDR('D', 'R'), + msgHdr = HDR('M', 'G'), /* generic message */ + infoHdr = HDR('I', 'N') +} nxpTfaHeaderType_t; + +/* + * equalizer file + */ +#define NXPTFA_EQ_VERSION '1' +#define NXPTFA_EQ_SUBVERSION "00" +typedef struct nxpTfaEqualizerFile { + nxpTfaHeader_t hdr; + uint8_t samplerate; // ==enum samplerates, assure 8 bits + nxpTfaFilter_t filter[TFA98XX_MAX_EQ];// note: API index counts from 1..10 +} nxpTfaEqualizerFile_t; + +/* + * patch file + */ +#define NXPTFA_PA_VERSION '1' +#define NXPTFA_PA_SUBVERSION "00" +typedef struct nxpTfaPatchFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaPatch_t; + +/* + * generic message file + * - the payload of this file includes the opcode and is send straight to the DSP + */ +#define NXPTFA_MG_VERSION '3' +#define NXPTFA_MG_SUBVERSION "00" +typedef struct nxpTfaMsgFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaMsgFile_t; + +/* + * NOTE the tfa98xx API defines the enum Tfa98xx_config_type that defines + * the subtypes as decribes below. + * tfa98xx_dsp_config_parameter_type() can be used to get the + * supported type for the active device.. + */ +/* + * config file V1 sub 1 + */ +#define NXPTFA_CO_VERSION '1' +#define NXPTFA_CO3_VERSION '3' +#define NXPTFA_CO_SUBVERSION1 "01" +typedef struct nxpTfaConfigS1File { + nxpTfaHeader_t hdr; + uint8_t data[55*3]; +} nxpTfaConfigS1_t; + +/* + * config file V1 sub 2 + */ +#define NXPTFA_CO_SUBVERSION2 "02" +typedef struct nxpTfaConfigS2File { + nxpTfaHeader_t hdr; + uint8_t data[67*3]; +} nxpTfaConfigS2_t; + +/* + * config file V1 sub 3 + */ +#define NXPTFA_CO_SUBVERSION3 "03" +typedef struct nxpTfaConfigS3File { + nxpTfaHeader_t hdr; + uint8_t data[67*3]; +} nxpTfaConfigS3_t; + +/* + * config file V1.0 + */ +#define NXPTFA_CO_SUBVERSION "00" +typedef struct nxpTfaConfigFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaConfig_t; + +/* + * preset file + */ +#define NXPTFA_PR_VERSION '1' +#define NXPTFA_PR_SUBVERSION "00" +typedef struct nxpTfaPresetFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaPreset_t; + +/* + * drc file + */ +#define NXPTFA_DR_VERSION '1' +#define NXPTFA_DR_SUBVERSION "00" +typedef struct nxpTfaDrcFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaDrc_t; + +/* + * drc file + * for tfa 2 there is also a xml-version + */ +#define NXPTFA_DR3_VERSION '3' +#define NXPTFA_DR3_SUBVERSION "00" +typedef struct nxpTfaDrcFile2 { + nxpTfaHeader_t hdr; + uint8_t version[3]; + uint8_t data[]; +} nxpTfaDrc2_t; + +/* + * volume step structures + */ +// VP01 +#define NXPTFA_VP1_VERSION '1' +#define NXPTFA_VP1_SUBVERSION "01" +typedef struct nxpTfaVolumeStep1 { + float attenuation; // IEEE single float + uint8_t preset[TFA98XX_PRESET_LENGTH]; +} nxpTfaVolumeStep1_t; + +// VP02 +#define NXPTFA_VP2_VERSION '2' +#define NXPTFA_VP2_SUBVERSION "01" +typedef struct nxpTfaVolumeStep2 { + float attenuation; // IEEE single float + uint8_t preset[TFA98XX_PRESET_LENGTH]; + nxpTfaFilter_t filter[TFA98XX_MAX_EQ];// note: API index counts from 1..10 +} nxpTfaVolumeStep2_t; + +/* + * volumestep file + */ +#define NXPTFA_VP_VERSION '1' +#define NXPTFA_VP_SUBVERSION "00" +typedef struct nxpTfaVolumeStepFile { + nxpTfaHeader_t hdr; + uint8_t vsteps; // can also be calulated from size+type + uint8_t samplerate; // ==enum samplerates, assure 8 bits + uint8_t payload; //start of variable length contents:N times volsteps +} nxpTfaVolumeStepFile_t; +/* + * volumestep2 file + */ +typedef struct nxpTfaVolumeStep2File { + nxpTfaHeader_t hdr; + uint8_t vsteps; // can also be calulated from size+type + uint8_t samplerate; // ==enum samplerates, assure 8 bits + nxpTfaVolumeStep2_t vstep[]; //start of variable length contents:N times volsteps +} nxpTfaVolumeStep2File_t; + +/* + * volumestepMax2 file + */ +typedef struct nxpTfaVolumeStepMax2File { + nxpTfaHeader_t hdr; + uint8_t version[3]; + uint8_t NrOfVsteps; + uint8_t vstepsBin[]; +} nxpTfaVolumeStepMax2File_t; + +/* + * volumestepMax2 file + * This volumestep should ONLY be used for the use of bin2hdr! + * This can only be used to find the messagetype of the vstep (without header) + */ +typedef struct nxpTfaVolumeStepMax2_1File { + uint8_t version[3]; + uint8_t NrOfVsteps; + uint8_t vstepsBin[]; +} nxpTfaVolumeStepMax2_1File_t; + +struct nxpTfaVolumeStepRegisterInfo { + uint8_t NrOfRegisters; + uint16_t registerInfo[]; +}; + +struct nxpTfaVolumeStepMessageInfo { + uint8_t NrOfMessages; + uint8_t MessageType; + uint24_t MessageLength; + uint8_t CmdId[3]; + uint8_t ParameterData[]; +}; +/**************************old v2 *************************************************/ + +/* + * subv 00 volumestep file + */ +typedef struct nxpTfaOldHeader { + uint16_t id; + char version[2]; // "V_" : V=version, vv=subversion + char subversion[2]; // "vv" : vv=subversion + uint16_t size; // data size in bytes following CRC + uint32_t CRC; // 32-bits CRC for following data +} nxpTfaOldHeader_t; + +typedef struct nxpOldTfaFilter { + double bq[5]; + int32_t type; + double frequency; + double Q; + double gain; + uint8_t enabled; +} nxpTfaOldFilter_t ; + +typedef struct nxpTfaOldVolumeStep2 { + float attenuation; // IEEE single float + uint8_t preset[TFA98XX_PRESET_LENGTH]; + nxpTfaOldFilter_t eq[10]; +} nxpTfaOldVolumeStep2_t; + +typedef struct nxpTfaOldVolumeStepFile { + nxpTfaOldHeader_t hdr; + nxpTfaOldVolumeStep2_t step[]; +} nxpTfaOldVolumeStep2File_t; +/**************************end old v2 *************************************************/ + +/* + * speaker file header + */ +struct nxpTfaSpkHeader { + struct nxpTfaHeader hdr; + char name[8]; // speaker nick name (e.g. “dumbo”) + char vendor[16]; + char type[8]; + // dimensions (mm) + uint8_t height; + uint8_t width; + uint8_t depth; + uint16_t ohm; +}; + +/* + * speaker file + */ +#define NXPTFA_SP_VERSION '1' +#define NXPTFA_SP_SUBVERSION "00" +typedef struct nxpTfaSpeakerFile { + nxpTfaHeader_t hdr; + char name[8]; // speaker nick name (e.g. “dumbo”) + char vendor[16]; + char type[8]; + // dimensions (mm) + uint8_t height; + uint8_t width; + uint8_t depth; + uint8_t ohm_primary; + uint8_t ohm_secondary; + uint8_t data[]; //payload TFA98XX_SPEAKERPARAMETER_LENGTH +} nxpTfaSpeakerFile_t; + +#define NXPTFA_VP3_VERSION '3' +#define NXPTFA_VP3_SUBVERSION "00" + +struct nxpTfaFWVer { + uint8_t Major; + uint8_t minor; + uint8_t minor_update:6; + uint8_t Update:2; +}; + +struct nxpTfaFWMsg { + struct nxpTfaFWVer fwVersion; + struct nxpTfaMsg payload; +}; + +typedef struct nxpTfaLiveData { + char name[25]; + char addrs[25]; + int tracker; + int scalefactor; +} nxpTfaLiveData_t; + +#define NXPTFA_SP3_VERSION '3' +#define NXPTFA_SP3_SUBVERSION "00" +struct nxpTfaSpeakerFileMax2 { + nxpTfaHeader_t hdr; + char name[8]; // speaker nick name (e.g. “dumbo”) + char vendor[16]; + char type[8]; + // dimensions (mm) + uint8_t height; + uint8_t width; + uint8_t depth; + uint8_t ohm_primary; + uint8_t ohm_secondary; + struct nxpTfaFWMsg FWmsg; //payload including FW ver and Cmd ID +}; + +/* + * parameter container file + */ +/* + * descriptors + * Note 1: append new DescriptorType at the end + * Note 2: add new descriptors to dsc_name[] in tfaContUtil.c + */ +typedef enum nxpTfaDescriptorType { + dscDevice, // device list + dscProfile, // profile list + dscRegister, // register patch + dscString, // ascii, zero terminated string + dscFile, // filename + file contents + dscPatch, // patch file + dscMarker, // marker to indicate end of a list + dscMode, + dscSetInputSelect, + dscSetOutputSelect, + dscSetProgramConfig, + dscSetLagW, + dscSetGains, + dscSetvBatFactors, + dscSetSensesCal, + dscSetSensesDelay, + dscBitfield, + dscDefault, // used to reset bitfields to there default values + dscLiveData, + dscLiveDataString, + dscGroup, + dscCmd, + dscSetMBDrc, + dscFilter, + dscNoInit, + dscFeatures, + dscCfMem, // coolflux memory x,y,io + dscSetFwkUseCase, + dscSetVddpConfig, + dsc_last // trailer +} nxpTfaDescriptorType_t; + +#define TFA_BITFIELDDSCMSK 0x7fffffff +typedef struct nxpTfaDescPtr { + uint32_t offset:24; + uint32_t type:8; // (== enum nxpTfaDescriptorType, assure 8bits length) +} nxpTfaDescPtr_t; + +/* + * generic file descriptor + */ +typedef struct nxpTfaFileDsc { + nxpTfaDescPtr_t name; + uint32_t size; // file data length in bytes + uint8_t data[]; //payload +} nxpTfaFileDsc_t; + + +/* + * device descriptor list + */ +typedef struct nxpTfaDeviceList { + uint8_t length; // nr of items in the list + uint8_t bus; // bus + uint8_t dev; // device + uint8_t func; // subfunction or subdevice + uint32_t devid; // device hw fw id + nxpTfaDescPtr_t name; // device name + nxpTfaDescPtr_t list[]; // items list +} nxpTfaDeviceList_t; + +/* + * profile descriptor list + */ +typedef struct nxpTfaProfileList { + uint32_t length:8; // nr of items in the list + name + uint32_t group:8; // profile group number + uint32_t ID:16; // profile ID + nxpTfaDescPtr_t name; // profile name + nxpTfaDescPtr_t list[]; // items list (lenght-1 items) +} nxpTfaProfileList_t; +#define TFA_PROFID 0x1234 + +/* + * livedata descriptor list + */ +typedef struct nxpTfaLiveDataList { + uint32_t length:8; // nr of items in the list + uint32_t ID:24; // profile ID + nxpTfaDescPtr_t name; // livedata name + nxpTfaDescPtr_t list[]; // items list +} nxpTfaLiveDataList_t; +#define TFA_LIVEDATAID 0x5678 + +/* + * Bitfield descriptor + */ +typedef struct nxpTfaBitfield { + uint16_t value; + uint16_t field; // ==datasheet defined, 16 bits +} nxpTfaBitfield_t; + +/* + * Bitfield enumuration bits descriptor + */ +typedef struct nxpTfaBfEnum { + unsigned int len:4; // this is the actual length-1 + unsigned int pos:4; + unsigned int address:8; +} nxpTfaBfEnum_t; + +/* + * Register patch descriptor + */ +typedef struct nxpTfaRegpatch { + uint8_t address; // register address + uint16_t value; // value to write + uint16_t mask; // mask of bits to write +} nxpTfaRegpatch_t; + +/* + * Mode descriptor + */ +typedef struct nxpTfaUseCase { + int value; // mode value, maps to enum Tfa98xx_Mode +} nxpTfaMode_t; + +/* + * NoInit descriptor + */ +typedef struct nxpTfaNoInit { + uint8_t value; // noInit value +} nxpTfaNoInit_t; + +/* + * Features descriptor + */ +typedef struct nxpTfaFeatures { + uint16_t value[3]; // features value +} nxpTfaFeatures_t; + + +/* + * the container file + * - the size field is 32bits long (generic=16) + * - all char types are in ASCII + */ +#define NXPTFA_PM_VERSION '1' +#define NXPTFA_PM3_VERSION '3' +#define NXPTFA_PM_SUBVERSION '1' +typedef struct nxpTfaContainer { + char id[2]; // "XX" : XX=type + char version[2]; // "V_" : V=version, vv=subversion + char subversion[2]; // "vv" : vv=subversion + uint32_t size; // data size in bytes following CRC + uint32_t CRC; // 32-bits CRC for following data + uint16_t rev; // "extra chars for rev nr" + char customer[8]; // “name of customer” + char application[8]; // “application name” + char type[8]; // “application type name” + uint16_t ndev; // "nr of device lists" + uint16_t nprof; // "nr of profile lists" + uint16_t nliveData; // "nr of livedata lists" + nxpTfaDescPtr_t index[]; // start of item index table +} nxpTfaContainer_t; + +#pragma pack (pop) + +#endif /* TFA98XXPARAMETERS_H_ */ diff --git a/sound/soc/codecs/tfa98xx_tfafieldnames.h b/sound/soc/codecs/tfa98xx_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..09f98337c54c1ce8acc8c91a0b52dd82e97d5529 --- /dev/null +++ b/sound/soc/codecs/tfa98xx_tfafieldnames.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +typedef struct TfaBfName { + unsigned short bfEnum; + char *bfName; +} tfaBfName_t; + +typedef struct TfaIrqName { + unsigned short irqEnum; + char *irqName; +} tfaIrqName_t; + +#include "tfa1_tfafieldnames.h" +#include "tfa2_tfafieldnames_N1C.h" +/* diffs for specific devices */ +#include "tfa9887_tfafieldnames.h" +#include "tfa9890_tfafieldnames.h" +#include "tfa9891_tfafieldnames.h" +#include "tfa9872_tfafieldnames.h" +#include "tfa9912_tfafieldnames.h" +#include "tfa9896_tfafieldnames.h" +#include "tfa9874_tfafieldnames.h" +#include "tfa9878_tfafieldnames.h" +#include "tfa9894_tfafieldnames.h" +#include "tfa9894_tfafieldnames_N2.h" + +/* missing 'common' defs break the build but unused in TFA1 context */ +#define TFA1_BF_AMPINSEL -1 +#define TFA1_BF_MANSCONF -1 +#define TFA1_BF_MANCOLD -1 +#define TFA1_BF_INTSMUTE -1 +#define TFA1_BF_CFSMR -1 +#define TFA1_BF_CFSML -1 +#define TFA1_BF_DCMCCAPI -1 +#define TFA1_BF_DCMCCSB -1 +#define TFA1_BF_USERDEF -1 +#define TFA1_BF_MANSTATE -1 +#define TFA1_BF_MANOPER -1 +#define TFA1_BF_REFCKSEL -1 +#define TFA1_BF_VOLSEC -1 +#define TFA1_BF_FRACTDEL -1 +#define TFA1_BF_ACKDMG -1 +#define TFA1_BF_SSRIGHTE -1 +#define TFA1_BF_SSLEFTE -1 +#define TFA1_BF_R25CL -1 +#define TFA1_BF_R25CR -1 +#define TFA1_BF_SWPROFIL 0x8045 /*!< profile save */ +#define TFA1_BF_SWVSTEP 0x80a5 /*!< vstep save */ + +/* missing 'common' defs break the build */ +#define TFA2_BF_CFSM -1 + + +/* MTP access uses registers + * defs are derived from corresponding bitfield names as used in the BF macros + */ +#define MTPKEY2 MTPK /* unlock key2 MTPK */ +#define MTP0 MTPOTC /* MTP data */ +#define MTP_CONTROL CIMTP /* copy i2c to mtp */ + +/* interrupt enable register uses HW name in TFA2 */ +#define TFA2_BF_INTENVDDS TFA2_BF_IEVDDS + + +/* TFA9891 specific bit field names */ +#define TFA1_BF_SAAMGAIN 0x2202 +#define TFA2_BF_SAAMGAIN -1 + +/* TFA9872 specific bit field names */ +#define TFA2_BF_IELP0 TFA9872_BF_IELP0 +#define TFA2_BF_ISTLP0 TFA9872_BF_ISTLP0 +#define TFA2_BF_IPOLP0 TFA9872_BF_IPOLP0 +#define TFA2_BF_IELP1 TFA9872_BF_IELP1 +#define TFA2_BF_ISTLP1 TFA9872_BF_ISTLP1 +#define TFA2_BF_IPOLP1 TFA9872_BF_IPOLP1 +#define TFA2_BF_LP0 TFA9872_BF_LP0 +#define TFA2_BF_LP1 TFA9872_BF_LP1 +#define TFA2_BF_R25C TFA9872_BF_R25C +#define TFA2_BF_SAMMODE TFA9872_BF_SAMMODE + +/* interrupt bit field names of TFA2 and TFA1 do not match */ +#define TFA1_BF_IEACS TFA1_BF_INTENACS +#define TFA1_BF_IPOACS TFA1_BF_INTPOLACS +#define TFA1_BF_ISTACS TFA1_BF_INTOACS +#define TFA1_BF_ISTVDDS TFA1_BF_INTOVDDS +#define TFA1_BF_ICLVDDS TFA1_BF_INTIVDDS +#define TFA1_BF_IPOVDDS TFA1_BF_INTPOLVDDS +#define TFA1_BF_IENOCLK TFA1_BF_INTENNOCLK +#define TFA1_BF_ISTNOCLK TFA1_BF_INTONOCLK +#define TFA1_BF_IPONOCLK TFA1_BF_INTPOLNOCLK + +/* interrupt bit fields not available on TFA1 */ +#define TFA1_BF_IECLKOOR -1 +#define TFA1_BF_ISTCLKOOR -1 +#define TFA1_BF_IEMWSRC -1 +#define TFA1_BF_ISTMWSRC -1 +#define TFA1_BF_IPOMWSRC -1 +#define TFA1_BF_IEMWSMU -1 +#define TFA1_BF_ISTMWSMU -1 +#define TFA1_BF_IPOMWSMU -1 +#define TFA1_BF_IEMWCFC -1 +#define TFA1_BF_ISTMWCFC -1 +#define TFA1_BF_IPOMWCFC -1 +#define TFA1_BF_CLKOOR -1 +#define TFA1_BF_MANWAIT1 -1 +#define TFA1_BF_MANWAIT2 -1 +#define TFA1_BF_MANMUTE -1 +#define TFA1_BF_IPCLKOOR -1 +#define TFA1_BF_ICLCLKOOR -1 +#define TFA1_BF_IPOSWS -1 +#define TFA1_BF_IESWS -1 +#define TFA1_BF_ISTSWS -1 +#define TFA1_BF_IESPKS -1 +#define TFA1_BF_ISTSPKS -1 +#define TFA1_BF_IPOSPKS -1 +#define TFA1_BF_IECLKS -1 +#define TFA1_BF_ISTCLKS -1 +#define TFA1_BF_IPOCLKS -1 +#define TFA1_BF_IEAMPS -1 +#define TFA1_BF_ISTAMPS -1 +#define TFA1_BF_IPOAMPS -1 +#define TFA1_BF_IELP0 -1 +#define TFA1_BF_ISTLP0 -1 +#define TFA1_BF_IPOLP0 -1 +#define TFA1_BF_IELP1 -1 +#define TFA1_BF_ISTLP1 -1 +#define TFA1_BF_IPOLP1 -1 +#define TFA1_BF_LP0 -1 +#define TFA1_BF_LP1 -1 +#define TFA1_BF_R25C -1 +#define TFA1_BF_SAMMODE -1 + +/* TDM STATUS fields not available on TFA1 */ +#define TFA1_BF_TDMLUTER -1 +#define TFA1_BF_TDMERR -1 diff --git a/sound/soc/codecs/tfa9912_tfafieldnames.h b/sound/soc/codecs/tfa9912_tfafieldnames.h new file mode 100644 index 0000000000000000000000000000000000000000..34043ec052b85f404e72a5384ac4fa5719d20f68 --- /dev/null +++ b/sound/soc/codecs/tfa9912_tfafieldnames.h @@ -0,0 +1,1769 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9912_TFAFIELDNAMES_H +#define _TFA9912_TFAFIELDNAMES_H + + +#define TFA9912_I2CVERSION 1.43 + +typedef enum nxpTfa9912BfEnumList { + TFA9912_BF_PWDN = 0x0000, /*!< Powerdown selection */ + TFA9912_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9912_BF_CFE = 0x0020, /*!< Enable CoolFlux */ + TFA9912_BF_AMPE = 0x0030, /*!< Enables the Amplifier */ + TFA9912_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ + TFA9912_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA9912_BF_AMPC = 0x0060, /*!< CoolFlux controls amplifier */ + TFA9912_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9912_BF_FSSSEL = 0x0090, /*!< Audio sample reference */ + TFA9912_BF_BYPOCP = 0x00b0, /*!< Bypass OCP */ + TFA9912_BF_TSTOCP = 0x00c0, /*!< OCP testing control */ + TFA9912_BF_AMPINSEL = 0x0101, /*!< Amplifier input selection */ + TFA9912_BF_MANSCONF = 0x0120, /*!< I2C configured */ + TFA9912_BF_MANCOLD = 0x0130, /*!< Execute cold start */ + TFA9912_BF_MANAOOSC = 0x0140, /*!< Internal osc off at PWDN */ + TFA9912_BF_MANROBOD = 0x0150, /*!< Reaction on BOD */ + TFA9912_BF_BODE = 0x0160, /*!< BOD Enable */ + TFA9912_BF_BODHYS = 0x0170, /*!< BOD Hysteresis */ + TFA9912_BF_BODFILT = 0x0181, /*!< BOD filter */ + TFA9912_BF_BODTHLVL = 0x01a1, /*!< BOD threshold */ + TFA9912_BF_MUTETO = 0x01d0, /*!< Time out SB mute sequence */ + TFA9912_BF_RCVNS = 0x01e0, /*!< Noise shaper selection */ + TFA9912_BF_MANWDE = 0x01f0, /*!< Watchdog enable */ + TFA9912_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ + TFA9912_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ + TFA9912_BF_FRACTDEL = 0x0255, /*!< V/I Fractional delay */ + TFA9912_BF_BYPHVBF = 0x02b0, /*!< Bypass HVBAT filter */ + TFA9912_BF_TDMC = 0x02c0, /*!< TDM Compatibility with TFA9872 */ + TFA9912_BF_ENBLADC10 = 0x02e0, /*!< ADC10 Enable - I2C direct mode */ + TFA9912_BF_REV = 0x030f, /*!< Revision info */ + TFA9912_BF_REFCKEXT = 0x0401, /*!< PLL external ref clock */ + TFA9912_BF_REFCKSEL = 0x0420, /*!< PLL internal ref clock */ + TFA9912_BF_ENCFCKSEL = 0x0430, /*!< Coolflux DSP clock scaling, low power mode */ + TFA9912_BF_CFCKSEL = 0x0441, /*!< Coolflux DSP clock scaler selection for low power mode */ + TFA9912_BF_TDMINFSEL = 0x0460, /*!< TDM clock selection */ + TFA9912_BF_DISBLAUTOCLKSEL = 0x0470, /*!< Disable Automatic dsp clock source selection */ + TFA9912_BF_SELCLKSRC = 0x0480, /*!< I2C selection of DSP clock when auto select is disabled */ + TFA9912_BF_SELTIMSRC = 0x0490, /*!< I2C selection of Watchdog and Timer clock */ + TFA9912_BF_SSLEFTE = 0x0500, /*!< */ + TFA9912_BF_SPKSSEN = 0x0510, /*!< Enable speaker path */ + TFA9912_BF_VSLEFTE = 0x0520, /*!< */ + TFA9912_BF_VSRIGHTE = 0x0530, /*!< Voltage sense */ + TFA9912_BF_CSLEFTE = 0x0540, /*!< */ + TFA9912_BF_CSRIGHTE = 0x0550, /*!< Current sense */ + TFA9912_BF_SSPDME = 0x0560, /*!< Sub-system PDM */ + TFA9912_BF_PGALE = 0x0570, /*!< Enable PGA chop clock for left channel */ + TFA9912_BF_PGARE = 0x0580, /*!< Enable PGA chop clock */ + TFA9912_BF_SSTDME = 0x0590, /*!< Sub-system TDM */ + TFA9912_BF_SSPBSTE = 0x05a0, /*!< Sub-system boost */ + TFA9912_BF_SSADCE = 0x05b0, /*!< Sub-system ADC */ + TFA9912_BF_SSFAIME = 0x05c0, /*!< Sub-system FAIM */ + TFA9912_BF_SSCFTIME = 0x05d0, /*!< CF Sub-system timer */ + TFA9912_BF_SSCFWDTE = 0x05e0, /*!< CF Sub-system WDT */ + TFA9912_BF_FAIMVBGOVRRL = 0x05f0, /*!< Over rule of vbg for FaIM access */ + TFA9912_BF_SAMSPKSEL = 0x0600, /*!< Input selection for TAP/SAM */ + TFA9912_BF_PDM2IISEN = 0x0610, /*!< PDM2IIS Bridge enable */ + TFA9912_BF_TAPRSTBYPASS = 0x0620, /*!< Tap decimator reset bypass - Bypass the decimator reset from tapdec */ + TFA9912_BF_CARDECISEL0 = 0x0631, /*!< Cardec input 0 sel */ + TFA9912_BF_CARDECISEL1 = 0x0651, /*!< Cardec input sel */ + TFA9912_BF_TAPDECSEL = 0x0670, /*!< Select TAP/Cardec for TAP */ + TFA9912_BF_COMPCOUNT = 0x0680, /*!< Comparator o/p filter selection */ + TFA9912_BF_STARTUPMODE = 0x0691, /*!< Startup Mode Selection */ + TFA9912_BF_AUTOTAP = 0x06b0, /*!< Enable auto tap switching */ + TFA9912_BF_COMPINITIME = 0x06c1, /*!< Comparator initialization time to be used in Tap Machine */ + TFA9912_BF_ANAPINITIME = 0x06e1, /*!< Analog initialization time to be used in Tap Machine */ + TFA9912_BF_CCHKTH = 0x0707, /*!< Clock check Higher Threshold */ + TFA9912_BF_CCHKTL = 0x0787, /*!< Clock check Higher Threshold */ + TFA9912_BF_AMPOCRT = 0x0802, /*!< Amplifier on-off criteria for shutdown */ + TFA9912_BF_AMPTCRR = 0x0832, /*!< Amplifier on-off criteria for tap mode entry */ + TFA9912_BF_STGS = 0x0d00, /*!< PDM side tone gain selector */ + TFA9912_BF_STGAIN = 0x0d18, /*!< Side tone gain */ + TFA9912_BF_STSMUTE = 0x0da0, /*!< Side tone soft mute */ + TFA9912_BF_ST1C = 0x0db0, /*!< side tone one s complement */ + TFA9912_BF_CMFBEL = 0x0e80, /*!< CMFB enable left */ + TFA9912_BF_VDDS = 0x1000, /*!< POR */ + TFA9912_BF_PLLS = 0x1010, /*!< PLL lock */ + TFA9912_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA9912_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA9912_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA9912_BF_CLKS = 0x1050, /*!< Clocks stable */ + TFA9912_BF_MTPB = 0x1060, /*!< MTP busy */ + TFA9912_BF_NOCLK = 0x1070, /*!< Lost clock */ + TFA9912_BF_ACS = 0x1090, /*!< Cold Start */ + TFA9912_BF_SWS = 0x10a0, /*!< Amplifier engage */ + TFA9912_BF_WDS = 0x10b0, /*!< Watchdog */ + TFA9912_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA9912_BF_AREFS = 0x10d0, /*!< References enable */ + TFA9912_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA9912_BF_BODNOK = 0x10f0, /*!< BOD */ + TFA9912_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9912_BF_DCDCA = 0x1110, /*!< DCDC active */ + TFA9912_BF_DCOCPOK = 0x1120, /*!< DCDC OCP nmos */ + TFA9912_BF_DCPEAKCUR = 0x1130, /*!< Indicates current is max in DC-to-DC converter */ + TFA9912_BF_DCHVBAT = 0x1140, /*!< DCDC level 1x */ + TFA9912_BF_DCH114 = 0x1150, /*!< DCDC level 1.14x */ + TFA9912_BF_DCH107 = 0x1160, /*!< DCDC level 1.07x */ + TFA9912_BF_STMUTEB = 0x1170, /*!< side tone (un)mute busy */ + TFA9912_BF_STMUTE = 0x1180, /*!< side tone mute state */ + TFA9912_BF_TDMLUTER = 0x1190, /*!< TDM LUT error */ + TFA9912_BF_TDMSTAT = 0x11a2, /*!< TDM status bits */ + TFA9912_BF_TDMERR = 0x11d0, /*!< TDM error */ + TFA9912_BF_HAPTIC = 0x11e0, /*!< Status haptic driver */ + TFA9912_BF_OCPOAP = 0x1300, /*!< OCPOK pmos A */ + TFA9912_BF_OCPOAN = 0x1310, /*!< OCPOK nmos A */ + TFA9912_BF_OCPOBP = 0x1320, /*!< OCPOK pmos B */ + TFA9912_BF_OCPOBN = 0x1330, /*!< OCPOK nmos B */ + TFA9912_BF_CLIPAH = 0x1340, /*!< Clipping A to Vddp */ + TFA9912_BF_CLIPAL = 0x1350, /*!< Clipping A to gnd */ + TFA9912_BF_CLIPBH = 0x1360, /*!< Clipping B to Vddp */ + TFA9912_BF_CLIPBL = 0x1370, /*!< Clipping B to gnd */ + TFA9912_BF_OCDS = 0x1380, /*!< OCP amplifier */ + TFA9912_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ + TFA9912_BF_TCMPTRG = 0x13a0, /*!< Status Tap comparator triggered */ + TFA9912_BF_TAPDET = 0x13b0, /*!< Status Tap detected */ + TFA9912_BF_MANWAIT1 = 0x13c0, /*!< Wait HW I2C settings */ + TFA9912_BF_MANWAIT2 = 0x13d0, /*!< Wait CF config */ + TFA9912_BF_MANMUTE = 0x13e0, /*!< Audio mute sequence */ + TFA9912_BF_MANOPER = 0x13f0, /*!< Operating state */ + TFA9912_BF_SPKSL = 0x1400, /*!< Left speaker status */ + TFA9912_BF_SPKS = 0x1410, /*!< Speaker status */ + TFA9912_BF_CLKOOR = 0x1420, /*!< External clock status */ + TFA9912_BF_MANSTATE = 0x1433, /*!< Device manager status */ + TFA9912_BF_DCMODE = 0x1471, /*!< DCDC mode status bits */ + TFA9912_BF_DSPCLKSRC = 0x1490, /*!< DSP clock source selected by manager */ + TFA9912_BF_STARTUPMODSTAT = 0x14a1, /*!< Startup Mode Selected by Manager(Read Only) */ + TFA9912_BF_TSPMSTATE = 0x14c3, /*!< Tap Machine State */ + TFA9912_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9912_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9912_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/13 V) */ + TFA9912_BF_DCILCF = 0x17a0, /*!< DCDC current limiting for DSP */ + TFA9912_BF_TDMUC = 0x2000, /*!< Mode setting */ + TFA9912_BF_DIO4SEL = 0x2011, /*!< DIO4 Input selection */ + TFA9912_BF_TDME = 0x2040, /*!< Enable TDM interface */ + TFA9912_BF_TDMMODE = 0x2050, /*!< Slave/master */ + TFA9912_BF_TDMCLINV = 0x2060, /*!< Reception data to BCK clock */ + TFA9912_BF_TDMFSLN = 0x2073, /*!< FS length */ + TFA9912_BF_TDMFSPOL = 0x20b0, /*!< FS polarity */ + TFA9912_BF_TDMNBCK = 0x20c3, /*!< N-BCK's in FS */ + TFA9912_BF_TDMSLOTS = 0x2103, /*!< N-slots in Frame */ + TFA9912_BF_TDMSLLN = 0x2144, /*!< N-bits in slot */ + TFA9912_BF_TDMBRMG = 0x2194, /*!< N-bits remaining */ + TFA9912_BF_TDMDEL = 0x21e0, /*!< data delay to FS */ + TFA9912_BF_TDMADJ = 0x21f0, /*!< data adjustment */ + TFA9912_BF_TDMOOMP = 0x2201, /*!< Received audio compression */ + TFA9912_BF_TDMSSIZE = 0x2224, /*!< Sample size per slot */ + TFA9912_BF_TDMTXDFO = 0x2271, /*!< Format unused bits in a slot */ + TFA9912_BF_TDMTXUS0 = 0x2291, /*!< Format unused slots GAINIO */ + TFA9912_BF_TDMTXUS1 = 0x22b1, /*!< Format unused slots DIO1 */ + TFA9912_BF_TDMTXUS2 = 0x22d1, /*!< Format unused slots DIO2 */ + TFA9912_BF_TDMGIE = 0x2300, /*!< Control gain (channel in 0) */ + TFA9912_BF_TDMDCE = 0x2310, /*!< Control audio left (channel in 1 ) */ + TFA9912_BF_TDMSPKE = 0x2320, /*!< Control audio right (channel in 2 ) */ + TFA9912_BF_TDMCSE = 0x2330, /*!< Current sense */ + TFA9912_BF_TDMVSE = 0x2340, /*!< Voltage sense */ + TFA9912_BF_TDMGOE = 0x2350, /*!< DSP Gainout */ + TFA9912_BF_TDMCF2E = 0x2360, /*!< DSP 2 */ + TFA9912_BF_TDMCF3E = 0x2370, /*!< DSP 3 */ + TFA9912_BF_TDMCFE = 0x2380, /*!< DSP */ + TFA9912_BF_TDMES6 = 0x2390, /*!< Loopback of Audio left (channel 1) */ + TFA9912_BF_TDMES7 = 0x23a0, /*!< Loopback of Audio right (channel 2) */ + TFA9912_BF_TDMCF4E = 0x23b0, /*!< AEC ref right control */ + TFA9912_BF_TDMPD1E = 0x23c0, /*!< PDM 1 control */ + TFA9912_BF_TDMPD2E = 0x23d0, /*!< PDM 2 control */ + TFA9912_BF_TDMGIN = 0x2401, /*!< IO gainin */ + TFA9912_BF_TDMLIO = 0x2421, /*!< IO audio left */ + TFA9912_BF_TDMRIO = 0x2441, /*!< IO audio right */ + TFA9912_BF_TDMCSIO = 0x2461, /*!< IO Current Sense */ + TFA9912_BF_TDMVSIO = 0x2481, /*!< IO voltage sense */ + TFA9912_BF_TDMGOIO = 0x24a1, /*!< IO gain out */ + TFA9912_BF_TDMCFIO2 = 0x24c1, /*!< IO DSP 2 */ + TFA9912_BF_TDMCFIO3 = 0x24e1, /*!< IO DSP 3 */ + TFA9912_BF_TDMCFIO = 0x2501, /*!< IO DSP */ + TFA9912_BF_TDMLPB6 = 0x2521, /*!< IO Source 6 */ + TFA9912_BF_TDMLPB7 = 0x2541, /*!< IO Source 7 */ + TFA9912_BF_TDMGS = 0x2603, /*!< Control gainin */ + TFA9912_BF_TDMDCS = 0x2643, /*!< tdm slot for audio left (channel 1) */ + TFA9912_BF_TDMSPKS = 0x2683, /*!< tdm slot for audio right (channel 2) */ + TFA9912_BF_TDMCSS = 0x26c3, /*!< Slot Position of Current Sense Out */ + TFA9912_BF_TDMVSS = 0x2703, /*!< Slot Position of Voltage sense */ + TFA9912_BF_TDMCGOS = 0x2743, /*!< Slot Position of GAIN out */ + TFA9912_BF_TDMCF2S = 0x2783, /*!< Slot Position DSPout2 */ + TFA9912_BF_TDMCF3S = 0x27c3, /*!< Slot Position DSPout3 */ + TFA9912_BF_TDMCFS = 0x2803, /*!< Slot Position of DSPout */ + TFA9912_BF_TDMEDAT6S = 0x2843, /*!< Slot Position of loopback channel left */ + TFA9912_BF_TDMEDAT7S = 0x2883, /*!< Slot Position of loopback channel right */ + TFA9912_BF_TDMTXUS3 = 0x2901, /*!< Format unused slots D3 */ + TFA9912_BF_PDMSM = 0x3100, /*!< PDM control */ + TFA9912_BF_PDMSTSEL = 0x3110, /*!< PDM Decimator input selection */ + TFA9912_BF_PDMSTENBL = 0x3120, /*!< Side tone input enable */ + TFA9912_BF_PDMLSEL = 0x3130, /*!< PDM data selection for left channel during PDM direct mode */ + TFA9912_BF_PDMRSEL = 0x3140, /*!< PDM data selection for right channel during PDM direct mode */ + TFA9912_BF_MICVDDE = 0x3150, /*!< Enable MICVDD */ + TFA9912_BF_PDMCLRAT = 0x3201, /*!< PDM BCK/Fs ratio */ + TFA9912_BF_PDMGAIN = 0x3223, /*!< PDM gain */ + TFA9912_BF_PDMOSEL = 0x3263, /*!< PDM output selection - RE/FE data combination */ + TFA9912_BF_SELCFHAPD = 0x32a0, /*!< Select the source for haptic data output (not for customer) */ + TFA9912_BF_ISTVDDS = 0x4000, /*!< Status POR */ + TFA9912_BF_ISTPLLS = 0x4010, /*!< Status PLL lock */ + TFA9912_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ + TFA9912_BF_ISTOVDS = 0x4030, /*!< Status OVP alarm */ + TFA9912_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ + TFA9912_BF_ISTCLKS = 0x4050, /*!< Status clocks stable */ + TFA9912_BF_ISTMTPB = 0x4060, /*!< Status MTP busy */ + TFA9912_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ + TFA9912_BF_ISTSPKS = 0x4080, /*!< Status speaker error */ + TFA9912_BF_ISTACS = 0x4090, /*!< Status cold start */ + TFA9912_BF_ISTSWS = 0x40a0, /*!< Status amplifier engage */ + TFA9912_BF_ISTWDS = 0x40b0, /*!< Status watchdog */ + TFA9912_BF_ISTAMPS = 0x40c0, /*!< Status amplifier enable */ + TFA9912_BF_ISTAREFS = 0x40d0, /*!< Status Ref enable */ + TFA9912_BF_ISTADCCR = 0x40e0, /*!< Status Control ADC */ + TFA9912_BF_ISTBODNOK = 0x40f0, /*!< Status BOD */ + TFA9912_BF_ISTBSTCU = 0x4100, /*!< Status DCDC current limiting */ + TFA9912_BF_ISTBSTHI = 0x4110, /*!< Status DCDC active */ + TFA9912_BF_ISTBSTOC = 0x4120, /*!< Status DCDC OCP */ + TFA9912_BF_ISTBSTPKCUR = 0x4130, /*!< Status bst peakcur */ + TFA9912_BF_ISTBSTVC = 0x4140, /*!< Status DCDC level 1x */ + TFA9912_BF_ISTBST86 = 0x4150, /*!< Status DCDC level 1.14x */ + TFA9912_BF_ISTBST93 = 0x4160, /*!< Status DCDC level 1.07x */ + TFA9912_BF_ISTRCVLD = 0x4170, /*!< Status rcvldop ready */ + TFA9912_BF_ISTOCPL = 0x4180, /*!< Status ocp alarm left */ + TFA9912_BF_ISTOCPR = 0x4190, /*!< Status ocp alarm */ + TFA9912_BF_ISTMWSRC = 0x41a0, /*!< Status Waits HW I2C settings */ + TFA9912_BF_ISTMWCFC = 0x41b0, /*!< Status waits CF config */ + TFA9912_BF_ISTMWSMU = 0x41c0, /*!< Status Audio mute sequence */ + TFA9912_BF_ISTCFMER = 0x41d0, /*!< Status cfma error */ + TFA9912_BF_ISTCFMAC = 0x41e0, /*!< Status cfma ack */ + TFA9912_BF_ISTCLKOOR = 0x41f0, /*!< Status flag_clk_out_of_range */ + TFA9912_BF_ISTTDMER = 0x4200, /*!< Status tdm error */ + TFA9912_BF_ISTCLPL = 0x4210, /*!< Status clip left */ + TFA9912_BF_ISTCLPR = 0x4220, /*!< Status clip */ + TFA9912_BF_ISTOCPM = 0x4230, /*!< Status mic ocpok */ + TFA9912_BF_ISTLP1 = 0x4250, /*!< Status low power mode1 */ + TFA9912_BF_ISTLA = 0x4260, /*!< Status low amplitude detection */ + TFA9912_BF_ISTVDDP = 0x4270, /*!< Status VDDP greater than VBAT */ + TFA9912_BF_ISTTAPDET = 0x4280, /*!< Status Tap detected */ + TFA9912_BF_ISTAUDMOD = 0x4290, /*!< Status Audio Mode activated */ + TFA9912_BF_ISTSAMMOD = 0x42a0, /*!< Status SAM Mode activated */ + TFA9912_BF_ISTTAPMOD = 0x42b0, /*!< Status Tap Mode Activated */ + TFA9912_BF_ISTTAPTRG = 0x42c0, /*!< Status Tap comparator triggered */ + TFA9912_BF_ICLVDDS = 0x4400, /*!< Clear POR */ + TFA9912_BF_ICLPLLS = 0x4410, /*!< Clear PLL lock */ + TFA9912_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ + TFA9912_BF_ICLOVDS = 0x4430, /*!< Clear OVP alarm */ + TFA9912_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ + TFA9912_BF_ICLCLKS = 0x4450, /*!< Clear clocks stable */ + TFA9912_BF_ICLMTPB = 0x4460, /*!< Clear mtp busy */ + TFA9912_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ + TFA9912_BF_ICLSPKS = 0x4480, /*!< Clear speaker error */ + TFA9912_BF_ICLACS = 0x4490, /*!< Clear cold started */ + TFA9912_BF_ICLSWS = 0x44a0, /*!< Clear amplifier engage */ + TFA9912_BF_ICLWDS = 0x44b0, /*!< Clear watchdog */ + TFA9912_BF_ICLAMPS = 0x44c0, /*!< Clear enbl amp */ + TFA9912_BF_ICLAREFS = 0x44d0, /*!< Clear ref enable */ + TFA9912_BF_ICLADCCR = 0x44e0, /*!< Clear control ADC */ + TFA9912_BF_ICLBODNOK = 0x44f0, /*!< Clear BOD */ + TFA9912_BF_ICLBSTCU = 0x4500, /*!< Clear DCDC current limiting */ + TFA9912_BF_ICLBSTHI = 0x4510, /*!< Clear DCDC active */ + TFA9912_BF_ICLBSTOC = 0x4520, /*!< Clear DCDC OCP */ + TFA9912_BF_ICLBSTPC = 0x4530, /*!< Clear bst peakcur */ + TFA9912_BF_ICLBSTVC = 0x4540, /*!< Clear DCDC level 1x */ + TFA9912_BF_ICLBST86 = 0x4550, /*!< Clear DCDC level 1.14x */ + TFA9912_BF_ICLBST93 = 0x4560, /*!< Clear DCDC level 1.07x */ + TFA9912_BF_ICLRCVLD = 0x4570, /*!< Clear rcvldop ready */ + TFA9912_BF_ICLOCPL = 0x4580, /*!< Clear ocp alarm left */ + TFA9912_BF_ICLOCPR = 0x4590, /*!< Clear ocp alarm */ + TFA9912_BF_ICLMWSRC = 0x45a0, /*!< Clear wait HW I2C settings */ + TFA9912_BF_ICLMWCFC = 0x45b0, /*!< Clear wait cf config */ + TFA9912_BF_ICLMWSMU = 0x45c0, /*!< Clear audio mute sequence */ + TFA9912_BF_ICLCFMER = 0x45d0, /*!< Clear cfma err */ + TFA9912_BF_ICLCFMAC = 0x45e0, /*!< Clear cfma ack */ + TFA9912_BF_ICLCLKOOR = 0x45f0, /*!< Clear flag_clk_out_of_range */ + TFA9912_BF_ICLTDMER = 0x4600, /*!< Clear tdm error */ + TFA9912_BF_ICLCLPL = 0x4610, /*!< Clear clip left */ + TFA9912_BF_ICLCLP = 0x4620, /*!< Clear clip */ + TFA9912_BF_ICLOCPM = 0x4630, /*!< Clear mic ocpok */ + TFA9912_BF_ICLLP1 = 0x4650, /*!< Clear low power mode1 */ + TFA9912_BF_ICLLA = 0x4660, /*!< Clear low amplitude detection */ + TFA9912_BF_ICLVDDP = 0x4670, /*!< Clear VDDP greater then VBAT */ + TFA9912_BF_ICLTAPDET = 0x4680, /*!< Clear Tap detected */ + TFA9912_BF_ICLAUDMOD = 0x4690, /*!< Clear Audio Mode activated */ + TFA9912_BF_ICLSAMMOD = 0x46a0, /*!< Clear SAM Mode activated */ + TFA9912_BF_ICLTAPMOD = 0x46b0, /*!< Clear Tap Mode Activated */ + TFA9912_BF_ICLTAPTRG = 0x46c0, /*!< Clear Comparator Interrupt */ + TFA9912_BF_IEVDDS = 0x4800, /*!< Enable por */ + TFA9912_BF_IEPLLS = 0x4810, /*!< Enable pll lock */ + TFA9912_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ + TFA9912_BF_IEOVDS = 0x4830, /*!< Enable OVP alarm */ + TFA9912_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ + TFA9912_BF_IECLKS = 0x4850, /*!< Enable clocks stable */ + TFA9912_BF_IEMTPB = 0x4860, /*!< Enable mtp busy */ + TFA9912_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ + TFA9912_BF_IESPKS = 0x4880, /*!< Enable speaker error */ + TFA9912_BF_IEACS = 0x4890, /*!< Enable cold started */ + TFA9912_BF_IESWS = 0x48a0, /*!< Enable amplifier engage */ + TFA9912_BF_IEWDS = 0x48b0, /*!< Enable watchdog */ + TFA9912_BF_IEAMPS = 0x48c0, /*!< Enable enbl amp */ + TFA9912_BF_IEAREFS = 0x48d0, /*!< Enable ref enable */ + TFA9912_BF_IEADCCR = 0x48e0, /*!< Enable Control ADC */ + TFA9912_BF_IEBODNOK = 0x48f0, /*!< Enable BOD */ + TFA9912_BF_IEBSTCU = 0x4900, /*!< Enable DCDC current limiting */ + TFA9912_BF_IEBSTHI = 0x4910, /*!< Enable DCDC active */ + TFA9912_BF_IEBSTOC = 0x4920, /*!< Enable DCDC OCP */ + TFA9912_BF_IEBSTPC = 0x4930, /*!< Enable bst peakcur */ + TFA9912_BF_IEBSTVC = 0x4940, /*!< Enable DCDC level 1x */ + TFA9912_BF_IEBST86 = 0x4950, /*!< Enable DCDC level 1.14x */ + TFA9912_BF_IEBST93 = 0x4960, /*!< Enable DCDC level 1.07x */ + TFA9912_BF_IERCVLD = 0x4970, /*!< Enable rcvldop ready */ + TFA9912_BF_IEOCPL = 0x4980, /*!< Enable ocp alarm left */ + TFA9912_BF_IEOCPR = 0x4990, /*!< Enable ocp alarm */ + TFA9912_BF_IEMWSRC = 0x49a0, /*!< Enable waits HW I2C settings */ + TFA9912_BF_IEMWCFC = 0x49b0, /*!< Enable man wait cf config */ + TFA9912_BF_IEMWSMU = 0x49c0, /*!< Enable man Audio mute sequence */ + TFA9912_BF_IECFMER = 0x49d0, /*!< Enable cfma err */ + TFA9912_BF_IECFMAC = 0x49e0, /*!< Enable cfma ack */ + TFA9912_BF_IECLKOOR = 0x49f0, /*!< Enable flag_clk_out_of_range */ + TFA9912_BF_IETDMER = 0x4a00, /*!< Enable tdm error */ + TFA9912_BF_IECLPL = 0x4a10, /*!< Enable clip left */ + TFA9912_BF_IECLPR = 0x4a20, /*!< Enable clip */ + TFA9912_BF_IEOCPM1 = 0x4a30, /*!< Enable mic ocpok */ + TFA9912_BF_IELP1 = 0x4a50, /*!< Enable low power mode1 */ + TFA9912_BF_IELA = 0x4a60, /*!< Enable low amplitude detection */ + TFA9912_BF_IEVDDP = 0x4a70, /*!< Enable VDDP greater than VBAT */ + TFA9912_BF_IETAPDET = 0x4a80, /*!< Enable Tap detected */ + TFA9912_BF_IEAUDMOD = 0x4a90, /*!< Enable Audio Mode activated */ + TFA9912_BF_IESAMMOD = 0x4aa0, /*!< Enable SAM Mode activated */ + TFA9912_BF_IETAPMOD = 0x4ab0, /*!< Enable Tap Mode Activated */ + TFA9912_BF_IETAPTRG = 0x4ac0, /*!< Enable comparator interrupt */ + TFA9912_BF_IPOVDDS = 0x4c00, /*!< Polarity por */ + TFA9912_BF_IPOPLLS = 0x4c10, /*!< Polarity pll lock */ + TFA9912_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ + TFA9912_BF_IPOOVDS = 0x4c30, /*!< Polarity OVP alarm */ + TFA9912_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ + TFA9912_BF_IPOCLKS = 0x4c50, /*!< Polarity clocks stable */ + TFA9912_BF_IPOMTPB = 0x4c60, /*!< Polarity mtp busy */ + TFA9912_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ + TFA9912_BF_IPOSPKS = 0x4c80, /*!< Polarity speaker error */ + TFA9912_BF_IPOACS = 0x4c90, /*!< Polarity cold started */ + TFA9912_BF_IPOSWS = 0x4ca0, /*!< Polarity amplifier engage */ + TFA9912_BF_IPOWDS = 0x4cb0, /*!< Polarity watchdog */ + TFA9912_BF_IPOAMPS = 0x4cc0, /*!< Polarity enbl amp */ + TFA9912_BF_IPOAREFS = 0x4cd0, /*!< Polarity ref enable */ + TFA9912_BF_IPOADCCR = 0x4ce0, /*!< Polarity Control ADC */ + TFA9912_BF_IPOBODNOK = 0x4cf0, /*!< Polarity BOD */ + TFA9912_BF_IPOBSTCU = 0x4d00, /*!< Polarity DCDC current limiting */ + TFA9912_BF_IPOBSTHI = 0x4d10, /*!< Polarity DCDC active */ + TFA9912_BF_IPOBSTOC = 0x4d20, /*!< Polarity DCDC OCP */ + TFA9912_BF_IPOBSTPC = 0x4d30, /*!< Polarity bst peakcur */ + TFA9912_BF_IPOBSTVC = 0x4d40, /*!< Polarity DCDC level 1x */ + TFA9912_BF_IPOBST86 = 0x4d50, /*!< Polarity DCDC level 1.14x */ + TFA9912_BF_IPOBST93 = 0x4d60, /*!< Polarity DCDC level 1.07x */ + TFA9912_BF_IPORCVLD = 0x4d70, /*!< Polarity rcvldop ready */ + TFA9912_BF_IPOOCPL = 0x4d80, /*!< Polarity ocp alarm left */ + TFA9912_BF_IPOOCPR = 0x4d90, /*!< Polarity ocp alarm */ + TFA9912_BF_IPOMWSRC = 0x4da0, /*!< Polarity waits HW I2C settings */ + TFA9912_BF_IPOMWCFC = 0x4db0, /*!< Polarity man wait cf config */ + TFA9912_BF_IPOMWSMU = 0x4dc0, /*!< Polarity man audio mute sequence */ + TFA9912_BF_IPOCFMER = 0x4dd0, /*!< Polarity cfma err */ + TFA9912_BF_IPOCFMAC = 0x4de0, /*!< Polarity cfma ack */ + TFA9912_BF_IPOCLKOOR = 0x4df0, /*!< Polarity flag_clk_out_of_range */ + TFA9912_BF_IPOTDMER = 0x4e00, /*!< Polarity tdm error */ + TFA9912_BF_IPOCLPL = 0x4e10, /*!< Polarity clip left */ + TFA9912_BF_IPOCLPR = 0x4e20, /*!< Polarity clip */ + TFA9912_BF_IPOOCPM = 0x4e30, /*!< Polarity mic ocpok */ + TFA9912_BF_IPOLP1 = 0x4e50, /*!< Polarity low power mode1 */ + TFA9912_BF_IPOLA = 0x4e60, /*!< Polarity low amplitude detection */ + TFA9912_BF_IPOVDDP = 0x4e70, /*!< Polarity VDDP greater than VBAT */ + TFA9912_BF_IPOLTAPDET = 0x4e80, /*!< PolarityTap detected */ + TFA9912_BF_IPOLAUDMOD = 0x4e90, /*!< PolarityAudio Mode activated */ + TFA9912_BF_IPOLSAMMOD = 0x4ea0, /*!< PolaritySAM Mode activated */ + TFA9912_BF_IPOLTAPMOD = 0x4eb0, /*!< Polarity Tap Mode Activated */ + TFA9912_BF_IPOLTAPTRG = 0x4ec0, /*!< PolarityTap Comparator Trigger */ + TFA9912_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time */ + TFA9912_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ + TFA9912_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ + TFA9912_BF_BSSRR = 0x5082, /*!< Battery Safeguard release time */ + TFA9912_BF_BSSHY = 0x50b1, /*!< Battery Safeguard hysteresis */ + TFA9912_BF_BSSAC = 0x50d0, /*!< Reset clipper - Auto clear */ + TFA9912_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9912_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA9912_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ + TFA9912_BF_INTSMUTE = 0x5110, /*!< Soft mute HW */ + TFA9912_BF_CFSML = 0x5120, /*!< Soft mute FW left */ + TFA9912_BF_CFSM = 0x5130, /*!< Soft mute FW */ + TFA9912_BF_HPFBYPL = 0x5140, /*!< Bypass HPF left */ + TFA9912_BF_HPFBYP = 0x5150, /*!< Bypass HPF */ + TFA9912_BF_DPSAL = 0x5160, /*!< Enable DPSA left */ + TFA9912_BF_DPSA = 0x5170, /*!< Enable DPSA */ + TFA9912_BF_VOL = 0x5187, /*!< FW volume control for primary audio channel */ + TFA9912_BF_HNDSFRCV = 0x5200, /*!< Selection receiver */ + TFA9912_BF_CLIPCTRL = 0x5222, /*!< Clip control setting */ + TFA9912_BF_AMPGAIN = 0x5257, /*!< Amplifier gain */ + TFA9912_BF_SLOPEE = 0x52d0, /*!< Enables slope control */ + TFA9912_BF_SLOPESET = 0x52e0, /*!< Slope speed setting (bin. coded) */ + TFA9912_BF_CFTAPPAT = 0x5c07, /*!< Coolflux tap pattern */ + TFA9912_BF_TAPDBGINFO = 0x5c83, /*!< Reserved */ + TFA9912_BF_TATPSTAT1 = 0x5d0f, /*!< Tap Status 1 from CF FW */ + TFA9912_BF_TCOMPTHR = 0x5f03, /*!< Comparator threshold (in uV) */ + TFA9912_BF_PGAGAIN = 0x6081, /*!< PGA gain selection */ + TFA9912_BF_TDMSPKG = 0x6123, /*!< System gain (INPLEV 0) */ + TFA9912_BF_LPM1LVL = 0x6505, /*!< low power mode1 detector ctrl threshold for low_audio_lvl */ + TFA9912_BF_LPM1HLD = 0x6565, /*!< Low power mode1 detector, ctrl hold time before low audio is reckoned to be low audio */ + TFA9912_BF_LPM1DIS = 0x65c0, /*!< low power mode1 detector control */ + TFA9912_BF_DCDIS = 0x6630, /*!< DCDC */ + TFA9912_BF_TDMSRCMAP = 0x6801, /*!< tdm source mapping */ + TFA9912_BF_TDMSRCAS = 0x6821, /*!< frame a selection */ + TFA9912_BF_TDMSRCBS = 0x6841, /*!< frame b selection */ + TFA9912_BF_ANC1C = 0x68a0, /*!< ANC one s complement */ + TFA9912_BF_SAMMODE = 0x6901, /*!< Sam mode */ + TFA9912_BF_DCMCC = 0x7033, /*!< Max coil current */ + TFA9912_BF_DCCV = 0x7071, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9912_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ + TFA9912_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ + TFA9912_BF_DCINSEL = 0x70c1, /*!< DCDC IIR input Selection */ + TFA9912_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ + TFA9912_BF_DCTRIP = 0x7504, /*!< Adaptive boost trip levels 1, effective only when boost_intelligent is set to 1 */ + TFA9912_BF_DCTRIP2 = 0x7554, /*!< Adaptive boost trip level 2, effective only when boost_intelligent is set to 1 */ + TFA9912_BF_DCTRIPT = 0x75a4, /*!< Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9912_BF_DCVOF = 0x7635, /*!< First boost voltage level */ + TFA9912_BF_DCVOS = 0x7695, /*!< Second boost voltage level */ + TFA9912_BF_RST = 0x9000, /*!< Reset */ + TFA9912_BF_DMEM = 0x9011, /*!< Target memory */ + TFA9912_BF_AIF = 0x9030, /*!< Auto increment */ + TFA9912_BF_CFINT = 0x9040, /*!< Interrupt - auto clear */ + TFA9912_BF_CFCGATE = 0x9050, /*!< Coolflux clock gating disabling control */ + TFA9912_BF_REQCMD = 0x9080, /*!< Firmware event request rpc command */ + TFA9912_BF_REQRST = 0x9090, /*!< Firmware event request reset restart */ + TFA9912_BF_REQMIPS = 0x90a0, /*!< Firmware event request short on mips */ + TFA9912_BF_REQMUTED = 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA9912_BF_REQVOL = 0x90c0, /*!< Firmware event request volume ready */ + TFA9912_BF_REQDMG = 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA9912_BF_REQCAL = 0x90e0, /*!< Firmware event request calibration completed */ + TFA9912_BF_REQRSV = 0x90f0, /*!< Firmware event request reserved */ + TFA9912_BF_MADD = 0x910f, /*!< Memory address */ + TFA9912_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA9912_BF_ERR = 0x9307, /*!< Error flags */ + TFA9912_BF_ACKCMD = 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA9912_BF_ACKRST = 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA9912_BF_ACKMIPS = 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA9912_BF_ACKMUTED = 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA9912_BF_ACKVOL = 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA9912_BF_ACKDMG = 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA9912_BF_ACKCAL = 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA9912_BF_ACKRSV = 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA9912_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ + TFA9912_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ + TFA9912_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ + TFA9912_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ + TFA9912_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9912_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9912_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9912_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9912_BF_SWPROFIL = 0xee0f, /*!< Software profile data */ + TFA9912_BF_SWVSTEP = 0xef0f, /*!< Software vstep information */ + TFA9912_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ + TFA9912_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9912_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ + TFA9912_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9912_BF_DCMCCCL = 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9912_BF_USERDEF = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9912_BF_R25C = 0xf40f, /*!< Ron resistance of speaker coil */ +} nxpTfa9912BfEnumList_t; +#define TFA9912_NAMETABLE static tfaBfName_t Tfa9912DatasheetNames[] = {\ + { 0x0, "PWDN"}, /* Powerdown selection , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux , */\ + { 0x30, "AMPE"}, /* Enables the Amplifier , */\ + { 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux controls amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x90, "FSSSEL"}, /* Audio sample reference , */\ + { 0xb0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xc0, "TSTOCP"}, /* OCP testing control , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* I2C configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ + { 0x150, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x160, "BODE"}, /* BOD Enable , */\ + { 0x170, "BODHYS"}, /* BOD Hysteresis , */\ + { 0x181, "BODFILT"}, /* BOD filter , */\ + { 0x1a1, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1e0, "RCVNS"}, /* Noise shaper selection , */\ + { 0x1f0, "MANWDE"}, /* Watchdog enable , */\ + { 0x203, "AUDFS"}, /* Sample rate (fs) , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ + { 0x2b0, "BYPHVBF"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "TDMC"}, /* TDM Compatibility with TFA9872 , */\ + { 0x2e0, "ENBLADC10"}, /* ADC10 Enable - I2C direct mode , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ + { 0x430, "ENCFCKSEL"}, /* Coolflux DSP clock scaling, low power mode , */\ + { 0x441, "CFCKSEL"}, /* Coolflux DSP clock scaler selection for low power mode, */\ + { 0x460, "TDMINFSEL"}, /* TDM clock selection , */\ + { 0x470, "DISBLAUTOCLKSEL"}, /* Disable Automatic dsp clock source selection , */\ + { 0x480, "SELCLKSRC"}, /* I2C selection of DSP clock when auto select is disabled, */\ + { 0x490, "SELTIMSRC"}, /* I2C selection of Watchdog and Timer clock , */\ + { 0x500, "SSLEFTE"}, /* , */\ + { 0x510, "SPKSSEN"}, /* Enable speaker path , */\ + { 0x520, "VSLEFTE"}, /* , */\ + { 0x530, "VSRIGHTE"}, /* Voltage sense , */\ + { 0x540, "CSLEFTE"}, /* , */\ + { 0x550, "CSRIGHTE"}, /* Current sense , */\ + { 0x560, "SSPDME"}, /* Sub-system PDM , */\ + { 0x570, "PGALE"}, /* Enable PGA chop clock for left channel , */\ + { 0x580, "PGARE"}, /* Enable PGA chop clock , */\ + { 0x590, "SSTDME"}, /* Sub-system TDM , */\ + { 0x5a0, "SSPBSTE"}, /* Sub-system boost , */\ + { 0x5b0, "SSADCE"}, /* Sub-system ADC , */\ + { 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ + { 0x5d0, "SSCFTIME"}, /* CF Sub-system timer , */\ + { 0x5e0, "SSCFWDTE"}, /* CF Sub-system WDT , */\ + { 0x5f0, "FAIMVBGOVRRL"}, /* Over rule of vbg for FaIM access , */\ + { 0x600, "SAMSPKSEL"}, /* Input selection for TAP/SAM , */\ + { 0x610, "PDM2IISEN"}, /* PDM2IIS Bridge enable , */\ + { 0x620, "TAPRSTBYPASS"}, /* Tap decimator reset bypass - Bypass the decimator reset from tapdec, */\ + { 0x631, "CARDECISEL0"}, /* Cardec input 0 sel , */\ + { 0x651, "CARDECISEL1"}, /* Cardec input sel , */\ + { 0x670, "TAPDECSEL"}, /* Select TAP/Cardec for TAP , */\ + { 0x680, "COMPCOUNT"}, /* Comparator o/p filter selection , */\ + { 0x691, "STARTUPMODE"}, /* Startup Mode Selection , */\ + { 0x6b0, "AUTOTAP"}, /* Enable auto tap switching , */\ + { 0x6c1, "COMPINITIME"}, /* Comparator initialization time to be used in Tap Machine, */\ + { 0x6e1, "ANAPINITIME"}, /* Analog initialization time to be used in Tap Machine, */\ + { 0x707, "CCHKTH"}, /* Clock check Higher Threshold , */\ + { 0x787, "CCHKTL"}, /* Clock check Higher Threshold , */\ + { 0x802, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x832, "AMPTCRR"}, /* Amplifier on-off criteria for tap mode entry , */\ + { 0xd00, "STGS"}, /* PDM side tone gain selector , */\ + { 0xd18, "STGAIN"}, /* Side tone gain , */\ + { 0xda0, "STSMUTE"}, /* Side tone soft mute , */\ + { 0xdb0, "ST1C"}, /* side tone one s complement , */\ + { 0xe80, "CMFBEL"}, /* CMFB enable left , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "CLKS"}, /* Clocks stable , */\ + { 0x1060, "MTPB"}, /* MTP busy , */\ + { 0x1070, "NOCLK"}, /* Lost clock , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "SWS"}, /* Amplifier engage , */\ + { 0x10b0, "WDS"}, /* Watchdog , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos , */\ + { 0x1130, "DCPEAKCUR"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "STMUTEB"}, /* side tone (un)mute busy , */\ + { 0x1180, "STMUTE"}, /* side tone mute state , */\ + { 0x1190, "TDMLUTER"}, /* TDM LUT error , */\ + { 0x11a2, "TDMSTAT"}, /* TDM status bits , */\ + { 0x11d0, "TDMERR"}, /* TDM error , */\ + { 0x11e0, "HAPTIC"}, /* Status haptic driver , */\ + { 0x1300, "OCPOAP"}, /* OCPOK pmos A , */\ + { 0x1310, "OCPOAN"}, /* OCPOK nmos A , */\ + { 0x1320, "OCPOBP"}, /* OCPOK pmos B , */\ + { 0x1330, "OCPOBN"}, /* OCPOK nmos B , */\ + { 0x1340, "CLIPAH"}, /* Clipping A to Vddp , */\ + { 0x1350, "CLIPAL"}, /* Clipping A to gnd , */\ + { 0x1360, "CLIPBH"}, /* Clipping B to Vddp , */\ + { 0x1370, "CLIPBL"}, /* Clipping B to gnd , */\ + { 0x1380, "OCDS"}, /* OCP amplifier , */\ + { 0x1390, "CLIPS"}, /* Amplifier clipping , */\ + { 0x13a0, "TCMPTRG"}, /* Status Tap comparator triggered , */\ + { 0x13b0, "TAPDET"}, /* Status Tap detected , */\ + { 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ + { 0x13d0, "MANWAIT2"}, /* Wait CF config , */\ + { 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x13f0, "MANOPER"}, /* Operating state , */\ + { 0x1400, "SPKSL"}, /* Left speaker status , */\ + { 0x1410, "SPKS"}, /* Speaker status , */\ + { 0x1420, "CLKOOR"}, /* External clock status , */\ + { 0x1433, "MANSTATE"}, /* Device manager status , */\ + { 0x1471, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1490, "DSPCLKSRC"}, /* DSP clock source selected by manager , */\ + { 0x14a1, "STARTUPMODSTAT"}, /* Startup Mode Selected by Manager(Read Only) , */\ + { 0x14c3, "TSPMSTATE"}, /* Tap Machine State , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x17a0, "DCILCF"}, /* DCDC current limiting for DSP , */\ + { 0x2000, "TDMUC"}, /* Mode setting , */\ + { 0x2011, "DIO4SEL"}, /* DIO4 Input selection , */\ + { 0x2040, "TDME"}, /* Enable TDM interface , */\ + { 0x2050, "TDMMODE"}, /* Slave/master , */\ + { 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2073, "TDMFSLN"}, /* FS length , */\ + { 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ + { 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ + { 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x21e0, "TDMDEL"}, /* data delay to FS , */\ + { 0x21f0, "TDMADJ"}, /* data adjustment , */\ + { 0x2201, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2271, "TDMTXDFO"}, /* Format unused bits in a slot , */\ + { 0x2291, "TDMTXUS0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "TDMTXUS1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "TDMTXUS2"}, /* Format unused slots DIO2 , */\ + { 0x2300, "TDMGIE"}, /* Control gain (channel in 0) , */\ + { 0x2310, "TDMDCE"}, /* Control audio left (channel in 1 ) , */\ + { 0x2320, "TDMSPKE"}, /* Control audio right (channel in 2 ) , */\ + { 0x2330, "TDMCSE"}, /* Current sense , */\ + { 0x2340, "TDMVSE"}, /* Voltage sense , */\ + { 0x2350, "TDMGOE"}, /* DSP Gainout , */\ + { 0x2360, "TDMCF2E"}, /* DSP 2 , */\ + { 0x2370, "TDMCF3E"}, /* DSP 3 , */\ + { 0x2380, "TDMCFE"}, /* DSP , */\ + { 0x2390, "TDMES6"}, /* Loopback of Audio left (channel 1) , */\ + { 0x23a0, "TDMES7"}, /* Loopback of Audio right (channel 2) , */\ + { 0x23b0, "TDMCF4E"}, /* AEC ref right control , */\ + { 0x23c0, "TDMPD1E"}, /* PDM 1 control , */\ + { 0x23d0, "TDMPD2E"}, /* PDM 2 control , */\ + { 0x2401, "TDMGIN"}, /* IO gainin , */\ + { 0x2421, "TDMLIO"}, /* IO audio left , */\ + { 0x2441, "TDMRIO"}, /* IO audio right , */\ + { 0x2461, "TDMCSIO"}, /* IO Current Sense , */\ + { 0x2481, "TDMVSIO"}, /* IO voltage sense , */\ + { 0x24a1, "TDMGOIO"}, /* IO gain out , */\ + { 0x24c1, "TDMCFIO2"}, /* IO DSP 2 , */\ + { 0x24e1, "TDMCFIO3"}, /* IO DSP 3 , */\ + { 0x2501, "TDMCFIO"}, /* IO DSP , */\ + { 0x2521, "TDMLPB6"}, /* IO Source 6 , */\ + { 0x2541, "TDMLPB7"}, /* IO Source 7 , */\ + { 0x2603, "TDMGS"}, /* Control gainin , */\ + { 0x2643, "TDMDCS"}, /* tdm slot for audio left (channel 1) , */\ + { 0x2683, "TDMSPKS"}, /* tdm slot for audio right (channel 2) , */\ + { 0x26c3, "TDMCSS"}, /* Slot Position of Current Sense Out , */\ + { 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense , */\ + { 0x2743, "TDMCGOS"}, /* Slot Position of GAIN out , */\ + { 0x2783, "TDMCF2S"}, /* Slot Position DSPout2 , */\ + { 0x27c3, "TDMCF3S"}, /* Slot Position DSPout3 , */\ + { 0x2803, "TDMCFS"}, /* Slot Position of DSPout , */\ + { 0x2843, "TDMEDAT6S"}, /* Slot Position of loopback channel left , */\ + { 0x2883, "TDMEDAT7S"}, /* Slot Position of loopback channel right , */\ + { 0x2901, "TDMTXUS3"}, /* Format unused slots D3 , */\ + { 0x3100, "PDMSM"}, /* PDM control , */\ + { 0x3110, "PDMSTSEL"}, /* PDM Decimator input selection , */\ + { 0x3120, "PDMSTENBL"}, /* Side tone input enable , */\ + { 0x3130, "PDMLSEL"}, /* PDM data selection for left channel during PDM direct mode, */\ + { 0x3140, "PDMRSEL"}, /* PDM data selection for right channel during PDM direct mode, */\ + { 0x3150, "MICVDDE"}, /* Enable MICVDD , */\ + { 0x3201, "PDMCLRAT"}, /* PDM BCK/Fs ratio , */\ + { 0x3223, "PDMGAIN"}, /* PDM gain , */\ + { 0x3263, "PDMOSEL"}, /* PDM output selection - RE/FE data combination , */\ + { 0x32a0, "SELCFHAPD"}, /* Select the source for haptic data output (not for customer), */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTPLLS"}, /* Status PLL lock , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOVDS"}, /* Status OVP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTCLKS"}, /* Status clocks stable , */\ + { 0x4060, "ISTMTPB"}, /* Status MTP busy , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTSPKS"}, /* Status speaker error , */\ + { 0x4090, "ISTACS"}, /* Status cold start , */\ + { 0x40a0, "ISTSWS"}, /* Status amplifier engage , */\ + { 0x40b0, "ISTWDS"}, /* Status watchdog , */\ + { 0x40c0, "ISTAMPS"}, /* Status amplifier enable , */\ + { 0x40d0, "ISTAREFS"}, /* Status Ref enable , */\ + { 0x40e0, "ISTADCCR"}, /* Status Control ADC , */\ + { 0x40f0, "ISTBODNOK"}, /* Status BOD , */\ + { 0x4100, "ISTBSTCU"}, /* Status DCDC current limiting , */\ + { 0x4110, "ISTBSTHI"}, /* Status DCDC active , */\ + { 0x4120, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4130, "ISTBSTPKCUR"}, /* Status bst peakcur , */\ + { 0x4140, "ISTBSTVC"}, /* Status DCDC level 1x , */\ + { 0x4150, "ISTBST86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "ISTBST93"}, /* Status DCDC level 1.07x , */\ + { 0x4170, "ISTRCVLD"}, /* Status rcvldop ready , */\ + { 0x4180, "ISTOCPL"}, /* Status ocp alarm left , */\ + { 0x4190, "ISTOCPR"}, /* Status ocp alarm , */\ + { 0x41a0, "ISTMWSRC"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "ISTMWCFC"}, /* Status waits CF config , */\ + { 0x41c0, "ISTMWSMU"}, /* Status Audio mute sequence , */\ + { 0x41d0, "ISTCFMER"}, /* Status cfma error , */\ + { 0x41e0, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x41f0, "ISTCLKOOR"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "ISTTDMER"}, /* Status tdm error , */\ + { 0x4210, "ISTCLPL"}, /* Status clip left , */\ + { 0x4220, "ISTCLPR"}, /* Status clip , */\ + { 0x4230, "ISTOCPM"}, /* Status mic ocpok , */\ + { 0x4250, "ISTLP1"}, /* Status low power mode1 , */\ + { 0x4260, "ISTLA"}, /* Status low amplitude detection , */\ + { 0x4270, "ISTVDDP"}, /* Status VDDP greater than VBAT , */\ + { 0x4280, "ISTTAPDET"}, /* Status Tap detected , */\ + { 0x4290, "ISTAUDMOD"}, /* Status Audio Mode activated , */\ + { 0x42a0, "ISTSAMMOD"}, /* Status SAM Mode activated , */\ + { 0x42b0, "ISTTAPMOD"}, /* Status Tap Mode Activated , */\ + { 0x42c0, "ISTTAPTRG"}, /* Status Tap comparator triggered , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLPLLS"}, /* Clear PLL lock , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOVDS"}, /* Clear OVP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLCLKS"}, /* Clear clocks stable , */\ + { 0x4460, "ICLMTPB"}, /* Clear mtp busy , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLSPKS"}, /* Clear speaker error , */\ + { 0x4490, "ICLACS"}, /* Clear cold started , */\ + { 0x44a0, "ICLSWS"}, /* Clear amplifier engage , */\ + { 0x44b0, "ICLWDS"}, /* Clear watchdog , */\ + { 0x44c0, "ICLAMPS"}, /* Clear enbl amp , */\ + { 0x44d0, "ICLAREFS"}, /* Clear ref enable , */\ + { 0x44e0, "ICLADCCR"}, /* Clear control ADC , */\ + { 0x44f0, "ICLBODNOK"}, /* Clear BOD , */\ + { 0x4500, "ICLBSTCU"}, /* Clear DCDC current limiting , */\ + { 0x4510, "ICLBSTHI"}, /* Clear DCDC active , */\ + { 0x4520, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4530, "ICLBSTPC"}, /* Clear bst peakcur , */\ + { 0x4540, "ICLBSTVC"}, /* Clear DCDC level 1x , */\ + { 0x4550, "ICLBST86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "ICLBST93"}, /* Clear DCDC level 1.07x , */\ + { 0x4570, "ICLRCVLD"}, /* Clear rcvldop ready , */\ + { 0x4580, "ICLOCPL"}, /* Clear ocp alarm left , */\ + { 0x4590, "ICLOCPR"}, /* Clear ocp alarm , */\ + { 0x45a0, "ICLMWSRC"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "ICLMWCFC"}, /* Clear wait cf config , */\ + { 0x45c0, "ICLMWSMU"}, /* Clear audio mute sequence , */\ + { 0x45d0, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x45e0, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x45f0, "ICLCLKOOR"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "ICLTDMER"}, /* Clear tdm error , */\ + { 0x4610, "ICLCLPL"}, /* Clear clip left , */\ + { 0x4620, "ICLCLP"}, /* Clear clip , */\ + { 0x4630, "ICLOCPM"}, /* Clear mic ocpok , */\ + { 0x4650, "ICLLP1"}, /* Clear low power mode1 , */\ + { 0x4660, "ICLLA"}, /* Clear low amplitude detection , */\ + { 0x4670, "ICLVDDP"}, /* Clear VDDP greater then VBAT , */\ + { 0x4680, "ICLTAPDET"}, /* Clear Tap detected , */\ + { 0x4690, "ICLAUDMOD"}, /* Clear Audio Mode activated , */\ + { 0x46a0, "ICLSAMMOD"}, /* Clear SAM Mode activated , */\ + { 0x46b0, "ICLTAPMOD"}, /* Clear Tap Mode Activated , */\ + { 0x46c0, "ICLTAPTRG"}, /* Clear Comparator Interrupt , */\ + { 0x4800, "IEVDDS"}, /* Enable por , */\ + { 0x4810, "IEPLLS"}, /* Enable pll lock , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOVDS"}, /* Enable OVP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IECLKS"}, /* Enable clocks stable , */\ + { 0x4860, "IEMTPB"}, /* Enable mtp busy , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IESPKS"}, /* Enable speaker error , */\ + { 0x4890, "IEACS"}, /* Enable cold started , */\ + { 0x48a0, "IESWS"}, /* Enable amplifier engage , */\ + { 0x48b0, "IEWDS"}, /* Enable watchdog , */\ + { 0x48c0, "IEAMPS"}, /* Enable enbl amp , */\ + { 0x48d0, "IEAREFS"}, /* Enable ref enable , */\ + { 0x48e0, "IEADCCR"}, /* Enable Control ADC , */\ + { 0x48f0, "IEBODNOK"}, /* Enable BOD , */\ + { 0x4900, "IEBSTCU"}, /* Enable DCDC current limiting , */\ + { 0x4910, "IEBSTHI"}, /* Enable DCDC active , */\ + { 0x4920, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4930, "IEBSTPC"}, /* Enable bst peakcur , */\ + { 0x4940, "IEBSTVC"}, /* Enable DCDC level 1x , */\ + { 0x4950, "IEBST86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "IEBST93"}, /* Enable DCDC level 1.07x , */\ + { 0x4970, "IERCVLD"}, /* Enable rcvldop ready , */\ + { 0x4980, "IEOCPL"}, /* Enable ocp alarm left , */\ + { 0x4990, "IEOCPR"}, /* Enable ocp alarm , */\ + { 0x49a0, "IEMWSRC"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "IEMWCFC"}, /* Enable man wait cf config , */\ + { 0x49c0, "IEMWSMU"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "IECFMER"}, /* Enable cfma err , */\ + { 0x49e0, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x49f0, "IECLKOOR"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "IETDMER"}, /* Enable tdm error , */\ + { 0x4a10, "IECLPL"}, /* Enable clip left , */\ + { 0x4a20, "IECLPR"}, /* Enable clip , */\ + { 0x4a30, "IEOCPM1"}, /* Enable mic ocpok , */\ + { 0x4a50, "IELP1"}, /* Enable low power mode1 , */\ + { 0x4a60, "IELA"}, /* Enable low amplitude detection , */\ + { 0x4a70, "IEVDDP"}, /* Enable VDDP greater than VBAT , */\ + { 0x4a80, "IETAPDET"}, /* Enable Tap detected , */\ + { 0x4a90, "IEAUDMOD"}, /* Enable Audio Mode activated , */\ + { 0x4aa0, "IESAMMOD"}, /* Enable SAM Mode activated , */\ + { 0x4ab0, "IETAPMOD"}, /* Enable Tap Mode Activated , */\ + { 0x4ac0, "IETAPTRG"}, /* Enable comparator interrupt , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity por , */\ + { 0x4c10, "IPOPLLS"}, /* Polarity pll lock , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOVDS"}, /* Polarity OVP alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOCLKS"}, /* Polarity clocks stable , */\ + { 0x4c60, "IPOMTPB"}, /* Polarity mtp busy , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOSPKS"}, /* Polarity speaker error , */\ + { 0x4c90, "IPOACS"}, /* Polarity cold started , */\ + { 0x4ca0, "IPOSWS"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "IPOWDS"}, /* Polarity watchdog , */\ + { 0x4cc0, "IPOAMPS"}, /* Polarity enbl amp , */\ + { 0x4cd0, "IPOAREFS"}, /* Polarity ref enable , */\ + { 0x4ce0, "IPOADCCR"}, /* Polarity Control ADC , */\ + { 0x4cf0, "IPOBODNOK"}, /* Polarity BOD , */\ + { 0x4d00, "IPOBSTCU"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "IPOBSTHI"}, /* Polarity DCDC active , */\ + { 0x4d20, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "IPOBSTPC"}, /* Polarity bst peakcur , */\ + { 0x4d40, "IPOBSTVC"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "IPOBST86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "IPOBST93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d70, "IPORCVLD"}, /* Polarity rcvldop ready , */\ + { 0x4d80, "IPOOCPL"}, /* Polarity ocp alarm left , */\ + { 0x4d90, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4da0, "IPOMWSRC"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "IPOMWCFC"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "IPOMWSMU"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4de0, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4df0, "IPOCLKOOR"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "IPOTDMER"}, /* Polarity tdm error , */\ + { 0x4e10, "IPOCLPL"}, /* Polarity clip left , */\ + { 0x4e20, "IPOCLPR"}, /* Polarity clip , */\ + { 0x4e30, "IPOOCPM"}, /* Polarity mic ocpok , */\ + { 0x4e50, "IPOLP1"}, /* Polarity low power mode1 , */\ + { 0x4e60, "IPOLA"}, /* Polarity low amplitude detection , */\ + { 0x4e70, "IPOVDDP"}, /* Polarity VDDP greater than VBAT , */\ + { 0x4e80, "IPOLTAPDET"}, /* PolarityTap detected , */\ + { 0x4e90, "IPOLAUDMOD"}, /* PolarityAudio Mode activated , */\ + { 0x4ea0, "IPOLSAMMOD"}, /* PolaritySAM Mode activated , */\ + { 0x4eb0, "IPOLTAPMOD"}, /* Polarity Tap Mode Activated , */\ + { 0x4ec0, "IPOLTAPTRG"}, /* PolarityTap Comparator Trigger , */\ + { 0x5001, "BSSCR"}, /* Battery Safeguard attack time , */\ + { 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery Safeguard release time , */\ + { 0x50b1, "BSSHY"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "BSSAC"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5100, "BSSS"}, /* Vbat prot steepness , */\ + { 0x5110, "INTSMUTE"}, /* Soft mute HW , */\ + { 0x5120, "CFSML"}, /* Soft mute FW left , */\ + { 0x5130, "CFSM"}, /* Soft mute FW , */\ + { 0x5140, "HPFBYPL"}, /* Bypass HPF left , */\ + { 0x5150, "HPFBYP"}, /* Bypass HPF , */\ + { 0x5160, "DPSAL"}, /* Enable DPSA left , */\ + { 0x5170, "DPSA"}, /* Enable DPSA , */\ + { 0x5187, "VOL"}, /* FW volume control for primary audio channel , */\ + { 0x5200, "HNDSFRCV"}, /* Selection receiver , */\ + { 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x52d0, "SLOPEE"}, /* Enables slope control , */\ + { 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ + { 0x5c07, "CFTAPPAT"}, /* Coolflux tap pattern , */\ + { 0x5c83, "TAPDBGINFO"}, /* Reserved , */\ + { 0x5d0f, "TATPSTAT1"}, /* Tap Status 1 from CF FW , */\ + { 0x5f03, "TCOMPTHR"}, /* Comparator threshold (in uV) , */\ + { 0x6081, "PGAGAIN"}, /* PGA gain selection , */\ + { 0x6123, "TDMSPKG"}, /* System gain (INPLEV 0) , */\ + { 0x6505, "LPM1LVL"}, /* low power mode1 detector ctrl threshold for low_audio_lvl , */\ + { 0x6565, "LPM1HLD"}, /* Low power mode1 detector, ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x65c0, "LPM1DIS"}, /* low power mode1 detector control , */\ + { 0x6630, "DCDIS"}, /* DCDC , */\ + { 0x6801, "TDMSRCMAP"}, /* tdm source mapping , */\ + { 0x6821, "TDMSRCAS"}, /* frame a selection , */\ + { 0x6841, "TDMSRCBS"}, /* frame b selection , */\ + { 0x68a0, "ANC1C"}, /* ANC one s complement , */\ + { 0x6901, "SAMMODE"}, /* Sam mode , */\ + { 0x7033, "DCMCC"}, /* Max coil current , */\ + { 0x7071, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7090, "DCIE"}, /* Adaptive boost mode , */\ + { 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ + { 0x70c1, "DCINSEL"}, /* DCDC IIR input Selection , */\ + { 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7504, "DCTRIP"}, /* Adaptive boost trip levels 1, effective only when boost_intelligent is set to 1, */\ + { 0x7554, "DCTRIP2"}, /* Adaptive boost trip level 2, effective only when boost_intelligent is set to 1, */\ + { 0x75a4, "DCTRIPT"}, /* Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x7635, "DCVOF"}, /* First boost voltage level , */\ + { 0x7695, "DCVOS"}, /* Second boost voltage level , */\ + { 0x9000, "RST"}, /* Reset , */\ + { 0x9011, "DMEM"}, /* Target memory , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* Memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* Error flags , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* MTP KEY2 register , */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xee0f, "SWPROFIL"}, /* Software profile data , */\ + { 0xef0f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "DCMCCCL"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "USERDEF"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf40f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9912_BITNAMETABLE static tfaBfName_t Tfa9912BitNames[] = {\ + { 0x0, "powerdown"}, /* Powerdown selection , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux , */\ + { 0x30, "enbl_amplifier"}, /* Enables the Amplifier , */\ + { 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux controls amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x90, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xc0, "test_ocp"}, /* OCP testing control , */\ + { 0x101, "vamp_sel"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* I2C configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "enbl_fro8m_auto_off"}, /* Internal osc off at PWDN , */\ + { 0x150, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x160, "enbl_bod"}, /* BOD Enable , */\ + { 0x170, "enbl_bod_hyst"}, /* BOD Hysteresis , */\ + { 0x181, "bod_delay"}, /* BOD filter , */\ + { 0x1a1, "bod_lvlsel"}, /* BOD threshold , */\ + { 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1e0, "pwm_sel_rcv_ns"}, /* Noise shaper selection , */\ + { 0x1f0, "man_enbl_watchdog"}, /* Watchdog enable , */\ + { 0x203, "audio_fs"}, /* Sample rate (fs) , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ + { 0x2b0, "bypass_hvbat_filter"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "tdm_tfa9872_compatible"}, /* TDM Compatibility with TFA9872 , */\ + { 0x2d0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ + { 0x2e0, "enbl_adc10"}, /* ADC10 Enable - I2C direct mode , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ + { 0x430, "cf_clock_scaling"}, /* Coolflux DSP clock scaling, low power mode , */\ + { 0x441, "sel_cf_clock"}, /* Coolflux DSP clock scaler selection for low power mode, */\ + { 0x460, "tdm_intf_sel"}, /* TDM clock selection , */\ + { 0x470, "disable_auto_sel_refclk"}, /* Disable Automatic dsp clock source selection , */\ + { 0x480, "sel_clk_src"}, /* I2C selection of DSP clock when auto select is disabled, */\ + { 0x490, "wdt_tim_clk_src"}, /* I2C selection of Watchdog and Timer clock , */\ + { 0x510, "enbl_spkr_ss"}, /* Enable speaker path , */\ + { 0x530, "enbl_volsense"}, /* Voltage sense , */\ + { 0x550, "enbl_cursense"}, /* Current sense , */\ + { 0x560, "enbl_pdm_ss"}, /* Sub-system PDM , */\ + { 0x580, "enbl_pga_chop"}, /* Enable PGA chop clock , */\ + { 0x590, "enbl_tdm_ss"}, /* Sub-system TDM , */\ + { 0x5a0, "enbl_bst_ss"}, /* Sub-system boost , */\ + { 0x5b0, "enbl_adc10_ss"}, /* Sub-system ADC , */\ + { 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ + { 0x5d0, "enbl_tim_clk"}, /* CF Sub-system timer , */\ + { 0x5e0, "enbl_wdt_clk"}, /* CF Sub-system WDT , */\ + { 0x5f0, "faim_enable_vbg"}, /* Over rule of vbg for FaIM access , */\ + { 0x600, "aux_spkr_sel"}, /* Input selection for TAP/SAM , */\ + { 0x620, "bypass_tapdec_reset"}, /* Tap decimator reset bypass - Bypass the decimator reset from tapdec, */\ + { 0x631, "car_dec_in_sel0"}, /* Cardec input 0 sel , */\ + { 0x651, "car_dec_in_sel1"}, /* Cardec input sel , */\ + { 0x670, "tapdec_sel"}, /* Select TAP/Cardec for TAP , */\ + { 0x680, "comp_count"}, /* Comparator o/p filter selection , */\ + { 0x691, "startup_mode"}, /* Startup Mode Selection , */\ + { 0x6b0, "enable_auto_tap_switching"}, /* Enable auto tap switching , */\ + { 0x6c1, "comp_init_time"}, /* Comparator initialization time to be used in Tap Machine, */\ + { 0x6e1, "ana_init_time"}, /* Analog initialization time to be used in Tap Machine, */\ + { 0x707, "clkchk_th_hi"}, /* Clock check Higher Threshold , */\ + { 0x787, "clkchk_th_lo"}, /* Clock check Higher Threshold , */\ + { 0x802, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x832, "ctrl_on2tap_criterion"}, /* Amplifier on-off criteria for tap mode entry , */\ + { 0xd00, "side_tone_gain_sel"}, /* PDM side tone gain selector , */\ + { 0xd18, "side_tone_gain"}, /* Side tone gain , */\ + { 0xda0, "mute_side_tone"}, /* Side tone soft mute , */\ + { 0xdb0, "side_tone_1scomplement"}, /* side tone one s complement , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1060, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1070, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10b0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_soft_mute_busy"}, /* side tone (un)mute busy , */\ + { 0x1180, "flag_soft_mute_state"}, /* side tone mute state , */\ + { 0x1190, "flag_tdm_lut_error"}, /* TDM LUT error , */\ + { 0x11a2, "flag_tdm_status"}, /* TDM status bits , */\ + { 0x11d0, "flag_tdm_error"}, /* TDM error , */\ + { 0x1300, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1310, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1320, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1330, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1340, "flag_clipa_high"}, /* Clipping A to Vddp , */\ + { 0x1350, "flag_clipa_low"}, /* Clipping A to gnd , */\ + { 0x1360, "flag_clipb_high"}, /* Clipping B to Vddp , */\ + { 0x1370, "flag_clipb_low"}, /* Clipping B to gnd , */\ + { 0x1380, "flag_ocp_alarm"}, /* OCP amplifier , */\ + { 0x1390, "flag_clip"}, /* Amplifier clipping , */\ + { 0x13a0, "flag_tap_comp_trig"}, /* Status Tap comparator triggered , */\ + { 0x13b0, "flag_cf_tapdetected"}, /* Status Tap detected , */\ + { 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ + { 0x13d0, "flag_man_wait_cf_config"}, /* Wait CF config , */\ + { 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x1410, "flag_cf_speakererror"}, /* Speaker status , */\ + { 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1433, "man_state"}, /* Device manager status , */\ + { 0x1471, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1490, "man_dsp_clk_src"}, /* DSP clock source selected by manager , */\ + { 0x14a1, "man_startup_mode"}, /* Startup Mode Selected by Manager(Read Only) , */\ + { 0x14c3, "tap_machine_state"}, /* Tap Machine State , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x17a0, "flag_bst_bstcur_cf"}, /* DCDC current limiting for DSP , */\ + { 0x2000, "tdm_usecase"}, /* Mode setting , */\ + { 0x2011, "dio4_input_sel"}, /* DIO4 Input selection , */\ + { 0x2040, "tdm_enable"}, /* Enable TDM interface , */\ + { 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2073, "tdm_fs_ws_length"}, /* FS length , */\ + { 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ + { 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ + { 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ + { 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2271, "tdm_txdata_format"}, /* Format unused bits in a slot , */\ + { 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "tdm_txdata_format_unused_slot_sd1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "tdm_txdata_format_unused_slot_sd2"}, /* Format unused slots DIO2 , */\ + { 0x2300, "tdm_sink0_enable"}, /* Control gain (channel in 0) , */\ + { 0x2310, "tdm_sink1_enable"}, /* Control audio left (channel in 1 ) , */\ + { 0x2320, "tdm_sink2_enable"}, /* Control audio right (channel in 2 ) , */\ + { 0x2330, "tdm_source0_enable"}, /* Current sense , */\ + { 0x2340, "tdm_source1_enable"}, /* Voltage sense , */\ + { 0x2350, "tdm_source2_enable"}, /* DSP Gainout , */\ + { 0x2360, "tdm_source3_enable"}, /* DSP 2 , */\ + { 0x2370, "tdm_source4_enable"}, /* DSP 3 , */\ + { 0x2380, "tdm_source5_enable"}, /* DSP , */\ + { 0x2390, "tdm_source6_enable"}, /* Loopback of Audio left (channel 1) , */\ + { 0x23a0, "tdm_source7_enable"}, /* Loopback of Audio right (channel 2) , */\ + { 0x2401, "tdm_sink0_io"}, /* IO gainin , */\ + { 0x2421, "tdm_sink1_io"}, /* IO audio left , */\ + { 0x2441, "tdm_sink2_io"}, /* IO audio right , */\ + { 0x2461, "tdm_source0_io"}, /* IO Current Sense , */\ + { 0x2481, "tdm_source1_io"}, /* IO voltage sense , */\ + { 0x24a1, "tdm_source2_io"}, /* IO gain out , */\ + { 0x24c1, "tdm_source3_io"}, /* IO DSP 2 , */\ + { 0x24e1, "tdm_source4_io"}, /* IO DSP 3 , */\ + { 0x2501, "tdm_source5_io"}, /* IO DSP , */\ + { 0x2521, "tdm_source6_io"}, /* IO Source 6 , */\ + { 0x2541, "tdm_source7_io"}, /* IO Source 7 , */\ + { 0x2603, "tdm_sink0_slot"}, /* Control gainin , */\ + { 0x2643, "tdm_sink1_slot"}, /* tdm slot for audio left (channel 1) , */\ + { 0x2683, "tdm_sink2_slot"}, /* tdm slot for audio right (channel 2) , */\ + { 0x26c3, "tdm_source0_slot"}, /* Slot Position of Current Sense Out , */\ + { 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense , */\ + { 0x2743, "tdm_source2_slot"}, /* Slot Position of GAIN out , */\ + { 0x2783, "tdm_source3_slot"}, /* Slot Position DSPout2 , */\ + { 0x27c3, "tdm_source4_slot"}, /* Slot Position DSPout3 , */\ + { 0x2803, "tdm_source5_slot"}, /* Slot Position of DSPout , */\ + { 0x2843, "tdm_source6_slot"}, /* Slot Position of loopback channel left , */\ + { 0x2883, "tdm_source7_slot"}, /* Slot Position of loopback channel right , */\ + { 0x2901, "tdm_txdata_format_unused_slot_sd3"}, /* Format unused slots D3 , */\ + { 0x3100, "pdm_mode"}, /* PDM control , */\ + { 0x3110, "pdm_input_sel"}, /* PDM Decimator input selection , */\ + { 0x3120, "enbl_pdm_side_tone"}, /* Side tone input enable , */\ + { 0x3201, "pdm_nbck"}, /* PDM BCK/Fs ratio , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_pll_lock"}, /* Status PLL lock , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ovpok"}, /* Status OVP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_clocks_stable"}, /* Status clocks stable , */\ + { 0x4060, "int_out_flag_mtp_busy"}, /* Status MTP busy , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cf_speakererror"}, /* Status speaker error , */\ + { 0x4090, "int_out_flag_cold_started"}, /* Status cold start , */\ + { 0x40a0, "int_out_flag_engage"}, /* Status amplifier engage , */\ + { 0x40b0, "int_out_flag_watchdog_reset"}, /* Status watchdog , */\ + { 0x40c0, "int_out_flag_enbl_amp"}, /* Status amplifier enable , */\ + { 0x40d0, "int_out_flag_enbl_ref"}, /* Status Ref enable , */\ + { 0x40e0, "int_out_flag_adc10_ready"}, /* Status Control ADC , */\ + { 0x40f0, "int_out_flag_bod_vddd_nok"}, /* Status BOD , */\ + { 0x4100, "int_out_flag_bst_bstcur"}, /* Status DCDC current limiting , */\ + { 0x4110, "int_out_flag_bst_hiz"}, /* Status DCDC active , */\ + { 0x4120, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4130, "int_out_flag_bst_peakcur"}, /* Status bst peakcur , */\ + { 0x4140, "int_out_flag_bst_voutcomp"}, /* Status DCDC level 1x , */\ + { 0x4150, "int_out_flag_bst_voutcomp86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "int_out_flag_bst_voutcomp93"}, /* Status DCDC level 1.07x , */\ + { 0x4190, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ + { 0x41a0, "int_out_flag_man_wait_src_settings"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "int_out_flag_man_wait_cf_config"}, /* Status waits CF config , */\ + { 0x41c0, "int_out_flag_man_start_mute_audio"}, /* Status Audio mute sequence , */\ + { 0x41d0, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x41e0, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x41f0, "int_out_flag_clk_out_of_range"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "int_out_flag_tdm_error"}, /* Status tdm error , */\ + { 0x4220, "int_out_flag_clip"}, /* Status clip , */\ + { 0x4250, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 , */\ + { 0x4260, "int_out_flag_low_amplitude"}, /* Status low amplitude detection , */\ + { 0x4270, "int_out_flag_vddp_gt_vbat"}, /* Status VDDP greater than VBAT , */\ + { 0x4280, "int_out_newtap"}, /* Status Tap detected , */\ + { 0x4290, "int_out_audiomodeactive"}, /* Status Audio Mode activated , */\ + { 0x42a0, "int_out_sammodeactive"}, /* Status SAM Mode activated , */\ + { 0x42b0, "int_out_tapmodeactive"}, /* Status Tap Mode Activated , */\ + { 0x42c0, "int_out_flag_tap_comp_trig"}, /* Status Tap comparator triggered , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_pll_lock"}, /* Clear PLL lock , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ovpok"}, /* Clear OVP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_clocks_stable"}, /* Clear clocks stable , */\ + { 0x4460, "int_in_flag_mtp_busy"}, /* Clear mtp busy , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cf_speakererror"}, /* Clear speaker error , */\ + { 0x4490, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44a0, "int_in_flag_engage"}, /* Clear amplifier engage , */\ + { 0x44b0, "int_in_flag_watchdog_reset"}, /* Clear watchdog , */\ + { 0x44c0, "int_in_flag_enbl_amp"}, /* Clear enbl amp , */\ + { 0x44d0, "int_in_flag_enbl_ref"}, /* Clear ref enable , */\ + { 0x44e0, "int_in_flag_adc10_ready"}, /* Clear control ADC , */\ + { 0x44f0, "int_in_flag_bod_vddd_nok"}, /* Clear BOD , */\ + { 0x4500, "int_in_flag_bst_bstcur"}, /* Clear DCDC current limiting , */\ + { 0x4510, "int_in_flag_bst_hiz"}, /* Clear DCDC active , */\ + { 0x4520, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4530, "int_in_flag_bst_peakcur"}, /* Clear bst peakcur , */\ + { 0x4540, "int_in_flag_bst_voutcomp"}, /* Clear DCDC level 1x , */\ + { 0x4550, "int_in_flag_bst_voutcomp86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "int_in_flag_bst_voutcomp93"}, /* Clear DCDC level 1.07x , */\ + { 0x4590, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ + { 0x45a0, "int_in_flag_man_wait_src_settings"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "int_in_flag_man_wait_cf_config"}, /* Clear wait cf config , */\ + { 0x45c0, "int_in_flag_man_start_mute_audio"}, /* Clear audio mute sequence , */\ + { 0x45d0, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x45e0, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x45f0, "int_in_flag_clk_out_of_range"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ + { 0x4620, "int_in_flag_clip"}, /* Clear clip , */\ + { 0x4650, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 , */\ + { 0x4660, "int_in_flag_low_amplitude"}, /* Clear low amplitude detection , */\ + { 0x4670, "int_in_flag_vddp_gt_vbat"}, /* Clear VDDP greater then VBAT , */\ + { 0x4680, "int_in_newtap"}, /* Clear Tap detected , */\ + { 0x4690, "int_in_audiomodeactive"}, /* Clear Audio Mode activated , */\ + { 0x46a0, "int_in_sammodeactive"}, /* Clear SAM Mode activated , */\ + { 0x46b0, "int_in_tapmodeactive"}, /* Clear Tap Mode Activated , */\ + { 0x46c0, "int_in_flag_tap_comp_trig"}, /* Clear Comparator Interrupt , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable por , */\ + { 0x4810, "int_enable_flag_pll_lock"}, /* Enable pll lock , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ovpok"}, /* Enable OVP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_clocks_stable"}, /* Enable clocks stable , */\ + { 0x4860, "int_enable_flag_mtp_busy"}, /* Enable mtp busy , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cf_speakererror"}, /* Enable speaker error , */\ + { 0x4890, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48a0, "int_enable_flag_engage"}, /* Enable amplifier engage , */\ + { 0x48b0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog , */\ + { 0x48c0, "int_enable_flag_enbl_amp"}, /* Enable enbl amp , */\ + { 0x48d0, "int_enable_flag_enbl_ref"}, /* Enable ref enable , */\ + { 0x48e0, "int_enable_flag_adc10_ready"}, /* Enable Control ADC , */\ + { 0x48f0, "int_enable_flag_bod_vddd_nok"}, /* Enable BOD , */\ + { 0x4900, "int_enable_flag_bst_bstcur"}, /* Enable DCDC current limiting , */\ + { 0x4910, "int_enable_flag_bst_hiz"}, /* Enable DCDC active , */\ + { 0x4920, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4930, "int_enable_flag_bst_peakcur"}, /* Enable bst peakcur , */\ + { 0x4940, "int_enable_flag_bst_voutcomp"}, /* Enable DCDC level 1x , */\ + { 0x4950, "int_enable_flag_bst_voutcomp86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "int_enable_flag_bst_voutcomp93"}, /* Enable DCDC level 1.07x , */\ + { 0x4990, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ + { 0x49a0, "int_enable_flag_man_wait_src_settings"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "int_enable_flag_man_wait_cf_config"}, /* Enable man wait cf config , */\ + { 0x49c0, "int_enable_flag_man_start_mute_audio"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x49e0, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x49f0, "int_enable_flag_clk_out_of_range"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ + { 0x4a20, "int_enable_flag_clip"}, /* Enable clip , */\ + { 0x4a50, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 , */\ + { 0x4a60, "int_enable_flag_low_amplitude"}, /* Enable low amplitude detection , */\ + { 0x4a70, "int_enable_flag_vddp_gt_vbat"}, /* Enable VDDP greater than VBAT , */\ + { 0x4a80, "int_enable_newtap"}, /* Enable Tap detected , */\ + { 0x4a90, "int_enable_audiomodeactive"}, /* Enable Audio Mode activated , */\ + { 0x4aa0, "int_enable_sammodeactive"}, /* Enable SAM Mode activated , */\ + { 0x4ab0, "int_enable_tapmodeactive"}, /* Enable Tap Mode Activated , */\ + { 0x4ac0, "int_enable_flag_tap_comp_trig"}, /* Enable comparator interrupt , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ + { 0x4c10, "int_polarity_flag_pll_lock"}, /* Polarity pll lock , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ovpok"}, /* Polarity OVP alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_clocks_stable"}, /* Polarity clocks stable , */\ + { 0x4c60, "int_polarity_flag_mtp_busy"}, /* Polarity mtp busy , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cf_speakererror"}, /* Polarity speaker error , */\ + { 0x4c90, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4ca0, "int_polarity_flag_engage"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog , */\ + { 0x4cc0, "int_polarity_flag_enbl_amp"}, /* Polarity enbl amp , */\ + { 0x4cd0, "int_polarity_flag_enbl_ref"}, /* Polarity ref enable , */\ + { 0x4ce0, "int_polarity_flag_adc10_ready"}, /* Polarity Control ADC , */\ + { 0x4cf0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity BOD , */\ + { 0x4d00, "int_polarity_flag_bst_bstcur"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "int_polarity_flag_bst_hiz"}, /* Polarity DCDC active , */\ + { 0x4d20, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "int_polarity_flag_bst_peakcur"}, /* Polarity bst peakcur , */\ + { 0x4d40, "int_polarity_flag_bst_voutcomp"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "int_polarity_flag_bst_voutcomp86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "int_polarity_flag_bst_voutcomp93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d90, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4da0, "int_polarity_flag_man_wait_src_settings"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "int_polarity_flag_man_wait_cf_config"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "int_polarity_flag_man_start_mute_audio"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4de0, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4df0, "int_polarity_flag_clk_out_of_range"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ + { 0x4e20, "int_polarity_flag_clip"}, /* Polarity clip , */\ + { 0x4e50, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 , */\ + { 0x4e60, "int_polarity_flag_low_amplitude"}, /* Polarity low amplitude detection , */\ + { 0x4e70, "int_polarity_flag_vddp_gt_vbat"}, /* Polarity VDDP greater than VBAT , */\ + { 0x4e80, "int_polarity_newtap"}, /* PolarityTap detected , */\ + { 0x4e90, "int_polarity_audiomodeactive"}, /* PolarityAudio Mode activated , */\ + { 0x4ea0, "int_polarity_sammodeactive"}, /* PolaritySAM Mode activated , */\ + { 0x4eb0, "int_polarity_tapmodeactive"}, /* Polarity Tap Mode Activated , */\ + { 0x4ec0, "int_polarity_flag_tap_comp_trig"}, /* PolarityTap Comparator Trigger , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery Safeguard release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ + { 0x5110, "soft_mute"}, /* Soft mute HW , */\ + { 0x5130, "cf_mute"}, /* Soft mute FW , */\ + { 0x5150, "bypass_hp"}, /* Bypass HPF , */\ + { 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0x5187, "cf_volume"}, /* FW volume control for primary audio channel , */\ + { 0x5222, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5257, "gain"}, /* Amplifier gain , */\ + { 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for Battery Safeguard, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "enbl_low_latency"}, /* CF low latency outputs for add module , */\ + { 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5430, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5582, "dpsa_drive"}, /* Drive setting (bin. coded) - I2C direct mode , */\ + { 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually , */\ + { 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop - I2C direct mode, */\ + { 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5820, "pwm_shape"}, /* PWM shape , */\ + { 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clock is 1/(k*2048*fs), */\ + { 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ + { 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ + { 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ + { 0x5c07, "flag_cf_tap_pattern"}, /* Coolflux tap pattern , */\ + { 0x5c83, "tap_debug_info"}, /* Reserved , */\ + { 0x5d0f, "tap_status_1"}, /* Tap Status 1 from CF FW , */\ + { 0x5f03, "tap_comp_threshold"}, /* Comparator threshold (in uV) , */\ + { 0x6081, "pga_gain_set"}, /* PGA gain selection , */\ + { 0x60b0, "pga_lowpass_enable"}, /* Lowpass enable , */\ + { 0x60c0, "pga_pwr_enable"}, /* PGA power enable , */\ + { 0x60d0, "pga_switch_enable"}, /* PGA switch enable , */\ + { 0x60e0, "pga_switch_aux_enable"}, /* Switch enable aux , */\ + { 0x6123, "ctrl_att"}, /* System gain (INPLEV 0) , */\ + { 0x6265, "zero_lvl"}, /* ctrl threshold for zero X-ing , */\ + { 0x62c1, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ + { 0x6305, "threshold_lvl"}, /* ctrl threshold for low_audio_lvl , */\ + { 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x6465, "lpm1_zero_lvl"}, /* low power mode1 detector ctrl threshold for zero X-ing , */\ + { 0x64e1, "lpm1_mode"}, /* low power mode1 detector ctrl select mode , */\ + { 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 detector ctrl threshold for low_audio_lvl , */\ + { 0x6565, "lpm1_hold_time"}, /* Low power mode1 detector, ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ + { 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ + { 0x6630, "dcdcoff_mode"}, /* DCDC , */\ + { 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x6700, "enbl_minion"}, /* Enables minion (small) power stage - direct ctrl , */\ + { 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ + { 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtered vs unfiltered compare , */\ + { 0x6761, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x6801, "tdm_source_mapping"}, /* tdm source mapping , */\ + { 0x6821, "tdm_sourcea_frame_sel"}, /* frame a selection , */\ + { 0x6841, "tdm_sourceb_frame_sel"}, /* frame b selection , */\ + { 0x6901, "sam_mode"}, /* Sam mode , */\ + { 0x6931, "pdmdat_h_sel"}, /* pdm out value when pdm_clk is higth , */\ + { 0x6951, "pdmdat_l_sel"}, /* pdm out value when pdm_clk is low , */\ + { 0x6970, "cs_sam_set"}, /* Enable SAM input for current sense - I2C Direct Mode, */\ + { 0x6980, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x6990, "sam_spkr_sel"}, /* SAM o/p sel during SAM and audio , */\ + { 0x6b00, "disable_engage"}, /* Disable auto engage , */\ + { 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x6c60, "sel_clip_pwms"}, /* To select clip-flags , */\ + { 0x6c72, "pwms_clip_lvl"}, /* To set the amount of pwm pulse that may be skipped before clip-flag is triggered. , */\ + { 0x6ca5, "spare_out"}, /* spare_out , */\ + { 0x6d0f, "spare_in"}, /* spare_in , */\ + { 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ + { 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ + { 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ + { 0x7033, "boost_cur"}, /* Max coil current , */\ + { 0x7071, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x70c1, "dcdc_sel"}, /* DCDC IIR input Selection , */\ + { 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7174, "bst_slopecur"}, /* For testing direct control slope current - I2C direct mode, */\ + { 0x71c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller - I2C direct mode, */\ + { 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator - I2C direct mode , */\ + { 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7230, "enbl_bst_peakcur"}, /* Enable peak current - I2C direct mode , */\ + { 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage - I2C direct mode , */\ + { 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac - I2C direct mode , */\ + { 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators - I2C direct mode , */\ + { 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators - I2C direct mode , */\ + { 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators - I2C direct mode , */\ + { 0x7290, "enbl_bst_windac"}, /* Enable window dac - I2C direct mode , */\ + { 0x72a5, "bst_windac"}, /* for testing direct control windac - I2C direct mode, */\ + { 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x74f0, "ignore_flag_voutcomp86"}, /* Ignore flag_voutcomp86 , */\ + { 0x7504, "boost_trip_lvl_1st"}, /* Adaptive boost trip levels 1, effective only when boost_intelligent is set to 1, */\ + { 0x7554, "boost_trip_lvl_2nd"}, /* Adaptive boost trip level 2, effective only when boost_intelligent is set to 1, */\ + { 0x75a4, "boost_trip_lvl_track"}, /* Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x7602, "track_decay"}, /* DCDC Boost decay speed after a peak value, effective only when boost_track is set to 1, */\ + { 0x7635, "frst_boost_voltage"}, /* First boost voltage level , */\ + { 0x7695, "scnd_boost_voltage"}, /* Second boost voltage level , */\ + { 0x7720, "pga_test_ldo_bypass"}, /* bypass internal PGA LDO , */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8200, "enbl_cmfb"}, /* Current sense common mode feedback control , */\ + { 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8222, "cmfb_gain"}, /* Current sense common mode feedback control gain , */\ + { 0x8256, "cmfb_offset"}, /* Current sense common mode feedback control offset , */\ + { 0x8305, "cs_ktemp"}, /* First order temperature compensation coefficient , */\ + { 0x8364, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC - I2C direct mode , */\ + { 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 - I2C direct mode, */\ + { 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 - I2C direct mode, */\ + { 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 - I2C direct mode, */\ + { 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO - I2C direct mode , */\ + { 0x8760, "enbl_cs_nofloating_n"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8770, "enbl_cs_nofloating_p"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO -- I2C direct mode , */\ + { 0x8800, "volsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ + { 0x8810, "vol_cur_sense_dc_offset"}, /* voltage and current sense decimator offset control, */\ + { 0x8902, "cursense_comp_delay"}, /* To align compensation signal with current sense signal, */\ + { 0x8930, "cursense_comp_sign"}, /* To change polarity of compensation for current sense compensation, */\ + { 0x8940, "enbl_cursense_comp"}, /* To enable current sense compensation , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset , */\ + { 0x9011, "cf_dmem"}, /* Target memory , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* Memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* Error flags , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa400, "faim_set_clkws"}, /* Sets the FaIM controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the FaIM are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the FaIM are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb050, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually - - I2C direct mode, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high - I2C direct mode, */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc130, "tap_comp_enable"}, /* Tap Comparator enable control - I2C direct mode , */\ + { 0xc140, "tap_comp_switch_enable"}, /* Tap Comparator Switch enable control - I2C direct mode, */\ + { 0xc150, "tap_comp_switch_aux_enable"}, /* Tap Comparator Switch enable control - I2C direct mode, */\ + { 0xc161, "tap_comp_test_enable"}, /* Comparator threshold - fine value , */\ + { 0xc180, "curdist_enable"}, /* Enable control - I2C direct mode , */\ + { 0xc190, "vbg2i_enbl"}, /* Enable control - I2C direct mode , */\ + { 0xc1a0, "bg_filt_bypass_enbl"}, /* Enable control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0xc3d0, "test_abistfft_enbl"}, /* FFT Coolflux , */\ + { 0xc3e0, "test_pwr_switch"}, /* Test mode for digital power switches core sw/mem sw/micvdd sw, */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc560, "bypass_fro8"}, /* Bypass fro8 with pdm_clk , */\ + { 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc5b0, "pga_test_enable"}, /* Enable PGA test mode , */\ + { 0xc5c0, "pga_test_offset_enable"}, /* Enable PGA test offset , */\ + { 0xc5d0, "pga_test_shortinput_enable"}, /* Enable PGA test short input , */\ + { 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc660, "enbl_powerswitch"}, /* Vddd core power switch control - overrules the manager control, */\ + { 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DIO4 (see Digimux list for details), */\ + { 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to DIO3 (see Digimux list for details), */\ + { 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to TDO (see Digimux list for details), */\ + { 0xc901, "dio1_ehs"}, /* Speed/load setting for DIO1 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc921, "dio2_ehs"}, /* Speed/load setting for DIO2 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc941, "dio3_ehs"}, /* Speed/load setting for DIO3 cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc961, "dio4_ehs"}, /* Speed/load setting for DIO4 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc981, "spdmo_ehs"}, /* Speed/load setting for PDMO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9a1, "tdo_ehs"}, /* Speed/load setting for TDM IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9c0, "int_ehs"}, /* Slew Rate INT IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xc9d0, "pdmclk_ehs"}, /* Slew RateBCK2/PDMCLK IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xc9e0, "fs2_ehs"}, /* Slew Rate DS2 IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xc9f0, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xcb54, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xcba4, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xcc05, "pll_seli_lbw"}, /* PLL SELI - Low B/W PLL control mode or I2C direct PLL control mode only, */\ + { 0xcc64, "pll_selp_lbw"}, /* PLL SELP - Low B/W PLL control mode or I2C direct PLL control mode only, */\ + { 0xccb3, "pll_selr_lbw"}, /* PLL SELR - Low B/W PLL control mode or I2C direct PLL control mode only, */\ + { 0xccf0, "sel_user_pll_bw"}, /* PLL Low Bandwidth Mode control , */\ + { 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ + { 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcec0, "enbl_fro8"}, /* Enables FRO8M in I2C direct control mode only , */\ + { 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd283, "tsig_gain"}, /* Test signal gain , */\ + { 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd580, "enbl_clk_range_chk"}, /* Clock out of range , */\ + { 0xd601, "clkdiv_dsp_sel"}, /* DSP clock divider selection in direct clock control mode, */\ + { 0xd621, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ + { 0xd641, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ + { 0xd661, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ + { 0xd681, "dsp_tap_clk"}, /* Dsp clock frequency selection in TAP mode; , */\ + { 0xd6a1, "sel_wdt_clk"}, /* Watch dog clock post divider value , */\ + { 0xd6c1, "sel_tim_clk"}, /* Timer clock post divider value , */\ + { 0xd700, "ads1_ehs"}, /* Slew Rate ADS1 IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xd710, "ads2_ehs"}, /* Slew Rate ADS2 IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xd822, "test_parametric_io"}, /* test io parametric , */\ + { 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ + { 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ + { 0xd880, "bst_dcmbst"}, /* dcm boost - I2C direct mode , */\ + { 0xd8a1, "force_pga_clock"}, /* force pga clock , */\ + { 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ + { 0xd900, "overrules_usercase"}, /* Overrule Mode control use , */\ + { 0xd910, "ovr_switch_ref"}, /* Overrule Value , */\ + { 0xd920, "ovr_enbl_pll"}, /* Overrule Value , */\ + { 0xd930, "ovr_switch_amp"}, /* Overrule Value , */\ + { 0xd940, "ovr_enbl_clk_cs"}, /* Overrule Value , */\ + { 0xd951, "ovr_sel_clk_cs"}, /* CS clock selection overrule , */\ + { 0xd970, "ovr_switch_cs"}, /* Overrule Value , */\ + { 0xd980, "ovr_enbl_csvs_ss"}, /* Overrule Value , */\ + { 0xd990, "ovr_enbl_comp"}, /* Overrule Value , */\ + { 0xed00, "enbl_fro8cal"}, /* Enable FRO calibration , */\ + { 0xed10, "start_fro8_calibration"}, /* Start FRO8 Calibration , */\ + { 0xed20, "fro8_calibration_done"}, /* FRO8 Calibration done - Read Only , */\ + { 0xed45, "fro8_auto_trim_val"}, /* Calibration value from Auto Calibration block, to be written into MTP - Read Only, */\ + { 0xee0f, "sw_profile"}, /* Software profile data , */\ + { 0xef0f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "spare_mtp1_9_6"}, /* HW gain module - left channel (2's complement) , */\ + { 0xf1a5, "spare_mtp1_15_10"}, /* Offset for amplifier, HW gain module - left channel (2's complement), */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf2a3, "spare_mtp2_13_10"}, /* Trimming of LDO (2.7V) , */\ + { 0xf307, "spare_mtp3_7_0"}, /* SPARE , */\ + { 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf40f, "calibr_R25C"}, /* Ron resistance of speaker coil , */\ + { 0xf50f, "spare_mtp5_15_0"}, /* SPARE , */\ + { 0xf600, "mtp_lock_enbl_coolflux"}, /* Disable function dcdcoff_mode , */\ + { 0xf610, "mtp_pwm_delay_enbl_clk_auto_gating"}, /* Auto clock gating on pwm_delay , */\ + { 0xf620, "mtp_ocp_enbl_clk_auto_gating"}, /* Auto clock gating on module ocp , */\ + { 0xf630, "mtp_disable_clk_a_gating"}, /* Disable clock_a gating , */\ + { 0xf642, "spare_mtp6_6_3"}, /* SPARE , */\ + { 0xf686, "spare_mtp6_14_8"}, /* Offset of left amplifier level shifter B , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf910, "disable_sam_mode"}, /* Disable sam mode , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Disable programming of max dcdc boost voltage , */\ + { 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf987, "type_bits_fw"}, /* MTP-control FW - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ + { 0xff05, "fro8_trim"}, /* 8 MHz oscillator trim code , */\ + { 0xff61, "fro8_short_nwell_r"}, /* Short 4 or 6 n-well resistors , */\ + { 0xff81, "fro8_boost_i"}, /* Self bias current selection , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9912_irq { + tfa9912_irq_stvdds = 0, + tfa9912_irq_stplls = 1, + tfa9912_irq_stotds = 2, + tfa9912_irq_stovds = 3, + tfa9912_irq_stuvds = 4, + tfa9912_irq_stclks = 5, + tfa9912_irq_stmtpb = 6, + tfa9912_irq_stnoclk = 7, + tfa9912_irq_stspks = 8, + tfa9912_irq_stacs = 9, + tfa9912_irq_stsws = 10, + tfa9912_irq_stwds = 11, + tfa9912_irq_stamps = 12, + tfa9912_irq_starefs = 13, + tfa9912_irq_stadccr = 14, + tfa9912_irq_stbodnok = 15, + tfa9912_irq_stbstcu = 16, + tfa9912_irq_stbsthi = 17, + tfa9912_irq_stbstoc = 18, + tfa9912_irq_stbstpkcur = 19, + tfa9912_irq_stbstvc = 20, + tfa9912_irq_stbst86 = 21, + tfa9912_irq_stbst93 = 22, + tfa9912_irq_strcvld = 23, + tfa9912_irq_stocpl = 24, + tfa9912_irq_stocpr = 25, + tfa9912_irq_stmwsrc = 26, + tfa9912_irq_stmwcfc = 27, + tfa9912_irq_stmwsmu = 28, + tfa9912_irq_stcfmer = 29, + tfa9912_irq_stcfmac = 30, + tfa9912_irq_stclkoor = 31, + tfa9912_irq_sttdmer = 32, + tfa9912_irq_stclpl = 33, + tfa9912_irq_stclpr = 34, + tfa9912_irq_stocpm = 35, + tfa9912_irq_stlp1 = 37, + tfa9912_irq_stla = 38, + tfa9912_irq_stvddp = 39, + tfa9912_irq_sttapdet = 40, + tfa9912_irq_staudmod = 41, + tfa9912_irq_stsammod = 42, + tfa9912_irq_sttapmod = 43, + tfa9912_irq_sttaptrg = 44, + tfa9912_irq_max = 45, + tfa9912_irq_all = -1 /* all irqs */}; + +#define TFA9912_IRQ_NAMETABLE static tfaIrqName_t Tfa9912IrqNames[] = {\ + { 0, "STVDDS"},\ + { 1, "STPLLS"},\ + { 2, "STOTDS"},\ + { 3, "STOVDS"},\ + { 4, "STUVDS"},\ + { 5, "STCLKS"},\ + { 6, "STMTPB"},\ + { 7, "STNOCLK"},\ + { 8, "STSPKS"},\ + { 9, "STACS"},\ + { 10, "STSWS"},\ + { 11, "STWDS"},\ + { 12, "STAMPS"},\ + { 13, "STAREFS"},\ + { 14, "STADCCR"},\ + { 15, "STBODNOK"},\ + { 16, "STBSTCU"},\ + { 17, "STBSTHI"},\ + { 18, "STBSTOC"},\ + { 19, "STBSTPKCUR"},\ + { 20, "STBSTVC"},\ + { 21, "STBST86"},\ + { 22, "STBST93"},\ + { 23, "STRCVLD"},\ + { 24, "STOCPL"},\ + { 25, "STOCPR"},\ + { 26, "STMWSRC"},\ + { 27, "STMWCFC"},\ + { 28, "STMWSMU"},\ + { 29, "STCFMER"},\ + { 30, "STCFMAC"},\ + { 31, "STCLKOOR"},\ + { 32, "STTDMER"},\ + { 33, "STCLPL"},\ + { 34, "STCLPR"},\ + { 35, "STOCPM"},\ + { 36, "36"},\ + { 37, "STLP1"},\ + { 38, "STLA"},\ + { 39, "STVDDP"},\ + { 40, "STTAPDET"},\ + { 41, "STAUDMOD"},\ + { 42, "STSAMMOD"},\ + { 43, "STTAPMOD"},\ + { 44, "STTAPTRG"},\ + { 45, "45"},\ +}; +#endif /* _TFA9912_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa_container.c b/sound/soc/codecs/tfa_container.c new file mode 100644 index 0000000000000000000000000000000000000000..0cea84f53cc373c61659e4d8bd4b4295c8964c45 --- /dev/null +++ b/sound/soc/codecs/tfa_container.c @@ -0,0 +1,2410 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#include "dbgprint.h" +#include "tfa_container.h" +#include "tfa.h" +#include "tfa98xx_tfafieldnames.h" +#include "tfa_internal.h" + + /* defines */ +#define MODULE_BIQUADFILTERBANK 2 +#define BIQUAD_COEFF_SIZE 6 +#define ERR -1 + +/* module globals */ +/* This is used to SET the slave with the --slave option */ +static uint8_t gslave_address; + +static int float_to_int(uint32_t x) +{ + unsigned int e = (0x7F + 31) - ((*(unsigned int *)&x & 0x7F800000) >> 23); + unsigned int m = 0x80000000 | (*(unsigned int *)&x << 8); + + return -(int)((m >> e) & -(e < 32)); +} + +/* + * check the container file + */ +enum tfa_error tfa_load_cnt(void *cnt, int length) +{ + nxpTfaContainer_t *cntbuf = (nxpTfaContainer_t *)cnt; + + if (length > TFA_MAX_CNT_LENGTH) { + pr_err("incorrect length\n"); + return tfa_error_container; + } + + if (HDR(cntbuf->id[0], cntbuf->id[1]) == 0) { + pr_err("header is 0\n"); + return tfa_error_container; + } + + if ((HDR(cntbuf->id[0], cntbuf->id[1])) != paramsHdr) { + pr_err("wrong header type: 0x%02x 0x%02x\n", + cntbuf->id[0], cntbuf->id[1]); + return tfa_error_container; + } + + if (cntbuf->size == 0) { + pr_err("data size is 0\n"); + return tfa_error_container; + } + + /* check CRC */ + if (tfaContCrcCheckContainer(cntbuf)) { + pr_err("CRC error\n"); + return tfa_error_container; + } + + /* check sub version level */ + if ((cntbuf->subversion[1] != NXPTFA_PM_SUBVERSION) && + (cntbuf->subversion[0] != '0')) { + pr_err("container sub-version not supported: %c%c\n", + cntbuf->subversion[0], cntbuf->subversion[1]); + return tfa_error_container; + } + + return tfa_error_ok; +} + +/* + * Dump the contents of the file header + */ +void tfaContShowHeader(nxpTfaHeader_t *hdr) +{ + char _id[2]; + + pr_debug("File header\n"); + + _id[1] = hdr->id >> 8; + _id[0] = hdr->id & 0xff; + pr_debug("\tid:%.2s version:%.2s subversion:%.2s\n", _id, + hdr->version, hdr->subversion); + pr_debug("\tsize:%d CRC:0x%08x \n", hdr->size, hdr->CRC); + pr_debug("\tcustomer:%.8s application:%.8s type:%.8s\n", hdr->customer, + hdr->application, hdr->type); +} + +/* + * return device list dsc from index + */ +nxpTfaDeviceList_t *tfaContGetDevList(nxpTfaContainer_t *cont, int dev_idx) +{ + uint8_t *base = (uint8_t *)cont; + + if (cont == NULL) + return NULL; + + if ((dev_idx < 0) || (dev_idx >= cont->ndev)) + return NULL; + + if (cont->index[dev_idx].type != dscDevice) + return NULL; + + base += cont->index[dev_idx].offset; + return (nxpTfaDeviceList_t *)base; +} + +/* + * get the Nth profile for the Nth device + */ +nxpTfaProfileList_t *tfaContGetDevProfList(nxpTfaContainer_t *cont, + int devIdx, int profIdx) +{ + nxpTfaDeviceList_t *dev; + int idx, hit; + uint8_t *base = (uint8_t *)cont; + + dev = tfaContGetDevList(cont, devIdx); + if (dev) { + for (idx = 0, hit = 0; idx < dev->length; idx++) { + if (dev->list[idx].type == dscProfile) { + if (profIdx == hit++) + return (nxpTfaProfileList_t *)(dev->list[idx].offset + base); + } + } + } + + return NULL; +} + +/* + * get the number of profiles for the Nth device + */ +int tfa_cnt_get_dev_nprof(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev; + int idx, nprof = 0; + + if (tfa->cnt == NULL) + return 0; + + if ((tfa->dev_idx < 0) || (tfa->dev_idx >= tfa->cnt->ndev)) + return 0; + + dev = tfaContGetDevList(tfa->cnt, tfa->dev_idx); + if (dev) { + for (idx = 0; idx < dev->length; idx++) { + if (dev->list[idx].type == dscProfile) { + nprof++; + } + } + } + + return nprof; +} + +/* + * get the Nth lifedata for the Nth device + */ +nxpTfaLiveDataList_t *tfaContGetDevLiveDataList(nxpTfaContainer_t *cont, + int devIdx, int lifeDataIdx) +{ + nxpTfaDeviceList_t *dev; + int idx, hit; + uint8_t *base = (uint8_t *)cont; + + dev = tfaContGetDevList(cont, devIdx); + if (dev) { + for (idx = 0, hit = 0; idx < dev->length; idx++) { + if (dev->list[idx].type == dscLiveData) { + if (lifeDataIdx == hit++) + return (nxpTfaLiveDataList_t *) + (dev->list[idx].offset + base); + } + } + } + + return NULL; +} + +/* + * Get the max volume step associated with Nth profile for the Nth device + */ +int tfacont_get_max_vstep(struct tfa_device *tfa, int prof_idx) +{ + nxpTfaVolumeStep2File_t *vp; + struct nxpTfaVolumeStepMax2File *vp3; + int vstep_count = 0; + vp = (nxpTfaVolumeStep2File_t *)tfacont_getfiledata(tfa, prof_idx, + volstepHdr); + if (vp == NULL) + return 0; + /* check the header type to load different NrOfVStep appropriately */ + if (tfa->tfa_family == 2) { + /* this is actually tfa2, so re-read the buffer*/ + vp3 = (struct nxpTfaVolumeStepMax2File *) + tfacont_getfiledata(tfa, prof_idx, volstepHdr); + if (vp3) { + vstep_count = vp3->NrOfVsteps; + } + } else { + /* this is max1*/ + if (vp) { + vstep_count = vp->vsteps; + } + } + return vstep_count; +} + +/** + * Get the file contents associated with the device or profile + * Search within the device tree, if not found, search within the profile + * tree. There can only be one type of file within profile or device. + */ +nxpTfaFileDsc_t *tfacont_getfiledata(struct tfa_device *tfa, + int prof_idx, enum nxpTfaHeaderType type) +{ + nxpTfaDeviceList_t *dev; + nxpTfaProfileList_t *prof; + nxpTfaFileDsc_t *file; + nxpTfaHeader_t *hdr; + unsigned int i; + + if (tfa->cnt == NULL) { + pr_err("invalid pointer to container file\n"); + return NULL; + } + + dev = tfaContGetDevList(tfa->cnt, tfa->dev_idx); + if (dev == NULL) { + pr_err("invalid pointer to container file device list\n"); + return NULL; + } + + /* process the device list until a file type is encountered */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscFile) { + file = (nxpTfaFileDsc_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt); + if (file != NULL) { + hdr = (nxpTfaHeader_t *)file->data; + /* check for file type */ + if (hdr->id == type) { + return (nxpTfaFileDsc_t *)&file->data; + } + } + } + } + + /* File not found in device tree. + * So, look in the profile list until the file type is encountered + */ + prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + if (prof == NULL) { + pr_err("invalid pointer to container file profile list\n"); + return NULL; + } + + for (i = 0; i < prof->length; i++) { + if (prof->list[i].type == dscFile) { + file = (nxpTfaFileDsc_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + if (file != NULL) { + hdr = (nxpTfaHeader_t *)file->data; + if (hdr != NULL) { + /* check for file type */ + if (hdr->id == type) { + return (nxpTfaFileDsc_t *)&file->data; + } + } + } + } + } + + if (tfa->verbose) + pr_debug("%s: no file found of type %d\n", __FUNCTION__, type); + + return NULL; +} + +/* + * write a parameter file to the device + */ +static enum Tfa98xx_Error tfaContWriteVstep(struct tfa_device *tfa, + nxpTfaVolumeStep2File_t *vp, int vstep) +{ + enum Tfa98xx_Error err; + unsigned short vol; + + if (vstep < vp->vsteps) { + /* vol = (unsigned short)(voldB / (-0.5f)); */ + vol = (unsigned short)(-2 * float_to_int(*((uint32_t *)&vp->vstep[vstep].attenuation))); + if (vol > 255) /* restricted to 8 bits */ + vol = 255; + + err = tfa98xx_set_volume_level(tfa, vol); + if (err != Tfa98xx_Error_Ok) + return err; + + err = tfa98xx_dsp_write_preset(tfa, sizeof(vp->vstep[0].preset), vp->vstep[vstep].preset); + if (err != Tfa98xx_Error_Ok) + return err; + err = tfa_cont_write_filterbank(tfa, vp->vstep[vstep].filter); + + } else { + pr_err("Incorrect volume given. The value vstep[%d] >= %d\n", vstep, vp->vsteps); + err = Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) + pr_debug("vstep[%d][%d]\n", tfa->dev_idx, vstep); + + return err; +} + +static struct nxpTfaVolumeStepMessageInfo * +tfaContGetmsgInfoFromReg(struct nxpTfaVolumeStepRegisterInfo *regInfo) +{ + char *p = (char *)regInfo; + p += sizeof(regInfo->NrOfRegisters) + (regInfo->NrOfRegisters * sizeof(uint32_t)); + return (struct nxpTfaVolumeStepMessageInfo *) p; +} + +static int +tfaContGetmsgLen(struct nxpTfaVolumeStepMessageInfo *msgInfo) +{ + return (msgInfo->MessageLength.b[0] << 16) + + (msgInfo->MessageLength.b[1] << 8) + msgInfo->MessageLength.b[2]; +} + +static struct nxpTfaVolumeStepMessageInfo * +tfaContGetNextmsgInfo(struct nxpTfaVolumeStepMessageInfo *msgInfo) +{ + char *p = (char *)msgInfo; + int msgLen = tfaContGetmsgLen(msgInfo); + int type = msgInfo->MessageType; + + p += sizeof(msgInfo->MessageType) + sizeof(msgInfo->MessageLength); + if (type == 3) + p += msgLen; + else + p += msgLen * 3; + + return (struct nxpTfaVolumeStepMessageInfo *) p; +} + +static struct nxpTfaVolumeStepRegisterInfo* +tfaContGetNextRegFromEndInfo(struct nxpTfaVolumeStepMessageInfo *msgInfo) +{ + char *p = (char *)msgInfo; + p += sizeof(msgInfo->NrOfMessages); + return (struct nxpTfaVolumeStepRegisterInfo *) p; + +} + +static struct nxpTfaVolumeStepRegisterInfo* +tfaContGetRegForVstep(nxpTfaVolumeStepMax2File_t *vp, int idx) +{ + int i, j, nrMessage; + + struct nxpTfaVolumeStepRegisterInfo *regInfo + = (struct nxpTfaVolumeStepRegisterInfo *) vp->vstepsBin; + struct nxpTfaVolumeStepMessageInfo *msgInfo = NULL; + + for (i = 0; i < idx; i++) { + msgInfo = tfaContGetmsgInfoFromReg(regInfo); + nrMessage = msgInfo->NrOfMessages; + + for (j = 0; j < nrMessage; j++) { + msgInfo = tfaContGetNextmsgInfo(msgInfo); + } + regInfo = tfaContGetNextRegFromEndInfo(msgInfo); + } + + return regInfo; +} + +#pragma pack (push, 1) +struct tfa_partial_msg_block { + uint8_t offset; + uint16_t change; + uint8_t update[16][3]; +}; +#pragma pack (pop) + +static enum Tfa98xx_Error tfaContWriteVstepMax2_One(struct tfa_device *tfa, + struct nxpTfaVolumeStepMessageInfo *new_msg, + struct nxpTfaVolumeStepMessageInfo *old_msg, + int enable_partial_update) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int len = (tfaContGetmsgLen(new_msg) - 1) * 3; + char *buf = (char *)new_msg->ParameterData; + uint8_t *partial = NULL; + uint8_t cmdid[3]; + int use_partial_coeff = 0; + + if (enable_partial_update) { + if (new_msg->MessageType != old_msg->MessageType) { + pr_debug("Message type differ - Disable Partial Update\n"); + enable_partial_update = 0; + } else if (tfaContGetmsgLen(new_msg) != tfaContGetmsgLen(old_msg)) { + pr_debug("Message Length differ - Disable Partial Update\n"); + enable_partial_update = 0; + } + } + + if ((enable_partial_update) && (new_msg->MessageType == 1)) { + /* No patial updates for message type 1 (Coefficients) */ + enable_partial_update = 0; + if ((tfa->rev & 0xff) == 0x88) + use_partial_coeff = 1; + else if ((tfa->rev & 0xff) == 0x13) + use_partial_coeff = 1; + } + + /* Change Message Len to the actual buffer len */ + memcpy(cmdid, new_msg->CmdId, sizeof(cmdid)); + + /* The algoparams and mbdrc msg id will be changed to the reset type when SBSL=0 + * if SBSL=1 the msg will remain unchanged. It's up to the tuning engineer to choose the 'without_reset' + * types inside the vstep. In other words: the reset msg is applied during SBSL==0 else it remains unchanged. + */ + if (tfa_needs_reset(tfa) == 1) { + if (new_msg->MessageType == 0) { + cmdid[2] = SB_PARAM_SET_ALGO_PARAMS; + if (tfa->verbose) + pr_debug("P-ID for SetAlgoParams modified!\n"); + } else if (new_msg->MessageType == 2) { + cmdid[2] = SB_PARAM_SET_MBDRC; + if (tfa->verbose) + pr_debug("P-ID for SetMBDrc modified!\n"); + } + } + + /* + * +sizeof(struct tfa_partial_msg_block) will allow to fit one + * additonnal partial block If the partial update goes over the len of + * a regular message ,we can safely write our block and check afterward + * that we are over the size of a usual update + */ + if (enable_partial_update) { + partial = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (!partial) + pr_debug("Partial update memory error - Disabling\n"); + } + + if (partial) { + uint8_t offset = 0, i = 0; + uint16_t *change; + uint8_t *n = new_msg->ParameterData; + uint8_t *o = old_msg->ParameterData; + uint8_t *p = partial; + uint8_t *trim = partial; + + /* set dspFiltersReset */ + *p++ = 0x02; + *p++ = 0x00; + *p++ = 0x00; + + while ((o < (old_msg->ParameterData + len)) && + (p < (partial + len - 3))) { + if ((offset == 0xff) || + (memcmp(n, o, 3 * sizeof(uint8_t)))) { + *p++ = offset; + change = (uint16_t *)p; + *change = 0; + p += 2; + + for (i = 0; + (i < 16) && (o < (old_msg->ParameterData + len)); + i++, n += 3, o += 3) { + if (memcmp(n, o, 3 * sizeof(uint8_t))) { + *change |= BIT(i); + memcpy(p, n, 3); + p += 3; + trim = p; + } + } + + offset = 0; + *change = cpu_to_be16(*change); + } else { + n += 3; + o += 3; + offset++; + } + } + + if (trim == partial) { + pr_debug("No Change in message - discarding %d bytes\n", len); + len = 0; + + } else if (trim < (partial + len - 3)) { + pr_debug("Using partial update: %d -> %d bytes\n", len, (int)(trim - partial + 3)); + + /* Add the termination marker */ + memset(trim, 0x00, 3); + trim += 3; + + /* Signal This will be a partial update */ + cmdid[2] |= BIT(6); + buf = (char *)partial; + len = (int)(trim - partial); + } else { + pr_debug("Partial too big - use regular update\n"); + } + } + + if (use_partial_coeff) { + err = dsp_partial_coefficients(tfa, old_msg->ParameterData, new_msg->ParameterData); + } else if (len) { + uint8_t *buffer; + + if (tfa->verbose) + pr_debug("Command-ID used: 0x%02x%02x%02x \n", cmdid[0], cmdid[1], cmdid[2]); + + buffer = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (buffer == NULL) { + err = Tfa98xx_Error_Fail; + } else { + memcpy(&buffer[0], cmdid, 3); + memcpy(&buffer[3], buf, len); + err = dsp_msg(tfa, 3 + len, (char *)buffer); + kmem_cache_free(tfa->cachep, buffer); + } + } + + if (partial) + kmem_cache_free(tfa->cachep, partial); + + return err; +} + +static enum Tfa98xx_Error tfaContWriteVstepMax2(struct tfa_device *tfa, + nxpTfaVolumeStepMax2File_t *vp, int vstep_idx, + int vstep_msg_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + struct nxpTfaVolumeStepRegisterInfo *regInfo = NULL; + struct nxpTfaVolumeStepMessageInfo *msgInfo = NULL, *p_msgInfo = NULL; + nxpTfaBitfield_t bitF; + int i, nrMessages, enp = tfa->partial_enable; + + if (vstep_idx >= vp->NrOfVsteps) { + pr_debug("Volumestep %d is not available \n", vstep_idx); + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->p_regInfo == NULL) { + if (tfa->verbose) + pr_debug("Inital vstep write\n"); + enp = 0; + } + + regInfo = tfaContGetRegForVstep(vp, vstep_idx); + + msgInfo = tfaContGetmsgInfoFromReg(regInfo); + nrMessages = msgInfo->NrOfMessages; + + if (enp) { + p_msgInfo = tfaContGetmsgInfoFromReg(tfa->p_regInfo); + if (nrMessages != p_msgInfo->NrOfMessages) { + pr_debug("Message different - Disable partial update\n"); + enp = 0; + } + } + + for (i = 0; i < nrMessages; i++) { + /* Messagetype(3) is Smartstudio Info! Dont send this! */ + if (msgInfo->MessageType == 3) { + /* MessageLength is in bytes */ + msgInfo = tfaContGetNextmsgInfo(msgInfo); + if (enp) + p_msgInfo = tfaContGetNextmsgInfo(p_msgInfo); + continue; + } + + /* If no vstepMsgIndex is passed on, all message needs to be send */ + if ((vstep_msg_idx >= TFA_MAX_VSTEP_MSG_MARKER) || (vstep_msg_idx == i)) { + err = tfaContWriteVstepMax2_One(tfa, msgInfo, p_msgInfo, enp); + if (err != Tfa98xx_Error_Ok) { + /* + * Force a full update for the next write + * As the current status of the DSP is unknown + */ + tfa->p_regInfo = NULL; + return err; + } + } + + msgInfo = tfaContGetNextmsgInfo(msgInfo); + if (enp) + p_msgInfo = tfaContGetNextmsgInfo(p_msgInfo); + } + + tfa->p_regInfo = regInfo; + + for (i = 0; i < regInfo->NrOfRegisters * 2; i++) { + /* Byte swap the datasheetname */ + bitF.field = (uint16_t)(regInfo->registerInfo[i] >> 8) | (regInfo->registerInfo[i] << 8); + i++; + bitF.value = (uint16_t)regInfo->registerInfo[i] >> 8; + err = tfaRunWriteBitfield(tfa, bitF); + if (err != Tfa98xx_Error_Ok) + return err; + } + + /* Save the current vstep */ + tfa_dev_set_swvstep(tfa, (unsigned short)vstep_idx); + + return err; +} + +/* + * Write DRC message to the dsp + * If needed modify the cmd-id + */ + +enum Tfa98xx_Error tfaContWriteDrcFile(struct tfa_device *tfa, + int size, uint8_t data[]) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + uint8_t *msg = NULL; + + msg = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (msg == NULL) + return Tfa98xx_Error_Fail; + memcpy(msg, data, size); + + if (TFA_GET_BF(tfa, SBSL) == 0) { + /* Only do this when not set already */ + if (msg[2] != SB_PARAM_SET_MBDRC) { + msg[2] = SB_PARAM_SET_MBDRC; + + if (tfa->verbose) { + pr_debug("P-ID for SetMBDrc modified!: "); + pr_debug("Command-ID used: 0x%02x%02x%02x \n", + msg[0], msg[1], msg[2]); + } + } + } + + /* Send cmdId + payload to dsp */ + err = dsp_msg(tfa, size, (const char *)msg); + + kmem_cache_free(tfa->cachep, msg); + + return err; +} + + +/* + * write a parameter file to the device + * The VstepIndex and VstepMsgIndex are only used to write a specific msg from the vstep file. + */ +enum Tfa98xx_Error tfaContWriteFile(struct tfa_device *tfa, + nxpTfaFileDsc_t *file, int vstep_idx, int vstep_msg_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaHeader_t *hdr = (nxpTfaHeader_t *)file->data; + nxpTfaHeaderType_t type; + int size, i; + char subVerString[8] = { 0 }; + int subversion = 0; + + if (tfa->verbose) { + tfaContShowHeader(hdr); + } + + type = (nxpTfaHeaderType_t)hdr->id; + if ((type == msgHdr) || ((type == volstepHdr) && (tfa->tfa_family == 2))) { + subVerString[0] = hdr->subversion[0]; + subVerString[1] = hdr->subversion[1]; + subVerString[2] = '\0'; + + sscanf(subVerString, "%d", &subversion); + + if ((subversion > 0) && + (((hdr->customer[0]) == 'A') && ((hdr->customer[1]) == 'P') && + ((hdr->customer[2]) == 'I') && ((hdr->customer[3]) == 'V'))) { + if (tfa->is_probus_device) { + /* Temporary workaround (example: For climax --calibrate + * scenario for probus devices) + */ + err = tfaGetFwApiVersion(tfa, + (unsigned char *)&tfa->fw_itf_ver[0]); + if (err) { + pr_debug("[%s] cannot get FWAPI error = %d \n", + __FUNCTION__, err); + return err; + } + for (i = 0; i < 3; i++) { + //+4 to skip "?PIV" string part in the .msg file. + if (tfa->fw_itf_ver[i] != hdr->customer[i + 4]) { + ERRORMSG("Error: tfaContWriteFile: Expected FW API \ + version = %d.%d.%d, Msg File version: %d.%d.%d \n", + tfa->fw_itf_ver[0], + tfa->fw_itf_ver[1], + tfa->fw_itf_ver[2], + hdr->customer[4], + hdr->customer[5], + hdr->customer[6]); + return Tfa98xx_Error_Bad_Parameter; + } + } + } else if ((tfa->fw_itf_ver[2] != hdr->customer[4]) || + (tfa->fw_itf_ver[1] != hdr->customer[5]) || + ((tfa->fw_itf_ver[0] >> 6) & 0x03) != hdr->customer[6]) { + + ERRORMSG("Error: tfaContWriteFile: Expected FW API version = %d.%d.%d, Msg File version: %d.%d.%d \n", + (tfa->fw_itf_ver[2]) & 0xff, + (tfa->fw_itf_ver[1]) & 0xff, + (tfa->fw_itf_ver[0] >> 6) & 0x03, + hdr->customer[4], + hdr->customer[5], + hdr->customer[6]); + return Tfa98xx_Error_Bad_Parameter; + } + } + } + + switch (type) { + case msgHdr: /* generic DSP message */ + size = hdr->size - sizeof(nxpTfaMsgFile_t); + err = dsp_msg(tfa, size, (const char *)((nxpTfaMsgFile_t *)hdr)->data); + break; + case volstepHdr: + if (tfa->tfa_family == 2) { + err = tfaContWriteVstepMax2(tfa, + (nxpTfaVolumeStepMax2File_t *)hdr, + vstep_idx, vstep_msg_idx); + } else { + err = tfaContWriteVstep(tfa, (nxpTfaVolumeStep2File_t *)hdr, + vstep_idx); + } + break; + case speakerHdr: + if (tfa->tfa_family == 2) { + /* Remove header and xml_id */ + size = hdr->size - sizeof(struct nxpTfaSpkHeader) + - sizeof(struct nxpTfaFWVer); + + err = dsp_msg(tfa, size, + (const char *)(((nxpTfaSpeakerFile_t *)hdr)->data + + (sizeof(struct nxpTfaFWVer)))); + } else { + size = hdr->size - sizeof(nxpTfaSpeakerFile_t); + err = tfa98xx_dsp_write_speaker_parameters(tfa, size, + (const unsigned char *)((nxpTfaSpeakerFile_t *)hdr)->data); + } + break; + case presetHdr: + size = hdr->size - sizeof(nxpTfaPreset_t); + err = tfa98xx_dsp_write_preset(tfa, size, + (const unsigned char *)((nxpTfaPreset_t *)hdr)->data); + break; + case equalizerHdr: + err = tfa_cont_write_filterbank(tfa, ((nxpTfaEqualizerFile_t *)hdr)->filter); + break; + case patchHdr: + size = hdr->size - sizeof(nxpTfaPatch_t); // size is total length + err = tfa_dsp_patch(tfa, size, (const unsigned char *)((nxpTfaPatch_t *)hdr)->data); + break; + case configHdr: + size = hdr->size - sizeof(nxpTfaConfig_t); + err = tfa98xx_dsp_write_config(tfa, size, + (const unsigned char *)((nxpTfaConfig_t *)hdr)->data); + break; + case drcHdr: + if (hdr->version[0] == NXPTFA_DR3_VERSION) { + /* Size is total size - hdrsize(36) - xmlversion(3) */ + size = hdr->size - sizeof(nxpTfaDrc2_t); + err = tfaContWriteDrcFile(tfa, size, ((nxpTfaDrc2_t *)hdr)->data); + } else { + /* + * The DRC file is split as: + * 36 bytes for generic header (customer, application, and type) + * 127x3 (381) bytes first block contains the device and sample rate + * independent settings + * 127x3 (381) bytes block the device and sample rate specific values. + * The second block can always be recalculated from the first block, + * if vlsCal and the sample rate are known. + */ + //size = hdr->size - sizeof(nxpTfaDrc_t); + size = 381; /* fixed size for first block */ + + //+381 is done to only send the second part of the drc block + err = tfa98xx_dsp_write_drc(tfa, size, + ((const unsigned char *)((nxpTfaDrc_t *)hdr)->data + 381)); + } + break; + case infoHdr: + /* Ignore */ + break; + default: + pr_err("Header is of unknown type: 0x%x\n", type); + return Tfa98xx_Error_Bad_Parameter; + } + + return err; +} + +/** + * get the 1st of this dsc type this devicelist + */ +static nxpTfaDescPtr_t *tfa_cnt_get_dsc(nxpTfaContainer_t *cnt, nxpTfaDescriptorType_t type, int dev_idx) +{ + nxpTfaDeviceList_t *dev = tfaContDevice(cnt, dev_idx); + nxpTfaDescPtr_t *_this; + int i; + + if (!dev) { + return NULL; + } + /* process the list until a the type is encountered */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == (uint32_t)type) { + _this = (nxpTfaDescPtr_t *)(dev->list[i].offset + (uint8_t *)cnt); + return _this; + } + + } + + return NULL; +} + +/** + * get the device type from the patch in this devicelist + * - find the patch file for this devidx + * - return the devid from the patch or 0 if not found + */ +int tfa_cnt_get_devid(nxpTfaContainer_t *cnt, int dev_idx) +{ + nxpTfaPatch_t *patchfile; + nxpTfaDescPtr_t *patchdsc; + uint8_t *patchheader; + unsigned short devid, checkaddress; + int checkvalue; + + patchdsc = tfa_cnt_get_dsc(cnt, dscPatch, dev_idx); + if (!patchdsc) /* no patch for this device, assume non-i2c */ + return 0; + patchdsc += 2; /* first the filename dsc and filesize, so skip them */ + patchfile = (nxpTfaPatch_t *)patchdsc; + + patchheader = patchfile->data; + + checkaddress = (patchheader[1] << 8) + patchheader[2]; + checkvalue = + (patchheader[3] << 16) + (patchheader[4] << 8) + patchheader[5]; + + devid = patchheader[0]; + + if (checkaddress == 0xFFFF && checkvalue != 0xFFFFFF && checkvalue != 0) { + devid = patchheader[5] << 8 | patchheader[0]; /* full revid */ + } + + return devid; +} + +/** + * get the firmware version from the patch in this devicelist + */ +int tfa_cnt_get_patch_version(struct tfa_device *tfa) +{ + nxpTfaPatch_t *patchfile; + nxpTfaDescPtr_t *patchdsc; + uint8_t *data; + int size, version; + + if (tfa->cnt == NULL) + return ERR; + + patchdsc = tfa_cnt_get_dsc(tfa->cnt, dscPatch, tfa->dev_idx); + patchdsc += 2; /* first the filename dsc and filesize, so skip them */ + patchfile = (nxpTfaPatch_t *)patchdsc; + + size = patchfile->hdr.size - sizeof(nxpTfaPatch_t); + data = patchfile->data; + + version = (data[size - 3] << 16) + (data[size - 2] << 8) + data[size - 1]; + + return version; +} + + +/* + * get the slave for the device if it exists + */ +enum Tfa98xx_Error tfaContGetSlave(struct tfa_device *tfa, uint8_t *slave_addr) +{ + nxpTfaDeviceList_t *dev = NULL; + + /* Make sure the cnt file is loaded */ + if (tfa->cnt != NULL) { + dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + } + + if (dev == NULL) { + /* Check if slave argument is used! */ + if (gslave_address == 0) { + return Tfa98xx_Error_Bad_Parameter; + } else { + *slave_addr = gslave_address; + return Tfa98xx_Error_Ok; + } + } + + *slave_addr = dev->dev; + return Tfa98xx_Error_Ok; +} + +/* If no container file is given, we can always have used the slave argument */ +void tfaContSetSlave(uint8_t slave_addr) +{ + gslave_address = slave_addr; +} + +/* + * lookup slave and return device index + */ +int tfa_cont_get_idx(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev = NULL; + int i; + + for (i = 0; i < tfa->cnt->ndev; i++) { + dev = tfaContDevice(tfa->cnt, i); + if (dev->dev == tfa->slave_address) + break; + + } + if (i == tfa->cnt->ndev) + return ERR; + + return i; +} + +/* + * write a bit field + */ +enum Tfa98xx_Error tfaRunWriteBitfield(struct tfa_device *tfa, nxpTfaBitfield_t bf) +{ + enum Tfa98xx_Error error; + uint16_t value; + union { + uint16_t field; + nxpTfaBfEnum_t Enum; + } bfUni; + + value = bf.value; + bfUni.field = bf.field; +#ifdef TFA_DEBUG + if (tfa->verbose) + pr_debug("bitfield: %s=0x%x (0x%x[%d..%d]=0x%x)\n", tfaContBfName(bfUni.field, tfa->rev), value, + bfUni.Enum.address, bfUni.Enum.pos, bfUni.Enum.pos + bfUni.Enum.len, value); +#endif + error = tfa_set_bf(tfa, bfUni.field, value); + + return error; +} + +/* + * read a bit field + */ +enum Tfa98xx_Error tfaRunReadBitfield(struct tfa_device *tfa, nxpTfaBitfield_t *bf) +{ + enum Tfa98xx_Error error; + union { + uint16_t field; + nxpTfaBfEnum_t Enum; + } bfUni; + uint16_t regvalue, msk; + + bfUni.field = bf->field; + + error = reg_read(tfa, (unsigned char)(bfUni.Enum.address), ®value); + if (error) + return error; + + msk = ((1 << (bfUni.Enum.len + 1)) - 1) << bfUni.Enum.pos; + + regvalue &= msk; + bf->value = regvalue >> bfUni.Enum.pos; + + return error; +} + +/* + dsp mem direct write + */ +static enum Tfa98xx_Error tfaRunWriteDspMem(struct tfa_device *tfa, nxpTfaDspMem_t *cfmem) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int i; + + for (i = 0; i < cfmem->size; i++) { + if (tfa->verbose) + pr_debug("dsp mem (%d): 0x%02x=0x%04x\n", cfmem->type, cfmem->address, cfmem->words[i]); + + error = mem_write(tfa, cfmem->address++, cfmem->words[i], cfmem->type); + if (error) + return error; + } + + return error; +} + +/* + * write filter payload to DSP + * note that the data is in an aligned union for all filter variants + * the aa data is used but it's the same for all of them + */ +static enum Tfa98xx_Error tfaRunWriteFilter(struct tfa_device *tfa, nxpTfaContBiquad_t *bq) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + enum Tfa98xx_DMEM dmem; + uint16_t address; + uint8_t data[3 * 3 + sizeof(bq->aa.bytes)]; + int i, channel = 0, runs = 1; + int8_t saved_index = bq->aa.index; /* This is used to set back the index */ + + /* Channel=1 is primary, Channel=2 is secondary*/ + if (bq->aa.index > 100) { + bq->aa.index -= 100; + channel = 2; + } else if (bq->aa.index > 50) { + bq->aa.index -= 50; + channel = 1; + } else if ((tfa->rev & 0xff) == 0x88) { + runs = 2; + } + + if (tfa->verbose) { + if (channel == 2) + pr_debug("filter[%d,S]", bq->aa.index); + else if (channel == 1) + pr_debug("filter[%d,P]", bq->aa.index); + else + pr_debug("filter[%d]", bq->aa.index); + } + + for (i = 0; i < runs; i++) { + if (runs == 2) + channel++; + + /* get the target address for the filter on this device */ + dmem = tfa98xx_filter_mem(tfa, bq->aa.index, &address, channel); + if (dmem == Tfa98xx_DMEM_ERR) { + if (tfa->verbose) { + pr_debug("Warning: XFilter settings are applied via msg file (ini filter[x] format is skipped).\n"); + } + /* Dont exit with an error here, We could continue without problems */ + return Tfa98xx_Error_Ok; + } + + /* send a DSP memory message that targets the devices specific memory for the filter + * msg params: which_mem, start_offset, num_words + */ + memset(data, 0, 3 * 3); + data[2] = dmem; /* output[0] = which_mem */ + data[4] = address >> 8; /* output[1] = start_offset */ + data[5] = address & 0xff; + data[8] = sizeof(bq->aa.bytes) / 3; /*output[2] = num_words */ + memcpy(&data[9], bq->aa.bytes, sizeof(bq->aa.bytes)); /* payload */ + + if (tfa->tfa_family == 2) + error = tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, FW_PAR_ID_SET_MEMORY, sizeof(data), data); + else + error = tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, 4 /* param */, sizeof(data), data); + } + +#ifdef TFA_DEBUG + if (tfa->verbose) { + if (bq->aa.index == 13) { + pr_debug("=%d,%.0f,%.2f \n", + bq->in.type, bq->in.cutOffFreq, bq->in.leakage); + } else if (bq->aa.index >= 10 && bq->aa.index <= 12) { + pr_debug("=%d,%.0f,%.1f,%.1f \n", bq->aa.type, + bq->aa.cutOffFreq, bq->aa.rippleDb, bq->aa.rolloff); + } else { + pr_debug("= unsupported filter index \n"); + } + } +#endif + + /* Because we can load the same filters multiple times + * For example: When we switch profile we re-write in operating mode. + * We then need to remember the index (primary, secondary or both) + */ + bq->aa.index = saved_index; + + return error; +} + +/* + * write the register based on the input address, value and mask + * only the part that is masked will be updated + */ +static enum Tfa98xx_Error tfaRunWriteRegister(struct tfa_device *tfa, nxpTfaRegpatch_t *reg) +{ + enum Tfa98xx_Error error; + uint16_t value, newvalue; + + if (tfa->verbose) + pr_debug("register: 0x%02x=0x%04x (msk=0x%04x)\n", reg->address, reg->value, reg->mask); + + error = reg_read(tfa, reg->address, &value); + if (error) + return error; + + value &= ~reg->mask; + newvalue = reg->value & reg->mask; + + value |= newvalue; + error = reg_write(tfa, reg->address, value); + + return error; + +} + +// write reg and bitfield items in the devicelist to the target +enum Tfa98xx_Error tfaContWriteRegsDev(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + nxpTfaBitfield_t *bitF; + int i; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if (!dev) { + return Tfa98xx_Error_Bad_Parameter; + } + + /* process the list until a patch, file of profile is encountered */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscPatch || + dev->list[i].type == dscFile || + dev->list[i].type == dscProfile) + break; + + if (dev->list[i].type == dscBitfield) { + bitF = (nxpTfaBitfield_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt); + err = tfaRunWriteBitfield(tfa, *bitF); + } + if (dev->list[i].type == dscRegister) { + err = tfaRunWriteRegister(tfa, (nxpTfaRegpatch_t *)(dev->list[i].offset + (char *)tfa->cnt)); + } + + if (err) + break; + } + + return err; +} + +// write reg and bitfield items in the profilelist the target +enum Tfa98xx_Error tfaContWriteRegsProf(struct tfa_device *tfa, int prof_idx) +{ + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + nxpTfaBitfield_t *bitf; + unsigned int i; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if (!prof) { + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) + pr_debug("----- profile: %s (%d) -----\n", tfaContGetString(tfa->cnt, &prof->name), prof_idx); + + /* process the list until the end of the profile or the default section */ + for (i = 0; i < prof->length; i++) { + /* We only want to write the values before the default section when we switch profile */ + if (prof->list[i].type == dscDefault) + break; + + if (prof->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + err = tfaRunWriteBitfield(tfa, *bitf); + } + if (prof->list[i].type == dscRegister) { + err = tfaRunWriteRegister(tfa, (nxpTfaRegpatch_t *)(prof->list[i].offset + (char *)tfa->cnt)); + } + if (err) + break; + } + return err; +} + +// write patchfile in the devicelist to the target +enum Tfa98xx_Error tfaContWritePatch(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + nxpTfaFileDsc_t *file; + nxpTfaPatch_t *patchfile; + int size, i; + + if (!dev) { + return Tfa98xx_Error_Bad_Parameter; + } + /* process the list until a patch is encountered */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscPatch) { + file = (nxpTfaFileDsc_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt); + patchfile = (nxpTfaPatch_t *)&file->data; + if (tfa->verbose) + tfaContShowHeader(&patchfile->hdr); + size = patchfile->hdr.size - sizeof(nxpTfaPatch_t); // size is total length + err = tfa_dsp_patch(tfa, size, (const unsigned char *)patchfile->data); + if (err) + return err; + } + } + + return Tfa98xx_Error_Ok; +} + +/** + * Create a buffer which can be used to send to the dsp. + */ +static void create_dsp_buffer_msg(struct tfa_device *tfa, nxpTfaMsg_t *msg, char *buffer, int *size) +{ + int i, nr = 0; + + (void)tfa; + + /* Copy cmdId. Remember that the cmdId is reversed */ + buffer[nr++] = msg->cmdId[2]; + buffer[nr++] = msg->cmdId[1]; + buffer[nr++] = msg->cmdId[0]; + + /* Copy the data to the buffer */ + for (i = 0; i < msg->msg_size; i++) { + buffer[nr++] = (uint8_t)((msg->data[i] >> 16) & 0xffff); + buffer[nr++] = (uint8_t)((msg->data[i] >> 8) & 0xff); + buffer[nr++] = (uint8_t)(msg->data[i] & 0xff); + } + + *size = nr; +} + +// write all param files in the devicelist to the target +enum Tfa98xx_Error tfaContWriteFiles(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + nxpTfaFileDsc_t *file; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + char buffer[(MEMTRACK_MAX_WORDS * 3) + 3] = { 0 }; //every word requires 3 and 3 is the msg + int i, size = 0; + + if (!dev) { + return Tfa98xx_Error_Bad_Parameter; + } + /* process the list and write all files */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscFile) { + file = (nxpTfaFileDsc_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt); + if (tfaContWriteFile(tfa, file, 0, TFA_MAX_VSTEP_MSG_MARKER)) { + return Tfa98xx_Error_Bad_Parameter; + } + } + + if (dev->list[i].type == dscSetInputSelect || + dev->list[i].type == dscSetOutputSelect || + dev->list[i].type == dscSetProgramConfig || + dev->list[i].type == dscSetLagW || + dev->list[i].type == dscSetGains || + dev->list[i].type == dscSetvBatFactors || + dev->list[i].type == dscSetSensesCal || + dev->list[i].type == dscSetSensesDelay || + dev->list[i].type == dscSetMBDrc || + dev->list[i].type == dscSetFwkUseCase || + dev->list[i].type == dscSetVddpConfig) { + create_dsp_buffer_msg(tfa, (nxpTfaMsg_t *) + (dev->list[i].offset + (char *)tfa->cnt), buffer, &size); + if (tfa->verbose) { + pr_debug("command: %s=0x%02x%02x%02x \n", + tfaContGetCommandString(dev->list[i].type), + (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2]); + } + + err = dsp_msg(tfa, size, buffer); + } + + if (dev->list[i].type == dscCmd) { + size = *(uint16_t *)(dev->list[i].offset + (char *)tfa->cnt); + + err = dsp_msg(tfa, size, dev->list[i].offset + 2 + (char *)tfa->cnt); + if (tfa->verbose) { + const char *cmd_id = dev->list[i].offset + 2 + (char *)tfa->cnt; + pr_debug("Writing cmd=0x%02x%02x%02x \n", (uint8_t)cmd_id[0], (uint8_t)cmd_id[1], (uint8_t)cmd_id[2]); + } + } + if (err != Tfa98xx_Error_Ok) + break; + + if (dev->list[i].type == dscCfMem) { + err = tfaRunWriteDspMem(tfa, (nxpTfaDspMem_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt)); + } + + if (err != Tfa98xx_Error_Ok) + break; + } + + return err; +} + +/* + * write all param files in the profilelist to the target + * this is used during startup when maybe ACS is set + */ +enum Tfa98xx_Error tfaContWriteFilesProf(struct tfa_device *tfa, int prof_idx, int vstep_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + char buffer[(MEMTRACK_MAX_WORDS * 3) + 3] = { 0 }; //every word requires 3 and 3 is the msg + unsigned int i; + nxpTfaFileDsc_t *file; + nxpTfaPatch_t *patchfile; + int size; + + if (!prof) { + return Tfa98xx_Error_Bad_Parameter; + } + + /* process the list and write all files */ + for (i = 0; i < prof->length; i++) { + switch (prof->list[i].type) { + case dscFile: + file = (nxpTfaFileDsc_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + err = tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER); + break; + case dscPatch: + file = (nxpTfaFileDsc_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + patchfile = (nxpTfaPatch_t *)&file->data; + if (tfa->verbose) + tfaContShowHeader(&patchfile->hdr); + size = patchfile->hdr.size - sizeof(nxpTfaPatch_t); // size is total length + err = tfa_dsp_patch(tfa, size, (const unsigned char *)patchfile->data); + break; + case dscCfMem: + err = tfaRunWriteDspMem(tfa, (nxpTfaDspMem_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt)); + break; + case dscSetInputSelect: + case dscSetOutputSelect: + case dscSetProgramConfig: + case dscSetLagW: + case dscSetGains: + case dscSetvBatFactors: + case dscSetSensesCal: + case dscSetSensesDelay: + case dscSetMBDrc: + case dscSetFwkUseCase: + case dscSetVddpConfig: + create_dsp_buffer_msg(tfa, (nxpTfaMsg_t *) + (prof->list[i].offset + (uint8_t *)tfa->cnt), buffer, &size); + if (tfa->verbose) { + pr_debug("command: %s=0x%02x%02x%02x \n", + tfaContGetCommandString(prof->list[i].type), + (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2]); + } + + err = dsp_msg(tfa, size, buffer); + break; + default: + /* ignore any other type */ + break; + } + } + + return err; +} + +static enum Tfa98xx_Error tfaContWriteItem(struct tfa_device *tfa, nxpTfaDescPtr_t *dsc) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaRegpatch_t *reg; + nxpTfaMode_t *cas; + nxpTfaBitfield_t *bitf; + + // When no DSP should only write to HW registers. + if (tfa->ext_dsp == 0 && !(dsc->type == dscBitfield || dsc->type == dscRegister)) { + return Tfa98xx_Error_Ok; + } + + switch (dsc->type) { + case dscDefault: + case dscDevice: // ignore + case dscProfile: // profile list + break; + case dscRegister: // register patch + reg = (nxpTfaRegpatch_t *)(dsc->offset + (uint8_t *)tfa->cnt); + return tfaRunWriteRegister(tfa, reg); + //pr_debug("$0x%2x=0x%02x,0x%02x\n", reg->address, reg->mask, reg->value); + break; + case dscString: // ascii: zero terminated string + pr_debug(";string: %s\n", tfaContGetString(tfa->cnt, dsc)); + break; + case dscFile: // filename + file contents + case dscPatch: + break; + case dscMode: + cas = (nxpTfaMode_t *)(dsc->offset + (uint8_t *)tfa->cnt); + if (cas->value == Tfa98xx_Mode_RCV) + tfa98xx_select_mode(tfa, Tfa98xx_Mode_RCV); + else + tfa98xx_select_mode(tfa, Tfa98xx_Mode_Normal); + break; + case dscCfMem: + err = tfaRunWriteDspMem(tfa, (nxpTfaDspMem_t *)(dsc->offset + (uint8_t *)tfa->cnt)); + break; + case dscBitfield: + bitf = (nxpTfaBitfield_t *)(dsc->offset + (uint8_t *)tfa->cnt); + return tfaRunWriteBitfield(tfa, *bitf); + break; + case dscFilter: + return tfaRunWriteFilter(tfa, (nxpTfaContBiquad_t *)(dsc->offset + (uint8_t *)tfa->cnt)); + break; + } + + return err; +} + +static unsigned int tfa98xx_sr_from_field(unsigned int field) +{ + switch (field) { + case 0: + return 8000; + case 1: + return 11025; + case 2: + return 12000; + case 3: + return 16000; + case 4: + return 22050; + case 5: + return 24000; + case 6: + return 32000; + case 7: + return 44100; + case 8: + return 48000; + default: + return 0; + } +} + +enum Tfa98xx_Error tfa_write_filters(struct tfa_device *tfa, int prof_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + unsigned int i; + int status; + + if (!prof) { + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) { + pr_debug("----- profile: %s (%d) -----\n", tfaContGetString(tfa->cnt, &prof->name), prof_idx); + pr_debug("Waiting for CLKS... \n"); + } + + for (i = 10; i > 0; i--) { + err = tfa98xx_dsp_system_stable(tfa, &status); + if (status) + break; + else + msleep_interruptible(10); + } + + if (i == 0) { + if (tfa->verbose) + pr_err("Unable to write filters, CLKS=0 \n"); + + return Tfa98xx_Error_StateTimedOut; + } + + /* process the list until the end of the profile or the default section */ + for (i = 0; i < prof->length; i++) { + if (prof->list[i].type == dscFilter) { + if (tfaContWriteItem(tfa, &prof->list[i]) != Tfa98xx_Error_Ok) + return Tfa98xx_Error_Bad_Parameter; + } + } + + return err; +} + +unsigned int tfa98xx_get_profile_sr(struct tfa_device *tfa, unsigned int prof_idx) +{ + nxpTfaBitfield_t *bitf; + unsigned int i; + nxpTfaDeviceList_t *dev; + nxpTfaProfileList_t *prof; + int fs_profile = -1; + + dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + if (!dev) + return 0; + + prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + if (!prof) + return 0; + + /* Check profile fields first */ + for (i = 0; i < prof->length; i++) { + if (prof->list[i].type == dscDefault) + break; + + /* check for profile settingd (AUDFS) */ + if (prof->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + if (bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_profile = bitf->value; + break; + } + } + } + + if (tfa->verbose) + pr_debug("%s - profile fs: 0x%x = %dHz (%d - %d)\n", + __FUNCTION__, fs_profile, + tfa98xx_sr_from_field(fs_profile), + tfa->dev_idx, prof_idx); + + if (fs_profile != -1) + return tfa98xx_sr_from_field(fs_profile); + + /* Check for container default setting */ + /* process the list until a patch, file of profile is encountered */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscPatch || + dev->list[i].type == dscFile || + dev->list[i].type == dscProfile) + break; + + if (dev->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt); + if (bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_profile = bitf->value; + break; + } + } + /* Ignore register case */ + } + + if (tfa->verbose) + pr_debug("%s - default fs: 0x%x = %dHz (%d - %d)\n", + __FUNCTION__, fs_profile, + tfa98xx_sr_from_field(fs_profile), + tfa->dev_idx, prof_idx); + + if (fs_profile != -1) + return tfa98xx_sr_from_field(fs_profile); + + return 48000; /* default of HW */ +} + +static enum Tfa98xx_Error get_sample_rate_info(struct tfa_device *tfa, nxpTfaProfileList_t *prof, nxpTfaProfileList_t *previous_prof, int fs_previous_profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaBitfield_t *bitf; + unsigned int i; + int fs_default_profile = 8; /* default is 48kHz */ + int fs_next_profile = 8; /* default is 48kHz */ + + + /* ---------- default settings previous profile ---------- */ + for (i = 0; i < previous_prof->length; i++) { + /* Search for the default section */ + if (i == 0) { + while (previous_prof->list[i].type != dscDefault && i < previous_prof->length) { + i++; + } + i++; + } + + /* Only if we found the default section search for AUDFS */ + if (i < previous_prof->length) { + if (previous_prof->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(previous_prof->list[i].offset + (uint8_t *)tfa->cnt); + if (bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_default_profile = bitf->value; + break; + } + } + } + } + + /* ---------- settings next profile ---------- */ + for (i = 0; i < prof->length; i++) { + /* We only want to write the values before the default section */ + if (prof->list[i].type == dscDefault) + break; + /* search for AUDFS */ + if (prof->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + if (bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_next_profile = bitf->value; + break; + } + } + } + + /* Enable if needed for debugging! + if (tfa->verbose) { + pr_debug("sample rate from the previous profile: %d \n", fs_previous_profile); + pr_debug("sample rate in the default section: %d \n", fs_default_profile); + pr_debug("sample rate for the next profile: %d \n", fs_next_profile); + } + */ + + if (fs_next_profile != fs_default_profile) { + if (tfa->verbose) + pr_debug("Writing delay tables for AUDFS=%d \n", fs_next_profile); + + /* If the AUDFS from the next profile is not the same as + * the AUDFS from the default we need to write new delay tables + */ + err = tfa98xx_dsp_write_tables(tfa, fs_next_profile); + } else if (fs_default_profile != fs_previous_profile) { + if (tfa->verbose) + pr_debug("Writing delay tables for AUDFS=%d \n", fs_default_profile); + + /* But if we do not have a new AUDFS in the next profile and + * the AUDFS from the default profile is not the same as the AUDFS + * from the previous profile we also need to write new delay tables + */ + err = tfa98xx_dsp_write_tables(tfa, fs_default_profile); + } + + return err; +} + +/* + * process all items in the profilelist + * NOTE an error return during processing will leave the device muted + * + */ +enum Tfa98xx_Error tfaContWriteProfile(struct tfa_device *tfa, int prof_idx, int vstep_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + nxpTfaProfileList_t *previous_prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, tfa_dev_get_swprof(tfa)); + char buffer[(MEMTRACK_MAX_WORDS * 4) + 4] = { 0 }; //every word requires 3 or 4 bytes, and 3 or 4 is the msg + unsigned int i, k = 0, j = 0, tries = 0; + nxpTfaFileDsc_t *file; + int size = 0, ready, fs_previous_profile = 8; /* default fs is 48kHz*/ + + if (!prof || !previous_prof) { + pr_err("Error trying to get the (previous) swprofile \n"); + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) { + tfa98xx_trace_printk("device:%s profile:%s vstep:%d\n", tfaContDeviceName(tfa->cnt, tfa->dev_idx), + tfaContProfileName(tfa->cnt, tfa->dev_idx, prof_idx), vstep_idx); + } + + /* We only make a power cycle when the profiles are not in the same group */ + if (prof->group == previous_prof->group && prof->group != 0) { + if (tfa->verbose) { + pr_debug("The new profile (%s) is in the same group as the current profile (%s) \n", + tfaContGetString(tfa->cnt, &prof->name), tfaContGetString(tfa->cnt, &previous_prof->name)); + } + } else { + /* mute */ + err = tfaRunMute(tfa); + if (err) + return err; + + /* Get current sample rate before we start switching */ + fs_previous_profile = TFA_GET_BF(tfa, AUDFS); + + /* clear SBSL to make sure we stay in initCF state */ + if (tfa->tfa_family == 2) { + TFA_SET_BF_VOLATILE(tfa, SBSL, 0); + } + + /* When we switch profile we first power down the subsystem + * This should only be done when we are in operating mode + */ + if (((tfa->tfa_family == 2) && (TFA_GET_BF(tfa, MANSTATE) >= 6)) || (tfa->tfa_family != 2)) { + err = tfa98xx_powerdown(tfa, 1); + if (err) + return err; + + /* Wait until we are in PLL powerdown */ + do { + err = tfa98xx_dsp_system_stable(tfa, &ready); + if (!ready) + break; + else + msleep_interruptible(10); /* wait 10ms to avoid busload */ + tries++; + } while (tries <= 100); + + if (tries > 100) { + pr_debug("Wait for PLL powerdown timed out!\n"); + return Tfa98xx_Error_StateTimedOut; + } + } else { + pr_debug("No need to go to powerdown now \n"); + } + } + + /* set all bitfield settings */ + /* First set all default settings */ + if (tfa->verbose) { + pr_debug("---------- default settings profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &previous_prof->name), tfa_dev_get_swprof(tfa)); + } + + err = show_current_state(tfa); + + /* Loop profile length */ + for (i = 0; i < previous_prof->length; i++) { + /* Search for the default section */ + if (i == 0) { + while (previous_prof->list[i].type != dscDefault && i < previous_prof->length) { + i++; + } + i++; + } + + /* Only if we found the default section try writing the items */ + if (i < previous_prof->length) { + if (tfaContWriteItem(tfa, &previous_prof->list[i]) != Tfa98xx_Error_Ok) + return Tfa98xx_Error_Bad_Parameter; + } + } + + if (tfa->verbose) + pr_debug("---------- new settings profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &prof->name), prof_idx); + + /* set new settings */ + for (i = 0; i < prof->length; i++) { + /* Remember where we currently are with writing items*/ + j = i; + + /* We only want to write the values before the default section when we switch profile */ + /* process and write all non-file items */ + switch (prof->list[i].type) { + case dscFile: + case dscPatch: + case dscSetInputSelect: + case dscSetOutputSelect: + case dscSetProgramConfig: + case dscSetLagW: + case dscSetGains: + case dscSetvBatFactors: + case dscSetSensesCal: + case dscSetSensesDelay: + case dscSetMBDrc: + case dscSetFwkUseCase: + case dscSetVddpConfig: + case dscCmd: + case dscFilter: + case dscDefault: + /* When one of these files are found, we exit */ + i = prof->length; + break; + default: + err = tfaContWriteItem(tfa, &prof->list[i]); + if (err != Tfa98xx_Error_Ok) + return Tfa98xx_Error_Bad_Parameter; + break; + } + } + + if (prof->group != previous_prof->group || prof->group == 0) { + if (tfa->tfa_family == 2) + TFA_SET_BF_VOLATILE(tfa, MANSCONF, 1); + + /* Leave powerdown state */ + err = tfa_cf_powerup(tfa); + if (err) + return err; + + err = show_current_state(tfa); + + if (tfa->tfa_family == 2) { + /* Reset SBSL to 0 (workaround of enbl_powerswitch=0) */ + TFA_SET_BF_VOLATILE(tfa, SBSL, 0); + /* Sending commands to DSP we need to make sure RST is 0 (otherwise we get no response)*/ + TFA_SET_BF(tfa, RST, 0); + } + } + + /* Check if there are sample rate changes */ + err = get_sample_rate_info(tfa, prof, previous_prof, fs_previous_profile); + if (err) + return err; + + + /* Write files from previous profile (default section) + * Should only be used for the patch&trap patch (file) + */ + if (tfa->ext_dsp != 0) { + if (tfa->tfa_family == 2) { + for (i = 0; i < previous_prof->length; i++) { + /* Search for the default section */ + if (i == 0) { + while (previous_prof->list[i].type != dscDefault && i < previous_prof->length) { + i++; + } + i++; + } + + /* Only if we found the default section try writing the file */ + if (i < previous_prof->length) { + if (previous_prof->list[i].type == dscFile || previous_prof->list[i].type == dscPatch) { + /* Only write this once */ + if (tfa->verbose && k == 0) { + pr_debug("---------- files default profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &previous_prof->name), prof_idx); + k++; + } + file = (nxpTfaFileDsc_t *)(previous_prof->list[i].offset + (uint8_t *)tfa->cnt); + err = tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER); + } + } + } + } + + if (tfa->verbose) { + pr_debug("---------- files new profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &prof->name), prof_idx); + } + } + + /* write everything until end or the default section starts + * Start where we currenly left */ + for (i = j; i < prof->length; i++) { + /* We only want to write the values before the default section when we switch profile */ + + if (prof->list[i].type == dscDefault) { + break; + } + + switch (prof->list[i].type) { + case dscFile: + case dscPatch: + /* For tiberius stereo 1 device does not have a dsp! */ + if (tfa->ext_dsp != 0) { + file = (nxpTfaFileDsc_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + err = tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER); + } + break; + case dscSetInputSelect: + case dscSetOutputSelect: + case dscSetProgramConfig: + case dscSetLagW: + case dscSetGains: + case dscSetvBatFactors: + case dscSetSensesCal: + case dscSetSensesDelay: + case dscSetMBDrc: + case dscSetFwkUseCase: + case dscSetVddpConfig: + /* For tiberius stereo 1 device does not have a dsp! */ + if (tfa->ext_dsp != 0) { + create_dsp_buffer_msg(tfa, (nxpTfaMsg_t *) + (prof->list[i].offset + (char *)tfa->cnt), buffer, &size); + err = dsp_msg(tfa, size, buffer); + + if (tfa->verbose) { + pr_debug("command: %s=0x%02x%02x%02x \n", + tfaContGetCommandString(prof->list[i].type), + (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2]); + } + } + break; + case dscCmd: + /* For tiberius stereo 1 device does not have a dsp! */ + if (tfa->ext_dsp != 0) { + size = *(uint16_t *)(prof->list[i].offset + (char *)tfa->cnt); + err = dsp_msg(tfa, size, prof->list[i].offset + 2 + (char *)tfa->cnt); + if (tfa->verbose) { + const char *cmd_id = prof->list[i].offset + 2 + (char *)tfa->cnt; + pr_debug("Writing cmd=0x%02x%02x%02x \n", (uint8_t)cmd_id[0], (uint8_t)cmd_id[1], (uint8_t)cmd_id[2]); + } + } + break; + default: + /* This allows us to write bitfield, registers or xmem after files */ + if (tfaContWriteItem(tfa, &prof->list[i]) != Tfa98xx_Error_Ok) { + return Tfa98xx_Error_Bad_Parameter; + } + break; + } + + if (err != Tfa98xx_Error_Ok) { + return err; + } + } + + if ((prof->group != previous_prof->group || prof->group == 0) && (tfa->tfa_family == 2)) { + if (TFA_GET_BF(tfa, REFCKSEL) == 0) { + /* set SBSL to go to operation mode */ + TFA_SET_BF_VOLATILE(tfa, SBSL, 1); + } + } + + return err; +} + +/* + * process only vstep in the profilelist + * + */ +enum Tfa98xx_Error tfaContWriteFilesVstep(struct tfa_device *tfa, int prof_idx, int vstep_idx) +{ + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + unsigned int i; + nxpTfaFileDsc_t *file; + nxpTfaHeader_t *hdr; + nxpTfaHeaderType_t type; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if (!prof) + return Tfa98xx_Error_Bad_Parameter; + + if (tfa->verbose) + tfa98xx_trace_printk("device:%s profile:%s vstep:%d\n", tfaContDeviceName(tfa->cnt, tfa->dev_idx), + tfaContProfileName(tfa->cnt, tfa->dev_idx, prof_idx), vstep_idx); + + /* write vstep file only! */ + for (i = 0; i < prof->length; i++) { + if (prof->list[i].type == dscFile) { + file = (nxpTfaFileDsc_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + hdr = (nxpTfaHeader_t *)file->data; + type = (nxpTfaHeaderType_t)hdr->id; + + switch (type) { + case volstepHdr: + if (tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER)) + return Tfa98xx_Error_Bad_Parameter; + break; + default: + break; + } + } + } + + return err; +} + +char *tfaContGetString(nxpTfaContainer_t *cnt, nxpTfaDescPtr_t *dsc) +{ + if (dsc->type != dscString) + return "Undefined string"; + + return dsc->offset + (char *)cnt; +} + +char *tfaContGetCommandString(uint32_t type) +{ + if (type == dscSetInputSelect) + return "SetInputSelector"; + else if (type == dscSetOutputSelect) + return "SetOutputSelector"; + else if (type == dscSetProgramConfig) + return "SetProgramConfig"; + else if (type == dscSetLagW) + return "SetLagW"; + else if (type == dscSetGains) + return "SetGains"; + else if (type == dscSetvBatFactors) + return "SetvBatFactors"; + else if (type == dscSetSensesCal) + return "SetSensesCal"; + else if (type == dscSetSensesDelay) + return "SetSensesDelay"; + else if (type == dscSetMBDrc) + return "SetMBDrc"; + else if (type == dscSetFwkUseCase) + return "SetFwkUseCase"; + else if (type == dscSetVddpConfig) + return "SetVddpConfig"; + else if (type == dscFilter) + return "filter"; + else + return "Undefined string"; +} + +/* + * Get the name of the device at a certain index in the container file + * return device name + */ +char *tfaContDeviceName(nxpTfaContainer_t *cnt, int dev_idx) +{ + nxpTfaDeviceList_t *dev; + + dev = tfaContDevice(cnt, dev_idx); + if (dev == NULL) + return "!ERROR!"; + + return tfaContGetString(cnt, &dev->name); +} + +/* + * Get the application name from the container file application field + * note that the input stringbuffer should be sizeof(application field)+1 + * + */ +int tfa_cnt_get_app_name(struct tfa_device *tfa, char *name) +{ + unsigned int i; + int len = 0; + + for (i = 0; i < sizeof(tfa->cnt->application); i++) { + if (isalnum(tfa->cnt->application[i])) /* copy char if valid */ + name[len++] = tfa->cnt->application[i]; + if (tfa->cnt->application[i] == '\0') + break; + } + name[len++] = '\0'; + + return len; +} + +/* + * Get profile index of the calibration profile. + * Returns: (profile index) if found, (-2) if no + * calibration profile is found or (-1) on error + */ +int tfaContGetCalProfile(struct tfa_device *tfa) +{ + int prof, cal_idx = -2; + + if ((tfa->dev_idx < 0) || (tfa->dev_idx >= tfa->cnt->ndev)) + return ERR; + + /* search for the calibration profile in the list of profiles */ + for (prof = 0; prof < tfa->cnt->nprof; prof++) { + if (strstr(tfaContProfileName(tfa->cnt, + tfa->dev_idx, prof), ".cal") != NULL) { + cal_idx = prof; + pr_debug("Using calibration profile: '%s'\n", + tfaContProfileName(tfa->cnt, tfa->dev_idx, prof)); + break; + } + } + + return cal_idx; +} + +/** + * Is the profile a tap profile + */ +int tfaContIsTapProfile(struct tfa_device *tfa, int prof_idx) +{ + if ((tfa->dev_idx < 0) || (tfa->dev_idx >= tfa->cnt->ndev)) + return ERR; + + /* Check if next profile is tap profile */ + if (strstr(tfaContProfileName(tfa->cnt, + tfa->dev_idx, prof_idx), ".tap") != NULL) { + pr_debug("Using Tap profile: '%s'\n", + tfaContProfileName(tfa->cnt, tfa->dev_idx, prof_idx)); + return 1; + } + + return 0; +} + +/* + * Get the name of the profile at certain index for a device in the container + * file return profile name + */ +char *tfaContProfileName(nxpTfaContainer_t *cnt, int dev_idx, int prof_idx) +{ + nxpTfaProfileList_t *prof = NULL; + + /* the Nth profiles for this device */ + prof = tfaContGetDevProfList(cnt, dev_idx, prof_idx); + + /* If the index is out of bound */ + if (prof == NULL) + return "NONE"; + + return tfaContGetString(cnt, &prof->name); +} + +/* + * return 1st profile list + */ +nxpTfaProfileList_t *tfaContGet1stProfList(nxpTfaContainer_t *cont) +{ + nxpTfaProfileList_t *prof; + uint8_t *b = (uint8_t *)cont; + + int maxdev = 0; + nxpTfaDeviceList_t *dev; + + // get nr of devlists + maxdev = cont->ndev; + // get last devlist + dev = tfaContGetDevList(cont, maxdev - 1); + if (dev == NULL) + return NULL; + // the 1st profile starts after the last device list + b = (uint8_t *)dev + sizeof(nxpTfaDeviceList_t) + + dev->length * (sizeof(nxpTfaDescPtr_t)); + prof = (nxpTfaProfileList_t *)b; + return prof; +} + +/* + * return 1st livedata list + */ +nxpTfaLiveDataList_t *tfaContGet1stLiveDataList(nxpTfaContainer_t *cont) +{ + nxpTfaLiveDataList_t *ldata; + nxpTfaProfileList_t *prof; + nxpTfaDeviceList_t *dev; + uint8_t *b = (uint8_t *)cont; + int maxdev, maxprof; + + // get nr of devlists+1 + maxdev = cont->ndev; + // get nr of proflists + maxprof = cont->nprof; + + // get last devlist + dev = tfaContGetDevList(cont, maxdev - 1); + // the 1st livedata starts after the last device list + b = (uint8_t *)dev + sizeof(nxpTfaDeviceList_t) + + dev->length * (sizeof(nxpTfaDescPtr_t)); + + while (maxprof != 0) { + // get last proflist + prof = (nxpTfaProfileList_t *)b; + b += sizeof(nxpTfaProfileList_t) + + ((prof->length - 1) * (sizeof(nxpTfaDescPtr_t))); + maxprof--; + } + + /* Else the marker falls off */ + b += 4; //bytes + + ldata = (nxpTfaLiveDataList_t *)b; + return ldata; +} + +/* + * return the device list pointer + */ +nxpTfaDeviceList_t *tfaContDevice(nxpTfaContainer_t *cnt, int dev_idx) +{ + return tfaContGetDevList(cnt, dev_idx); +} + +/* + * return the next profile: + * - assume that all profiles are adjacent + * - calculate the total length of the input + * - the input profile + its length is the next profile + */ +nxpTfaProfileList_t *tfaContNextProfile(nxpTfaProfileList_t *prof) +{ + uint8_t *this, *next; /* byte pointers for byte pointer arithmetic */ + nxpTfaProfileList_t *nextprof; + int listlength; /* total length of list in bytes */ + + if (prof == NULL) + return NULL; + + if (prof->ID != TFA_PROFID) + return NULL; /* invalid input */ + + this = (uint8_t *)prof; + /* nr of items in the list, length includes name dsc so - 1*/ + listlength = (prof->length - 1) * sizeof(nxpTfaDescPtr_t); + /* the sizeof(nxpTfaProfileList_t) includes the list[0] length */ + next = this + listlength + + sizeof(nxpTfaProfileList_t);// - sizeof(nxpTfaDescPtr_t); + nextprof = (nxpTfaProfileList_t *)next; + + if (nextprof->ID != TFA_PROFID) + return NULL; + + return nextprof; +} + +/* + * return the next livedata + */ +nxpTfaLiveDataList_t *tfaContNextLiveData(nxpTfaLiveDataList_t *livedata) +{ + nxpTfaLiveDataList_t *nextlivedata = (nxpTfaLiveDataList_t *) + ((char *)livedata + (livedata->length * 4) + + sizeof(nxpTfaLiveDataList_t) - 4); + + if (nextlivedata->ID == TFA_LIVEDATAID) + return nextlivedata; + + return NULL; +} + +/* + * check CRC for container + * CRC is calculated over the bytes following the CRC field + * + * return non zero value on error + */ +int tfaContCrcCheckContainer(nxpTfaContainer_t *cont) +{ + uint8_t *base; + size_t size; + uint32_t crc; + // ptr to bytes following the CRC field + base = (uint8_t *)&cont->CRC + 4; + // nr of bytes following the CRC field + size = (size_t)(cont->size - (base - (uint8_t *)cont)); + crc = ~crc32_le(~0u, base, size); + + return crc != cont->CRC; +} + +static void get_all_features_from_cnt(struct tfa_device *tfa, + int *hw_feature_register, int sw_feature_register[2]) +{ + nxpTfaFeatures_t *features; + int i; + + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + + /* Init values in case no keyword is defined in cnt file: */ + *hw_feature_register = -1; + sw_feature_register[0] = -1; + sw_feature_register[1] = -1; + + if (dev == NULL) + return; + + // process the device list + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscFeatures) { + features = (nxpTfaFeatures_t *)(dev->list[i].offset + + (uint8_t *)tfa->cnt); + *hw_feature_register = features->value[0]; + sw_feature_register[0] = features->value[1]; + sw_feature_register[1] = features->value[2]; + break; + } + } +} + +/* wrapper function */ +void get_hw_features_from_cnt(struct tfa_device *tfa, int *hw_feature_register) +{ + int sw_feature_register[2]; + get_all_features_from_cnt(tfa, hw_feature_register, sw_feature_register); +} + +/* wrapper function */ +void get_sw_features_from_cnt(struct tfa_device *tfa, + int sw_feature_register[2]) +{ + int hw_feature_register; + get_all_features_from_cnt(tfa, &hw_feature_register, sw_feature_register); +} + +enum Tfa98xx_Error tfa98xx_factory_trimmer(struct tfa_device *tfa) +{ + return (tfa->dev_ops.factory_trimmer)(tfa); +} + +enum Tfa98xx_Error tfa_set_filters(struct tfa_device *tfa, int prof_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, + tfa->dev_idx, prof_idx); + unsigned int i; + + if (!prof) + return Tfa98xx_Error_Bad_Parameter; + + /* If we are in powerdown there is no need to set filters */ + if (TFA_GET_BF(tfa, PWDN) == 1) + return Tfa98xx_Error_Ok; + + /* loop the profile to find filter settings */ + for (i = 0; i < prof->length; i++) { + /* We only want to write the values before the default section */ + if (prof->list[i].type == dscDefault) + break; + + /* write all filter settings */ + if (prof->list[i].type == dscFilter) { + if (tfaContWriteItem(tfa, &prof->list[i]) != Tfa98xx_Error_Ok) + return err; + } + } + + return err; +} + +int tfa_tib_dsp_msgmulti(struct tfa_device *tfa, int length, + const char *buffer) +{ + uint8_t *buf = (uint8_t *)buffer; + static uint8_t *blob = NULL, *blobptr; /* TODO: not multi-thread safe */ + static int total; /* TODO: not multi-thread safe */ + int post_len = 0; + + /* checks for 24b_BE or 32_LE */ + int len_word_in_bytes = (tfa->convert_dsp32) ? 4 : 3; + /* + * TODO: get rid of these magic constants max size should depend + * on the tfa device type + */ + int tfadsp_max_msg_size = (tfa->convert_dsp32) ? 5336 : 4000; + + /* No data found*/ + if (length == -1 && blob == NULL) { + return ERR; + } + + if (length == -1) { + int i; + /* set last length field to zero */ + for (i = total; i < (total + len_word_in_bytes); i++) { + blob[i] = 0; + } + total += len_word_in_bytes; + memcpy(buf, blob, total); + + kfree(blob); + /* Set to NULL pointer, otherwise no new malloc is done! */ + blob = NULL; + return total; + } + + if (blob == NULL) { + if (tfa->verbose) + pr_debug("%s, Creating the multi-message \n\n", __FUNCTION__); + + blob = kmalloc(tfadsp_max_msg_size, GFP_KERNEL); + /* add command ID for multi-msg = 0x008015 */ + if (tfa->convert_dsp32) { + blob[0] = 0x15; + blob[1] = 0x80; + blob[2] = 0x0; + blob[3] = 0x0; + } else { + blob[0] = 0x0; + blob[1] = 0x80; + blob[2] = 0x15; + } + blobptr = blob; + blobptr += len_word_in_bytes; + total = len_word_in_bytes; + } + + if (tfa->verbose) { + pr_debug("%s, id:0x%02x%02x%02x, length:%d \n", __FUNCTION__, + buf[0], buf[1], buf[2], length); + } + + /* check total message size after concatination */ + post_len = total + length + (2 * len_word_in_bytes); + if (post_len > tfadsp_max_msg_size) { + /* pr_debug("New multi-message too large! (%d >= %d (max.)), + current length: %d\n", post_len, tfadsp_max_msg_size, total); */ + return Tfa98xx_Error_Buffer_too_small; + } + + /* add length field (length in words) to the multi message */ + if (tfa->convert_dsp32) { + *blobptr++ = (uint8_t)((length / len_word_in_bytes) & 0xff); /* lsb */ + *blobptr++ = (uint8_t)(((length / len_word_in_bytes) & 0xff00) >> 8); /* msb */ + *blobptr++ = 0x0; + *blobptr++ = 0x0; + } else { + *blobptr++ = 0x0; + /* msb */ + *blobptr++ = (uint8_t)(((length / len_word_in_bytes) & 0xff00) >> 8); + /* lsb */ + *blobptr++ = (uint8_t)((length / len_word_in_bytes) & 0xff); + } + memcpy(blobptr, buf, length); + blobptr += length; + total += (length + len_word_in_bytes); + + /* SetRe25 message is always the last message of the multi-msg */ + if (tfa->convert_dsp32) { + if (buf[1] == 0x81 && buf[0] == SB_PARAM_SET_RE25C) + return 1; /* 1 means last message is done! */ + } else { + if (buf[1] == 0x81 && buf[2] == SB_PARAM_SET_RE25C) + return 1; /* 1 means last message is done! */ + } + + return 0; +} diff --git a/sound/soc/codecs/tfa_container.h b/sound/soc/codecs/tfa_container.h new file mode 100644 index 0000000000000000000000000000000000000000..bc2286548d48f76948193756bdb97020ecc1f7df --- /dev/null +++ b/sound/soc/codecs/tfa_container.h @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFACONTAINER_H_ +#define TFACONTAINER_H_ + +/* static limits */ +#define TFACONT_MAXDEVS (4) /* maximum nr of devices */ +#define TFACONT_MAXPROFS (16) /* maximum nr of profiles */ + +#include "tfa98xx_parameters.h" + +/** +* Pass the container buffer, initialize and allocate internal memory. +* +* @param cnt pointer to the start of the buffer holding the container file +* @param length of the data in bytes +* @return +* - tfa_error_ok if normal +* - tfa_error_container invalid container data +* - tfa_error_bad_param invalid parameter +* +*/ +enum tfa_error tfa_load_cnt(void *cnt, int length); + +/** + * Return the descriptor string + * @param cnt pointer to the container struct + * @param dsc pointer to nxpTfa descriptor + * @return descriptor string + */ +char *tfaContGetString(nxpTfaContainer_t *cnt, nxpTfaDescPtr_t *dsc); + +/** + * Gets the string for the given command type number + * @param type number representing a command + * @return string of a command + */ +char *tfaContGetCommandString(uint32_t type); + +/** + * get the device type from the patch in this devicelist + * - find the patch file for this devidx + * - return the devid from the patch or 0 if not found + * @param cnt pointer to container file + * @param dev_idx device index + * @return descriptor string + */ +int tfa_cnt_get_devid(nxpTfaContainer_t *cnt, int dev_idx); + +/** + * Get the slave for the device if it exists. + * @param tfa the device struct pointer + * @param slave_addr the index of the device + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContGetSlave(struct tfa_device *tfa, uint8_t *slave_addr); + +void tfaContSetSlave(uint8_t slave_addr); + +/** + * Get the index for a skave address. + * @param tfa the device struct pointer + * @return the device index + */ +int tfa_cont_get_idx(struct tfa_device *tfa); + +/** + * Write reg and bitfield items in the devicelist to the target. + * @param tfa the device struct pointer + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteRegsDev(struct tfa_device *tfa); + +/** + * Write reg and bitfield items in the profilelist to the target. + * @param tfa the device struct pointer + * @param prof_idx the profile index + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteRegsProf(struct tfa_device *tfa, int prof_idx); + +/** + * Write a patchfile in the devicelist to the target. + * @param tfa the device struct pointer + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWritePatch(struct tfa_device *tfa); + +/** + * Write all param files in the devicelist to the target. + * @param tfa the device struct pointer + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteFiles(struct tfa_device *tfa); + +/** + * Get sample rate from passed profile index + * @param tfa the device struct pointer + * @param prof_idx the index of the profile + * @return sample rate value + */ +unsigned int tfa98xx_get_profile_sr(struct tfa_device *tfa, unsigned int prof_idx); + +/** + * Get the device name string + * @param cnt the pointer to the container struct + * @param dev_idx the index of the device + * @return device name string or error string if not found + */ +char *tfaContDeviceName(nxpTfaContainer_t *cnt, int dev_idx); + +/** + * Get the application name from the container file application field + * @param tfa the device struct pointer + * @param name the input stringbuffer with size: sizeof(application field)+1 + * @return actual string length + */ +int tfa_cnt_get_app_name(struct tfa_device *tfa, char *name); + +/** + * Get profile index of the calibration profile + * @param tfa the device struct pointer + * @return profile index, -2 if no calibration profile is found or -1 on error + */ +int tfaContGetCalProfile(struct tfa_device *tfa); + +/** + * Is the profile a tap profile ? + * @param tfa the device struct pointer + * @param prof_idx the index of the profile + * @return 1 if the profile is a tap profile or 0 if not + */ +int tfaContIsTapProfile(struct tfa_device *tfa, int prof_idx); + +/** + * Get the name of the profile at certain index for a device in the container file + * @param cnt the pointer to the container struct + * @param dev_idx the index of the device + * @param prof_idx the index of the profile + * @return profile name string or error string if not found + */ +char *tfaContProfileName(nxpTfaContainer_t *cnt, int dev_idx, int prof_idx); + +/** + * Process all items in the profilelist + * NOTE an error return during processing will leave the device muted + * @param tfa the device struct pointer + * @param prof_idx index of the profile + * @param vstep_idx index of the vstep + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteProfile(struct tfa_device *tfa, int prof_idx, int vstep_idx); + +/** + * Specify the speaker configurations (cmd id) (Left, right, both, none) + * @param dev_idx index of the device + * @param configuration name string of the configuration + */ +void tfa98xx_set_spkr_select(int dev_idx, char *configuration); + +enum Tfa98xx_Error tfa_cont_write_filterbank(struct tfa_device *tfa, nxpTfaFilter_t *filter); + +/** + * Write all param files in the profilelist to the target + * this is used during startup when maybe ACS is set + * @param tfa the device struct pointer + * @param prof_idx the index of the profile + * @param vstep_idx the index of the vstep + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteFilesProf(struct tfa_device *tfa, int prof_idx, int vstep_idx); +enum Tfa98xx_Error tfaContWriteFilesVstep(struct tfa_device *tfa, int prof_idx, int vstep_idx); +enum Tfa98xx_Error tfaContWriteDrcFile(struct tfa_device *tfa, int size, uint8_t data[]); + +/** + * Get the device list dsc from the tfaContainer + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @return device list pointer + */ +nxpTfaDeviceList_t *tfaContGetDevList(nxpTfaContainer_t *cont, int dev_idx); + +/** + * Get the Nth profile for the Nth device + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @param prof_idx the index of the profile + * @return profile list pointer + */ +nxpTfaProfileList_t *tfaContGetDevProfList(nxpTfaContainer_t *cont, int dev_idx, int prof_idx); + +/** + * Get the number of profiles for device from contaienr + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @return device list pointer + */ +int tfa_cnt_get_dev_nprof(struct tfa_device *tfa); + + +/** + * Get the Nth livedata for the Nth device + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @param livedata_idx the index of the livedata + * @return livedata list pointer + */ +nxpTfaLiveDataList_t *tfaContGetDevLiveDataList(nxpTfaContainer_t *cont, int dev_idx, int livedata_idx); + +/** + * Check CRC for container + * @param cont pointer to the tfaContainer + * @return error value 0 on error + */ +int tfaContCrcCheckContainer(nxpTfaContainer_t *cont); + +/** + * Get the device list pointer + * @param cnt pointer to the container struct + * @param dev_idx the index of the device + * @return pointer to device list + */ +nxpTfaDeviceList_t *tfaContDevice(nxpTfaContainer_t *cnt, int dev_idx); + +/** + * Return the pointer to the first profile in a list from the tfaContainer + * @param cont pointer to the tfaContainer + * @return pointer to first profile in profile list + */ +nxpTfaProfileList_t *tfaContGet1stProfList(nxpTfaContainer_t *cont); + +/** + * Return the pointer to the next profile in a list + * @param prof is the pointer to the profile list + * @return profile list pointer + */ +nxpTfaProfileList_t *tfaContNextProfile(nxpTfaProfileList_t *prof); + +/** + * Return the pointer to the first livedata in a list from the tfaContainer + * @param cont pointer to the tfaContainer + * @return pointer to first livedata in profile list + */ +nxpTfaLiveDataList_t *tfaContGet1stLiveDataList(nxpTfaContainer_t *cont); + +/** + * Return the pointer to the next livedata in a list + * @param livedata_idx is the pointer to the livedata list + * @return livedata list pointer + */ +nxpTfaLiveDataList_t *tfaContNextLiveData(nxpTfaLiveDataList_t *livedata_idx); + +/** + * Write a bit field + * @param tfa the device struct pointer + * @param bf bitfield to write + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaRunWriteBitfield(struct tfa_device *tfa, nxpTfaBitfield_t bf); + +/** + * Write a parameter file to the device + * @param tfa the device struct pointer + * @param file filedescriptor pointer + * @param vstep_idx index to vstep + * @param vstep_msg_idx index to vstep message + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteFile(struct tfa_device *tfa, nxpTfaFileDsc_t *file, int vstep_idx, int vstep_msg_idx); + +/** + * Get the max volume step associated with Nth profile for the Nth device + * @param tfa the device struct pointer + * @param prof_idx profile index + * @return the number of vsteps + */ +int tfacont_get_max_vstep(struct tfa_device *tfa, int prof_idx); + +/** + * Get the file contents associated with the device or profile + * Search within the device tree, if not found, search within the profile + * tree. There can only be one type of file within profile or device. + * @param tfa the device struct pointer + * @param prof_idx I2C profile index in the device + * @param type file type + * @return 0 NULL if file type is not found + * @return 1 file contents + */ +nxpTfaFileDsc_t *tfacont_getfiledata(struct tfa_device *tfa, int prof_idx, enum nxpTfaHeaderType type); + +/** + * Dump the contents of the file header + * @param hdr pointer to file header data + */ +void tfaContShowHeader(nxpTfaHeader_t *hdr); + +/** + * Read a bit field + * @param tfa the device struct pointer + * @param bf bitfield to read out + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaRunReadBitfield(struct tfa_device *tfa, nxpTfaBitfield_t *bf); + +/** + * Get hw feature bits from container file + * @param tfa the device struct pointer + * @param hw_feature_register pointer to where hw features are stored + */ +void get_hw_features_from_cnt(struct tfa_device *tfa, int *hw_feature_register); + +/** + * Get sw feature bits from container file + * @param tfa the device struct pointer + * @param sw_feature_register pointer to where sw features are stored + */ +void get_sw_features_from_cnt(struct tfa_device *tfa, int sw_feature_register[2]); + +/** + * Factory trimming for the Boost converter + * check if there is a correction needed + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfa98xx_factory_trimmer(struct tfa_device *tfa); + +/** + * Search for filters settings and if found then write them to the device + * @param tfa the device struct pointer + * @param prof_idx profile to look in + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfa_set_filters(struct tfa_device *tfa, int prof_idx); + +/** + * Get the firmware version from the patch in the container file + * @param tfa the device struct pointer + * @return firmware version + */ +int tfa_cnt_get_patch_version(struct tfa_device *tfa); + +int tfa_tib_dsp_msgmulti(struct tfa_device *tfa, int length, const char *buffer); + +#endif /* TFACONTAINER_H_ */ diff --git a/sound/soc/codecs/tfa_device.h b/sound/soc/codecs/tfa_device.h new file mode 100644 index 0000000000000000000000000000000000000000..18151d4142dac81372202b534287c9487c3c87dc --- /dev/null +++ b/sound/soc/codecs/tfa_device.h @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +/**\file + * + * The tfa_device interface controls a single I2C device instance by + * referencing to the device specific context provided by means of the + * tfa_device structure pointer. + * Multiple instances of tfa_device structures will be created and maintained + * by the caller. + * + * The API is functionally grouped as: + * - tfa_dev basic codec interface to probe, start/stop and control the device + * - state access to internal MTP storage + * - abstraction for interrupt bits and handling + * - container reading support + */ +#ifndef __TFA_DEVICE_H__ +#define __TFA_DEVICE_H__ + +#include "config.h" + +struct tfa_device; + +/* + * hw/sw feature bit settings in MTP + */ +enum featureSupport { + supportNotSet, /**< default means not set yet */ + supportNo, /**< no support */ + supportYes /**< supported */ +}; +/* + * supported Digital Audio Interfaces bitmap + */ +enum Tfa98xx_DAI { + Tfa98xx_DAI_I2S = 0x01, /**< I2S only */ + Tfa98xx_DAI_TDM = 0x02, /**< TDM, I2S */ + Tfa98xx_DAI_PDM = 0x04, /**< PDM */ +}; + +/* + * device ops function structure + */ +struct tfa_device_ops { + enum Tfa98xx_Error(*dsp_msg)(struct tfa_device *tfa, int length, + const char *buf); + enum Tfa98xx_Error(*dsp_msg_read)(struct tfa_device *tfa, int length, + unsigned char *bytes); + enum Tfa98xx_Error(*reg_read)(struct tfa_device *tfa, + unsigned char subaddress, unsigned short *value); + enum Tfa98xx_Error(*reg_write)(struct tfa_device *tfa, + unsigned char subaddress, unsigned short value); + enum Tfa98xx_Error(*mem_read)(struct tfa_device *tfa, + unsigned int start_offset, int num_words, int *pValues); + enum Tfa98xx_Error(*mem_write)(struct tfa_device *tfa, + unsigned short address, int value, int memtype); + + enum Tfa98xx_Error (*tfa_init)(struct tfa_device *tfa); /**< init typically for loading optimal settings */ + enum Tfa98xx_Error (*dsp_reset)(struct tfa_device *tfa, int state); /**< reset the coolflux dsp */ + enum Tfa98xx_Error (*dsp_system_stable)(struct tfa_device *tfa, int *ready); /**< ready when clocks are stable to allow DSP subsystem access */ + enum Tfa98xx_Error (*dsp_write_tables)(struct tfa_device *tfa, int sample_rate); /**< write the device/type specific delaytables */ + enum Tfa98xx_Error (*auto_copy_mtp_to_iic)(struct tfa_device *tfa); /**< Set auto_copy_mtp_to_iic */ + enum Tfa98xx_Error (*factory_trimmer)(struct tfa_device *tfa); /**< Factory trimming for the Boost converter */ + int (*set_swprof)(struct tfa_device *tfa, unsigned short new_value); /**< Set the sw profile in the struct and the hw register */ + int (*get_swprof)(struct tfa_device *tfa); /**< Get the sw profile from the hw register */ + int(*set_swvstep)(struct tfa_device *tfa, unsigned short new_value); /**< Set the sw vstep in the struct and the hw register */ + int(*get_swvstep)(struct tfa_device *tfa); /**< Get the sw vstep from the hw register */ + int(*get_mtpb)(struct tfa_device *tfa); /**< get status of MTB busy bit*/ + enum Tfa98xx_Error (*set_mute)(struct tfa_device *tfa, int mute); /**< set mute */ + enum Tfa98xx_Error (*faim_protect)(struct tfa_device *tfa, int state); /**< Protect FAIM from being corrupted */ + enum Tfa98xx_Error(*set_osc_powerdown)(struct tfa_device *tfa, int state); /**< Allow to change internal osc. gating settings */ + enum Tfa98xx_Error(*update_lpm)(struct tfa_device *tfa, int state); /**< Allow to change lowpowermode settings */ +}; + +/** + * Device states and modifier flags to allow a device/type independent fine + * grained control of the internal state.\n + * Values below 0x10 are referred to as base states which can be or-ed with + * state modifiers, from 0x10 and higher. + * + */ +enum tfa_state { + TFA_STATE_UNKNOWN, /**< unknown or invalid */ + TFA_STATE_POWERDOWN, /**< PLL in powerdown, Algo is up/warm */ + TFA_STATE_INIT_HW, /**< load I2C/PLL hardware setting (~wait2srcsettings) */ + TFA_STATE_INIT_CF, /**< coolflux HW access possible (~initcf) */ + TFA_STATE_INIT_FW, /**< DSP framework active (~patch loaded) */ + TFA_STATE_OPERATING, /**< Amp and Algo running */ + TFA_STATE_FAULT, /**< An alarm or error occurred */ + TFA_STATE_RESET, /**< I2C reset and ACS set */ + /* --sticky state modifiers-- */ + TFA_STATE_MUTE = 0x10, /**< Algo & Amp mute */ + TFA_STATE_UNMUTE = 0x20, /**< Algo & Amp unmute */ + TFA_STATE_CLOCK_ALWAYS = 0x40, /**< PLL connect to internal oscillator */ + TFA_STATE_CLOCK_AUDIO = 0x80, /**< PLL connect to audio clock (BCK/FS) */ + TFA_STATE_LOW_POWER = 0x100, /**< lowest possible power state */ +}; + +/** + * This is the main tfa device context structure, it will carry all information + * that is needed to handle a single I2C device instance. + * All functions dealing with the device will need access to the fields herein. + */ +struct tfa_device { + int dev_idx; /**< device container index */ + int in_use; + int buffer_size; /**< lowest level max buffer size */ + int has_msg; /**< support direct dsp messaging */ + unsigned char slave_address; /**< I2C slave address (not shifted) */ + unsigned short rev; /**< full revid of this device */ + unsigned char tfa_family; /**< tfa1/tfa2 */ + enum featureSupport supportDrc; + enum featureSupport supportFramework; + enum featureSupport support_saam; + int sw_feature_bits[2]; /**< cached copy of sw feature bits */ + int hw_feature_bits; /**< cached copy of hw feature bits */ + int profile; /**< active profile */ + int vstep; /**< active vstep */ + unsigned char spkr_count; + unsigned char spkr_select; + unsigned char support_tcoef;/**< legacy tfa9887, will be removed */ + enum Tfa98xx_DAI daimap; /**< supported audio interface types */ + int mohm[3]; /**< speaker calibration values in milli ohms -1 is error */ + struct tfa_device_ops dev_ops; + uint16_t interrupt_enable[3]; + uint16_t interrupt_status[3]; + int ext_dsp; /**< respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ + int bus; /* TODO fix ext_dsp and bus handling */ + int tfadsp_event; /**< enum tfadsp_event_en is for external registry */ + int verbose; /**< verbosity level for debug print output */ + enum tfa_state state; /**< last known state or-ed with optional state_modifier */ + struct nxpTfaContainer *cnt;/**< the loaded container file */ + struct nxpTfaVolumeStepRegisterInfo *p_regInfo; /**< remember vstep for partial updates */ + int partial_enable; /**< enable partial updates */ + void *data; /**< typically pointing to Linux driver structure owning this device */ + int convert_dsp32; /**< convert 24 bit DSP messages to 32 bit */ + int sync_iv_delay; /**< synchronize I/V delay at cold start */ + int is_probus_device; /**< probus device: device without internal DSP */ + int advance_keys_handling; + int needs_reset; /**< add the reset trigger for SetAlgoParams and SetMBDrc commands */ + struct kmem_cache *cachep; /**< Memory allocator handle */ + char fw_itf_ver[4]; /* Firmware ITF version */ +}; + +/** + * The tfa_dev_probe is called before accessing any device accessing functions. + * Access to the tfa device register 3 is attempted and will record the + * returned id for further use. If no device responds the function will abort. + * The recorded id will by used by the query functions to fill the remaining + * relevant data fields of the device structure. + * Data such as MTP features that requires device access will only be read when + * explicitly called and the result will be then cached in the struct. + * + * A structure pointer passed to this device needs to refer to existing memory + * space allocated by the caller. + * + * @param slave = I2C slave address of the target device (not shifted) + * @param tfa struct = points to memory that holds the context for this device + * instance + * + * @return + * - 0 if the I2C device responded to a read of register address 3\n + * when the device responds but with an unknown id a warning will be printed + * - -1 if no response from the I2C device + * + */ +int tfa_dev_probe(int slave, struct tfa_device *tfa); + +/** + * Start this instance at the profile and vstep as provided. + * The profile and vstep will be loaded first in case the current value differs + * from the requested values. + * Note that this call will not change the mute state of the tfa, which means + * that of this instance was called in muted state the caller will have to + * unmute in order to get audio. + * + * @param tfa struct = pointer to context of this device instance + * @param profile the selected profile to run + * @param vstep the selected vstep to use + * @return tfa_error enum + */ +enum tfa_error tfa_dev_start(struct tfa_device *tfa, int profile, int vstep); + + +/** + * Stop audio for this instance as gracefully as possible. + * Audio will be muted and the PLL will be shutdown together with any other + * device/type specific settings needed to prevent audio artifacts or + * workarounds. + * + * Note that this call will change state of the tfa to mute and powered down. + * + * @param tfa struct = pointer to context of this device instance + * @return tfa_error enum + */ +enum tfa_error tfa_dev_stop(struct tfa_device *tfa); + +/** + * This interface allows a device/type independent fine grained control of the + * internal state of the instance. + * Whenever a base state is requested an attempt is made to actively bring the device + * into this state. However this may depend on external conditions beyond control of + * this software layer. Therefore in case the state cannot be set an erro will + * be returned and the current state remains unchanged. + * The base states, lower values below 0x10, are all mutually exclusive, they higher ones + * can also function as a sticky modifier which means for example that operating + * state could be in either muted or unmuted state. Or in case of init_cf it can be + * internal clock (always) or external audio clock. + * This function is intended to be used for device mute/unmute synchronization + * when called from higher layers. Mostly internal calls will use this to control + * the startup and profile transitions in a device/type independent way. + * + * @param tfa struct = pointer to context of this device instance + * @param state struct = desired device state after function return + * @return tfa_error enum + */ +enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state, + int is_calibration); + +/** + * Retrieve the current state of this instance in an active way. + * The state field in tfa structure will reflect the result unless an error is + * returned. + * Note that the hardware state may change on external events an as such this + * field should be treated as volatile. + * + * @param tfa struct = pointer to context of this device instance + * @return tfa_error enum + * + */ +enum tfa_state tfa_dev_get_state(struct tfa_device *tfa); + + +/*****************************************************************************/ +/*****************************************************************************/ +/** + * MTP support functions + */ +enum tfa_mtp { + TFA_MTP_OTC, /**< */ + TFA_MTP_EX, /**< */ + TFA_MTP_RE25, /**< */ + TFA_MTP_RE25_PRIM, /**< */ + TFA_MTP_RE25_SEC, /**< */ + TFA_MTP_LOCK, /**< */ +}; + +/** + * + */ +int tfa_dev_mtp_get(struct tfa_device *tfa, enum tfa_mtp item); + +/** + * + */ +enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value); + + +//irq +/* tfa2 interrupt support + * !!! enum tfa9912_irq !!!*/ +/* + * interrupt bit function to clear + */ +int tfa_irq_clear(struct tfa_device *tfa, int bit); +/* + * return state of irq or -1 if illegal bit + */ +int tfa_irq_get(struct tfa_device *tfa, int bit); +/* + * interrupt bit function that operates on the shadow regs in the handle + */ +int tfa_irq_ena(struct tfa_device *tfa, int bit, int state); +/* + * interrupt bit function that sets the polarity + */ +int tfa_irq_set_pol(struct tfa_device *tfa, int bit, int state); + +/* + * mask interrupts by disabling them + */ +int tfa_irq_mask(struct tfa_device *tfa); +/* + * unmask interrupts by enabling them again + */ +int tfa_irq_unmask(struct tfa_device *tfa); +//cnt read +//debug? + +#endif /* __TFA_DEVICE_H__ */ + diff --git a/sound/soc/codecs/tfa_dsp.c b/sound/soc/codecs/tfa_dsp.c new file mode 100644 index 0000000000000000000000000000000000000000..9530d35695bedd308d08e45d9cb7de5d1209e967 --- /dev/null +++ b/sound/soc/codecs/tfa_dsp.c @@ -0,0 +1,4142 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#include "dbgprint.h" +#include "tfa_container.h" +#include "tfa.h" +#include "tfa98xx_tfafieldnames.h" +#include "tfa_internal.h" + + /* handle macro for bitfield */ +#define TFA_MK_BF(reg, pos, len) ((reg<<8)|(pos<<4)|(len-1)) + +/* abstract family for register */ +#define FAM_TFA98XX_CF_CONTROLS (TFA_FAM(tfa, RST) >> 8) +#define FAM_TFA98XX_CF_MEM (TFA_FAM(tfa, MEMA) >> 8) +#define FAM_TFA98XX_MTP0 (TFA_FAM(tfa, MTPOTC) >> 8) +#define FAM_TFA98xx_INT_EN (TFA_FAM(tfa, INTENVDDS) >> 8) + +#define CF_STATUS_I2C_CMD_ACK 0x01 + +/* Defines below are used for irq function (this removed the genregs include) */ +#define TFA98XX_INTERRUPT_ENABLE_REG1 0x48 +#define TFA98XX_INTERRUPT_IN_REG1 0x44 +#define TFA98XX_INTERRUPT_OUT_REG1 0x40 +#define TFA98XX_STATUS_POLARITY_REG1 0x4c +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK 0x2 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK 0x1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_POS 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_POS 0 +#define ERR -1 + +void tfanone_ops(struct tfa_device_ops *ops); +void tfa9872_ops(struct tfa_device_ops *ops); +void tfa9874_ops(struct tfa_device_ops *ops); +void tfa9878_ops(struct tfa_device_ops *ops); +void tfa9912_ops(struct tfa_device_ops *ops); +void tfa9888_ops(struct tfa_device_ops *ops); +void tfa9891_ops(struct tfa_device_ops *ops); +void tfa9897_ops(struct tfa_device_ops *ops); +void tfa9896_ops(struct tfa_device_ops *ops); +void tfa9890_ops(struct tfa_device_ops *ops); +void tfa9895_ops(struct tfa_device_ops *ops); +void tfa9894_ops(struct tfa_device_ops *ops); + +#ifndef MIN +#define MIN(A, B) (A < B?A:B) +#endif + +/* retry values */ +#define CFSTABLE_TRIES 10 +#define AMPOFFWAIT_TRIES 50 +#define MTPBWAIT_TRIES 50 +#define MTPEX_WAIT_NTRIES 50 + +/* calibration done executed */ +#define TFA_MTPEX_POS TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_POS /**/ + +int tfa_get_calibration_info(struct tfa_device *tfa, int channel) +{ + return tfa->mohm[channel]; +} + +/* return sign extended tap pattern */ +int tfa_get_tap_pattern(struct tfa_device *tfa) +{ + int value = tfa_get_bf(tfa, TFA9912_BF_CFTAPPAT); + int bitshift; + /* length of bitfield */ + uint8_t field_len = 1 + (TFA9912_BF_CFTAPPAT & 0x0f); + + bitshift = 8 * sizeof(int) - field_len; + /* signextend */ + value = (value << bitshift) >> bitshift; + + return value; +} +/* + * interrupt bit function to clear + */ +int tfa_irq_clear(struct tfa_device *tfa, enum tfa9912_irq bit) +{ + unsigned char reg; + + /* make bitfield enum */ + if (bit == tfa9912_irq_all) { + /* operate on all bits */ + for (reg = TFA98XX_INTERRUPT_IN_REG1; + reg < TFA98XX_INTERRUPT_IN_REG1 + 3; reg++) + reg_write(tfa, reg, 0xffff); /* all bits */ + } else if (bit < tfa9912_irq_max) { + reg = (unsigned char)(TFA98XX_INTERRUPT_IN_REG1 + (bit >> 4)); + reg_write(tfa, reg, 1 << (bit & 0x0f)); /* only this bit */ + } else + return ERR; + + return 0; +} +/* + * return state of irq or -1 if illegal bit + */ +int tfa_irq_get(struct tfa_device *tfa, enum tfa9912_irq bit) +{ + uint16_t value; + int reg, mask; + + if (bit < tfa9912_irq_max) { + /* only this bit */ + reg = TFA98XX_INTERRUPT_OUT_REG1 + (bit >> 4); + mask = 1 << (bit & 0x0f); + reg_read(tfa, (unsigned char)reg, &value); + } else + return ERR; + + return (value & mask) != 0; +} +/* + * interrupt bit function that operates on the shadow regs in the handle + */ + +int tfa_irq_ena(struct tfa_device *tfa, enum tfa9912_irq bit, int state) +{ + uint16_t value, new_value; + int reg = 0, mask; + /* */ + if (bit == tfa9912_irq_all) { + /* operate on all bits */ + for (reg = TFA98XX_INTERRUPT_ENABLE_REG1; reg <= + TFA98XX_INTERRUPT_ENABLE_REG1 + tfa9912_irq_max / 16; reg++) { + /* all bits */ + reg_write(tfa, (unsigned char)reg, state ? 0xffff : 0); + tfa->interrupt_enable[reg - TFA98XX_INTERRUPT_ENABLE_REG1] + = state ? 0xffff : 0; /* all bits */ + } + } else if (bit < tfa9912_irq_max) { + /* only this bit */ + reg = TFA98XX_INTERRUPT_ENABLE_REG1 + (bit >> 4); + mask = 1 << (bit & 0x0f); + reg_read(tfa, (unsigned char)reg, &value); + if (state) //set + new_value = (uint16_t)(value | mask); + else // clear + new_value = value & ~mask; + if (new_value != value) { + reg_write(tfa, (unsigned char)reg, new_value); /* only this bit */ + tfa->interrupt_enable[reg - TFA98XX_INTERRUPT_ENABLE_REG1] + = new_value; + } + } else + return ERR; + + return 0; +} + +/* + * mask interrupts by disabling them + */ +int tfa_irq_mask(struct tfa_device *tfa) +{ + int reg; + + /* operate on all bits */ + for (reg = TFA98XX_INTERRUPT_ENABLE_REG1; reg <= + TFA98XX_INTERRUPT_ENABLE_REG1 + tfa9912_irq_max / 16; reg++) + reg_write(tfa, (unsigned char)reg, 0); + + return 0; +} + +/* + * unmask interrupts by enabling them again + */ +int tfa_irq_unmask(struct tfa_device *tfa) +{ + int reg; + + /* operate on all bits */ + for (reg = TFA98XX_INTERRUPT_ENABLE_REG1; reg <= + TFA98XX_INTERRUPT_ENABLE_REG1 + tfa9912_irq_max / 16; reg++) + reg_write(tfa, (unsigned char)reg, + tfa->interrupt_enable[reg - TFA98XX_INTERRUPT_ENABLE_REG1]); + + return 0; +} + +/* + * interrupt bit function that sets the polarity + */ + +int tfa_irq_set_pol(struct tfa_device *tfa, enum tfa9912_irq bit, int state) +{ + uint16_t value, new_value; + int reg = 0, mask; + + if (bit == tfa9912_irq_all) { + /* operate on all bits */ + for (reg = TFA98XX_STATUS_POLARITY_REG1; reg <= + TFA98XX_STATUS_POLARITY_REG1 + tfa9912_irq_max / 16; reg++) { + /* all bits */ + reg_write(tfa, (unsigned char)reg, state ? 0xffff : 0); + } + } else if (bit < tfa9912_irq_max) { + /* only this bit */ + reg = TFA98XX_STATUS_POLARITY_REG1 + (bit >> 4); + mask = 1 << (bit & 0x0f); + reg_read(tfa, (unsigned char)reg, &value); + if (state) /* Active High */ + new_value = (uint16_t)(value | mask); + else /* Active Low */ + new_value = value & ~mask; + if (new_value != value) { + reg_write(tfa, (unsigned char)reg, new_value); /* only this bit */ + } + } else + return ERR; + + return 0; +} + +/* + * set device info and register device ops + */ +void tfa_set_query_info(struct tfa_device *tfa) +{ + /* invalidate device struct cached values */ + tfa->hw_feature_bits = -1; + tfa->sw_feature_bits[0] = -1; + tfa->sw_feature_bits[1] = -1; + tfa->profile = -1; + tfa->vstep = -1; + /* defaults */ + tfa->is_probus_device = 0; + tfa->advance_keys_handling = 0; /*artf65038*/ + tfa->tfa_family = 1; + tfa->daimap = Tfa98xx_DAI_I2S; /* all others */ + tfa->spkr_count = 1; + tfa->spkr_select = 0; + tfa->support_tcoef = supportYes; + tfa->supportDrc = supportNotSet; + tfa->support_saam = supportNotSet; + /* respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ + tfa->ext_dsp = -1; + tfa->bus = 0; + tfa->partial_enable = 0; + tfa->convert_dsp32 = 0; + tfa->sync_iv_delay = 0; + + /* TODO use the getfeatures() for retrieving the features [artf103523] + tfa->supportDrc = supportNotSet;*/ + + switch (tfa->rev & 0xff) { + case 0: /* tfanone : non-i2c external DSP device */ + /* e.g. qc adsp */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 0; + tfa->spkr_count = 0; + tfa->daimap = 0; + tfanone_ops(&tfa->dev_ops); /* register device operations via tfa hal*/ + tfa->bus = 1; + break; + case 0x72: + /* tfa9872 */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->is_probus_device = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9872_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x74: + /* tfa9874 */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->is_probus_device = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9874_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x78: + /* tfa9878 */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->is_probus_device = 1; + tfa->advance_keys_handling = 1; /*artf65038*/ + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9878_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x88: + /* tfa9888 */ + tfa->tfa_family = 2; + tfa->spkr_count = 2; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9888_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x97: + /* tfa9897 */ + tfa->supportDrc = supportNo; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9897_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x96: + /* tfa9896 */ + tfa->supportDrc = supportNo; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9896_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x92: + /* tfa9891 */ + tfa->spkr_count = 1; + tfa->daimap = (Tfa98xx_DAI_PDM | Tfa98xx_DAI_I2S); + tfa9891_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x91: + /* tfa9890B */ + tfa->spkr_count = 1; + tfa->daimap = (Tfa98xx_DAI_PDM | Tfa98xx_DAI_I2S); + break; + case 0x80: + case 0x81: + /* tfa9890 */ + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_I2S; + tfa->supportDrc = supportNo; + tfa->supportFramework = supportNo; + tfa9890_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x12: + /* tfa9895 */ + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_I2S; + tfa9895_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x13: + /* tfa9912 */ + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9912_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x94: + /* tfa9894 */ + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9894_ops(&tfa->dev_ops); /* register device operations */ + break; + + default: + pr_err("unknown device type : 0x%02x\n", tfa->rev); + _ASSERT(0); + break; + } +} + +/* + * lookup the device type and return the family type + */ +int tfa98xx_dev2family(int dev_type) +{ + /* only look at the die ID part (lsb byte) */ + switch (dev_type & 0xff) { + case 0x12: + case 0x80: + case 0x81: + case 0x91: + case 0x92: + case 0x97: + case 0x96: + return 1; + case 0x88: + case 0x72: + case 0x13: + case 0x74: + case 0x94: + return 2; + case 0x50: + return 3; + default: + return 0; + } +} + +/* + * return the target address for the filter on this device + + filter_index: + [0..9] reserved for EQ (not deployed, calc. is available) + [10..12] anti-alias filter + [13] integrator filter + + */ +enum Tfa98xx_DMEM tfa98xx_filter_mem(struct tfa_device *tfa, + int filter_index, unsigned short *address, int channel) +{ + enum Tfa98xx_DMEM dmem = -1; + int idx; + unsigned short bq_table[7][4] = { + /* index: 10, 11, 12, 13 */ + {346, 351, 356, 288}, //87 BRA_MAX_MRA4-2_7.00 + {346, 351, 356, 288}, //90 BRA_MAX_MRA6_9.02 + {467, 472, 477, 409}, //95 BRA_MAX_MRA7_10.02 + {406, 411, 416, 348}, //97 BRA_MAX_MRA9_12.01 + {467, 472, 477, 409}, //91 BRA_MAX_MRAA_13.02 + {8832, 8837, 8842, 8847}, //88 part1 + {8853, 8858, 8863, 8868} //88 part2 + /* Since the 88 is stereo we have 2 parts. + * Every index has 5 values except index 13 this one + * has 6 values + */ + }; + + if ((10 <= filter_index) && (filter_index <= 13)) { + dmem = Tfa98xx_DMEM_YMEM; /* for all devices */ + idx = filter_index - 10; + + switch (tfa->rev & 0xff) { // only compare lower byte + case 0x12: + *address = bq_table[2][idx]; + break; + case 0x97: + *address = bq_table[3][idx]; + break; + case 0x96: + *address = bq_table[3][idx]; + break; + case 0x80: + case 0x81: // for the RAM version + case 0x91: + *address = bq_table[1][idx]; + break; + case 0x92: + *address = bq_table[4][idx]; + break; + case 0x88: + /* Channel 1 = primary, 2 = secondary */ + if (channel == 1) + *address = bq_table[5][idx]; + else + *address = bq_table[6][idx]; + break; + case 0x72: + case 0x74: + case 0x13: + default: + /* unsupported case, possibly intermediate version */ + return ERR; + _ASSERT(0); + } + } + return dmem; +} + +/************************ query functions ******************************/ +/** +* return revision +* Used by the LTT +*/ +void tfa98xx_rev(int *major, int *minor, int *revision) +{ + char version_str[] = TFA98XX_API_REV_STR; + sscanf(version_str, "v%d.%d.%d", major, minor, revision); +} + +/** + * tfa_supported_speakers + * returns the number of the supported speaker count + */ +enum Tfa98xx_Error tfa_supported_speakers(struct tfa_device *tfa, + int *spkr_count) +{ + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + else + *spkr_count = tfa->spkr_count; + + return Tfa98xx_Error_Ok; +} + +/* + * tfa98xx_supported_saam + * returns the supportedspeaker as microphone feature + */ +enum Tfa98xx_Error tfa98xx_supported_saam(struct tfa_device *tfa, + enum Tfa98xx_saam *saam) +{ + int features; + enum Tfa98xx_Error error; + + if (tfa->support_saam == supportNotSet) { + error = tfa98xx_dsp_get_hw_feature_bits(tfa, &features); + if (error != Tfa98xx_Error_Ok) + return error; + tfa->support_saam = + (features & 0x8000) ? supportYes : supportNo; /* SAAM is bit15 */ + } + *saam = tfa->support_saam == supportYes ? Tfa98xx_saam : Tfa98xx_saam_none; + + return Tfa98xx_Error_Ok; +} + +/* + * tfa98xx_compare_features + * Obtains features_from_MTP and features_from_cnt + */ +enum Tfa98xx_Error tfa98xx_compare_features(struct tfa_device *tfa, + int features_from_MTP[3], int features_from_cnt[3]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint32_t value; + uint16_t mtpbf; + unsigned char bytes[3 * 2]; + int status; + + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) + return Tfa98xx_Error_NoClock; // Only test when we have a clock. + + /* Set proper MTP location per device: */ + if (tfa->tfa_family == 1) { + mtpbf = 0x850f; /* MTP5 for tfa1,16 bits */ + } else { + mtpbf = 0xf907; /* MTP9 for tfa2, 8 bits */ + } + + /* Read HW features from MTP: */ + value = tfa_read_reg(tfa, mtpbf) & 0xffff; + features_from_MTP[0] = tfa->hw_feature_bits = value; + + /* Read SW features: */ + error = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, + FW_PAR_ID_GET_FEATURE_INFO, sizeof(bytes), bytes); + if (error != Tfa98xx_Error_Ok) + /* old ROM code may respond with Tfa98xx_Error_RpcParamId */ + return error; + + tfa98xx_convert_bytes2data(sizeof(bytes), bytes, &features_from_MTP[1]); + + /* check if feature bits from MTP match feature bits from cnt file: */ + get_hw_features_from_cnt(tfa, &features_from_cnt[0]); + get_sw_features_from_cnt(tfa, &features_from_cnt[1]); + + return error; +} + +/********************************* device specific ops **********************/ +/* the wrapper for DspReset, in case of full */ +enum Tfa98xx_Error tfa98xx_dsp_reset(struct tfa_device *tfa, int state) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + error = (tfa->dev_ops.dsp_reset)(tfa, state); + + return error; +} + +/* the ops wrapper for tfa98xx_dsp_SystemStable */ +enum Tfa98xx_Error tfa98xx_dsp_system_stable(struct tfa_device *tfa, + int *ready) +{ + return (tfa->dev_ops.dsp_system_stable)(tfa, ready); +} + +/* the ops wrapper for tfa98xx_dsp_system_stable */ +enum Tfa98xx_Error tfa98xx_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + return (tfa->dev_ops.auto_copy_mtp_to_iic)(tfa); +} + +/* the ops wrapper for tfa98xx_faim_protect */ +enum Tfa98xx_Error tfa98xx_faim_protect(struct tfa_device *tfa, int state) +{ + return (tfa->dev_ops.faim_protect)(tfa, state); +} + +/* + * bring the device into a state similar to reset + */ +enum Tfa98xx_Error tfa98xx_init(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t value = 0; + + /* reset all i2C registers to default + * Write the register directly to avoid the read in the bitfield function. + * The I2CR bit may overwrite the full register because it is reset anyway. + * This will save a reg read transaction. + */ + TFA_SET_BF_VALUE(tfa, I2CR, 1, &value); + TFA_WRITE_REG(tfa, I2CR, value); + + /* Put DSP in reset */ + tfa98xx_dsp_reset(tfa, 1); /* in pair of tfaRunStartDSP() */ + + /* some other registers must be set for optimal amplifier behaviour + * This is implemented in a file specific for the type number + */ + if (tfa->dev_ops.tfa_init) + error = (tfa->dev_ops.tfa_init)(tfa); + + return error; +} + +enum Tfa98xx_Error tfa98xx_dsp_write_tables(struct tfa_device *tfa, + int sample_rate) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + error = (tfa->dev_ops.dsp_write_tables)(tfa, sample_rate); + + return error; +} + +/** Set internal oscillator into power down mode. +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - oscillator is on, 1 oscillator is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +enum Tfa98xx_Error tfa98xx_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + if (tfa->dev_ops.set_osc_powerdown) { + return tfa->dev_ops.set_osc_powerdown(tfa, state); + } + + return Tfa98xx_Error_Not_Implemented; +} + +/** update low power mode of the device. +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - LPMODE is on, 1 LPMODE is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +enum Tfa98xx_Error tfa98xx_update_lpm(struct tfa_device *tfa, int state) +{ + if (tfa->dev_ops.update_lpm) { + return tfa->dev_ops.update_lpm(tfa, state); + } + + return Tfa98xx_Error_Not_Implemented; +} +/** Check presence of powerswitch=1 in configuration and optimal setting. +* +* @param[in] tfa device description structure +* +* @return -1 when error, 0 or 1 depends on switch settings. +*/ +int tfa98xx_powerswitch_is_enabled(struct tfa_device *tfa) +{ + uint16_t value; + enum Tfa98xx_Error ret; + + if (((tfa->rev & 0xff) == 0x13) || ((tfa->rev & 0xff) == 0x88)) { + ret = reg_read(tfa, 0xc6, &value); + if (ret != Tfa98xx_Error_Ok) { + return ERR; + } + /* + * PLMA5539: Check actual value of powerswitch. TODO: regmap v1.40 + * should make this bit public. + */ + + return (int)(value & (1u << 6)); + } + + return 1; +} + +/********************* new tfa2 ***************************************/ +/* newly added messaging for tfa2 tfa1? */ +enum Tfa98xx_Error tfa98xx_dsp_get_memory(struct tfa_device *tfa, + int memoryType, int offset, int length, unsigned char bytes[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + char msg[4 * 3]; + int nr = 0; + + msg[nr++] = 8; + msg[nr++] = MODULE_FRAMEWORK + 128; + msg[nr++] = FW_PAR_ID_GET_MEMORY; + + msg[nr++] = 0; + msg[nr++] = 0; + msg[nr++] = (char)memoryType; + + msg[nr++] = 0; + msg[nr++] = (offset >> 8) & 0xff; + msg[nr++] = offset & 0xff; + + msg[nr++] = 0; + msg[nr++] = (length >> 8) & 0xff; + msg[nr++] = length & 0xff; + + /* send msg */ + error = dsp_msg(tfa, nr, (char *)msg); + + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the device (length * 3) */ + error = dsp_msg_read(tfa, length * 3, bytes); + + return error; +} + +enum Tfa98xx_Error tfa98xx_dsp_set_memory(struct tfa_device *tfa, + int memoryType, int offset, int length, int value) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int nr = 0; + char msg[5 * 3]; + + msg[nr++] = 8; + msg[nr++] = MODULE_FRAMEWORK + 128; + msg[nr++] = FW_PAR_ID_SET_MEMORY; + + msg[nr++] = 0; + msg[nr++] = 0; + msg[nr++] = (char)memoryType; + + msg[nr++] = 0; + msg[nr++] = (offset >> 8) & 0xff; + msg[nr++] = offset & 0xff; + + msg[nr++] = 0; + msg[nr++] = (length >> 8) & 0xff; + msg[nr++] = length & 0xff; + + msg[nr++] = (value >> 16) & 0xff; + msg[nr++] = (value >> 8) & 0xff; + msg[nr++] = value & 0xff; + + /* send msg */ + error = dsp_msg(tfa, nr, (char *)msg); + + return error; +} +/****************************** calibration support **************************/ +/* + * get/set the mtp with user controllable values + * + * check if the relevant clocks are available + */ +enum Tfa98xx_Error tfa98xx_get_mtp(struct tfa_device *tfa, uint16_t *value) +{ + int status; + int result; + + /* not possible if PLL in powerdown */ + if (TFA_GET_BF(tfa, PWDN)) { + pr_debug("PLL in powerdown\n"); + return Tfa98xx_Error_NoClock; + } + + tfa98xx_dsp_system_stable(tfa, &status); + if (status == 0) { + pr_debug("PLL not running\n"); + return Tfa98xx_Error_NoClock; + } + + result = TFA_READ_REG(tfa, MTP0); + if (result < 0) { + return -result; + } + *value = (uint16_t)result; + + return Tfa98xx_Error_Ok; +} + +/* + * lock or unlock KEY2 + * lock = 1 will lock + * lock = 0 will unlock + * + * note that on return all the hidden key will be off + */ +void tfa98xx_key2(struct tfa_device *tfa, int lock) +{ + /* unhide lock registers */ + reg_write(tfa, (tfa->tfa_family == 1) ? 0x40 : 0x0F, 0x5A6B); + /* lock/unlock key2 MTPK */ + TFA_WRITE_REG(tfa, MTPKEY2, lock ? 0 : 0x5A); + /* unhide lock registers */ + if (!tfa->advance_keys_handling) /*artf65038*/ + reg_write(tfa, (tfa->tfa_family == 1) ? 0x40 : 0x0F, 0); +} +void tfa2_manual_mtp_cpy(struct tfa_device *tfa, uint16_t reg_row_to_keep, + uint16_t reg_row_to_set, uint8_t row)///MCH_TO_TEST +{ + uint16_t value; + int loop = 0; + enum Tfa98xx_Error error; + /* Assure FAIM is enabled (enable it when neccesery) */ + if (tfa->is_probus_device) { + error = tfa98xx_faim_protect(tfa, 1); + if (tfa->verbose) { + pr_debug("FAIM enabled (err:%d).\n", error); + } + } + reg_read(tfa, (unsigned char)reg_row_to_keep, &value); + if (!row) { + reg_write(tfa, 0xA7, value); + reg_write(tfa, 0xA8, reg_row_to_set); + } else { + reg_write(tfa, 0xA7, reg_row_to_set); + reg_write(tfa, 0xA8, value); + } + reg_write(tfa, 0xA3, 0x10 | row); + if (tfa->is_probus_device) { + /* Assure FAIM is enabled (enable it when neccesery) */ + for (loop = 0; loop < 100 /*x10ms*/; loop++) { + msleep_interruptible(10); /* wait 10ms to avoid busload */ + if (tfa_dev_get_mtpb(tfa) == 0) + break; + } + error = tfa98xx_faim_protect(tfa, 0); + if (tfa->verbose) { + pr_debug("FAIM disabled (err:%d).\n", error); + } + } +} + +enum Tfa98xx_Error tfa98xx_set_mtp(struct tfa_device *tfa, uint16_t value, + uint16_t mask) +{ + unsigned short mtp_old, mtp_new; + int loop, status; + enum Tfa98xx_Error error; + + error = tfa98xx_get_mtp(tfa, &mtp_old); + + if (error != Tfa98xx_Error_Ok) + return error; + + mtp_new = (value & mask) | (mtp_old & ~mask); + + if (mtp_old == mtp_new) /* no change */ { + if (tfa->verbose) + pr_info("No change in MTP. Value not written! \n"); + return Tfa98xx_Error_Ok; + } + error = tfa98xx_update_lpm(tfa, 1); + if (error) { + return error; + } + /* Assure FAIM is enabled (enable it when neccesery) */ + error = tfa98xx_faim_protect(tfa, 1); + if (error) { + return error; + } + if (tfa->verbose) { + pr_debug("MTP clock enabled.\n"); + } + + /* assure that the clock is up, else we can't write MTP */ + error = tfa98xx_dsp_system_stable(tfa, &status); + if (error) { + return error; + } + if (status == 0) { + return Tfa98xx_Error_NoClock; + } + + tfa98xx_key2(tfa, 0); /* unlock */ + TFA_WRITE_REG(tfa, MTP0, mtp_new); /* write to i2c shadow reg */ + /* CIMTP=1 start copying all the data from i2c regs_mtp to mtp*/ + if (tfa->tfa_family == 2) + tfa2_manual_mtp_cpy(tfa, 0xF1, mtp_new, 0); + else + TFA_SET_BF(tfa, CIMTP, 1); + /* wait until MTP write is done */ + error = Tfa98xx_Error_StateTimedOut; + for (loop = 0; loop < 100 /*x10ms*/; loop++) { + msleep_interruptible(10); /* wait 10ms to avoid busload */ + if (tfa_dev_get_mtpb(tfa) == 0) { + error = Tfa98xx_Error_Ok; + break; + } + } + tfa98xx_key2(tfa, 1); /* lock */ + /* MTP setting failed due to timeout ?*/ + if (error) { + tfa98xx_faim_protect(tfa, 0); + return error; + } + + /* Disable the FAIM, if this is neccessary */ + error = tfa98xx_faim_protect(tfa, 0); + if (error) { + return error; + } + if (tfa->verbose) { + pr_debug("MTP clock disabled.\n"); + } + error = tfa98xx_update_lpm(tfa, 0); + if (error) { + return error; + } + return error; +} +/* + * clear mtpex + * set ACS + * start tfa + */ +int tfa_calibrate(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error; + + /* clear mtpex */ + error = tfa98xx_set_mtp(tfa, 0, TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK); + if (error) + return error; + + /* set RST=1 to put the DSP in Reset */ + TFA_SET_BF(tfa, RST, 1); + + /* set ACS/coldboot state */ + error = tfaRunColdboot(tfa, 1); + + /* start tfa by playing */ + return error; +} + +static short twos(short x) +{ + return (x < 0) ? x + 512 : x; +} + +void tfa98xx_set_exttemp(struct tfa_device *tfa, short ext_temp) +{ + if ((-256 <= ext_temp) && (ext_temp <= 255)) { + /* make twos complement */ + pr_debug("Using ext temp %d C\n", twos(ext_temp)); + TFA_SET_BF(tfa, TROS, 1); + TFA_SET_BF(tfa, EXTTS, twos(ext_temp)); + } else { + pr_debug("Clearing ext temp settings\n"); + TFA_SET_BF(tfa, TROS, 0); + } +} +short tfa98xx_get_exttemp(struct tfa_device *tfa) +{ + short ext_temp = (short)TFA_GET_BF(tfa, EXTTS); + return twos(ext_temp); +} + +/******************* tfa simple bitfield interfacing *************************/ +/* convenience functions */ +enum Tfa98xx_Error tfa98xx_set_volume_level(struct tfa_device *tfa, + unsigned short vol) +{ + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (vol > 255) /* restricted to 8 bits */ + vol = 255; + + /* 0x00 -> 0.0 dB + * 0x01 -> -0.5 dB + * ... + * 0xFE -> -127dB + * 0xFF -> muted + */ + + /* volume value is in the top 8 bits of the register */ + return -TFA_SET_BF(tfa, VOL, (uint16_t)vol); +} + +static enum Tfa98xx_Error +tfa98xx_set_mute_tfa2(struct tfa_device *tfa, enum Tfa98xx_Mute mute) +{ + enum Tfa98xx_Error error; + + if (tfa->dev_ops.set_mute == NULL) + return Tfa98xx_Error_Not_Supported; + + switch (mute) { + case Tfa98xx_Mute_Off: + error = tfa->dev_ops.set_mute(tfa, 0); + TFA_SET_BF(tfa, AMPE, 1); + break; + case Tfa98xx_Mute_Amplifier: + case Tfa98xx_Mute_Digital: + error = tfa->dev_ops.set_mute(tfa, 1); + TFA_SET_BF(tfa, AMPE, 0); + break; + default: + return Tfa98xx_Error_Bad_Parameter; + } + + return error; +} + +static enum Tfa98xx_Error +tfa98xx_set_mute_tfa1(struct tfa_device *tfa, enum Tfa98xx_Mute mute) +{ + enum Tfa98xx_Error error; + unsigned short audioctrl_value; + unsigned short sysctrl_value; + int value; + + value = TFA_READ_REG(tfa, CFSM); /* audio control register */ + if (value < 0) + return -value; + audioctrl_value = (unsigned short)value; + value = TFA_READ_REG(tfa, AMPE); /* system control register */ + if (value < 0) + return -value; + sysctrl_value = (unsigned short)value; + + switch (mute) { + case Tfa98xx_Mute_Off: + /* previous state can be digital or amplifier mute, + * clear the cf_mute and set the enbl_amplifier bits + * + * To reduce PLOP at power on it is needed to switch the + * amplifier on with the DCDC in follower mode + * (enbl_boost = 0 ?). + * This workaround is also needed when toggling the + * powerdown bit! + */ + TFA_SET_BF_VALUE(tfa, CFSM, 0, &audioctrl_value); + TFA_SET_BF_VALUE(tfa, AMPE, 1, &sysctrl_value); + TFA_SET_BF_VALUE(tfa, DCA, 1, &sysctrl_value); + break; + case Tfa98xx_Mute_Digital: + /* expect the amplifier to run */ + /* set the cf_mute bit */ + TFA_SET_BF_VALUE(tfa, CFSM, 1, &audioctrl_value); + /* set the enbl_amplifier bit */ + TFA_SET_BF_VALUE(tfa, AMPE, 1, &sysctrl_value); + /* clear active mode */ + TFA_SET_BF_VALUE(tfa, DCA, 0, &sysctrl_value); + break; + case Tfa98xx_Mute_Amplifier: + /* clear the cf_mute bit */ + TFA_SET_BF_VALUE(tfa, CFSM, 0, &audioctrl_value); + /* clear the enbl_amplifier bit and active mode */ + TFA_SET_BF_VALUE(tfa, AMPE, 0, &sysctrl_value); + TFA_SET_BF_VALUE(tfa, DCA, 0, &sysctrl_value); + break; + default: + return Tfa98xx_Error_Bad_Parameter; + } + + error = -TFA_WRITE_REG(tfa, CFSM, audioctrl_value); + if (error) + return error; + error = -TFA_WRITE_REG(tfa, AMPE, sysctrl_value); + return error; +} + +enum Tfa98xx_Error + tfa98xx_set_mute(struct tfa_device *tfa, enum Tfa98xx_Mute mute) +{ + if (tfa->in_use == 0) { + pr_err("device is not opened \n"); + return Tfa98xx_Error_NotOpen; + } + + if (tfa->tfa_family == 1) + return tfa98xx_set_mute_tfa1(tfa, mute); + else + return tfa98xx_set_mute_tfa2(tfa, mute); +} + +/****************** patching ***********************************************/ +static enum Tfa98xx_Error +tfa98xx_process_patch_file(struct tfa_device *tfa, int length, + const unsigned char *bytes) +{ + unsigned short size; + int index = 0; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + while (index < length) { + size = bytes[index] + bytes[index + 1] * 256; + index += 2; + if ((index + size) > length) { + /* outside the buffer, error in the input data */ + return Tfa98xx_Error_Bad_Parameter; + } + + if (size > tfa->buffer_size) { + /* too big, must fit buffer */ + return Tfa98xx_Error_Bad_Parameter; + } + + error = tfa98xx_write_raw(tfa, size, &bytes[index]); + if (error != Tfa98xx_Error_Ok) + break; + index += size; + } + return error; +} + + + +/* the patch contains a header with the following + * IC revision register: 1 byte, 0xFF means don't care + * XMEM address to check: 2 bytes, big endian, 0xFFFF means don't care + * XMEM value to expect: 3 bytes, big endian + */ +static enum Tfa98xx_Error +tfa98xx_check_ic_rom_version(struct tfa_device *tfa, + const unsigned char patchheader[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short checkrev, revid; + unsigned char lsb_revid; + unsigned short checkaddress; + int checkvalue; + int value = 0; + int status; + checkrev = patchheader[0]; + lsb_revid = tfa->rev & 0xff; /* only compare lower byte */ + + if ((checkrev != 0xFF) && (checkrev != lsb_revid)) + return Tfa98xx_Error_Not_Supported; + + checkaddress = (patchheader[1] << 8) + patchheader[2]; + checkvalue = + (patchheader[3] << 16) + (patchheader[4] << 8) + patchheader[5]; + if (checkaddress != 0xFFFF) { + /* before reading XMEM, check if we can access the DSP */ + error = tfa98xx_dsp_system_stable(tfa, &status); + if (error == Tfa98xx_Error_Ok) { + if (!status) { + /* DSP subsys not running */ + error = Tfa98xx_Error_DSP_not_running; + } + } + /* read register to check the correct ROM version */ + if (error == Tfa98xx_Error_Ok) { + error = mem_read(tfa, checkaddress, 1, &value); + } + if (error == Tfa98xx_Error_Ok) { + if (value != checkvalue) { + pr_err("patch file romid type check failed [0x%04x]: \ + expected 0x%02x, actual 0x%02x\n", + checkaddress, value, checkvalue); + error = Tfa98xx_Error_Not_Supported; + } + } + } else { /* == 0xffff */ + /* check if the revid subtype is in there */ + if (checkvalue != 0xFFFFFF && checkvalue != 0) { + revid = patchheader[5] << 8 | patchheader[0]; /* full revid */ + if (revid != tfa->rev) { + pr_err("patch file device type check failed: expected 0x%02x, actual 0x%02x\n", + tfa->rev, revid); + return Tfa98xx_Error_Not_Supported; + } + } + } + + return error; +} + + +#define PATCH_HEADER_LENGTH 6 +enum Tfa98xx_Error + tfa_dsp_patch(struct tfa_device *tfa, int patchLength, + const unsigned char *patchBytes) +{ + enum Tfa98xx_Error error; + int status; + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (patchLength < PATCH_HEADER_LENGTH) + return Tfa98xx_Error_Bad_Parameter; + + error = tfa98xx_check_ic_rom_version(tfa, patchBytes); + if (Tfa98xx_Error_Ok != error) { + return error; + } + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) + return Tfa98xx_Error_NoClock; // Only test when we have a clock. + /******MCH_TO_TEST**************/ + if (error == Tfa98xx_Error_Ok) { + error = tfaRunColdboot(tfa, 1); + if (error) + return Tfa98xx_Error_DSP_not_running; + } + /**************************/ + error = + tfa98xx_process_patch_file(tfa, patchLength - PATCH_HEADER_LENGTH, + patchBytes + PATCH_HEADER_LENGTH); + + return error; +} + +/****************** end patching *****************************************/ + +TFA_INTERNAL enum Tfa98xx_Error +tfa98xx_wait_result(struct tfa_device *tfa, int wait_retry_count) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int cf_status; /* the contents of the CF_STATUS register */ + int tries = 0; + do { + cf_status = TFA_GET_BF(tfa, ACK); + if (cf_status < 0) + error = -cf_status; + tries++; + } + // i2c_cmd_ack + /* don't wait forever, DSP is pretty quick to respond (< 1ms) */ + while ((error == Tfa98xx_Error_Ok) && + ((cf_status & CF_STATUS_I2C_CMD_ACK) == 0) && (tries < wait_retry_count)); + + if (tries >= wait_retry_count) { + /* something wrong with communication with DSP */ + error = Tfa98xx_Error_DSP_not_running; + } + return error; +} + +/* + * * support functions for data conversion + */ + /** + convert memory bytes to signed 24 bit integers + input: bytes contains "num_bytes" byte elements + output: data contains "num_bytes/3" int24 elements + */ +void tfa98xx_convert_bytes2data(int num_bytes, const unsigned char bytes[], + int data[]) +{ + int i; /* index for data */ + int k; /* index for bytes */ + int d; + int num_data = num_bytes / 3; + _ASSERT((num_bytes % 3) == 0); + for (i = 0, k = 0; i < num_data; ++i, k += 3) { + d = (bytes[k] << 16) | (bytes[k + 1] << 8) | (bytes[k + 2]); + _ASSERT(d >= 0); + _ASSERT(d < (1 << 24)); /* max 24 bits in use */ + if (bytes[k] & 0x80) /* sign bit was set */ + d = -((1 << 24) - d); + + data[i] = d; + } +} + + +/** + convert signed 32 bit integers to 24 bit aligned bytes + input: data contains "num_data" int elements + output: bytes contains "3 * num_data" byte elements +*/ +void tfa98xx_convert_data2bytes(int num_data, const int data[], + unsigned char bytes[]) +{ + int i; /* index for data */ + int k; /* index for bytes */ + int d; + /* note: cannot just take the lowest 3 bytes from the 32 bit + * integer, because also need to take care of clipping any + * value > 2&23 */ + for (i = 0, k = 0; i < num_data; ++i, k += 3) { + if (data[i] >= 0) + d = MIN(data[i], (1 << 23) - 1); + else { + /* 2's complement */ + d = (1 << 24) - MIN(-data[i], 1 << 23); + } + _ASSERT(d >= 0); + _ASSERT(d < (1 << 24)); /* max 24 bits in use */ + bytes[k] = (d >> 16) & 0xFF; /* MSB */ + bytes[k + 1] = (d >> 8) & 0xFF; + bytes[k + 2] = (d) & 0xFF; /* LSB */ + } +} + +/* + * DSP RPC message support functions + * depending on framework to be up and running + * need base i2c of memaccess (tfa1=0x70/tfa2=0x90) + */ + + + /* write dsp messages in function tfa_dsp_msg() */ + /* note the 'old' write_parameter() was more efficient because all + * i2c was in one burst transaction + */ + + /* + * TODO properly handle bitfields: state should be restored! + * (now it will change eg dmesg field to xmem) + */ +enum Tfa98xx_Error tfa_dsp_msg_write(struct tfa_device *tfa, int length, + const char *buffer) +{ + int offset = 0; + /* XMEM word size */ + int chunk_size = ROUND_DOWN(tfa->buffer_size, 3); + int remaining_bytes = length; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t cfctl; + int value; + + value = TFA_READ_REG(tfa, DMEM); + if (value < 0) { + error = -value; + return error; + } + cfctl = (uint16_t)value; + /* assume no I2C errors from here */ + /* set cf ctl to DMEM */ + TFA_SET_BF_VALUE(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM, &cfctl); + TFA_SET_BF_VALUE(tfa, AIF, 0, &cfctl); /* set to autoincrement */ + TFA_WRITE_REG(tfa, DMEM, cfctl); + + /* xmem[1] is start of message + * direct write to register to save cycles avoiding read-modify-write + */ + TFA_WRITE_REG(tfa, MADD, 1); + + /* due to autoincrement in cf_ctrl, next write will happen at + * the next address */ + while ((error == Tfa98xx_Error_Ok) && (remaining_bytes > 0)) { + if (remaining_bytes < chunk_size) + chunk_size = remaining_bytes; + /* else chunk_size remains at initialize value above */ + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, + chunk_size, (const unsigned char *)buffer + offset); + remaining_bytes -= chunk_size; + offset += chunk_size; + } + + /* notify the DSP */ + if (error == Tfa98xx_Error_Ok) { + /* cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ + /* set the cf_req1 and cf_int bit */ + TFA_SET_BF_VALUE(tfa, REQCMD, 0x01, &cfctl); /* bit 0 */ + TFA_SET_BF_VALUE(tfa, CFINT, 1, &cfctl); + error = -TFA_WRITE_REG(tfa, CFINT, cfctl); + } + + return error; +} + +enum Tfa98xx_Error tfa_dsp_msg_write_id(struct tfa_device *tfa, int length, + const char *buffer, uint8_t cmdid[3]) +{ + int offset = 0; + int chunk_size = ROUND_DOWN(tfa->buffer_size, 3); /* XMEM word size */ + int remaining_bytes = length; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t cfctl; + int value; + + value = TFA_READ_REG(tfa, DMEM); + if (value < 0) { + error = -value; + return error; + } + cfctl = (uint16_t)value; + /* assume no I2C errors from here */ + /* set cf ctl to DMEM */ + TFA_SET_BF_VALUE(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM, &cfctl); + TFA_SET_BF_VALUE(tfa, AIF, 0, &cfctl); /* set to autoincrement */ + TFA_WRITE_REG(tfa, DMEM, cfctl); + + /* xmem[1] is start of message + * direct write to register to save cycles avoiding read-modify-write + */ + TFA_WRITE_REG(tfa, MADD, 1); + + /* write cmd-id */ + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, 3, + (const unsigned char *)cmdid); + + /* due to autoincrement in cf_ctrl, next write will happen at + * the next address */ + while ((error == Tfa98xx_Error_Ok) && (remaining_bytes > 0)) { + if (remaining_bytes < chunk_size) + chunk_size = remaining_bytes; + /* else chunk_size remains at initialize value above */ + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, + chunk_size, (const unsigned char *)buffer + offset); + remaining_bytes -= chunk_size; + offset += chunk_size; + } + + /* notify the DSP */ + if (error == Tfa98xx_Error_Ok) { + /* cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ + /* set the cf_req1 and cf_int bit */ + TFA_SET_BF_VALUE(tfa, REQCMD, 0x01, &cfctl); /* bit 0 */ + TFA_SET_BF_VALUE(tfa, CFINT, 1, &cfctl); + error = -TFA_WRITE_REG(tfa, CFINT, cfctl); + } + + return error; +} + +/* +* status function used by tfa_dsp_msg() to retrieve command/msg status: +* return a <0 status of the DSP did not ACK. +*/ +enum Tfa98xx_Error tfa_dsp_msg_status(struct tfa_device *tfa, int *pRpcStatus) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + error = tfa98xx_wait_result(tfa, 2); /* 2 is only one try */ + if (error == Tfa98xx_Error_DSP_not_running) { + *pRpcStatus = -1; + return Tfa98xx_Error_Ok; + } else if (error != Tfa98xx_Error_Ok) + return error; + + error = tfa98xx_check_rpc_status(tfa, pRpcStatus); + + return error; +} + +const char *tfa98xx_get_i2c_status_id_string(int status) +{ + const char *p_id_str; + + switch (status) { + case Tfa98xx_DSP_Not_Running: + p_id_str = "No response from DSP"; + break; + case Tfa98xx_I2C_Req_Done: + p_id_str = "Ok"; + break; + case Tfa98xx_I2C_Req_Busy: + p_id_str = "Request is being processed"; + break; + case Tfa98xx_I2C_Req_Invalid_M_ID: + p_id_str = "Provided M-ID does not fit in valid rang [0..2]"; + break; + case Tfa98xx_I2C_Req_Invalid_P_ID: + p_id_str = "Provided P-ID is not valid in the given M-ID context"; + break; + case Tfa98xx_I2C_Req_Invalid_CC: + p_id_str = "Invalid channel configuration bits (SC|DS|DP|DC) combination"; + break; + case Tfa98xx_I2C_Req_Invalid_Seq: + p_id_str = "Invalid sequence of commands, in case the DSP expects some \ + commands in a specific order"; + break; + case Tfa98xx_I2C_Req_Invalid_Param: + p_id_str = "Generic error, invalid parameter"; + break; + case Tfa98xx_I2C_Req_Buffer_Overflow: + p_id_str = "I2C buffer has overflowed: host has sent too many \ + parameters, memory integrity is not guaranteed"; + break; + case Tfa98xx_I2C_Req_Calib_Busy: + p_id_str = "Calibration not completed"; + break; + case Tfa98xx_I2C_Req_Calib_Failed: + p_id_str = "Calibration failed"; + break; + + default: + p_id_str = "Unspecified error"; + } + + return p_id_str; +} + +enum Tfa98xx_Error tfa_dsp_msg_read(struct tfa_device *tfa, int length, + unsigned char *bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int burst_size; /* number of words per burst size */ + int bytes_per_word = 3; + int num_bytes; + int offset = 0; + unsigned short start_offset = 2; /* msg starts @xmem[2] ,[1]=cmd */ + + if (length > TFA2_MAX_PARAM_SIZE) + return Tfa98xx_Error_Bad_Parameter; + + TFA_SET_BF(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM); + error = -TFA_WRITE_REG(tfa, MADD, start_offset); + if (error != Tfa98xx_Error_Ok) + return error; + + num_bytes = length; /* input param */ + while (num_bytes > 0) { + burst_size = ROUND_DOWN(tfa->buffer_size, bytes_per_word); + if (num_bytes < burst_size) + burst_size = num_bytes; + error = tfa98xx_read_data(tfa, FAM_TFA98XX_CF_MEM, burst_size, + bytes + offset); + if (error != Tfa98xx_Error_Ok) + return error; + + num_bytes -= burst_size; + offset += burst_size; + } + + return error; +} + +enum Tfa98xx_Error dsp_msg(struct tfa_device *tfa, int length24, + const char *buf24) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int lastmessage = 0; + uint8_t *blob; + int i; + int *intbuf = NULL; + char *buf = (char *)buf24; + int length = length24; + + if (tfa->convert_dsp32) { + int idx = 0; + + length = 4 * length24 / 3; + intbuf = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + buf = (char *)intbuf; + + /* convert 24 bit DSP messages to a 32 bit integer */ + for (i = 0; i < length24; i += 3) { + int tmp = (buf24[i] << 16) + (buf24[i + 1] << 8) + buf24[i + 2]; + /* Sign extend to 32-bit from 24-bit */ + intbuf[idx++] = ((int32_t)tmp << 8) >> 8; + } + } + + /* Only create multi-msg when the dsp is cold */ + if (tfa->ext_dsp == 1) { + /* Creating the multi-msg */ + error = tfa_tib_dsp_msgmulti(tfa, length, buf); + if (error == Tfa98xx_Error_Fail) + return Tfa98xx_Error_Fail; + + /* if the buffer is full we need to send the existing message + * and add the current message + */ + if (error == Tfa98xx_Error_Buffer_too_small) { + int len; + + /* (a) send the existing (full) message */ + blob = kmalloc(64 * 1024, GFP_KERNEL); // max length is 64k + len = tfa_tib_dsp_msgmulti(tfa, -1, (const char *)blob); + if (tfa->verbose) { + pr_debug("Multi-message buffer full. Sending multi-message,\ + length=%d \n", len); + } + if (tfa->has_msg == 0) /* via i2c */ { + /* Send tot the target selected */ + error = (tfa->dev_ops.dsp_msg)(tfa, len, (const char *)blob); + } else { /* via msg hal */ + error = tfa98xx_write_dsp(tfa, len, (const char *)blob); + } + kfree(blob); + + /* (b) add the current DSP message to a new multi-message */ + error = tfa_tib_dsp_msgmulti(tfa, length, buf); + if (error == Tfa98xx_Error_Fail) { + return Tfa98xx_Error_Fail; + } + } + + lastmessage = error; + + /* When the lastmessage is done we can send the multi-msg to the target */ + if (lastmessage == 1) { + + /* Get the full multi-msg data */ + blob = kmalloc(64 * 1024, GFP_KERNEL); //max length is 64k + length = tfa_tib_dsp_msgmulti(tfa, -1, (const char *)blob); + + if (tfa->verbose) + pr_debug("Last message for the multi-message received.\ + Multi-message length=%d \n", length); + + if (tfa->has_msg == 0) /* via i2c */ { + /* Send tot the target selected */ + error = (tfa->dev_ops.dsp_msg)(tfa, length, (const char *)blob); + } else { /* via msg hal */ + error = tfa98xx_write_dsp(tfa, length, (const char *)blob); + } + + kfree(blob); /* Free the kmalloc blob */ + lastmessage = 0; /* reset to be able to re-start */ + } + } else { + if (tfa->has_msg == 0) /* via i2c */ { + error = (tfa->dev_ops.dsp_msg)(tfa, length, buf); + } else { /* via msg hal */ + error = tfa98xx_write_dsp(tfa, length, (const char *)buf); + } + } + + if (error != Tfa98xx_Error_Ok) + /* Get actual error code from softDSP */ + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); + + /* DSP verbose has argument 0x04 */ + if ((tfa->verbose & 0x04) != 0) { + pr_debug("DSP w [%d]: ", length); + for (i = 0; i < length; i++) + pr_debug("0x%02x ", (uint8_t)buf[i]); + pr_debug("\n"); + } + + if (tfa->convert_dsp32) { + kmem_cache_free(tfa->cachep, intbuf); + } + + return error; +} + +enum Tfa98xx_Error dsp_msg_read(struct tfa_device *tfa, int length24, unsigned char *bytes24) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int i; + int length = length24; + unsigned char *bytes = bytes24; + + if (tfa->convert_dsp32) { + length = 4 * length24 / 3; + bytes = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + } + + if (tfa->has_msg == 0) /* via i2c */ { + error = (tfa->dev_ops.dsp_msg_read)(tfa, length, bytes); + } else { /* via msg hal */ + error = tfa98xx_read_dsp(tfa, length, bytes); + } + + if (error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + /* DSP verbose has argument 0x04 */ + if ((tfa->verbose & 0x04) != 0) { + pr_debug("DSP R [%d]: ", length); + for (i = 0; i < length; i++) + pr_debug("0x%02x ", (uint8_t)bytes[i]); + pr_debug("\n"); + } + + if (tfa->convert_dsp32) { + int idx = 0; + + /* convert 32 bit LE to 24 bit BE */ + for (i = 0; i < length; i += 4) { + bytes24[idx++] = bytes[i + 2]; + bytes24[idx++] = bytes[i + 1]; + bytes24[idx++] = bytes[i + 0]; + } + + kmem_cache_free(tfa->cachep, bytes); + } + + return error; +} + +enum Tfa98xx_Error reg_read(struct tfa_device *tfa, unsigned char subaddress, unsigned short *value) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.reg_read)(tfa, subaddress, value); + if (error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + +enum Tfa98xx_Error reg_write(struct tfa_device *tfa, unsigned char subaddress, unsigned short value) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.reg_write)(tfa, subaddress, value); + if (error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + +enum Tfa98xx_Error mem_read(struct tfa_device *tfa, unsigned int start_offset, int num_words, int *pValues) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.mem_read)(tfa, start_offset, num_words, pValues); + if (error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + +enum Tfa98xx_Error mem_write(struct tfa_device *tfa, unsigned short address, int value, int memtype) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.mem_write)(tfa, address, value, memtype); + if (error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + + +/* + * write/read raw msg functions : + * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes. + * The functions will return immediately and do not not wait for DSP reponse. + */ +#define MAX_WORDS (300) +enum Tfa98xx_Error tfa_dsp_msg(struct tfa_device *tfa, int length, const char *buf) +{ + enum Tfa98xx_Error error; + int tries, rpc_status = Tfa98xx_I2C_Req_Done; + + /* write the message and notify the DSP */ + error = tfa_dsp_msg_write(tfa, length, buf); + if (error != Tfa98xx_Error_Ok) + return error; + + /* get the result from the DSP (polling) */ + for (tries = TFA98XX_WAITRESULT_NTRIES; tries > 0; tries--) { + error = tfa_dsp_msg_status(tfa, &rpc_status); + if (error == Tfa98xx_Error_Ok && rpc_status == Tfa98xx_I2C_Req_Done) + break; + /* If the rpc status is a specific error we want to know it. + * If it is busy or not running it should retry + */ + if (rpc_status != Tfa98xx_I2C_Req_Busy && rpc_status != Tfa98xx_DSP_Not_Running) + break; + } + + if (rpc_status != Tfa98xx_I2C_Req_Done) { + /* DSP RPC call returned an error */ + error = (enum Tfa98xx_Error) (rpc_status + Tfa98xx_Error_RpcBase); + pr_debug("DSP msg status: %d (%s)\n", rpc_status, tfa98xx_get_i2c_status_id_string(rpc_status)); + } + return error; +} + +/** + * write/read raw msg functions: + * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes. + * The functions will return immediately and do not not wait for DSP reponse. + * An ID is added to modify the command-ID + */ +enum Tfa98xx_Error tfa_dsp_msg_id(struct tfa_device *tfa, int length, const char *buf, uint8_t cmdid[3]) +{ + enum Tfa98xx_Error error; + int tries, rpc_status = Tfa98xx_I2C_Req_Done; + + /* write the message and notify the DSP */ + error = tfa_dsp_msg_write_id(tfa, length, buf, cmdid); + if (error != Tfa98xx_Error_Ok) + return error; + + /* get the result from the DSP (polling) */ + for (tries = TFA98XX_WAITRESULT_NTRIES; tries > 0; tries--) { + error = tfa_dsp_msg_status(tfa, &rpc_status); + if (error == Tfa98xx_Error_Ok && rpc_status == Tfa98xx_I2C_Req_Done) + break; + } + + if (rpc_status != Tfa98xx_I2C_Req_Done) { + /* DSP RPC call returned an error */ + error = (enum Tfa98xx_Error) (rpc_status + Tfa98xx_Error_RpcBase); + pr_debug("DSP msg status: %d (%s)\n", rpc_status, tfa98xx_get_i2c_status_id_string(rpc_status)); + } + return error; +} + +/* read the return code for the RPC call */ +TFA_INTERNAL enum Tfa98xx_Error +tfa98xx_check_rpc_status(struct tfa_device *tfa, int *pRpcStatus) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + /* the value to sent to the * CF_CONTROLS register: cf_req=00000000, + * cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ + unsigned short cf_ctrl = 0x0002; + /* memory address to be accessed (0: Status, 1: ID, 2: parameters) */ + unsigned short cf_mad = 0x0000; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + if (pRpcStatus == NULL) + return Tfa98xx_Error_Bad_Parameter; + + /* 1) write DMEM=XMEM to the DSP XMEM */ + { + /* minimize the number of I2C transactions by making use of the autoincrement in I2C */ + unsigned char buffer[4]; + /* first the data for CF_CONTROLS */ + buffer[0] = (unsigned char)((cf_ctrl >> 8) & 0xFF); + buffer[1] = (unsigned char)(cf_ctrl & 0xFF); + /* write the contents of CF_MAD which is the subaddress following CF_CONTROLS */ + buffer[2] = (unsigned char)((cf_mad >> 8) & 0xFF); + buffer[3] = (unsigned char)(cf_mad & 0xFF); + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_CONTROLS, sizeof(buffer), buffer); + } + if (error == Tfa98xx_Error_Ok) { + /* read 1 word (24 bit) from XMEM */ + error = tfa98xx_dsp_read_mem(tfa, 0, 1, pRpcStatus); + } + + return error; +} + +/***************************** xmem only **********************************/ +enum Tfa98xx_Error + tfa98xx_dsp_read_mem(struct tfa_device *tfa, + unsigned int start_offset, int num_words, int *pValues) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned char *bytes; + int burst_size; /* number of words per burst size */ + const int bytes_per_word = 3; + int dmem; + int num_bytes; + int *p; + + bytes = (unsigned char *)kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (bytes == NULL) + return Tfa98xx_Error_Fail; + + /* If no offset is given, assume XMEM! */ + if (((start_offset >> 16) & 0xf) > 0) + dmem = (start_offset >> 16) & 0xf; + else + dmem = Tfa98xx_DMEM_XMEM; + + /* Remove offset from adress */ + start_offset = start_offset & 0xffff; + num_bytes = num_words * bytes_per_word; + p = pValues; + + TFA_SET_BF(tfa, DMEM, (uint16_t)dmem); + error = -TFA_WRITE_REG(tfa, MADD, (unsigned short)start_offset); + if (error != Tfa98xx_Error_Ok) + goto tfa98xx_dsp_read_mem_exit; + + for (; num_bytes > 0;) { + burst_size = ROUND_DOWN(tfa->buffer_size, bytes_per_word); + if (num_bytes < burst_size) + burst_size = num_bytes; + + _ASSERT(burst_size <= sizeof(bytes)); + error = tfa98xx_read_data(tfa, FAM_TFA98XX_CF_MEM, burst_size, bytes); + if (error != Tfa98xx_Error_Ok) + goto tfa98xx_dsp_read_mem_exit; + + tfa98xx_convert_bytes2data(burst_size, bytes, p); + + num_bytes -= burst_size; + p += burst_size / bytes_per_word; + } + +tfa98xx_dsp_read_mem_exit: + kmem_cache_free(tfa->cachep, bytes); + + return error; +} + + +enum Tfa98xx_Error + tfa98xx_dsp_write_mem_word(struct tfa_device *tfa, unsigned short address, int value, int memtype) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned char bytes[3]; + + TFA_SET_BF(tfa, DMEM, (uint16_t)memtype); + + error = -TFA_WRITE_REG(tfa, MADD, address); + if (error != Tfa98xx_Error_Ok) + return error; + + tfa98xx_convert_data2bytes(1, &value, bytes); + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, 3, bytes); + + return error; +} + +enum Tfa98xx_Error tfa_cont_write_filterbank(struct tfa_device *tfa, nxpTfaFilter_t *filter) +{ + unsigned char biquad_index; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + for (biquad_index = 0; biquad_index < 10; biquad_index++) { + if (filter[biquad_index].enabled) { + error = tfa_dsp_cmd_id_write(tfa, MODULE_BIQUADFILTERBANK, + biquad_index + 1, //start @1 + sizeof(filter[biquad_index].biquad.bytes), + filter[biquad_index].biquad.bytes); + } else { + error = Tfa98xx_DspBiquad_Disable(tfa, biquad_index + 1); + } + if (error) + return error; + + } + + return error; +} + +enum Tfa98xx_Error + Tfa98xx_DspBiquad_Disable(struct tfa_device *tfa, int biquad_index) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int coeff_buffer[BIQUAD_COEFF_SIZE]; + unsigned char bytes[3 + BIQUAD_COEFF_SIZE * 3]; + int nr = 0; + + if (biquad_index > TFA98XX_BIQUAD_NUM) + return Tfa98xx_Error_Bad_Parameter; + if (biquad_index < 1) + return Tfa98xx_Error_Bad_Parameter; + + /* make opcode */ + bytes[nr++] = 0; + bytes[nr++] = MODULE_BIQUADFILTERBANK + 128; + bytes[nr++] = (unsigned char)biquad_index; + + + /* set in correct order and format for the DSP */ + coeff_buffer[0] = (int)-8388608; /* -1.0f */ + coeff_buffer[1] = 0; + coeff_buffer[2] = 0; + coeff_buffer[3] = 0; + coeff_buffer[4] = 0; + coeff_buffer[5] = 0; + + /* convert to packed 24 */ + tfa98xx_convert_data2bytes(BIQUAD_COEFF_SIZE, coeff_buffer, &bytes[nr]); + nr += BIQUAD_COEFF_SIZE * 3; + + error = dsp_msg(tfa, nr, (char *)bytes); + + return error; +} + +/* wrapper for dsp_msg that adds opcode */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + const unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char *buffer; + int nr = 0; + + buffer = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (buffer == NULL) + return Tfa98xx_Error_Fail; + + buffer[nr++] = tfa->spkr_select; + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + memcpy(&buffer[nr], data, num_bytes); + nr += num_bytes; + + error = dsp_msg(tfa, nr, (char *)buffer); + + kmem_cache_free(tfa->cachep, buffer); + + return error; +} + +/* wrapper for dsp_msg that adds opcode */ +/* this is as the former tfa98xx_dsp_get_param() */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write_read(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char buffer[3]; + int nr = 0; + + if (num_bytes <= 0) { + pr_debug("Error: The number of READ bytes is smaller or equal to 0! \n"); + return Tfa98xx_Error_Fail; + } + + if ((tfa->is_probus_device) && (tfa->cnt->ndev == 1) && + (param_id == SB_PARAM_GET_RE25C || + param_id == SB_PARAM_GET_LSMODEL || + param_id == SB_PARAM_GET_ALGO_PARAMS)) { + /* Modifying the ID for GetRe25C */ + buffer[nr++] = 4; + } else { + buffer[nr++] = tfa->spkr_select; + } + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + error = dsp_msg(tfa, nr, (char *)buffer); + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the dsp */ + error = dsp_msg_read(tfa, num_bytes, data); + return error; +} + +/* wrapper for dsp_msg that adds opcode and 3 bytes required for coefs */ +enum Tfa98xx_Error tfa_dsp_cmd_id_coefs(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char buffer[2 * 3]; + int nr = 0; + + buffer[nr++] = tfa->spkr_select; + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + buffer[nr++] = 0; + buffer[nr++] = 0; + buffer[nr++] = 0; + + error = dsp_msg(tfa, nr, (char *)buffer); + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the dsp */ + error = dsp_msg_read(tfa, num_bytes, data); + + return error; +} + +/* wrapper for dsp_msg that adds opcode and 3 bytes required for MBDrcDynamics */ +enum Tfa98xx_Error tfa_dsp_cmd_id_MBDrc_dynamics(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int index_subband, + int num_bytes, unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char buffer[2 * 3]; + int nr = 0; + + buffer[nr++] = tfa->spkr_select; + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + buffer[nr++] = 0; + buffer[nr++] = 0; + buffer[nr++] = (unsigned char)index_subband; + + error = dsp_msg(tfa, nr, (char *)buffer); + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the dsp */ + error = dsp_msg_read(tfa, num_bytes, data); + + return error; +} + +enum Tfa98xx_Error + tfa98xx_dsp_write_preset(struct tfa_device *tfa, int length, + const unsigned char *p_preset_bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + if (p_preset_bytes != NULL) { + /* by design: keep the data opaque and no + * interpreting/calculation */ + error = tfa_dsp_cmd_id_write(tfa, MODULE_SPEAKERBOOST, + SB_PARAM_SET_PRESET, length, + p_preset_bytes); + } else { + error = Tfa98xx_Error_Bad_Parameter; + } + return error; +} + +/* + * get features from MTP + */ +enum Tfa98xx_Error + tfa98xx_dsp_get_hw_feature_bits(struct tfa_device *tfa, int *features) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint32_t value; + uint16_t mtpbf; + + /* return the cache data if it's valid */ + if (tfa->hw_feature_bits != -1) { + *features = tfa->hw_feature_bits; + } else { + /* for tfa1 check if we have clock */ + if (tfa->tfa_family == 1) { + int status; + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) { + get_hw_features_from_cnt(tfa, features); + /* skip reading MTP: */ + return (*features == -1) ? Tfa98xx_Error_Fail : Tfa98xx_Error_Ok; + } + mtpbf = 0x850f; /* MTP5 for tfa1,16 bits */ + } else + mtpbf = 0xf907; /* MTP9 for tfa2, 8 bits */ + value = tfa_read_reg(tfa, mtpbf) & 0xffff; + *features = tfa->hw_feature_bits = value; + } + + return error; +} + +enum Tfa98xx_Error + tfa98xx_dsp_get_sw_feature_bits(struct tfa_device *tfa, int features[2]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + const int byte_size = 2 * 3; + unsigned char bytes[2 * 3]; + + /* return the cache data if it's valid */ + if (tfa->sw_feature_bits[0] != -1) { + features[0] = tfa->sw_feature_bits[0]; + features[1] = tfa->sw_feature_bits[1]; + } else { + /* for tfa1 check if we have clock */ + if (tfa->tfa_family == 1) { + int status; + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) { + get_sw_features_from_cnt(tfa, features); + /* skip reading MTP: */ + return (features[0] == -1) ? Tfa98xx_Error_Fail : Tfa98xx_Error_Ok; + } + } + error = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, + FW_PAR_ID_GET_FEATURE_INFO, byte_size, bytes); + + if (error != Tfa98xx_Error_Ok) { + /* old ROM code may respond with Tfa98xx_Error_RpcParamId */ + return error; + } + + tfa98xx_convert_bytes2data(byte_size, bytes, features); + } + return error; +} + +enum Tfa98xx_Error tfa98xx_dsp_get_state_info(struct tfa_device *tfa, unsigned char bytes[], unsigned int *statesize) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int bSupportFramework = 0; + unsigned int stateSize = 9; + + err = tfa98xx_dsp_support_framework(tfa, &bSupportFramework); + if (err == Tfa98xx_Error_Ok) { + if (bSupportFramework) { + err = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, + FW_PARAM_GET_STATE, 3 * stateSize, bytes); + } else { + /* old ROM code, ask SpeakerBoost and only do first portion */ + stateSize = 8; + err = tfa_dsp_cmd_id_write_read(tfa, MODULE_SPEAKERBOOST, + SB_PARAM_GET_STATE, 3 * stateSize, bytes); + } + } + + *statesize = stateSize; + + return err; +} + +enum Tfa98xx_Error tfa98xx_dsp_support_drc(struct tfa_device *tfa, int *pbSupportDrc) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + *pbSupportDrc = 0; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + if (tfa->supportDrc != supportNotSet) { + *pbSupportDrc = (tfa->supportDrc == supportYes); + } else { + int featureBits[2]; + + error = tfa98xx_dsp_get_sw_feature_bits(tfa, featureBits); + if (error == Tfa98xx_Error_Ok) { + /* easy case: new API available */ + /* bit=0 means DRC enabled */ + *pbSupportDrc = (featureBits[0] & FEATURE1_DRC) == 0; + } else if (error == Tfa98xx_Error_RpcParamId) { + /* older ROM code, doesn't support it */ + *pbSupportDrc = 0; + error = Tfa98xx_Error_Ok; + } + /* else some other error, return transparently */ + /* pbSupportDrc only changed when error == Tfa98xx_Error_Ok */ + + if (error == Tfa98xx_Error_Ok) { + tfa->supportDrc = *pbSupportDrc ? supportYes : supportNo; + } + } + return error; +} + +enum Tfa98xx_Error + tfa98xx_dsp_support_framework(struct tfa_device *tfa, int *pbSupportFramework) +{ + int featureBits[2] = { 0, 0 }; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + _ASSERT(pbSupportFramework != 0); + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (tfa->supportFramework != supportNotSet) { + if (tfa->supportFramework == supportNo) + *pbSupportFramework = 0; + else + *pbSupportFramework = 1; + } else { + error = tfa98xx_dsp_get_sw_feature_bits(tfa, featureBits); + if (error == Tfa98xx_Error_Ok) { + *pbSupportFramework = 1; + tfa->supportFramework = supportYes; + } else { + *pbSupportFramework = 0; + tfa->supportFramework = supportNo; + error = Tfa98xx_Error_Ok; + } + } + + /* *pbSupportFramework only changed when error == Tfa98xx_Error_Ok */ + return error; +} + +enum Tfa98xx_Error + tfa98xx_dsp_write_speaker_parameters(struct tfa_device *tfa, + int length, const unsigned char *p_speaker_bytes) +{ + enum Tfa98xx_Error error; + int bSupportDrc; + + if (p_speaker_bytes != NULL) { + /* by design: keep the data opaque and no + * interpreting/calculation */ + /* Use long WaitResult retry count */ + error = tfa_dsp_cmd_id_write( + tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_LSMODEL, length, + p_speaker_bytes); + } else { + error = Tfa98xx_Error_Bad_Parameter; + } + + if (error != Tfa98xx_Error_Ok) + return error; + + error = tfa98xx_dsp_support_drc(tfa, &bSupportDrc); + if (error != Tfa98xx_Error_Ok) + return error; + + if (bSupportDrc) { + /* Need to set AgcGainInsert back to PRE, + * as the SetConfig forces it to POST */ + uint8_t bytes[3] = { 0, 0, 0 }; + + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_AGCINS, + 3, + bytes); + } + + return error; +} + +enum Tfa98xx_Error + tfa98xx_dsp_write_config(struct tfa_device *tfa, int length, + const unsigned char *p_config_bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int bSupportDrc; + + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_CONFIG, length, + p_config_bytes); + if (error != Tfa98xx_Error_Ok) + return error; + + error = tfa98xx_dsp_support_drc(tfa, &bSupportDrc); + if (error != Tfa98xx_Error_Ok) + return error; + + if (bSupportDrc) { + /* Need to set AgcGainInsert back to PRE, + * as the SetConfig forces it to POST */ + uint8_t bytes[3] = { 0, 0, 0 }; + + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_AGCINS, + 3, + bytes); + } + + return error; +} + +/* load all the parameters for the DRC settings from a file */ +enum Tfa98xx_Error tfa98xx_dsp_write_drc(struct tfa_device *tfa, + int length, const unsigned char *p_drc_bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + if (p_drc_bytes != NULL) { + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_DRC, length, + p_drc_bytes); + + } else { + error = Tfa98xx_Error_Bad_Parameter; + } + return error; +} + +enum Tfa98xx_Error tfa98xx_powerdown(struct tfa_device *tfa, int powerdown) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + error = TFA_SET_BF(tfa, PWDN, (uint16_t)powerdown); + + if (powerdown) { + /* Workaround for ticket PLMA5337 */ + if (tfa->tfa_family == 2) { + TFA_SET_BF_VOLATILE(tfa, AMPE, 0); + } + } + + return error; +} + +enum Tfa98xx_Error + tfa98xx_select_mode(struct tfa_device *tfa, enum Tfa98xx_Mode mode) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (error == Tfa98xx_Error_Ok) { + switch (mode) { + + default: + error = Tfa98xx_Error_Bad_Parameter; + } + } + + return error; +} + +int tfa_set_bf(struct tfa_device *tfa, const uint16_t bf, const uint16_t value) +{ + enum Tfa98xx_Error err; + uint16_t regvalue, msk, oldvalue; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) { + pr_err("Error getting bf :%d \n", -err); + return -err; + } + + oldvalue = regvalue; + msk = ((1 << (len + 1)) - 1) << pos; + regvalue &= ~msk; + regvalue |= value << pos; + + /* Only write when the current register value is not the same as the new value */ + if (oldvalue != regvalue) { + err = reg_write(tfa, address, regvalue); + if (err) { + pr_err("Error setting bf :%d \n", -err); + return -err; + } + } + + return 0; +} + +int tfa_set_bf_volatile(struct tfa_device *tfa, const uint16_t bf, const uint16_t value) +{ + enum Tfa98xx_Error err; + uint16_t regvalue, msk; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) { + pr_err("Error getting bf :%d \n", -err); + return -err; + } + + msk = ((1 << (len + 1)) - 1) << pos; + regvalue &= ~msk; + regvalue |= value << pos; + + err = reg_write(tfa, address, regvalue); + if (err) { + pr_err("Error setting bf :%d \n", -err); + return -err; + } + + return 0; +} + +int tfa_get_bf(struct tfa_device *tfa, const uint16_t bf) +{ + enum Tfa98xx_Error err; + uint16_t regvalue, msk; + uint16_t value; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) { + pr_err("Error getting bf :%d \n", -err); + return -err; + } + + msk = ((1 << (len + 1)) - 1) << pos; + regvalue &= msk; + value = regvalue >> pos; + + return value; +} + +int tfa_set_bf_value(const uint16_t bf, const uint16_t bf_value, uint16_t *p_reg_value) +{ + uint16_t regvalue, msk; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + + regvalue = *p_reg_value; + + msk = ((1 << (len + 1)) - 1) << pos; + regvalue &= ~msk; + regvalue |= bf_value << pos; + + *p_reg_value = regvalue; + + return 0; +} + +uint16_t tfa_get_bf_value(const uint16_t bf, const uint16_t reg_value) +{ + uint16_t msk, value; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + + msk = ((1 << (len + 1)) - 1) << pos; + value = (reg_value & msk) >> pos; + + return value; +} + + +int tfa_write_reg(struct tfa_device *tfa, const uint16_t bf, const uint16_t reg_value) +{ + enum Tfa98xx_Error err; + + /* bitfield enum - 8..15 : address */ + uint8_t address = (bf >> 8) & 0xff; + + err = reg_write(tfa, address, reg_value); + if (err) + return -err; + + return 0; +} + +int tfa_read_reg(struct tfa_device *tfa, const uint16_t bf) +{ + enum Tfa98xx_Error err; + uint16_t regvalue; + + /* bitfield enum - 8..15 : address */ + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) + return -err; + + return regvalue; +} + +/* + * powerup the coolflux subsystem and wait for it + */ +enum Tfa98xx_Error tfa_cf_powerup(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int tries, status; + + /* power on the sub system */ + TFA_SET_BF_VOLATILE(tfa, PWDN, 0); + + // wait until everything is stable, in case clock has been off + if (tfa->verbose) + pr_info("Waiting for DSP system stable...\n"); + for (tries = CFSTABLE_TRIES; tries > 0; tries--) { + err = tfa98xx_dsp_system_stable(tfa, &status); + _ASSERT(err == Tfa98xx_Error_Ok); + if (status) + break; + else + msleep_interruptible(10); /* wait 10ms to avoid busload */ + } + if (tries == 0) {// timedout + pr_err("DSP subsystem start timed out\n"); + return Tfa98xx_Error_StateTimedOut; + } + + return err; +} + +/* + * Enable/Disable the I2S output for TFA1 devices + * without TDM interface + */ +static enum Tfa98xx_Error tfa98xx_aec_output(struct tfa_device *tfa, int enable) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if ((tfa->daimap & Tfa98xx_DAI_TDM) == Tfa98xx_DAI_TDM) + return err; + + if (tfa->tfa_family == 1) + err = -tfa_set_bf(tfa, TFA1_BF_I2SDOE, (enable != 0)); + else { + pr_err("I2SDOE on unsupported family\n"); + err = Tfa98xx_Error_Not_Supported; + } + + return err; +} + +/* + * Print the current state of the hardware manager + * Device manager status information, man_state from TFA9888_N1B_I2C_regmap_V12 + */ +int is_94_N2_device(struct tfa_device *tfa) +{ + return ((((tfa->rev) & 0xff) == 0x94) && (((tfa->rev >> 8) & 0xff) > 0x1a)); +} +enum Tfa98xx_Error show_current_state(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int manstate = -1; + + if (tfa->tfa_family == 2 && tfa->verbose) { + if (is_94_N2_device(tfa)) + manstate = tfa_get_bf(tfa, TFA9894N2_BF_MANSTATE); + else + manstate = TFA_GET_BF(tfa, MANSTATE); + if (manstate < 0) + return -manstate; + + pr_debug("Current HW manager state: "); + + switch (manstate) { + case 0: + pr_debug("power_down_state \n"); + break; + case 1: + pr_debug("wait_for_source_settings_state \n"); + break; + case 2: + pr_debug("connnect_pll_input_state \n"); + break; + case 3: + pr_debug("disconnect_pll_input_state \n"); + break; + case 4: + pr_debug("enable_pll_state \n"); + break; + case 5: + pr_debug("enable_cgu_state \n"); + break; + case 6: + pr_debug("init_cf_state \n"); + break; + case 7: + pr_debug("enable_amplifier_state \n"); + break; + case 8: + pr_debug("alarm_state \n"); + break; + case 9: + pr_debug("operating_state \n"); + break; + case 10: + pr_debug("mute_audio_state \n"); + break; + case 11: + pr_debug("disable_cgu_pll_state \n"); + break; + default: + pr_debug("Unable to find current state \n"); + break; + } + } + + return err; +} + +enum Tfa98xx_Error tfaGetFwApiVersion(struct tfa_device *tfa, unsigned char *pFirmwareVersion) +{ + enum Tfa98xx_Error err = 0; + char cmd_buf[4]; + int cmd_len, res_len; + + if (tfa == NULL) + return Tfa98xx_Error_Bad_Parameter; + if (!tfa->is_probus_device) { + err = mem_read(tfa, FW_VAR_API_VERSION, 1, (int *)pFirmwareVersion); + if (err) { + pr_debug("%s Error: Unable to get API Version from DSP \n", __FUNCTION__); + return err; + } + } else { + cmd_len = 0x03; + + /* GetAPI: Command is 0x00 0x80 0xFE */ + cmd_buf[0] = 0x00; + cmd_buf[1] = 0x80; + cmd_buf[2] = 0xFE; + + /* Write the command.*/ + + err = tfa98xx_write_dsp(tfa, cmd_len, (const char *)cmd_buf); + + /* Read the API Value.*/ + if (err == 0) { + res_len = 3; + err = tfa98xx_read_dsp(tfa, res_len, (unsigned char *)pFirmwareVersion); + + } + } + return err; + +} + + +/* + * start the speakerboost algorithm + * this implies a full system startup when the system was not already started + * + */ +enum Tfa98xx_Error tfaRunSpeakerBoost(struct tfa_device *tfa, int force, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int value; + + if (force) { + err = tfaRunColdStartup(tfa, profile); + if (err) + return err; + } + + /* Returns 1 when device is "cold" and 0 when device is warm */ + value = tfa_is_cold(tfa); + + pr_debug("Startup of device [%s] is a %sstart\n", tfaContDeviceName(tfa->cnt, tfa->dev_idx), value ? "cold" : "warm"); + /* cold start and not tap profile */ + if (value) { + /* Run startup and write all files */ + err = tfaRunSpeakerStartup(tfa, force, profile); + if (err) + return err; + + /* Save the current profile and set the vstep to 0 */ + /* This needs to be overwriten even in CF bypass */ + tfa_dev_set_swprof(tfa, (unsigned short)profile); + tfa_dev_set_swvstep(tfa, 0); + + /* Synchonize I/V delay on 96/97 at cold start */ + if ((tfa->tfa_family == 1) && (tfa->daimap == Tfa98xx_DAI_TDM)) + tfa->sync_iv_delay = 1; + } + + return err; +} + +enum Tfa98xx_Error tfaRunSpeakerStartup(struct tfa_device *tfa, int force, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if (!force) { // in case of force CF already runnning + err = tfaRunStartup(tfa, profile); + PRINT_ASSERT(err); + if (err) + return err; + + /* Startup with CF in bypass then return here */ + if (tfa_cf_enabled(tfa) == 0) + return err; + + /* respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ + if (tfa->ext_dsp == -1) { + err = tfaRunStartDSP(tfa); + if (err) + return err; + } + } + + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1 */ + tfa98xx_auto_copy_mtp_to_iic(tfa); + + err = tfaGetFwApiVersion(tfa, (unsigned char *)&tfa->fw_itf_ver[0]); + if (err) { + pr_debug("[%s] cannot get FWAPI error = %d \n", __FUNCTION__, err); + return err; + } + /* write all the files from the device list */ + err = tfaContWriteFiles(tfa); + if (err) { + pr_debug("[%s] tfaContWriteFiles error = %d \n", __FUNCTION__, err); + return err; + } + + /* write all the files from the profile list (use volumstep 0) */ + err = tfaContWriteFilesProf(tfa, profile, 0); + if (err) { + pr_debug("[%s] tfaContWriteFilesProf error = %d \n", __FUNCTION__, err); + return err; + } + + return err; +} + +/* + * Run calibration + */ +enum Tfa98xx_Error tfaRunSpeakerCalibration(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int calibrateDone; + + /* return if there is no audio running */ + if ((tfa->tfa_family == 2) && TFA_GET_BF(tfa, NOCLK)) + return Tfa98xx_Error_NoClock; + + /* When MTPOTC is set (cal=once) unlock key2 */ + if (TFA_GET_BF(tfa, MTPOTC) == 1) { + tfa98xx_key2(tfa, 0); + } + + /* await calibration, this should return ok */ + err = tfaRunWaitCalibration(tfa, &calibrateDone); + if (err == Tfa98xx_Error_Ok) { + err = tfa_dsp_get_calibration_impedance(tfa); + PRINT_ASSERT(err); + } + + /* When MTPOTC is set (cal=once) re-lock key2 */ + if (TFA_GET_BF(tfa, MTPOTC) == 1) { + tfa98xx_key2(tfa, 1); + } + + return err; +} + +enum Tfa98xx_Error tfaRunColdboot(struct tfa_device *tfa, int state) +{ +#define CF_CONTROL 0x8100 + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int tries = 10; + + /* repeat set ACS bit until set as requested */ + while (state != TFA_GET_BF(tfa, ACS)) { + /* set colstarted in CF_CONTROL to force ACS */ + err = mem_write(tfa, CF_CONTROL, state, Tfa98xx_DMEM_IOMEM); + PRINT_ASSERT(err); + + if (tries-- == 0) { + pr_debug("coldboot (ACS) did not %s\n", state ? "set" : "clear"); + return Tfa98xx_Error_Other; + } + } + + return err; +} + + + +/* + * load the patch if any + * else tell no loaded + */ +static enum Tfa98xx_Error tfa_run_load_patch(struct tfa_device *tfa) +{ + return tfaContWritePatch(tfa); +} + +/* + * this will load the patch witch will implicitly start the DSP + * if no patch is available the DPS is started immediately + */ +enum Tfa98xx_Error tfaRunStartDSP(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + err = tfa_run_load_patch(tfa); + if (err) { /* patch load is fatal so return immediately*/ + return err; + } + + /* Clear count_boot, should be reset to 0 before the DSP reset is released */ + err = mem_write(tfa, 512, 0, Tfa98xx_DMEM_XMEM); + PRINT_ASSERT(err); + + /* Reset DSP once for sure after initializing */ + if (err == Tfa98xx_Error_Ok) { + err = tfa98xx_dsp_reset(tfa, 0); + PRINT_ASSERT(err); + } + + /* Sample rate is needed to set the correct tables */ + err = tfa98xx_dsp_write_tables(tfa, TFA_GET_BF(tfa, AUDFS)); + PRINT_ASSERT(err); + + return err; +} + +/* + * start the clocks and wait until the AMP is switching + * on return the DSP sub system will be ready for loading + */ +enum Tfa98xx_Error tfaRunStartup(struct tfa_device *tfa, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + int i, noinit = 0, audfs = 0, fractdel = 0; + + if (dev == NULL) + return Tfa98xx_Error_Fail; + + if (dev->bus) /* no i2c device, do nothing */ + return Tfa98xx_Error_Ok; + + /* process the device list to see if the user implemented the noinit */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscNoInit) { + noinit = 1; + break; + } + } + + if (!noinit) { + /* Read AUDFS & FRACTDEL prior to (re)init. */ + audfs = TFA_GET_BF(tfa, AUDFS); + fractdel = TFA_GET_BF(tfa, FRACTDEL); + /* load the optimal TFA98XX in HW settings */ + err = tfa98xx_init(tfa); + PRINT_ASSERT(err); + + /* Restore audfs & fractdel after coldboot, so we can calibrate with correct fs setting. + * in case something else was given in cnt file, profile below will apply this. */ + TFA_SET_BF(tfa, AUDFS, audfs); + TFA_SET_BF(tfa, FRACTDEL, fractdel); + } else { + pr_debug("\nWarning: No init keyword found in the cnt file. Init is skipped! \n"); + } + + /* I2S settings to define the audio input properties + * these must be set before the subsys is up */ + // this will run the list until a non-register item is encountered + err = tfaContWriteRegsDev(tfa); // write device register settings + PRINT_ASSERT(err); + // also write register the settings from the default profile + // NOTE we may still have ACS=1 so we can switch sample rate here + err = tfaContWriteRegsProf(tfa, profile); + PRINT_ASSERT(err); + + /* Factory trimming for the Boost converter */ + tfa98xx_factory_trimmer(tfa); + + /* Go to the initCF state */ + tfa_dev_set_state(tfa, TFA_STATE_INIT_CF, strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, profile), ".cal") != NULL); + + err = show_current_state(tfa); + + return err; +} + +/* + * run the startup/init sequence and set ACS bit + */ +enum Tfa98xx_Error tfaRunColdStartup(struct tfa_device *tfa, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + err = tfaRunStartup(tfa, profile); + PRINT_ASSERT(err); + if (err) + return err; + + if (!tfa->is_probus_device) { + /* force cold boot */ + err = tfaRunColdboot(tfa, 1); // set ACS + PRINT_ASSERT(err); + if (err) + return err; + } + + /* start */ + err = tfaRunStartDSP(tfa); + PRINT_ASSERT(err); + + return err; +} + +/* + * + */ +enum Tfa98xx_Error tfaRunMute(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int status; + int tries = 0; + + /* signal the TFA98XX to mute */ + if (tfa->tfa_family == 1) { + err = tfa98xx_set_mute(tfa, Tfa98xx_Mute_Amplifier); + + if (err == Tfa98xx_Error_Ok) { + /* now wait for the amplifier to turn off */ + do { + status = TFA_GET_BF(tfa, SWS); + if (status != 0) + msleep_interruptible(10); /* wait 10ms to avoid busload */ + else + break; + tries++; + } while (tries < AMPOFFWAIT_TRIES); + + + if (tfa->verbose) + pr_debug("-------------------- muted --------------------\n"); + + /*The amplifier is always switching*/ + if (tries == AMPOFFWAIT_TRIES) + return Tfa98xx_Error_Other; + } + } + + return err; +} +/* + * + */ +enum Tfa98xx_Error tfaRunUnmute(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + /* signal the TFA98XX to mute */ + err = tfa98xx_set_mute(tfa, Tfa98xx_Mute_Off); + + if (tfa->verbose) + pr_debug("-------------------unmuted ------------------\n"); + + return err; +} + +static void individual_calibration_results(struct tfa_device *tfa) +{ + int value_P, value_S; + + /* Read the calibration result in xmem (529=primary channel) (530=secondary channel) */ + mem_read(tfa, 529, 1, &value_P); + mem_read(tfa, 530, 1, &value_S); + + if (value_P != 1 && value_S != 1) + pr_debug("Calibration failed on both channels! \n"); + else if (value_P != 1) { + pr_debug("Calibration failed on Primary (Left) channel! \n"); + TFA_SET_BF_VOLATILE(tfa, SSLEFTE, 0); /* Disable the sound for the left speaker */ + } else if (value_S != 1) { + pr_debug("Calibration failed on Secondary (Right) channel! \n"); + TFA_SET_BF_VOLATILE(tfa, SSRIGHTE, 0); /* Disable the sound for the right speaker */ + } + + TFA_SET_BF_VOLATILE(tfa, AMPINSEL, 0); /* Set amplifier input to TDM */ + TFA_SET_BF_VOLATILE(tfa, SBSL, 1); +} + +/* + * wait for calibrateDone + */ +enum Tfa98xx_Error tfaRunWaitCalibration(struct tfa_device *tfa, int *calibrateDone) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int tries = 0, mtp_busy = 1, tries_mtp_busy = 0; + + *calibrateDone = 0; + + /* in case of calibrate once wait for MTPEX */ + if (TFA_GET_BF(tfa, MTPOTC)) { + // Check if MTP_busy is clear! + while (tries_mtp_busy < MTPBWAIT_TRIES) { + mtp_busy = tfa_dev_get_mtpb(tfa); + if (mtp_busy == 1) + msleep_interruptible(10); /* wait 10ms to avoid busload */ + else + break; + tries_mtp_busy++; + } + + if (tries_mtp_busy < MTPBWAIT_TRIES) { + /* Because of the msleep TFA98XX_API_WAITRESULT_NTRIES is way to long! + * Setting this to 25 will take it atleast 25*50ms = 1.25 sec + */ + while ((*calibrateDone == 0) && (tries < MTPEX_WAIT_NTRIES)) { + *calibrateDone = TFA_GET_BF(tfa, MTPEX); + if (*calibrateDone == 1) + break; + msleep_interruptible(50); /* wait 50ms to avoid busload */ + tries++; + } + + if (tries >= MTPEX_WAIT_NTRIES) { + tries = TFA98XX_API_WAITRESULT_NTRIES; + } + } else { + pr_err("MTP bussy after %d tries\n", MTPBWAIT_TRIES); + } + } + + /* poll xmem for calibrate always + * calibrateDone = 0 means "calibrating", + * calibrateDone = -1 (or 0xFFFFFF) means "fails" + * calibrateDone = 1 means calibration done + */ + while ((*calibrateDone != 1) && (tries < TFA98XX_API_WAITRESULT_NTRIES)) { + err = mem_read(tfa, TFA_FW_XMEM_CALIBRATION_DONE, 1, calibrateDone); + if (*calibrateDone == -1) + break; + tries++; + } + + if (*calibrateDone != 1) { + pr_err("Calibration failed! \n"); + err = Tfa98xx_Error_Bad_Parameter; + } else if (tries == TFA98XX_API_WAITRESULT_NTRIES) { + pr_debug("Calibration has timedout! \n"); + err = Tfa98xx_Error_StateTimedOut; + } else if (tries_mtp_busy == 1000) { + pr_err("Calibrate Failed: MTP_busy stays high! \n"); + err = Tfa98xx_Error_StateTimedOut; + } + + /* Give reason why calibration failed! */ + if (err != Tfa98xx_Error_Ok) { + if ((tfa->tfa_family == 2) && (TFA_GET_BF(tfa, REFCKSEL) == 1)) { + pr_err("Unable to calibrate the device with the internal clock! \n"); + } + } + + /* Check which speaker calibration failed. Only for 88C */ + if ((err != Tfa98xx_Error_Ok) && ((tfa->rev & 0x0FFF) == 0xc88)) { + individual_calibration_results(tfa); + } + + return err; +} + +/* + * tfa_dev_start will only do the basics: Going from powerdown to operating or a profile switch. + * for calibrating or akoustic shock handling use the tfa98xxCalibration function. + */ +enum tfa_error tfa_dev_start(struct tfa_device *tfa, int next_profile, int vstep) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int active_profile = -1; + + /* Get currentprofile */ + active_profile = tfa_dev_get_swprof(tfa); + if (active_profile == 0xff) + active_profile = -1; + /* TfaRun_SpeakerBoost implies un-mute */ + pr_debug("Active_profile:%s, next_profile:%s\n", + tfaContProfileName(tfa->cnt, tfa->dev_idx, active_profile), + tfaContProfileName(tfa->cnt, tfa->dev_idx, next_profile)); + + err = show_current_state(tfa); + + if (tfa->tfa_family == 1) { /* TODO move this to ini file */ + /* Enable I2S output on TFA1 devices without TDM */ + err = tfa98xx_aec_output(tfa, 1); + if (err != Tfa98xx_Error_Ok) + goto error_exit; + } + + if (tfa->bus != 0) { /* non i2c */ +#ifndef __KERNEL__ + tfadsp_fw_start(tfa, next_profile, vstep); +#endif /* __KERNEL__ */ + } else { + /* Check if we need coldstart or ACS is set */ + err = tfaRunSpeakerBoost(tfa, 0, next_profile); + if (err != Tfa98xx_Error_Ok) + goto error_exit; + + /* Make sure internal oscillator is running for DSP devices (non-dsp and max1 this is no-op) */ + tfa98xx_set_osc_powerdown(tfa, 0); + + /* Go to the Operating state */ + tfa_dev_set_state(tfa, TFA_STATE_OPERATING | TFA_STATE_MUTE, 0); + } + active_profile = tfa_dev_get_swprof(tfa); + + /* Profile switching */ + if ((next_profile != active_profile && active_profile >= 0)) { + err = tfaContWriteProfile(tfa, next_profile, vstep); + if (err != Tfa98xx_Error_Ok) + goto error_exit; + } + + /* If the profile contains the .standby suffix go to powerdown + * else we should be in operating state + */ + if (strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, next_profile), ".standby") != NULL) { + tfa_dev_set_swprof(tfa, (unsigned short)next_profile); + tfa_dev_set_swvstep(tfa, (unsigned short)vstep); + goto error_exit; + } + + err = show_current_state(tfa); + + if ((TFA_GET_BF(tfa, CFE) != 0) && (vstep != tfa->vstep) && (vstep != -1)) { + err = tfaContWriteFilesVstep(tfa, next_profile, vstep); + if (err != Tfa98xx_Error_Ok) + goto error_exit; + } + + + /* Always search and apply filters after a startup */ + err = tfa_set_filters(tfa, next_profile); + if (err != Tfa98xx_Error_Ok) + goto error_exit; + + tfa_dev_set_swprof(tfa, (unsigned short)next_profile); + tfa_dev_set_swvstep(tfa, (unsigned short)vstep); + + /* PLMA5539: Gives information about current setting of powerswitch */ + if (tfa->verbose) { + if (!tfa98xx_powerswitch_is_enabled(tfa)) + pr_info("Device start without powerswitch enabled!\n"); + } + +error_exit: + show_current_state(tfa); + + return (enum tfa_error)err; +} + +enum tfa_error tfa_dev_stop(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + /* mute */ + tfaRunMute(tfa); + + /* Make sure internal oscillator is not running for DSP devices (non-dsp and max1 this is no-op) */ + tfa98xx_set_osc_powerdown(tfa, 1); + + /* powerdown CF */ + err = tfa98xx_powerdown(tfa, 1); + if (err != Tfa98xx_Error_Ok) + return (enum tfa_error)err; + + /* disable I2S output on TFA1 devices without TDM */ + err = tfa98xx_aec_output(tfa, 0); + + return (enum tfa_error)err; +} + +/* + * int registers and coldboot dsp + */ +int tfa_reset(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int state = -1; + int retry_cnt = 0; + + /* Check device state. Print warning if reset is done from other state than powerdown (when verbose) */ + state = tfa_dev_get_state(tfa); + if (tfa->verbose) { + if (((tfa->tfa_family == 1) && state != TFA_STATE_RESET) || + ((tfa->tfa_family == 2) && state != TFA_STATE_POWERDOWN)) { + pr_info("WARNING: Device reset should be performed in POWERDOWN state\n"); + } + } + + /* Split TFA1 behavior from TFA2*/ + if (tfa->tfa_family == 1) { + err = TFA_SET_BF(tfa, I2CR, 1); + if (err) + return err; + err = tfa98xx_powerdown(tfa, 0); + if (err) + return err; + err = tfa_cf_powerup(tfa); + if (err) + return err; + err = tfaRunColdboot(tfa, 1); + if (err) + return err; + err = TFA_SET_BF(tfa, I2CR, 1); + } else { + /* Probus devices needs extra protection to ensure proper reset + behavior, this step is valid only in state other than powerdown */ + if (tfa->is_probus_device && state != TFA_STATE_POWERDOWN) { + err = TFA_SET_BF_VOLATILE(tfa, AMPE, 0); + if (err) + return err; + err = tfa98xx_powerdown(tfa, 1); + if (err) + return err; + } + + err = TFA_SET_BF_VOLATILE(tfa, I2CR, 1); + if (err) + return err; + + /* Restore MANSCONF to POR state */ + err = TFA_SET_BF_VOLATILE(tfa, MANSCONF, 0); + if (err) + return err; + + /* Probus devices HW are already reseted here, + Last step is to send init message to softDSP */ + if (tfa->is_probus_device) { + if (tfa->ext_dsp > 0) { + err = tfa98xx_init_dsp(tfa); + /* ext_dsp status from warm to cold after reset */ + if (tfa->ext_dsp == 2) { + tfa->ext_dsp = 1; + } + } + } else { + /* Restore MANCOLD to POR state */ + TFA_SET_BF_VOLATILE(tfa, MANCOLD, 1); + + /* Coolflux has to be powered on to ensure proper ACS + bit state */ + + /* Powerup CF to access CF io */ + err = tfa98xx_powerdown(tfa, 0); + if (err) + return err; + + /* For clock */ + err = tfa_cf_powerup(tfa); + if (err) + return err; + + /* Force cold boot */ + err = tfaRunColdboot(tfa, 1); /* Set ACS */ + if (err) + return err; + + /* Set PWDN = 1, this will transfer device into powerdown state */ + err = TFA_SET_BF_VOLATILE(tfa, PWDN, 1); + if (err) + return err; + + /* 88 needs SBSL on top of PWDN bit to start transition, + for 92 and 94 this doesn't matter */ + err = TFA_SET_BF_VOLATILE(tfa, SBSL, 1); + if (err) + return err; + + /* Powerdown state should be reached within 1ms */ + for (retry_cnt = 0; retry_cnt < TFA98XX_WAITRESULT_NTRIES; retry_cnt++) { + if (is_94_N2_device(tfa)) + state = tfa_get_bf(tfa, TFA9894N2_BF_MANSTATE); + else + state = TFA_GET_BF(tfa, MANSTATE); + if (state < 0) { + return err; + } + + /* Check for MANSTATE=Powerdown (0) */ + if (state == 0) + break; + msleep_interruptible(2); + } + + /* Reset all I2C registers to default values, + now device state is consistent, same as after powerup */ + err = TFA_SET_BF(tfa, I2CR, 1); + } + } + + return err; +} + +/* + * Write all the bytes specified by num_bytes and data + */ +enum Tfa98xx_Error + tfa98xx_write_data(struct tfa_device *tfa, + unsigned char subaddress, int num_bytes, + const unsigned char data[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + /* subaddress followed by data */ + const int bytes2write = num_bytes + 1; + unsigned char *write_data; + + if (num_bytes > TFA2_MAX_PARAM_SIZE) + return Tfa98xx_Error_Bad_Parameter; + + write_data = (unsigned char *)kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (write_data == NULL) + return Tfa98xx_Error_Fail; + + write_data[0] = subaddress; + memcpy(&write_data[1], data, num_bytes); + + error = tfa98xx_write_raw(tfa, bytes2write, write_data); + + kmem_cache_free(tfa->cachep, write_data); + return error; +} + +/* + * fill the calibration value as milli ohms in the struct + * + * assume that the device has been calibrated + */ +enum Tfa98xx_Error tfa_dsp_get_calibration_impedance(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned char bytes[3 * 2] = { 0 }; + int nr_bytes, i, data[2], calibrateDone, spkr_count = 0, cal_idx = 0; + unsigned int scaled_data; + int tries = 0; + + error = tfa_supported_speakers(tfa, &spkr_count); + + if (tfa_dev_mtp_get(tfa, TFA_MTP_OTC)) { + pr_debug("Getting calibration values from MTP\n"); + + if ((tfa->rev & 0xFF) == 0x88) { + for (i = 0; i < spkr_count; i++) { + if (i == 0) + tfa->mohm[i] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25_PRIM); + else + tfa->mohm[i] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25_SEC); + } + } else { + tfa->mohm[0] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25); + } + } else { + pr_debug("Getting calibration values from Speakerboost\n"); + + /* Make sure the calibrateDone bit is set before getting the values from speakerboost! + * This does not work for 72 (because the dsp cannot set this bit) + */ + if (!tfa->is_probus_device) { + /* poll xmem for calibrate always + * calibrateDone = 0 means "calibrating", + * calibrateDone = -1 (or 0xFFFFFF) means "fails" + * calibrateDone = 1 means calibration done + */ + calibrateDone = 0; + while ((calibrateDone != 1) && (tries < TFA98XX_API_WAITRESULT_NTRIES)) { + error = mem_read(tfa, TFA_FW_XMEM_CALIBRATION_DONE, 1, &calibrateDone); + if (calibrateDone == 1) + break; + tries++; + } + + if (calibrateDone != 1) { + pr_err("Calibration failed! \n"); + error = Tfa98xx_Error_Bad_Parameter; + } else if (tries == TFA98XX_API_WAITRESULT_NTRIES) { + pr_debug("Calibration has timedout! \n"); + error = Tfa98xx_Error_StateTimedOut; + } + } + /* SoftDSP interface differs from hw-dsp interfaces */ + if (tfa->is_probus_device && tfa->cnt->ndev > 1) { + spkr_count = tfa->cnt->ndev; + } + + nr_bytes = spkr_count * 3; + error = tfa_dsp_cmd_id_write_read(tfa, MODULE_SPEAKERBOOST, SB_PARAM_GET_RE25C, nr_bytes, bytes); + if (error == Tfa98xx_Error_Ok) { + tfa98xx_convert_bytes2data(nr_bytes, bytes, data); + + for (i = 0; i < spkr_count; i++) { + + /* for probus devices, calibration values coming from soft-dsp speakerboost, + are ordered in a different way. Re-align to standard representation. */ + cal_idx = i; + if ((tfa->is_probus_device && tfa->dev_idx >= 1)) { + cal_idx = 0; + } + + /* signed data has a limit of 30 Ohm */ + scaled_data = data[i]; + + if (tfa->tfa_family == 2) + tfa->mohm[cal_idx] = (scaled_data * 1000) / TFA2_FW_ReZ_SCALE; + else + tfa->mohm[cal_idx] = (scaled_data * 1000) / TFA1_FW_ReZ_SCALE; + } + } + } + + return error; +} + +/* start count from 1, 0 is invalid */ +int tfa_dev_get_swprof(struct tfa_device *tfa) +{ + return (tfa->dev_ops.get_swprof)(tfa); +} + +int tfa_dev_set_swprof(struct tfa_device *tfa, unsigned short new_value) +{ + return (tfa->dev_ops.set_swprof)(tfa, new_value + 1); +} + +/* same value for all channels + * start count from 1, 0 is invalid */ +int tfa_dev_get_swvstep(struct tfa_device *tfa) +{ + return (tfa->dev_ops.get_swvstep)(tfa); +} + +int tfa_dev_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + return (tfa->dev_ops.set_swvstep)(tfa, new_value + 1); +} + +/* + function overload for MTPB + */ +int tfa_dev_get_mtpb(struct tfa_device *tfa) +{ + return (tfa->dev_ops.get_mtpb)(tfa); +} + +int tfa_is_cold(struct tfa_device *tfa) +{ + int value; + + /* + * check for cold boot status + */ + if (tfa->is_probus_device) { + if (tfa->ext_dsp > 0) { + if (tfa->ext_dsp == 2) + value = 0; // warm + else /* no dsp or cold */ + value = 1; // cold + } else { + value = (TFA_GET_BF(tfa, MANSCONF) == 0); + } + } else { + value = TFA_GET_BF(tfa, ACS); + } + + return value; +} + +int tfa_needs_reset(struct tfa_device *tfa) +{ + int value; + + /* checks if the DSP commands SetAlgoParams and SetMBDrc + * need a DSP reset (now: at coldstart or during calibration) + */ + if (tfa_is_cold(tfa) == 1 || tfa->needs_reset == 1) + value = 1; + else + value = 0; + + return value; +} + +int tfa_cf_enabled(struct tfa_device *tfa) +{ + int value; + + /* For 72 there is no CF */ + if (tfa->is_probus_device) { + value = (tfa->ext_dsp != 0); + } else { + value = TFA_GET_BF(tfa, CFE); + } + + return value; +} + +#define NR_COEFFS 6 +#define NR_BIQUADS 28 +#define BQ_SIZE (3 * NR_COEFFS) +#define DSP_MSG_OVERHEAD 27 + +#pragma pack (push, 1) +struct dsp_msg_all_coeff { + uint8_t select_eq[3]; + uint8_t biquad[NR_BIQUADS][NR_COEFFS][3]; +}; +#pragma pack (pop) + +/* number of biquads for each equalizer */ +static const int eq_biquads[] = { + 10, 10, 2, 2, 2, 2 +}; + +#define NR_EQ (int)(sizeof(eq_biquads) / sizeof(int)) + +enum Tfa98xx_Error dsp_partial_coefficients(struct tfa_device *tfa, uint8_t *prev, uint8_t *next) +{ + uint8_t bq, eq; + int eq_offset; + int new_cost, old_cost; + uint32_t eq_biquad_mask[NR_EQ]; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + struct dsp_msg_all_coeff *data1 = (struct dsp_msg_all_coeff *)prev; + struct dsp_msg_all_coeff *data2 = (struct dsp_msg_all_coeff *)next; + + old_cost = DSP_MSG_OVERHEAD + 3 + sizeof(struct dsp_msg_all_coeff); + new_cost = 0; + + eq_offset = 0; + for (eq = 0; eq < NR_EQ; eq++) { + uint8_t *eq1 = &data1->biquad[eq_offset][0][0]; + uint8_t *eq2 = &data2->biquad[eq_offset][0][0]; + + eq_biquad_mask[eq] = 0; + + if (memcmp(eq1, eq2, BQ_SIZE*eq_biquads[eq]) != 0) { + int nr_bq = 0; + int bq_sz, eq_sz; + + for (bq = 0; bq < eq_biquads[eq]; bq++) { + uint8_t *bq1 = &eq1[bq*BQ_SIZE]; + uint8_t *bq2 = &eq2[bq*BQ_SIZE]; + + if (memcmp(bq1, bq2, BQ_SIZE) != 0) { + eq_biquad_mask[eq] |= (1 << bq); + nr_bq++; + } + } + + bq_sz = (2 * 3 + BQ_SIZE) * nr_bq; + eq_sz = 2 * 3 + BQ_SIZE * eq_biquads[eq]; + + /* dsp message i2c transaction overhead */ + bq_sz += DSP_MSG_OVERHEAD * nr_bq; + eq_sz += DSP_MSG_OVERHEAD; + + if (bq_sz >= eq_sz) { + eq_biquad_mask[eq] = 0xffffffff; + + new_cost += eq_sz; + + } else { + new_cost += bq_sz; + } + } + pr_debug("eq_biquad_mask[%d] = 0x%.8x\n", eq, eq_biquad_mask[eq]); + + eq_offset += eq_biquads[eq]; + } + + pr_debug("cost for writing all coefficients = %d\n", old_cost); + pr_debug("cost for writing changed coefficients = %d\n", new_cost); + + if (new_cost >= old_cost) { + const int buffer_sz = 3 + sizeof(struct dsp_msg_all_coeff); + uint8_t *buffer; + + buffer = kmalloc(buffer_sz, GFP_KERNEL); + if (buffer == NULL) + return Tfa98xx_Error_Fail; + + /* cmd id */ + buffer[0] = 0x00; + buffer[1] = 0x82; + buffer[2] = 0x00; + + /* parameters */ + memcpy(&buffer[3], data2, sizeof(struct dsp_msg_all_coeff)); + + err = dsp_msg(tfa, buffer_sz, (const char *)buffer); + + kfree(buffer); + if (err) + return err; + + } else { + eq_offset = 0; + for (eq = 0; eq < NR_EQ; eq++) { + uint8_t *eq2 = &data2->biquad[eq_offset][0][0]; + + if (eq_biquad_mask[eq] == 0xffffffff) { + const int msg_sz = 6 + BQ_SIZE * eq_biquads[eq]; + uint8_t *msg; + + msg = kmalloc(msg_sz, GFP_KERNEL); + if (msg == NULL) + return Tfa98xx_Error_Fail; + + /* cmd id */ + msg[0] = 0x00; + msg[1] = 0x82; + msg[2] = 0x00; + + /* select eq and bq */ + msg[3] = 0x00; + msg[4] = eq + 1; + msg[5] = 0x00; /* all biquads */ + + /* biquad parameters */ + memcpy(&msg[6], eq2, BQ_SIZE * eq_biquads[eq]); + + err = dsp_msg(tfa, msg_sz, (const char *)msg); + + kfree(msg); + if (err) + return err; + + } else if (eq_biquad_mask[eq] != 0) { + for (bq = 0; bq < eq_biquads[eq]; bq++) { + + if (eq_biquad_mask[eq] & (1 << bq)) { + uint8_t *bq2 = &eq2[bq*BQ_SIZE]; + const int msg_sz = 6 + BQ_SIZE; + uint8_t *msg; + + msg = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (msg == NULL) + return Tfa98xx_Error_Fail; + + /* cmd id */ + msg[0] = 0x00; + msg[1] = 0x82; + msg[2] = 0x00; + + /* select eq and bq*/ + msg[3] = 0x00; + msg[4] = eq + 1; + msg[5] = bq + 1; + + /* biquad parameters */ + memcpy(&msg[6], bq2, BQ_SIZE); + + err = dsp_msg(tfa, msg_sz, (const char *)msg); + + kmem_cache_free(tfa->cachep, msg); + if (err) + return err; + } + } + } + eq_offset += eq_biquads[eq]; + } + } + + return err; +} + +/* fill context info */ +int tfa_dev_probe(int slave, struct tfa_device *tfa) +{ + uint16_t rev; + + tfa->slave_address = (unsigned char)slave; + + /* read revid via low level hal, register 3 */ + if (tfa98xx_read_register16(tfa, 3, &rev) != Tfa98xx_Error_Ok) { + PRINT("\nError: Unable to read revid from slave:0x%02x \n", slave); + return ERR; + } + + tfa->rev = rev; + tfa->dev_idx = -1; + tfa->state = TFA_STATE_UNKNOWN; + tfa->p_regInfo = NULL; + + tfa_set_query_info(tfa); + + tfa->in_use = 1; + + return 0; +} + +enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state, int is_calibration) +{ + enum tfa_error err = tfa_error_ok; + int loop = 50, ready = 0; + int count; + + /* Base states */ + /* Do not change the order of setting bits as this is important! */ + switch (state & 0x0f) { + case TFA_STATE_POWERDOWN: /* PLL in powerdown, Algo up */ + break; + case TFA_STATE_INIT_HW: /* load I2C/PLL hardware setting (~wait2srcsettings) */ + break; + case TFA_STATE_INIT_CF: /* coolflux HW access possible (~initcf) */ + /* Start with SBSL=0 to stay in initCF state */ + if (!tfa->is_probus_device) + TFA_SET_BF(tfa, SBSL, 0); + + /* We want to leave Wait4SrcSettings state for max2 */ + if (tfa->tfa_family == 2) + TFA_SET_BF(tfa, MANSCONF, 1); + + /* And finally set PWDN to 0 to leave powerdown state */ + TFA_SET_BF(tfa, PWDN, 0); + + /* Make sure the DSP is running! */ + do { + err = (enum tfa_error)tfa98xx_dsp_system_stable(tfa, + &ready); + if (err != tfa_error_ok) + return err; + if (ready) + break; + } while (loop--); + if (((!tfa->is_probus_device) && (is_calibration)) || ((tfa->rev & 0xff) == 0x13)) { + /* Enable FAIM when clock is stable, to avoid MTP corruption */ + err = (enum tfa_error)tfa98xx_faim_protect(tfa, 1); + if (tfa->verbose) { + pr_debug("FAIM enabled (err:%d).\n", err); + } + } + break; + case TFA_STATE_INIT_FW: /* DSP framework active (~patch loaded) */ + break; + case TFA_STATE_OPERATING: /* Amp and Algo running */ + /* Depending on our previous state we need to set 3 bits */ + TFA_SET_BF(tfa, PWDN, 0); /* Coming from state 0 */ + TFA_SET_BF(tfa, MANSCONF, 1); /* Coming from state 1 */ + if (!tfa->is_probus_device) + TFA_SET_BF(tfa, SBSL, 1); /* Coming from state 6 */ + else + TFA_SET_BF(tfa, AMPE, 1); /* No SBSL for probus device, we set AMPE to 1 */ + + /* + * Disable MTP clock to protect memory. + * However in case of calibration wait for DSP! (This should be case only during calibration). + */ + if (TFA_GET_BF(tfa, MTPOTC) == 1 && tfa->tfa_family == 2) { + count = MTPEX_WAIT_NTRIES * 4; /* Calibration takes a lot of time */ + while ((TFA_GET_BF(tfa, MTPEX) != 1) && count) { + msleep_interruptible(10); + count--; + } + } + if (((!tfa->is_probus_device) && (is_calibration)) || ((tfa->rev & 0xff) == 0x13)) { + err = (enum tfa_error)tfa98xx_faim_protect(tfa, 0); + if (tfa->verbose) { + pr_debug("FAIM disabled (err:%d).\n", err); + } + } + /* Synchonize I/V delay on 96/97 at cold start */ + if (tfa->sync_iv_delay) { + if (tfa->verbose) + pr_debug("syncing I/V delay for %x\n", + (tfa->rev & 0xff)); + + /* wait for ACS to be cleared */ + count = 10; + while ((TFA_GET_BF(tfa, ACS) == 1) && + (count-- > 0)) { + msleep_interruptible(1); + } + + tfa98xx_dsp_reset(tfa, 1); + tfa98xx_dsp_reset(tfa, 0); + tfa->sync_iv_delay = 0; + } + break; + case TFA_STATE_FAULT: /* An alarm or error occurred */ + break; + case TFA_STATE_RESET: /* I2C reset and ACS set */ + tfa98xx_init(tfa); + break; + default: + if (state & 0x0f) + return tfa_error_bad_param; + } + + /* state modifiers */ + + if (state & TFA_STATE_MUTE) + tfa98xx_set_mute(tfa, Tfa98xx_Mute_Amplifier); + + if (state & TFA_STATE_UNMUTE) + tfa98xx_set_mute(tfa, Tfa98xx_Mute_Off); + + tfa->state = state; + + return tfa_error_ok; +} + +enum tfa_state tfa_dev_get_state(struct tfa_device *tfa) +{ + int cold = 0; + int manstate; + + /* different per family type */ + if (tfa->tfa_family == 1) { + cold = TFA_GET_BF(tfa, ACS); + if (cold && TFA_GET_BF(tfa, PWDN)) + tfa->state = TFA_STATE_RESET; + else if (!cold && TFA_GET_BF(tfa, SWS)) + tfa->state = TFA_STATE_OPERATING; + } else /* family 2 */ { + if (is_94_N2_device(tfa)) + manstate = tfa_get_bf(tfa, TFA9894N2_BF_MANSTATE); + else + manstate = TFA_GET_BF(tfa, MANSTATE); + switch (manstate) { + case 0: + tfa->state = TFA_STATE_POWERDOWN; + break; + case 8: /* if dsp reset if off assume framework is running */ + tfa->state = TFA_GET_BF(tfa, RST) ? TFA_STATE_INIT_CF : TFA_STATE_INIT_FW; + break; + case 9: + tfa->state = TFA_STATE_OPERATING; + break; + default: + break; + } + } + + return tfa->state; +} + +int tfa_dev_mtp_get(struct tfa_device *tfa, enum tfa_mtp item) +{ + int value = 0; + + switch (item) { + case TFA_MTP_OTC: + value = TFA_GET_BF(tfa, MTPOTC); + break; + case TFA_MTP_EX: + value = TFA_GET_BF(tfa, MTPEX); + break; + case TFA_MTP_RE25: + case TFA_MTP_RE25_PRIM: + if (tfa->tfa_family == 2) { + if ((tfa->rev & 0xFF) == 0x88) + value = TFA_GET_BF(tfa, R25CL); + else if ((tfa->rev & 0xFF) == 0x13) + value = tfa_get_bf(tfa, TFA9912_BF_R25C); + else + value = TFA_GET_BF(tfa, R25C); + } else { + reg_read(tfa, 0x83, (unsigned short *)&value); + } + break; + case TFA_MTP_RE25_SEC: + if ((tfa->rev & 0xFF) == 0x88) { + value = TFA_GET_BF(tfa, R25CR); + } else { + pr_debug("Error: Current device has no secondary Re25 channel \n"); + } + break; + case TFA_MTP_LOCK: + break; + } + + return value; +} + +enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, + int value) +{ + enum tfa_error err = tfa_error_ok; + + switch (item) { + case TFA_MTP_OTC: + err = (enum tfa_error)tfa98xx_set_mtp(tfa, (uint16_t)value, + TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK); + break; + case TFA_MTP_EX: + err = (enum tfa_error)tfa98xx_set_mtp(tfa, (uint16_t)value, + TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK); + break; + case TFA_MTP_RE25: + case TFA_MTP_RE25_PRIM: + if (tfa->tfa_family == 2) { + tfa98xx_key2(tfa, 0); /* unlock */ + if ((tfa->rev & 0xFF) == 0x88) + TFA_SET_BF(tfa, R25CL, (uint16_t)value); + else { + if (tfa->is_probus_device == 1 && TFA_GET_BF(tfa, MTPOTC) == 1) + tfa2_manual_mtp_cpy(tfa, 0xF4, value, 2); + TFA_SET_BF(tfa, R25C, (uint16_t)value); + } + tfa98xx_key2(tfa, 1); /* lock */ + } + break; + case TFA_MTP_RE25_SEC: + if ((tfa->rev & 0xFF) == 0x88) { + TFA_SET_BF(tfa, R25CR, (uint16_t)value); + } else { + pr_debug("Error: Current device has no secondary Re25 channel \n"); + err = tfa_error_bad_param; + } + break; + case TFA_MTP_LOCK: + break; + } + + return (enum tfa_error)err; +} + +int tfa_get_pga_gain(struct tfa_device *tfa) +{ + return TFA_GET_BF(tfa, SAAMGAIN); +} + +int tfa_set_pga_gain(struct tfa_device *tfa, uint16_t value) +{ + + return TFA_SET_BF(tfa, SAAMGAIN, value); +} + +int tfa_get_noclk(struct tfa_device *tfa) +{ + return TFA_GET_BF(tfa, NOCLK); +} + + +enum Tfa98xx_Error tfa_status(struct tfa_device *tfa) +{ + int value; + uint16_t val; + + /* + * check IC status bits: cold start + * and DSP watch dog bit to re init + */ + value = TFA_READ_REG(tfa, VDDS); /* STATUSREG */ + if (value < 0) + return -value; + val = (uint16_t)value; + + /* pr_debug("SYS_STATUS0: 0x%04x\n", val); */ + if (TFA_GET_BF_VALUE(tfa, ACS, val) || + TFA_GET_BF_VALUE(tfa, WDS, val)) { + + if (TFA_GET_BF_VALUE(tfa, ACS, val)) + pr_err("ERROR: ACS\n"); + if (TFA_GET_BF_VALUE(tfa, WDS, val)) + pr_err("ERROR: WDS\n"); + + return Tfa98xx_Error_DSP_not_running; + } + + if (TFA_GET_BF_VALUE(tfa, SPKS, val)) + pr_err("ERROR: SPKS\n"); + if (!TFA_GET_BF_VALUE(tfa, SWS, val)) + pr_err("ERROR: SWS\n"); + + /* Check secondary errors */ + if (!TFA_GET_BF_VALUE(tfa, CLKS, val) || + !TFA_GET_BF_VALUE(tfa, UVDS, val) || + !TFA_GET_BF_VALUE(tfa, OVDS, val) || + !TFA_GET_BF_VALUE(tfa, OTDS, val) || + !TFA_GET_BF_VALUE(tfa, PLLS, val) || + (!(tfa->daimap & Tfa98xx_DAI_TDM) && + !TFA_GET_BF_VALUE(tfa, VDDS, val))) + pr_err("Misc errors detected: STATUS_FLAG0 = 0x%x\n", val); + + if ((tfa->daimap & Tfa98xx_DAI_TDM) && (tfa->tfa_family == 2)) { + value = TFA_READ_REG(tfa, TDMERR); /* STATUS_FLAGS1 */ + if (value < 0) + return -value; + val = (uint16_t)value; + if (TFA_GET_BF_VALUE(tfa, TDMERR, val) || + TFA_GET_BF_VALUE(tfa, TDMLUTER, val)) + pr_err("TDM related errors: STATUS_FLAG1 = 0x%x\n", val); + } + + return Tfa98xx_Error_Ok; +} + +int tfa_plop_noise_interrupt(struct tfa_device *tfa, int profile, int vstep) +{ + enum Tfa98xx_Error err; + int no_clk = 0; + + /* Remove sticky bit by reading it once */ + TFA_GET_BF(tfa, NOCLK); + + /* No clock detected */ + if (tfa_irq_get(tfa, tfa9912_irq_stnoclk)) { + no_clk = TFA_GET_BF(tfa, NOCLK); + + /* Detect for clock is lost! (clock is not stable) */ + if (no_clk == 1) { + /* Clock is lost. Set I2CR to remove POP noise */ + pr_info("No clock detected. Resetting the I2CR to avoid pop on 72! \n"); + err = (enum Tfa98xx_Error)tfa_dev_start(tfa, profile, + vstep); + if (err != Tfa98xx_Error_Ok) { + pr_err("Error loading i2c registers (tfa_dev_start), err=%d\n", err); + } else { + pr_info("Setting i2c registers after I2CR succesfull\n"); + tfa_dev_set_state(tfa, TFA_STATE_UNMUTE, 0); + } + + /* Remove sticky bit by reading it once */ + tfa_get_noclk(tfa); + + /* This is only for SAAM on the 72. + Since the NOCLK interrupt is only enabled for 72 this is the place + However: Not tested yet! But also does not harm normal flow! + */ + if (strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, profile), ".saam")) { + pr_info("Powering down from a SAAM profile, workaround PLMA4766 used! \n"); + TFA_SET_BF(tfa, PWDN, 1); + TFA_SET_BF(tfa, AMPE, 0); + TFA_SET_BF(tfa, SAMMODE, 0); + } + } + + /* If clk is stable set polarity to check for LOW (no clock)*/ + tfa_irq_set_pol(tfa, tfa9912_irq_stnoclk, (no_clk == 0)); + + /* clear interrupt */ + tfa_irq_clear(tfa, tfa9912_irq_stnoclk); + } + + /* return no_clk to know we called tfa_dev_start */ + return no_clk; +} + +void tfa_lp_mode_interrupt(struct tfa_device *tfa) +{ + const int irq_stclp0 = 36; /* FIXME: this 72 interrupt does not excist for 9912 */ + int lp0, lp1; + + if (tfa_irq_get(tfa, irq_stclp0)) { + lp0 = TFA_GET_BF(tfa, LP0); + if (lp0 > 0) { + pr_info("lowpower mode 0 detected\n"); + } else { + pr_info("lowpower mode 0 not detected\n"); + } + + tfa_irq_set_pol(tfa, irq_stclp0, (lp0 == 0)); + + /* clear interrupt */ + tfa_irq_clear(tfa, irq_stclp0); + } + + if (tfa_irq_get(tfa, tfa9912_irq_stclpr)) { + lp1 = TFA_GET_BF(tfa, LP1); + if (lp1 > 0) { + pr_info("lowpower mode 1 detected\n"); + } else { + pr_info("lowpower mode 1 not detected\n"); + } + + tfa_irq_set_pol(tfa, tfa9912_irq_stclpr, (lp1 == 0)); + + /* clear interrupt */ + tfa_irq_clear(tfa, tfa9912_irq_stclpr); + } +} diff --git a/sound/soc/codecs/tfa_dsp_fw.h b/sound/soc/codecs/tfa_dsp_fw.h new file mode 100644 index 0000000000000000000000000000000000000000..dd48949c53ab8d3d0dc9d4b87b27728a5040a6f4 --- /dev/null +++ b/sound/soc/codecs/tfa_dsp_fw.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA98XX_INTERNALS_H +#define TFA98XX_INTERNALS_H + +#include "config.h" + +#include "tfa_service.h" //TODO cleanup for enum Tfa98xx_Status_ID + +/** + * Return a text version of the firmware status ID code + * @param status the given status ID code + * @return the firmware status ID string + */ +const char *tfadsp_fw_status_string(enum Tfa98xx_Status_ID status); +int tfadsp_fw_start(struct tfa_device *tfa, int prof_idx, int vstep_idx); +int tfadsp_fw_get_api_version(struct tfa_device *tfa, uint8_t *buffer); +#define FW_MAXTAG 150 +int tfadsp_fw_get_tag(struct tfa_device *tfa, uint8_t *buffer); +int tfadsp_fw_get_status_change(struct tfa_device *tfa, uint8_t *buffer); +int tfadsp_fw_set_re25(struct tfa_device *tfa, int prim, int sec); +int tfadsp_fw_get_re25(struct tfa_device *tfa, uint8_t *buffer); + +/* + * the order matches the ACK bits order in TFA98XX_CF_STATUS + */ +enum tfa_fw_event { /* not all available on each device */ + tfa_fw_i2c_cmd_ack, + tfa_fw_reset_start, + tfa_fw_short_on_mips, + tfa_fw_soft_mute_ready, + tfa_fw_volume_ready, + tfa_fw_error_damage, + tfa_fw_calibrate_done, + tfa_fw_max +}; + +/* the following type mappings are compiler specific */ +#define subaddress_t unsigned char + +/* module Ids */ +#define MODULE_FRAMEWORK 0 +#define MODULE_SPEAKERBOOST 1 +#define MODULE_BIQUADFILTERBANK 2 +#define MODULE_TAPTRIGGER 5 +#define MODULE_SETRE 9 + +/* RPC commands */ +/* SET */ +#define FW_PAR_ID_SET_MEMORY 0x03 +#define FW_PAR_ID_SET_SENSES_DELAY 0x04 +#define FW_PAR_ID_SETSENSESCAL 0x05 +#define FW_PAR_ID_SET_INPUT_SELECTOR 0x06 +#define FW_PAR_ID_SET_OUTPUT_SELECTOR 0x08 +#define FW_PAR_ID_SET_PROGRAM_CONFIG 0x09 +#define FW_PAR_ID_SET_GAINS 0x0A +#define FW_PAR_ID_SET_MEMTRACK 0x0B +#define FW_PAR_ID_SET_FWKUSECASE 0x11 +#define TFA1_FW_PAR_ID_SET_CURRENT_DELAY 0x03 +#define TFA1_FW_PAR_ID_SET_CURFRAC_DELAY 0x06 +/* GET */ +#define FW_PAR_ID_GET_MEMORY 0x83 +#define FW_PAR_ID_GLOBAL_GET_INFO 0x84 +#define FW_PAR_ID_GET_FEATURE_INFO 0x85 +#define FW_PAR_ID_GET_MEMTRACK 0x8B +#define FW_PAR_ID_GET_TAG 0xFF +#define FW_PAR_ID_GET_API_VERSION 0xFE +#define FW_PAR_ID_GET_STATUS_CHANGE 0x8D + +/* Load a full model into SpeakerBoost. */ +/* SET */ +#define SB_PARAM_SET_ALGO_PARAMS 0x00 +#define SB_PARAM_SET_LAGW 0x01 +#define SB_PARAM_SET_ALGO_PARAMS_WITHOUT_RESET 0x02 +#define SB_PARAM_SET_RE25C 0x05 +#define SB_PARAM_SET_LSMODEL 0x06 +#define SB_PARAM_SET_MBDRC 0x07 +#define SB_PARAM_SET_MBDRC_WITHOUT_RESET 0x08 +#define SB_PARAM_SET_EXCURSION_FILTERS 0x0A +#define SB_PARAM_SET_DRC 0x0F +/* GET */ +#define SB_PARAM_GET_ALGO_PARAMS 0x80 +#define SB_PARAM_GET_LAGW 0x81 +#define SB_PARAM_GET_RE25C 0x85 +#define SB_PARAM_GET_LSMODEL 0x86 +#define SB_PARAM_GET_MBDRC 0x87 +#define SB_PARAM_GET_MBDRC_DYNAMICS 0x89 +#define SB_PARAM_GET_EXCURSION_FILTERS 0x8A +#define SB_PARAM_GET_TAG 0xFF + +#define SB_PARAM_SET_EQ 0x0A /* 2 Equaliser Filters. */ +#define SB_PARAM_SET_PRESET 0x0D /* Load a preset */ +#define SB_PARAM_SET_CONFIG 0x0E /* Load a config */ +#define SB_PARAM_SET_AGCINS 0x10 +#define SB_PARAM_SET_CURRENT_DELAY 0x03 +#define SB_PARAM_GET_STATE 0xC0 +#define SB_PARAM_GET_XMODEL 0xC1 /* Gets current Excursion Model. */ +#define SB_PARAM_GET_XMODEL_COEFFS 0x8C /* Get coefficients for XModel */ +#define SB_PARAM_GET_EXCURSION_FILTERS 0x8A /* Get excursion filters */ +#define SB_PARAM_SET_EXCURSION_FILTERS 0x0A /* Set excursion filters */ + +/* SET: TAPTRIGGER */ +#define TAP_PARAM_SET_ALGO_PARAMS 0x01 +#define TAP_PARAM_SET_DECIMATION_PARAMS 0x02 + +/* GET: TAPTRIGGER*/ +#define TAP_PARAM_GET_ALGO_PARAMS 0x81 +#define TAP_PARAM_GET_TAP_RESULTS 0x84 + +/* sets the speaker calibration impedance (@25 degrees celsius) */ +#define SB_PARAM_SET_RE0 0x89 + +#define BFB_PAR_ID_SET_COEFS 0x00 +#define BFB_PAR_ID_GET_COEFS 0x80 +#define BFB_PAR_ID_GET_CONFIG 0x81 + +/* for compatibility */ +#define FW_PARAM_GET_STATE FW_PAR_ID_GLOBAL_GET_INFO +#define FW_PARAM_GET_FEATURE_BITS FW_PAR_ID_GET_FEATURE_BITS + +/* RPC Status results */ +#define STATUS_OK 0 +#define STATUS_INVALID_MODULE_ID 2 +#define STATUS_INVALID_PARAM_ID 3 +#define STATUS_INVALID_INFO_ID 4 + +/* the maximum message length in the communication with the DSP */ +#define TFA2_MAX_PARAM_SIZE (507*3) /* TFA2 */ +#define TFA1_MAX_PARAM_SIZE (145*3) /* TFA1 */ + +#define ROUND_DOWN(a, n) (((a)/(n))*(n)) + +/* feature bits */ +#define FEATURE1_TCOEF 0x100 /* bit8 set means tCoefA expected */ +#define FEATURE1_DRC 0x200 /* bit9 NOT set means DRC expected */ + +/* DSP firmware xmem defines */ +#define TFA1_FW_XMEM_CALIBRATION_DONE 231 +#define TFA2_FW_XMEM_CALIBRATION_DONE 516 +#define TFA1_FW_XMEM_COUNT_BOOT 0xa1 +#define TFA2_FW_XMEM_COUNT_BOOT 512 +#define TFA2_FW_XMEM_CMD_COUNT 520 + +/* note that the following defs rely on the handle variable */ +#define TFA_FW_XMEM_CALIBRATION_DONE TFA_FAM_FW(tfa, XMEM_CALIBRATION_DONE) +#define TFA_FW_XMEM_COUNT_BOOT TFA_FAM_FW(tfa, XMEM_COUNT_BOOT) +#define TFA_FW_XMEM_CMD_COUNT TFA_FAM_FW(tfa, XMEM_CMD_COUNT) + +#define TFA2_FW_ReZ_SCALE 65536 +#define TFA1_FW_ReZ_SCALE 16384 + +#endif /* TFA98XX_INTERNALS_H */ diff --git a/sound/soc/codecs/tfa_ext.h b/sound/soc/codecs/tfa_ext.h new file mode 100644 index 0000000000000000000000000000000000000000..5ded093de4f88e01e95d08a02edd07a5a7e16321 --- /dev/null +++ b/sound/soc/codecs/tfa_ext.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA_SRC_TFA_EXT_H_ +#define TFA_SRC_TFA_EXT_H_ + +#include "tfa_device.h" + +/* + * events + */ +/** Maximum value for enumerator */ +#define LVM_MAXENUM (0xffff) +/** +This enum type specifies the different events that may trigger a callback. +*/ +enum tfadsp_event_en { + TFADSP_CMD_ACK = 1, /**< Command handling is completed */ + TFADSP_SOFT_MUTE_READY = 8, /**< Muting completed */ + TFADSP_VOLUME_READY = 16, /**< Volume change completed */ + TFADSP_DAMAGED_SPEAKER = 32, /**< Damaged speaker was detected */ + TFADSP_CALIBRATE_DONE = 64, /**< Calibration is completed */ + TFADSP_SPARSESIG_DETECTED = 128, /**< Sparse signal detected */ + TFADSP_CMD_READY = 256, /**< Ready to receive commands */ + TFADSP_EXT_PWRUP = 0x8000,/**< DSP API has started, powered up */ + TFADSP_EXT_PWRDOWN = 0x8001,/**< DSP API stopped, power down */ + TFADSP_EVENT_DUMMY = LVM_MAXENUM +} ; + +typedef int (*tfa_event_handler_t)(struct tfa_device *tfa, enum tfadsp_event_en tfadsp_event); +typedef int (*dsp_send_message_t)(struct tfa_device *tfa, int length, const char *buf); +typedef int (*dsp_read_message_t)(struct tfa_device *tfa, int length, char *buf); +typedef int (*dsp_write_reg_t)(struct tfa_device *tfa, unsigned char subaddress, unsigned short value); + +int tfa_ext_register(dsp_write_reg_t tfa_write_reg, dsp_send_message_t tfa_send_message, dsp_read_message_t tfa_read_message, tfa_event_handler_t *tfa_event_handler); + +#endif /* TFA_SRC_TFA_EXT_H_ */ diff --git a/sound/soc/codecs/tfa_init.c b/sound/soc/codecs/tfa_init.c new file mode 100644 index 0000000000000000000000000000000000000000..e004b65223415ec31e0bfbf2513bd5d35621bdb4 --- /dev/null +++ b/sound/soc/codecs/tfa_init.c @@ -0,0 +1,1783 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#include "dbgprint.h" +#include "tfa_service.h" +#include "tfa_internal.h" +#include "tfa_container.h" +#include "tfa98xx_tfafieldnames.h" + + /* The CurrentSense4 registers are not in the datasheet */ +#define TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF (1<<2) +#define TFA98XX_CURRENTSENSE4 0x49 + +/***********************************************************************************/ +/* GLOBAL (Defaults) */ +/***********************************************************************************/ +static enum Tfa98xx_Error no_overload_function_available(struct tfa_device *tfa, int not_used) +{ + (void)tfa; + (void)not_used; + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error no_overload_function_available2(struct tfa_device *tfa) +{ + (void)tfa; + + return Tfa98xx_Error_Ok; +} + +/* tfa98xx_dsp_system_stable +* return: *ready = 1 when clocks are stable to allow DSP subsystem access +*/ +static enum Tfa98xx_Error tfa_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short status; + int value; + + /* check the contents of the STATUS register */ + value = TFA_READ_REG(tfa, AREFS); + if (value < 0) { + error = -value; + *ready = 0; + _ASSERT(error); /* an error here can be fatal */ + return error; + } + status = (unsigned short)value; + + /* check AREFS and CLKS: not ready if either is clear */ + *ready = !((TFA_GET_BF_VALUE(tfa, AREFS, status) == 0) + || (TFA_GET_BF_VALUE(tfa, CLKS, status) == 0)); + + return error; +} + +/* tfa98xx_toggle_mtp_clock + * Allows to stop clock for MTP/FAim needed for PLMA5505 */ +static enum Tfa98xx_Error tfa_faim_protect(struct tfa_device *tfa, int state) +{ + (void)tfa; + (void)state; + + return Tfa98xx_Error_Ok; +} + +/** Set internal oscillator into power down mode. + * + * This function is a worker for tfa98xx_set_osc_powerdown(). + * + * @param[in] tfa device description structure + * @param[in] state new state 0 - oscillator is on, 1 oscillator is off. + * + * @return Tfa98xx_Error_Ok when successfull, error otherwise. + */ +static enum Tfa98xx_Error tfa_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + /* This function has no effect in general case, only for tfa9912 */ + (void)tfa; + (void)state; + + return Tfa98xx_Error_Ok; +} +static enum Tfa98xx_Error tfa_update_lpm(struct tfa_device *tfa, int state) +{ + /* This function has no effect in general case, only for tfa9912 */ + (void)tfa; + (void)state; + + return Tfa98xx_Error_Ok; +} +static enum Tfa98xx_Error tfa_dsp_reset(struct tfa_device *tfa, int state) +{ + /* generic function */ + TFA_SET_BF_VOLATILE(tfa, RST, (uint16_t)state); + + return Tfa98xx_Error_Ok; +} + +int tfa_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int mtpk, active_value = tfa->profile; + + /* Also set the new value in the struct */ + tfa->profile = new_value - 1; + + /* for TFA1 devices */ + /* it's in MTP shadow, so unlock if not done already */ + mtpk = TFA_GET_BF(tfa, MTPK); /* get current key */ + TFA_SET_BF_VOLATILE(tfa, MTPK, 0x5a); + TFA_SET_BF_VOLATILE(tfa, SWPROFIL, new_value); /* set current profile */ + TFA_SET_BF_VOLATILE(tfa, MTPK, (uint16_t)mtpk); /* restore key */ + + return active_value; +} + +static int tfa_get_swprofile(struct tfa_device *tfa) +{ + return tfa->profile; +} + +static int tfa_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + int mtpk, active_value = tfa->vstep; + + /* Also set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* for TFA1 devices */ + /* it's in MTP shadow, so unlock if not done already */ + mtpk = TFA_GET_BF(tfa, MTPK); /* get current key */ + TFA_SET_BF_VOLATILE(tfa, MTPK, 0x5a); + TFA_SET_BF_VOLATILE(tfa, SWVSTEP, new_value); /* set current vstep */ + TFA_SET_BF_VOLATILE(tfa, MTPK, (uint16_t)mtpk); /* restore key */ + + return active_value; +} + +static int tfa_get_swvstep(struct tfa_device *tfa) +{ + int value = 0; + /* Set the new value in the hw register */ + value = TFA_GET_BF(tfa, SWVSTEP); + + /* Also set the new value in the struct */ + tfa->vstep = value - 1; + + return value - 1; /* invalid if 0 */ +} + +static int tfa_get_mtpb(struct tfa_device *tfa) +{ + + int value = 0; + + /* Set the new value in the hw register */ + value = TFA_GET_BF(tfa, MTPB); + + return value; +} + +static enum Tfa98xx_Error +tfa_set_mute_nodsp(struct tfa_device *tfa, int mute) +{ + (void)tfa; + (void)mute; + + return Tfa98xx_Error_Ok; +} + +void set_ops_defaults(struct tfa_device_ops *ops) +{ + /* defaults */ + ops->reg_read = tfa98xx_read_register16; + ops->reg_write = tfa98xx_write_register16; + ops->mem_read = tfa98xx_dsp_read_mem; + ops->mem_write = tfa98xx_dsp_write_mem_word; + ops->dsp_msg = tfa_dsp_msg; + ops->dsp_msg_read = tfa_dsp_msg_read; + ops->dsp_write_tables = no_overload_function_available; + ops->dsp_reset = tfa_dsp_reset; + ops->dsp_system_stable = tfa_dsp_system_stable; + ops->auto_copy_mtp_to_iic = no_overload_function_available2; + ops->factory_trimmer = no_overload_function_available2; + ops->set_swprof = tfa_set_swprofile; + ops->get_swprof = tfa_get_swprofile; + ops->set_swvstep = tfa_set_swvstep; + ops->get_swvstep = tfa_get_swvstep; + ops->get_mtpb = tfa_get_mtpb; + ops->set_mute = tfa_set_mute_nodsp; + ops->faim_protect = tfa_faim_protect; + ops->set_osc_powerdown = tfa_set_osc_powerdown; + ops->update_lpm = tfa_update_lpm; +} + +/***********************************************************************************/ +/* no TFA + * external DSP SB instance */ + /***********************************************************************************/ +static short tfanone_swvstep, swprof; //TODO emulate in hal plugin +static enum Tfa98xx_Error tfanone_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + (void)tfa; /* suppress warning */ + *ready = 1; /* assume always ready */ + + return Tfa98xx_Error_Ok; +} + +static int tfanone_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + swprof = new_value; + + return active_value; +} + +static int tfanone_get_swprofile(struct tfa_device *tfa) +{ + (void)tfa; /* suppress warning */ + return swprof; +} + +static int tfanone_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* Set the new value in the hw register */ + tfanone_swvstep = new_value; + + return new_value; +} + +static int tfanone_get_swvstep(struct tfa_device *tfa) +{ + (void)tfa; /* suppress warning */ + return tfanone_swvstep; +} + +void tfanone_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->dsp_system_stable = tfanone_dsp_system_stable; + ops->set_swprof = tfanone_set_swprofile; + ops->get_swprof = tfanone_get_swprofile; + ops->set_swvstep = tfanone_set_swvstep; + ops->get_swvstep = tfanone_get_swvstep; + +} + +/***********************************************************************************/ +/* TFA9912 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9912_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Fail; + + if (tfa) { + if (status == 0 || status == 1) { + ret = -(tfa_set_bf(tfa, TFA9912_BF_SSFAIME, (uint16_t)status)); + } + } + + return ret; +} + +static enum Tfa98xx_Error tfa9912_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock keys to write settings */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + + /* The optimal settings */ + if (tfa->rev == 0x1a13) { + + /* ----- generated code start ----- */ + /* ----- version 1.43 ----- */ + reg_write(tfa, 0x00, 0x0255); //POR=0x0245 + reg_write(tfa, 0x01, 0x838a); //POR=0x83ca + reg_write(tfa, 0x02, 0x2dc8); //POR=0x2828 + reg_write(tfa, 0x05, 0x762a); //POR=0x766a + reg_write(tfa, 0x22, 0x543c); //POR=0x545c + reg_write(tfa, 0x26, 0x0100); //POR=0x0010 + reg_write(tfa, 0x51, 0x0000); //POR=0x0080 + reg_write(tfa, 0x52, 0x551c); //POR=0x1afc + reg_write(tfa, 0x53, 0x003e); //POR=0x001e + reg_write(tfa, 0x61, 0x000c); //POR=0x0018 + reg_write(tfa, 0x63, 0x0a96); //POR=0x0a9a + reg_write(tfa, 0x65, 0x0a82); //POR=0x0a8b + reg_write(tfa, 0x66, 0x0701); //POR=0x0700 + reg_write(tfa, 0x6c, 0x00d5); //POR=0x02d5 + reg_write(tfa, 0x70, 0x26f8); //POR=0x06e0 + reg_write(tfa, 0x71, 0x3074); //POR=0x2074 + reg_write(tfa, 0x75, 0x4484); //POR=0x4585 + reg_write(tfa, 0x76, 0x72ea); //POR=0x54a2 + reg_write(tfa, 0x83, 0x0716); //POR=0x0617 + reg_write(tfa, 0x89, 0x0013); //POR=0x0014 + reg_write(tfa, 0xb0, 0x4c08); //POR=0x4c00 + reg_write(tfa, 0xc6, 0x004e); //POR=0x000e /* PLMA5539: Please make sure bit 6 is always on! */ + /* ----- generated code end ----- */ + + /* PLMA5505: MTP key open makes vulanable for MTP corruption */ + tfa9912_faim_protect(tfa, 0); + } else { + pr_info("Warning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + } + + return error; +} + +static enum Tfa98xx_Error tfa9912_factory_trimmer(struct tfa_device *tfa) +{ + unsigned short currentValue, delta; + int result; + + /* Factory trimming for the Boost converter */ + /* check if there is a correction needed */ + result = TFA_GET_BF(tfa, DCMCCAPI); + if (result) { + /* Get currentvalue of DCMCC and the Delta value */ + currentValue = (unsigned short)TFA_GET_BF(tfa, DCMCC); + delta = (unsigned short)TFA_GET_BF(tfa, USERDEF); + + /* check the sign bit (+/-) */ + result = TFA_GET_BF(tfa, DCMCCSB); + if (result == 0) { + /* Do not exceed the maximum value of 15 */ + if (currentValue + delta < 15) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue + delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue + delta); + } else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 15); + if (tfa->verbose) + pr_debug("Max coil current is set to: 15 \n"); + } + } else if (result == 1) { + /* Do not exceed the minimum value of 0 */ + if (currentValue - delta > 0) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue - delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue - delta); + } else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 0); + if (tfa->verbose) + pr_debug("Max coil current is set to: 0 \n"); + } + } + } + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error tfa9912_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1. Workaround for 72, 88 and 9912/9892(see PLMA5290) */ + return reg_write(tfa, 0xA3, 0x20); +} + +static int tfa9912_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9912_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9912_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9912_BF_SWPROFIL) - 1; +} + +static int tfa9912_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9912_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9912_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9912_BF_SWVSTEP) - 1; +} + +static enum Tfa98xx_Error +tfa9912_set_mute(struct tfa_device *tfa, int mute) +{ + tfa_set_bf(tfa, TFA9912_BF_CFSM, (const uint16_t)mute); + + return Tfa98xx_Error_Ok; +} + +/* Maksimum value for combination of boost_voltage and vout calibration offset (see PLMA5322, PLMA5528). */ +#define TFA9912_VBOOST_MAX 57 +#define TFA9912_CALIBR_BOOST_MAX 63 +#define TFA9912_DCDCCNT6_REG (TFA9912_BF_DCVOF >> 8) +#define TFA9912_CALIBR_REG 0xf1 + +static uint16_t tfa9912_vboost_fixup(struct tfa_device *tfa, uint16_t dcdc_cnt6) +{ + unsigned short cal_offset; + unsigned short boost_v_1st, boost_v_2nd; + uint16_t new_dcdc_cnt6; + + /* Get current calibr_vout_offset, this register is not supported by bitfields */ + reg_read(tfa, TFA9912_CALIBR_REG, &cal_offset); + cal_offset = (cal_offset & 0x001f); + new_dcdc_cnt6 = dcdc_cnt6; + + /* Get current boost_volatage values */ + boost_v_1st = tfa_get_bf_value(TFA9912_BF_DCVOF, new_dcdc_cnt6); + boost_v_2nd = tfa_get_bf_value(TFA9912_BF_DCVOS, new_dcdc_cnt6); + + /* Check boost voltages */ + if (boost_v_1st > TFA9912_VBOOST_MAX) + boost_v_1st = TFA9912_VBOOST_MAX; + + if (boost_v_2nd > TFA9912_VBOOST_MAX) + boost_v_2nd = TFA9912_VBOOST_MAX; + + /* Recalculate values, max for the sum is TFA9912_CALIBR_BOOST_MAX */ + if (boost_v_1st + cal_offset > TFA9912_CALIBR_BOOST_MAX) + boost_v_1st = TFA9912_CALIBR_BOOST_MAX - cal_offset; + + if (boost_v_2nd + cal_offset > TFA9912_CALIBR_BOOST_MAX) + boost_v_2nd = TFA9912_CALIBR_BOOST_MAX - cal_offset; + + tfa_set_bf_value(TFA9912_BF_DCVOF, boost_v_1st, &new_dcdc_cnt6); + tfa_set_bf_value(TFA9912_BF_DCVOS, boost_v_2nd, &new_dcdc_cnt6); + + /* Change register value only when it's neccesary */ + if (new_dcdc_cnt6 != dcdc_cnt6) { + if (tfa->verbose) + pr_debug("tfa9912: V boost fixup applied. Old 0x%04x, new 0x%04x\n", + dcdc_cnt6, new_dcdc_cnt6); + dcdc_cnt6 = new_dcdc_cnt6; + } + + return dcdc_cnt6; +} + +/* PLMA5322, PLMA5528 - Limit values of DCVOS and DCVOF to range specified in datasheet. */ +enum Tfa98xx_Error tfa9912_reg_write(struct tfa_device *tfa, unsigned char subaddress, unsigned short value) +{ + if (subaddress == TFA9912_DCDCCNT6_REG) { + /* Correct V boost (first and secondary) to ensure 12V is not exceeded. */ + value = tfa9912_vboost_fixup(tfa, value); + } + + return tfa98xx_write_register16(tfa, subaddress, value); +} + +/** Set internal oscillator into power down mode for TFA9912. +* +* This function is a worker for tfa98xx_set_osc_powerdown(). +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - oscillator is on, 1 oscillator is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +static enum Tfa98xx_Error tfa9912_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + if (state == 1 || state == 0) { + return -tfa_set_bf(tfa, TFA9912_BF_MANAOOSC, (uint16_t)state); + } + + return Tfa98xx_Error_Bad_Parameter; +} +/** update low power mode of the device. +* +* @param[in] tfa device description structure +* @param[in] state State of the low power mode1 detector control +* 0 - low power mode1 detector control enabled, +* 1 - low power mode1 detector control disabled(low power mode is also disabled). +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +static enum Tfa98xx_Error tfa9912_update_lpm(struct tfa_device *tfa, int state) +{ + if (state == 1 || state == 0) { + return -tfa_set_bf(tfa, TFA9912_BF_LPM1DIS, (uint16_t)state); + } + return Tfa98xx_Error_Bad_Parameter; +} + +void tfa9912_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9912_specific; + /* PLMA5322, PLMA5528 - Limits values of DCVOS and DCVOF. */ + ops->reg_write = tfa9912_reg_write; + ops->factory_trimmer = tfa9912_factory_trimmer; + ops->auto_copy_mtp_to_iic = tfa9912_auto_copy_mtp_to_iic; + ops->set_swprof = tfa9912_set_swprofile; + ops->get_swprof = tfa9912_get_swprofile; + ops->set_swvstep = tfa9912_set_swvstep; + ops->get_swvstep = tfa9912_get_swvstep; + ops->set_mute = tfa9912_set_mute; + ops->faim_protect = tfa9912_faim_protect; + ops->set_osc_powerdown = tfa9912_set_osc_powerdown; + ops->update_lpm = tfa9912_update_lpm; +} + +/***********************************************************************************/ +/* TFA9872 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9872_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t MANAOOSC = 0x0140; /* version 17 */ + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock key 1 and 2 */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + tfa98xx_key2(tfa, 0); + + switch (tfa->rev) { + case 0x1a72: + case 0x2a72: + /* ----- generated code start ----- */ + /* ----- version 26 ----- */ + reg_write(tfa, 0x00, 0x1801); //POR=0x0001 + reg_write(tfa, 0x02, 0x2dc8); //POR=0x2028 + reg_write(tfa, 0x20, 0x0890); //POR=0x2890 + reg_write(tfa, 0x22, 0x043c); //POR=0x045c + reg_write(tfa, 0x51, 0x0000); //POR=0x0080 + reg_write(tfa, 0x52, 0x1a1c); //POR=0x7ae8 + reg_write(tfa, 0x58, 0x161c); //POR=0x101c + reg_write(tfa, 0x61, 0x0198); //POR=0x0000 + reg_write(tfa, 0x65, 0x0a8b); //POR=0x0a9a + reg_write(tfa, 0x70, 0x07f5); //POR=0x06e6 + reg_write(tfa, 0x74, 0xcc84); //POR=0xd823 + reg_write(tfa, 0x82, 0x01ed); //POR=0x000d + reg_write(tfa, 0x83, 0x0014); //POR=0x0013 + reg_write(tfa, 0x84, 0x0021); //POR=0x0020 + reg_write(tfa, 0x85, 0x0001); //POR=0x0003 + /* ----- generated code end ----- */ + break; + case 0x1b72: + case 0x2b72: + case 0x3b72: + /* ----- generated code start ----- */ + /* ----- version 25.00 ----- */ + reg_write(tfa, 0x02, 0x2dc8); //POR=0x2828 + reg_write(tfa, 0x20, 0x0890); //POR=0x2890 + reg_write(tfa, 0x22, 0x043c); //POR=0x045c + reg_write(tfa, 0x23, 0x0001); //POR=0x0003 + reg_write(tfa, 0x51, 0x0000); //POR=0x0080 + reg_write(tfa, 0x52, 0x5a1c); //POR=0x7a08 + reg_write(tfa, 0x61, 0x0198); //POR=0x0000 + reg_write(tfa, 0x63, 0x0a9a); //POR=0x0a93 + reg_write(tfa, 0x65, 0x0a82); //POR=0x0a8d + reg_write(tfa, 0x6f, 0x01e3); //POR=0x02e4 + reg_write(tfa, 0x70, 0x06fd); //POR=0x06e6 + reg_write(tfa, 0x71, 0x307e); //POR=0x207e + reg_write(tfa, 0x74, 0xcc84); //POR=0xd913 + reg_write(tfa, 0x75, 0x1132); //POR=0x118a + reg_write(tfa, 0x82, 0x01ed); //POR=0x000d + reg_write(tfa, 0x83, 0x001a); //POR=0x0013 + /* ----- generated code end ----- */ + break; + default: + pr_info("\nWarning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + break; + } + + /* Turn off the osc1m to save power: PLMA4928 */ + error = tfa_set_bf(tfa, MANAOOSC, 1); + + /* Bypass OVP by setting bit 3 from register 0xB0 (bypass_ovp=1): PLMA5258 */ + error = reg_read(tfa, 0xB0, &value); + value |= 1 << 3; + error = reg_write(tfa, 0xB0, value); + + return error; +} + +static enum Tfa98xx_Error tfa9872_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1. Workaround for 72 and 88 (see PLMA5290) */ + return reg_write(tfa, 0xA3, 0x20); +} + +static int tfa9872_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9872_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9872_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9872_BF_SWPROFIL) - 1; +} + +static int tfa9872_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9872_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9872_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9872_BF_SWVSTEP) - 1; +} + +void tfa9872_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9872_specific; + ops->auto_copy_mtp_to_iic = tfa9872_auto_copy_mtp_to_iic; + ops->set_swprof = tfa9872_set_swprofile; + ops->get_swprof = tfa9872_get_swprofile; + ops->set_swvstep = tfa9872_set_swvstep; + ops->get_swvstep = tfa9872_get_swvstep; + ops->set_mute = tfa_set_mute_nodsp; +} + +/***********************************************************************************/ +/* TFA9874 */ +/***********************************************************************************/ + +static enum Tfa98xx_Error tfa9874_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + /* 0b = FAIM protection enabled 1b = FAIM protection disabled*/ + ret = tfa_set_bf_volatile(tfa, TFA9874_BF_OPENMTP, (uint16_t)(status)); + return ret; +} + + +static enum Tfa98xx_Error tfa9874_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock key 1 and 2 */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + tfa98xx_key2(tfa, 0); + + switch (tfa->rev) { + case 0x0a74: /* Initial revision ID */ + /* ----- generated code start ----- */ + /* V25 */ + reg_write(tfa, 0x02, 0x22a8); //POR=0x25c8 + reg_write(tfa, 0x51, 0x0020); //POR=0x0000 + reg_write(tfa, 0x52, 0x57dc); //POR=0x56dc + reg_write(tfa, 0x58, 0x16a4); //POR=0x1614 + reg_write(tfa, 0x61, 0x0110); //POR=0x0198 + reg_write(tfa, 0x66, 0x0701); //POR=0x0700 + reg_write(tfa, 0x6f, 0x00a3); //POR=0x01a3 + reg_write(tfa, 0x70, 0x07f8); //POR=0x06f8 + reg_write(tfa, 0x73, 0x0007); //POR=0x0005 + reg_write(tfa, 0x74, 0x5068); //POR=0xcc80 + reg_write(tfa, 0x75, 0x0d28); //POR=0x1138 + reg_write(tfa, 0x83, 0x0594); //POR=0x061a + reg_write(tfa, 0x84, 0x0001); //POR=0x0021 + reg_write(tfa, 0x85, 0x0001); //POR=0x0003 + reg_write(tfa, 0x88, 0x0000); //POR=0x0002 + reg_write(tfa, 0xc4, 0x2001); //POR=0x0001 + /* ----- generated code end ----- */ + break; + case 0x0b74: + /* ----- generated code start ----- */ + /* V1.6 */ + reg_write(tfa, 0x02, 0x22a8); //POR=0x25c8 + reg_write(tfa, 0x51, 0x0020); //POR=0x0000 + reg_write(tfa, 0x52, 0x57dc); //POR=0x56dc + reg_write(tfa, 0x58, 0x16a4); //POR=0x1614 + reg_write(tfa, 0x61, 0x0110); //POR=0x0198 + reg_write(tfa, 0x66, 0x0701); //POR=0x0700 + reg_write(tfa, 0x6f, 0x00a3); //POR=0x01a3 + reg_write(tfa, 0x70, 0x07f8); //POR=0x06f8 + reg_write(tfa, 0x73, 0x0047); //POR=0x0045 + reg_write(tfa, 0x74, 0x5068); //POR=0xcc80 + reg_write(tfa, 0x75, 0x0d28); //POR=0x1138 + reg_write(tfa, 0x83, 0x0595); //POR=0x061a + reg_write(tfa, 0x84, 0x0001); //POR=0x0021 + reg_write(tfa, 0x85, 0x0001); //POR=0x0003 + reg_write(tfa, 0x88, 0x0000); //POR=0x0002 + reg_write(tfa, 0xc4, 0x2001); //POR=0x0001 + /* ----- generated code end ----- */ + break; + case 0x0c74: + /* ----- generated code start ----- */ + /* V1.16 */ + reg_write(tfa, 0x02, 0x22c8); //POR=0x25c8 + reg_write(tfa, 0x52, 0x57dc); //POR=0x56dc + reg_write(tfa, 0x53, 0x003e); //POR=0x001e + reg_write(tfa, 0x56, 0x0400); //POR=0x0600 + reg_write(tfa, 0x61, 0x0110); //POR=0x0198 + reg_write(tfa, 0x6f, 0x00a5); //POR=0x01a3 + reg_write(tfa, 0x70, 0x07f8); //POR=0x06f8 + reg_write(tfa, 0x73, 0x0047); //POR=0x0045 + reg_write(tfa, 0x74, 0x5098); //POR=0xcc80 + reg_write(tfa, 0x75, 0x8d28); //POR=0x1138 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x83, 0x0799); //POR=0x061a + reg_write(tfa, 0x84, 0x0081); //POR=0x0021 + /* ----- generated code end ----- */ + break; + default: + pr_info("\nWarning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + break; + } + + return error; +} + +static int tfa9874_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9874_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9874_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9874_BF_SWPROFIL) - 1; +} + +static int tfa9874_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9874_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9874_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9874_BF_SWVSTEP) - 1; +} + +/* tfa98xx_dsp_system_stable +* return: *ready = 1 when clocks are stable to allow DSP subsystem access +*/ +static enum Tfa98xx_Error tfa9874_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + /* check CLKS: ready if set */ + *ready = tfa_get_bf(tfa, TFA9874_BF_CLKS) == 1; + + return error; +} + +static int tfa9874_get_mtpb(struct tfa_device *tfa) +{ + + int value; + value = tfa_get_bf(tfa, TFA9874_BF_MTPB); + return value; +} + +void tfa9874_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9874_specific; + ops->set_swprof = tfa9874_set_swprofile; + ops->get_swprof = tfa9874_get_swprofile; + ops->set_swvstep = tfa9874_set_swvstep; + ops->get_swvstep = tfa9874_get_swvstep; + ops->dsp_system_stable = tfa9874_dsp_system_stable; + ops->faim_protect = tfa9874_faim_protect; + ops->get_mtpb = tfa9874_get_mtpb; + ops->set_mute = tfa_set_mute_nodsp; +} +/***********************************************************************************/ +/* TFA9878 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9878_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + /* 0b = FAIM protection enabled 1b = FAIM protection disabled*/ + ret = tfa_set_bf_volatile(tfa, TFA9878_BF_OPENMTP, (uint16_t)(status)); + return ret; +} + + +static enum Tfa98xx_Error tfa9878_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock key 1 and 2 */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + tfa98xx_key2(tfa, 0); + + switch (tfa->rev) { + case 0x0a78: /* Initial revision ID */ +/* ----- generated code start ----- */ +/* ----- version 28 ----- */ + reg_write(tfa, 0x01, 0x2e18); //POR=0x2e88 + reg_write(tfa, 0x02, 0x0628); //POR=0x0008 + reg_write(tfa, 0x04, 0x0240); //POR=0x0340 + reg_write(tfa, 0x52, 0x587c); //POR=0x57dc + reg_write(tfa, 0x61, 0x0183); //POR=0x0a82 + reg_write(tfa, 0x63, 0x055a); //POR=0x0a9a + reg_write(tfa, 0x65, 0x0542); //POR=0x0a82 + reg_write(tfa, 0x71, 0x303e); //POR=0x307e + reg_write(tfa, 0x83, 0x009a); //POR=0x0799 + /* ----- generated code end ----- */ + + + break; + case 0x1a78: /* Initial revision ID */ + /* ----- generated code start ----- */ + /* ----- version 12 ----- */ + reg_write(tfa, 0x01, 0x2e18); //POR=0x2e88 + reg_write(tfa, 0x02, 0x0628); //POR=0x0008 + reg_write(tfa, 0x04, 0x0241); //POR=0x0340 + reg_write(tfa, 0x52, 0x587c); //POR=0x57dc + reg_write(tfa, 0x61, 0x0183); //POR=0x0a82 + reg_write(tfa, 0x63, 0x055a); //POR=0x0a9a + reg_write(tfa, 0x65, 0x0542); //POR=0x0a82 + reg_write(tfa, 0x70, 0xb7ff); //POR=0x37ff + reg_write(tfa, 0x71, 0x303e); //POR=0x307e + reg_write(tfa, 0x83, 0x009a); //POR=0x0799 + reg_write(tfa, 0x84, 0x0211); //POR=0x0011 + reg_write(tfa, 0x8c, 0x0210); //POR=0x0010 + reg_write(tfa, 0xce, 0x2202); //POR=0xa202 + reg_write(tfa, 0xd5, 0x0000); //POR=0x0100 + /* ----- generated code end ----- */ + + break; + default: + pr_info("\nWarning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + break; + } + + return error; +} + +static int tfa9878_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9878_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9878_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9878_BF_SWPROFIL) - 1; +} + +static int tfa9878_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9878_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9878_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9878_BF_SWVSTEP) - 1; +} + +/* tfa98xx_dsp_system_stable +* return: *ready = 1 when clocks are stable to allow DSP subsystem access +*/ +static enum Tfa98xx_Error tfa9878_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + /* check CLKS: ready if set */ + *ready = tfa_get_bf(tfa, TFA9878_BF_CLKS) == 1; + + return error; +} + +static int tfa9878_get_mtpb(struct tfa_device *tfa) +{ + + int value; + value = tfa_get_bf(tfa, TFA9878_BF_MTPB); + return value; +} + +void tfa9878_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9878_specific; + ops->set_swprof = tfa9878_set_swprofile; + ops->get_swprof = tfa9878_get_swprofile; + ops->set_swvstep = tfa9878_set_swvstep; + ops->get_swvstep = tfa9878_get_swvstep; + ops->dsp_system_stable = tfa9878_dsp_system_stable; + ops->faim_protect = tfa9878_faim_protect; + ops->get_mtpb = tfa9878_get_mtpb; + ops->set_mute = tfa_set_mute_nodsp; +} +/***********************************************************************************/ +/* TFA9888 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9888_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + int patch_version; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock keys to write settings */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + + /* Only N1C2 is supported */ + /* ----- generated code start ----- */ + /* --------- Version v1 ---------- */ + if (tfa->rev == 0x2c88) { + reg_write(tfa, 0x00, 0x164d); //POR=0x064d + reg_write(tfa, 0x01, 0x828b); //POR=0x92cb + reg_write(tfa, 0x02, 0x1dc8); //POR=0x1828 + reg_write(tfa, 0x0e, 0x0080); //POR=0x0000 + reg_write(tfa, 0x20, 0x089e); //POR=0x0890 + reg_write(tfa, 0x22, 0x543c); //POR=0x545c + reg_write(tfa, 0x23, 0x0006); //POR=0x0000 + reg_write(tfa, 0x24, 0x0014); //POR=0x0000 + reg_write(tfa, 0x25, 0x000a); //POR=0x0000 + reg_write(tfa, 0x26, 0x0100); //POR=0x0000 + reg_write(tfa, 0x28, 0x1000); //POR=0x0000 + reg_write(tfa, 0x51, 0x0000); //POR=0x00c0 + reg_write(tfa, 0x52, 0xfafe); //POR=0xbaf6 + reg_write(tfa, 0x70, 0x3ee4); //POR=0x3ee6 + reg_write(tfa, 0x71, 0x1074); //POR=0x3074 + reg_write(tfa, 0x83, 0x0014); //POR=0x0013 + /* ----- generated code end ----- */ + } else { + pr_info("Warning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + } + + patch_version = tfa_cnt_get_patch_version(tfa); + if (patch_version >= 0x060401) + tfa->partial_enable = 1; + + return error; +} + +static enum Tfa98xx_Error tfa9888_tfa_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + unsigned char buffer[15] = { 0 }; + int size = 15 * sizeof(char); + + /* Write the fractional delay in the hardware register 'cs_frac_delay' */ + switch (sample_rate) { + case 0: /* 8kHz */ + TFA_SET_BF(tfa, FRACTDEL, 40); + break; + case 1: /* 11.025KHz */ + TFA_SET_BF(tfa, FRACTDEL, 38); + break; + case 2: /* 12kHz */ + TFA_SET_BF(tfa, FRACTDEL, 37); + break; + case 3: /* 16kHz */ + TFA_SET_BF(tfa, FRACTDEL, 59); + break; + case 4: /* 22.05KHz */ + TFA_SET_BF(tfa, FRACTDEL, 56); + break; + case 5: /* 24kHz */ + TFA_SET_BF(tfa, FRACTDEL, 56); + break; + case 6: /* 32kHz */ + TFA_SET_BF(tfa, FRACTDEL, 52); + break; + case 7: /* 44.1kHz */ + TFA_SET_BF(tfa, FRACTDEL, 48); + break; + case 8: + default:/* 48kHz */ + TFA_SET_BF(tfa, FRACTDEL, 46); + break; + } + + /* First copy the msg_id to the buffer */ + buffer[0] = (uint8_t)0; + buffer[1] = (uint8_t)MODULE_FRAMEWORK + 128; + buffer[2] = (uint8_t)FW_PAR_ID_SET_SENSES_DELAY; + + /* Required for all FS exept 8kHz (8kHz is all zero) */ + if (sample_rate != 0) { + buffer[5] = 1; /* Vdelay_P */ + buffer[8] = 0; /* Idelay_P */ + buffer[11] = 1; /* Vdelay_S */ + buffer[14] = 0; /* Idelay_S */ + } + + /* send SetSensesDelay msg */ + return dsp_msg(tfa, size, (char *)buffer); +} + +static enum Tfa98xx_Error tfa9888_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1. Workaround for 72 and 88 (see PLMA5290) */ + return reg_write(tfa, 0xA3, 0x20); +} + +static enum Tfa98xx_Error tfa9888_factory_trimmer(struct tfa_device *tfa) +{ + unsigned short currentValue, delta; + int result; + + /* Factory trimming for the Boost converter */ + /* check if there is a correction needed */ + result = TFA_GET_BF(tfa, DCMCCAPI); + if (result) { + /* Get currentvalue of DCMCC and the Delta value */ + currentValue = (unsigned short)TFA_GET_BF(tfa, DCMCC); + delta = (unsigned short)TFA_GET_BF(tfa, USERDEF); + + /* check the sign bit (+/-) */ + result = TFA_GET_BF(tfa, DCMCCSB); + if (result == 0) { + /* Do not exceed the maximum value of 15 */ + if (currentValue + delta < 15) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue + delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue + delta); + } else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 15); + if (tfa->verbose) + pr_debug("Max coil current is set to: 15 \n"); + } + } else if (result == 1) { + /* Do not exceed the minimum value of 0 */ + if (currentValue - delta > 0) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue - delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue - delta); + } else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 0); + if (tfa->verbose) + pr_debug("Max coil current is set to: 0 \n"); + } + } + } + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error +tfa9888_set_mute(struct tfa_device *tfa, int mute) +{ + TFA_SET_BF(tfa, CFSMR, (const uint16_t)mute); + TFA_SET_BF(tfa, CFSML, (const uint16_t)mute); + + return Tfa98xx_Error_Ok; +} + +void tfa9888_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9888_specific; + ops->dsp_write_tables = tfa9888_tfa_dsp_write_tables; + ops->auto_copy_mtp_to_iic = tfa9888_auto_copy_mtp_to_iic; + ops->factory_trimmer = tfa9888_factory_trimmer; + ops->set_mute = tfa9888_set_mute; +} + +/***********************************************************************************/ +/* TFA9896 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9896_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + + if ((tfa->rev == 0x2b96) || (tfa->rev == 0x3b96)) { + ret = tfa_set_bf_volatile(tfa, TFA9896_BF_OPENMTP, (uint16_t)status); + } + + return ret; +} + +/***********************************************************************************/ +/* TFA9896 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9896_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short check_value; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers must already set to default POR value */ + + /* $48:[3] - 1 ==> 0; iddqtestbst - default value changed. + * When Iddqtestbst is set to "0", the slewrate is reduced. + * This will lower the overshoot on IN-B to avoid NMOS damage of booster. + */ + if (tfa->rev == 0x1b96) { + /* ----- generated code start v17 ----- */ + reg_write(tfa, 0x06, 0x000b); //POR=0x0001 + reg_write(tfa, 0x07, 0x3e7f); //POR=0x1e7f + reg_write(tfa, 0x0a, 0x0d8a); //POR=0x0592 + reg_write(tfa, 0x48, 0x0300); //POR=0x0308 + reg_write(tfa, 0x88, 0x0100); //POR=0x0000 + /* ----- generated code end ----- */ + } else if (tfa->rev == 0x2b96) { + /* ----- generated code start ----- v1*/ + reg_write(tfa, 0x06, 0x000b); //POR=0x0001 + reg_write(tfa, 0x07, 0x3e7f); //POR=0x1e7f + reg_write(tfa, 0x0a, 0x0d8a); //POR=0x0592 + reg_write(tfa, 0x48, 0x0300); //POR=0x0308 + reg_write(tfa, 0x88, 0x0100); //POR=0x0000 + /* ----- generated code end ----- */ + } else if (tfa->rev == 0x3b96) { + /* ----- generated code start ----- v1*/ + reg_write(tfa, 0x06, 0x000b); //POR=0x0001 + reg_write(tfa, 0x07, 0x3e7f); //POR=0x1e7f + reg_write(tfa, 0x0a, 0x0d8a); //POR=0x0592 + reg_write(tfa, 0x48, 0x0300); //POR=0x0308 + reg_write(tfa, 0x88, 0x0100); //POR=0x0000 + /* ----- generated code end ----- */ + } + /* $49:[0] - 1 ==> 0; CLIP - default value changed. 0 means CLIPPER on */ + error = reg_read(tfa, 0x49, &check_value); + check_value &= ~0x1; + error = reg_write(tfa, 0x49, check_value); + return error; +} + +/* +* the int24 values for the vsfw delay table +*/ +static unsigned char tfa9896_vsfwdelay_table[] = { + 0, 0, 2, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0, 0, 0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0, 0, 0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0, 0, 2, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0, 0, 2, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0, 0, 2, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0, 0, 2, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0, 0, 2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0, 0, 3 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +/* +* TODO make this tfa98xx +* Note that the former products write this table via the patch +* so moving this to the tfa98xx API requires also updating all patches +*/ +static enum Tfa98xx_Error tfa9896_dsp_write_vsfwdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURRENT_DELAY, sizeof(tfa9896_vsfwdelay_table), tfa9896_vsfwdelay_table); +} + +/* +* The int24 values for the fracdelay table +* For now applicable only for 8 and 48 kHz +*/ +static unsigned char tfa9896_cvfracdelay_table[] = { + 0, 0, 51, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0, 0, 0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0, 0, 0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0, 0, 38, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0, 0, 34, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0, 0, 33, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0, 0, 11, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0, 0, 2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0, 0, 62 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +static enum Tfa98xx_Error tfa9896_dsp_write_cvfracdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURFRAC_DELAY, sizeof(tfa9896_cvfracdelay_table), tfa9896_cvfracdelay_table);; +} + +static enum Tfa98xx_Error tfa9896_tfa_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + enum Tfa98xx_Error error; + + /* Not used for max1! */ + (void)sample_rate; + + error = tfa9896_dsp_write_vsfwdelay_table(tfa); + if (error == Tfa98xx_Error_Ok) { + error = tfa9896_dsp_write_cvfracdelay_table(tfa); + } + + return error; +} + +void tfa9896_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9896_specific; + ops->dsp_write_tables = tfa9896_tfa_dsp_write_tables; + ops->faim_protect = tfa9896_faim_protect; +} + +/***********************************************************************************/ +/* TFA9897 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9897_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short check_value; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers must already set to default POR value */ + + /* $48:[3] - 1 ==> 0; iddqtestbst - default value changed. + * When Iddqtestbst is set to "0", the slewrate is reduced. + * This will lower the overshoot on IN-B to avoid NMOS damage of booster */ + error = reg_write(tfa, 0x48, 0x0300); /* POR value = 0x308 */ + + /* $49:[0] - 1 ==> 0; CLIP - default value changed. 0 means CLIPPER on */ + error = reg_read(tfa, 0x49, &check_value); + check_value &= ~0x1; + error = reg_write(tfa, 0x49, check_value); + + return error; +} + +/* +* the int24 values for the vsfw delay table +*/ +static unsigned char tfa9897_vsfwdelay_table[] = { + 0, 0, 2, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0, 0, 0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0, 0, 0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0, 0, 2, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0, 0, 2, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0, 0, 2, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0, 0, 2, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0, 0, 2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0, 0, 3 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +/* +* TODO make this tfa98xx +* Note that the former products write this table via the patch +* so moving this to the tfa98xx API requires also updating all patches +*/ +static enum Tfa98xx_Error tfa9897_dsp_write_vsfwdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURRENT_DELAY, sizeof(tfa9897_vsfwdelay_table), tfa9897_vsfwdelay_table);; +} + +/* +* The int24 values for the fracdelay table +* For now applicable only for 8 and 48 kHz +*/ +static unsigned char tfa9897_cvfracdelay_table[] = { + 0, 0, 51, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0, 0, 0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0, 0, 0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0, 0, 38, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0, 0, 34, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0, 0, 33, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0, 0, 11, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0, 0, 2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0, 0, 62 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +static enum Tfa98xx_Error tfa9897_dsp_write_cvfracdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURFRAC_DELAY, sizeof(tfa9897_cvfracdelay_table), tfa9897_cvfracdelay_table);; +} + +static enum Tfa98xx_Error tfa9897_tfa_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + enum Tfa98xx_Error error; + + /* Not used for max1! */ + (void)sample_rate; + + error = tfa9897_dsp_write_vsfwdelay_table(tfa); + if (error == Tfa98xx_Error_Ok) { + error = tfa9897_dsp_write_cvfracdelay_table(tfa); + } + + return error; +} + +void tfa9897_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9897_specific; + ops->dsp_write_tables = tfa9897_tfa_dsp_write_tables; +} + +/***********************************************************************************/ +/* TFA9895 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9895_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int result; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers are already set to default */ + + result = TFA_SET_BF(tfa, AMPE, 1); + if (result < 0) + return -result; + + /* some other registers must be set for optimal amplifier behaviour */ + reg_write(tfa, 0x05, 0x13AB); + reg_write(tfa, 0x06, 0x001F); + /* peak voltage protection is always on, but may be written */ + reg_write(tfa, 0x08, 0x3C4E); + /*TFA98XX_SYSCTRL_DCA=0*/ + reg_write(tfa, 0x09, 0x024D); + reg_write(tfa, 0x41, 0x0308); + error = reg_write(tfa, 0x49, 0x0E82); + + return error; +} + +void tfa9895_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9895_specific; +} + +/***********************************************************************************/ +/* TFA9891 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9891_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* ----- generated code start ----- */ + /* ----- version 18.0 ----- */ + reg_write(tfa, 0x09, 0x025d); //POR=0x024d + reg_write(tfa, 0x10, 0x0018); //POR=0x0024 + reg_write(tfa, 0x22, 0x0003); //POR=0x0023 + reg_write(tfa, 0x25, 0x0001); //POR=0x0000 + reg_write(tfa, 0x46, 0x0000); //POR=0x4000 + reg_write(tfa, 0x55, 0x3ffb); //POR=0x7fff + /* ----- generated code end ----- */ + + return error; +} + +void tfa9891_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9891_specific; +} + +/***********************************************************************************/ +/* TFA9890 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9890_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short regRead = 0; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers are already set to default for N1C2 */ + + /* some PLL registers must be set optimal for amplifier behaviour */ + error = reg_write(tfa, 0x40, 0x5a6b); + if (error) + return error; + reg_read(tfa, 0x59, ®Read); + regRead |= 0x3; + reg_write(tfa, 0x59, regRead); + error = reg_write(tfa, 0x40, 0x0000); + error = reg_write(tfa, 0x47, 0x7BE1); + + return error; +} + +/* +* Disable clock gating +*/ +static enum Tfa98xx_Error tfa9890_clockgating(struct tfa_device *tfa, int on) +{ + enum Tfa98xx_Error error; + unsigned short value; + + /* for TFA9890 temporarily disable clock gating when dsp reset is used */ + error = reg_read(tfa, TFA98XX_CURRENTSENSE4, &value); + if (error) + return error; + + if (Tfa98xx_Error_Ok == error) { + if (on) /* clock gating on - clear the bit */ + value &= ~TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF; + else /* clock gating off - set the bit */ + value |= TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF; + + error = reg_write(tfa, TFA98XX_CURRENTSENSE4, value); + } + + return error; +} + +/* +* Tfa9890_DspReset will deal with clock gating control in order +* to reset the DSP for warm state restart +*/ +static enum Tfa98xx_Error tfa9890_dsp_reset(struct tfa_device *tfa, int state) +{ + enum Tfa98xx_Error error; + + /* for TFA9890 temporarily disable clock gating + when dsp reset is used */ + tfa9890_clockgating(tfa, 0); + + TFA_SET_BF(tfa, RST, (uint16_t)state); + + /* clock gating restore */ + error = tfa9890_clockgating(tfa, 1); + + return error; +} + +/* + * Tfa9890_DspSystemStable will compensate for the wrong behavior of CLKS + * to determine if the DSP subsystem is ready for patch and config loading. + * + * A MTP calibration register is checked for non-zero. + * + * Note: This only works after i2c reset as this will clear the MTP contents. + * When we are configured then the DSP communication will synchronize access. + * + */ +static enum Tfa98xx_Error tfa9890_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short status, mtp0; + int result, tries; + + /* check the contents of the STATUS register */ + result = TFA_READ_REG(tfa, AREFS); + if (result < 0) { + error = -result; + goto errorExit; + } + status = (unsigned short)result; + + /* if AMPS is set then we were already configured and running + * no need to check further + */ + *ready = (TFA_GET_BF_VALUE(tfa, AMPS, status) == 1); + if (*ready) /* if ready go back */ + return error; /* will be Tfa98xx_Error_Ok */ + + /* check AREFS and CLKS: not ready if either is clear */ + *ready = !((TFA_GET_BF_VALUE(tfa, AREFS, status) == 0) + || (TFA_GET_BF_VALUE(tfa, CLKS, status) == 0)); + if (!*ready) /* if not ready go back */ + return error; /* will be Tfa98xx_Error_Ok */ + + /* check MTPB + * mtpbusy will be active when the subsys copies MTP to I2C + * 2 times retry avoids catching this short mtpbusy active period + */ + for (tries = 2; tries > 0; tries--) { + result = TFA_GET_BF(tfa, MTPB);/*TODO_MTPB*/ + if (result < 0) { + error = -result; + goto errorExit; + } + status = (unsigned short)result; + + /* check the contents of the STATUS register */ + *ready = (result == 0); + if (*ready) /* if ready go on */ + break; + } + if (tries == 0) /* ready will be 0 if retries exausted */ + return Tfa98xx_Error_Ok; + + /* check the contents of MTP register for non-zero, + * this indicates that the subsys is ready */ + + error = reg_read(tfa, 0x84, &mtp0); + if (error) + goto errorExit; + + *ready = (mtp0 != 0); /* The MTP register written? */ + + return error; + +errorExit: + *ready = 0; + return error; +} + +void tfa9890_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9890_specific; + ops->dsp_reset = tfa9890_dsp_reset; + ops->dsp_system_stable = tfa9890_dsp_system_stable; +} + +/***********************************************************************************/ +/* TFA9894 */ +/***********************************************************************************/ +static int tfa9894_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + tfa_set_bf_volatile(tfa, TFA9894_BF_SWPROFIL, new_value); + return active_value; +} + +static int tfa9894_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9894_BF_SWPROFIL) - 1; +} + +static int tfa9894_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + tfa_set_bf_volatile(tfa, TFA9894_BF_SWVSTEP, new_value); + return new_value; +} + +static int tfa9894_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9894_BF_SWVSTEP) - 1; +} + +static int tfa9894_get_mtpb(struct tfa_device *tfa) +{ + int value = 0; + value = tfa_get_bf(tfa, TFA9894_BF_MTPB); + return value; +} + +/** Set internal oscillator into power down mode for TFA9894. +* +* This function is a worker for tfa98xx_set_osc_powerdown(). +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - oscillator is on, 1 oscillator is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +static enum Tfa98xx_Error tfa9894_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + if (state == 1 || state == 0) { + return -tfa_set_bf(tfa, TFA9894_BF_MANAOOSC, (uint16_t)state); + } + + return Tfa98xx_Error_Bad_Parameter; +} + +static enum Tfa98xx_Error tfa9894_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + /* 0b = FAIM protection enabled 1b = FAIM protection disabled*/ + ret = tfa_set_bf_volatile(tfa, TFA9894_BF_OPENMTP, (uint16_t)(status)); + return ret; +} + +static enum Tfa98xx_Error tfa9894_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + if (tfa->verbose) + if (is_94_N2_device(tfa)) + pr_debug("check_correct\n"); + /* Unlock keys to write settings */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + pr_debug("Device REFID:%x\n", tfa->rev); + /* The optimal settings */ + if (tfa->rev == 0x0a94) { + /* V36 */ + /* ----- generated code start ----- */ + reg_write(tfa, 0x00, 0xa245); //POR=0x8245 + reg_write(tfa, 0x02, 0x51e8); //POR=0x55c8 + reg_write(tfa, 0x52, 0xbe17); //POR=0xb617 + reg_write(tfa, 0x57, 0x0344); //POR=0x0366 + reg_write(tfa, 0x61, 0x0033); //POR=0x0073 + reg_write(tfa, 0x71, 0x00cf); //POR=0x018d + reg_write(tfa, 0x72, 0x34a9); //POR=0x44e8 + reg_write(tfa, 0x73, 0x3808); //POR=0x3806 + reg_write(tfa, 0x76, 0x0067); //POR=0x0065 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x81, 0x5715); //POR=0x561a + reg_write(tfa, 0x82, 0x0104); //POR=0x0044 + /* ----- generated code end ----- */ + } else if (tfa->rev == 0x1a94) { + /* V17 */ + /* ----- generated code start ----- */ + reg_write(tfa, 0x00, 0xa245); //POR=0x8245 + reg_write(tfa, 0x01, 0x15da); //POR=0x11ca + reg_write(tfa, 0x02, 0x5288); //POR=0x55c8 + reg_write(tfa, 0x52, 0xbe17); //POR=0xb617 + reg_write(tfa, 0x53, 0x0dbe); //POR=0x0d9e + reg_write(tfa, 0x56, 0x05c3); //POR=0x07c3 + reg_write(tfa, 0x57, 0x0344); //POR=0x0366 + reg_write(tfa, 0x61, 0x0032); //POR=0x0073 + reg_write(tfa, 0x71, 0x00cf); //POR=0x018d + reg_write(tfa, 0x72, 0x34a9); //POR=0x44e8 + reg_write(tfa, 0x73, 0x38c8); //POR=0x3806 + reg_write(tfa, 0x76, 0x0067); //POR=0x0065 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x81, 0x5799); //POR=0x561a + reg_write(tfa, 0x82, 0x0104); //POR=0x0044 + /* ----- generated code end ----- */ + + } else if (tfa->rev == 0x2a94 || tfa->rev == 0x3a94) { + /* ----- generated code start ----- */ + /* ----- version 25.00 ----- */ + reg_write(tfa, 0x01, 0x15da); //POR=0x11ca + reg_write(tfa, 0x02, 0x51e8); //POR=0x55c8 + reg_write(tfa, 0x04, 0x0200); //POR=0x0000 + reg_write(tfa, 0x52, 0xbe17); //POR=0xb617 + reg_write(tfa, 0x53, 0x0dbe); //POR=0x0d9e + reg_write(tfa, 0x57, 0x0344); //POR=0x0366 + reg_write(tfa, 0x61, 0x0032); //POR=0x0073 + reg_write(tfa, 0x71, 0x6ecf); //POR=0x6f8d + reg_write(tfa, 0x72, 0xb4a9); //POR=0x44e8 + reg_write(tfa, 0x73, 0x38c8); //POR=0x3806 + reg_write(tfa, 0x76, 0x0067); //POR=0x0065 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x81, 0x5799); //POR=0x561a + reg_write(tfa, 0x82, 0x0104); //POR=0x0044 + /* ----- generated code end ----- */ + } + return error; +} + +static enum Tfa98xx_Error +tfa9894_set_mute(struct tfa_device *tfa, int mute) +{ + tfa_set_bf(tfa, TFA9894_BF_CFSM, (const uint16_t)mute); + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error tfa9894_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + /* check CLKS: ready if set */ + *ready = tfa_get_bf(tfa, TFA9894_BF_CLKS) == 1; + + return error; +} + +void tfa9894_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9894_specific; + ops->dsp_system_stable = tfa9894_dsp_system_stable; + ops->set_mute = tfa9894_set_mute; + ops->faim_protect = tfa9894_faim_protect; + ops->get_mtpb = tfa9894_get_mtpb; + ops->set_swprof = tfa9894_set_swprofile; + ops->get_swprof = tfa9894_get_swprofile; + ops->set_swvstep = tfa9894_set_swvstep; + ops->get_swvstep = tfa9894_get_swvstep; + //ops->auto_copy_mtp_to_iic = tfa9894_auto_copy_mtp_to_iic; + ops->set_osc_powerdown = tfa9894_set_osc_powerdown; +} diff --git a/sound/soc/codecs/tfa_internal.h b/sound/soc/codecs/tfa_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..fe6407e043ad09a4b6447fea778eb93dbbdba53c --- /dev/null +++ b/sound/soc/codecs/tfa_internal.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +/* + * internal functions for TFA layer (not shared with SRV and HAL layer!) + */ + +#ifndef __TFA_INTERNAL_H__ +#define __TFA_INTERNAL_H__ + +#include "tfa_dsp_fw.h" +#include "tfa_ext.h" + +#if __GNUC__ >= 4 + #define TFA_INTERNAL __attribute__((visibility ("hidden"))) +#else + #define TFA_INTERNAL +#endif + +#define TFA98XX_GENERIC_SLAVE_ADDRESS 0x1C + +TFA_INTERNAL enum Tfa98xx_Error tfa98xx_check_rpc_status(struct tfa_device *tfa, + int *pRpcStatus); +TFA_INTERNAL enum Tfa98xx_Error tfa98xx_wait_result(struct tfa_device *tfa, + int waitRetryCount); + +#endif /* __TFA_INTERNAL_H__ */ + diff --git a/sound/soc/codecs/tfa_service.h b/sound/soc/codecs/tfa_service.h new file mode 100644 index 0000000000000000000000000000000000000000..240deb91186677a91ea178dbfd5fb4c35b0f38ea --- /dev/null +++ b/sound/soc/codecs/tfa_service.h @@ -0,0 +1,1024 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA_SERVICE_H +#define TFA_SERVICE_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" { +#include "NXP_I2C.h" +#endif + +/* + * Linux kernel module defines TFA98XX_GIT_VERSIONS in the + * linux_driver/Makefile + */ +#ifdef TFA98XX_GIT_VERSIONS + #define TFA98XX_API_REV_STR "v6.6.3"/*TFA98XX_GIT_VERSIONS*/ +#else + #define TFA98XX_API_REV_STR "v6.6.3" +#endif + +#include "tfa_device.h" + +/* + * data previously defined in Tfa9888_dsp.h + */ +#define MEMTRACK_MAX_WORDS 150 +#define LSMODEL_MAX_WORDS 150 +#define TFA98XX_MAXTAG (150) +#define FW_VAR_API_VERSION (521) + +/* Indexes and scaling factors of GetLSmodel */ +#define tfa9888_fs_IDX 128 +#define tfa9888_leakageFactor_IDX 130 +#define tfa9888_ReCorrection_IDX 131 +#define tfa9888_Bl_IDX 132 +#define ReZ_IDX 147 + +#define tfa9872_leakageFactor_IDX 128 +#define tfa9872_ReCorrection_IDX 129 +#define tfa9872_Bl_IDX 130 + +#define fs_SCALE (double)1 +#define leakageFactor_SCALE (double)8388608 +#define ReCorrection_SCALE (double)8388608 +#define Bl_SCALE (double)2097152 +#define tCoef_SCALE (double)8388608 + +/* ---------------------------- Max1 ---------------------------- */ +/* Headroom applied to the main input signal */ +#define SPKRBST_HEADROOM 7 +/* Exponent used for AGC Gain related variables */ +#define SPKRBST_AGCGAIN_EXP SPKRBST_HEADROOM +#define SPKRBST_TEMPERATURE_EXP 9 +/* Exponent used for Gain Corection related variables */ +#define SPKRBST_LIMGAIN_EXP 4 +#define SPKRBST_TIMECTE_EXP 1 +#define DSP_MAX_GAIN_EXP 7 +/* -------------------------------------------------------------- */ + +/* speaker related parameters */ +#define TFA2_SPEAKERPARAMETER_LENGTH (3*151) /* MAX2=450 */ +#define TFA1_SPEAKERPARAMETER_LENGTH (3*141) /* MAX1=423 */ + +/* vstep related parameters */ +#define TFA2_ALGOPARAMETER_LENGTH (3*304) /* N1B = (304) 305 is including the cmd-id */ +#define TFA72_ALGOPARAMETER_LENGTH_MONO (3*183) +#define TFA72_ALGOPARAMETER_LENGTH_STEREO (3*356) +#define TFA2_MBDRCPARAMETER_LENGTH (3*152) /* 154 is including the cmd-id */ +#define TFA72_MBDRCPARAMETER_LENGTH (3*98) +#define TFA1_PRESET_LENGTH 87 +#define TFA1_DRC_LENGTH 381 /* 127 words */ +#define TFA2_FILTERCOEFSPARAMETER_LENGTH (3*168) /* 170 is including the cmd-id */ +#define TFA72_FILTERCOEFSPARAMETER_LENGTH (3*156) + +/* Maximum number of retries for DSP result + * Keep this value low! + * If certain calls require longer wait conditions, the + * application should poll, not the API + * The total wait time depends on device settings. Those + * are application specific. + */ +#define TFA98XX_WAITRESULT_NTRIES 40 +#define TFA98XX_WAITRESULT_NTRIES_LONG 2000 + +/* following lengths are in bytes */ +#define TFA98XX_PRESET_LENGTH 87 +#define TFA98XX_CONFIG_LENGTH 201 +#define TFA98XX_DRC_LENGTH 381 /* 127 words */ + +typedef unsigned char Tfa98xx_Config_t[TFA98XX_CONFIG_LENGTH]; +typedef unsigned char Tfa98xx_Preset_t[TFA98XX_PRESET_LENGTH]; +typedef unsigned char Tfa98xx_DrcParameters_t[TFA98XX_DRC_LENGTH]; + +/* Type containing all the possible errors that can occur */ +enum Tfa98xx_Error { + Tfa98xx_Error_Ok = 0, + Tfa98xx_Error_Device, /* 1. Currently only used to keep in sync with tfa_error */ + Tfa98xx_Error_Bad_Parameter, /* 2. */ + Tfa98xx_Error_Fail, /* 3. generic failure, avoid mislead message */ + Tfa98xx_Error_NoClock, /* 4. no clock detected */ + Tfa98xx_Error_StateTimedOut, /* 5. */ + Tfa98xx_Error_DSP_not_running, /* 6. communication with the DSP failed */ + Tfa98xx_Error_AmpOn, /* 7. amp is still running */ + Tfa98xx_Error_NotOpen, /* 8. the given handle is not open */ + Tfa98xx_Error_InUse, /* 9. too many handles */ + Tfa98xx_Error_Buffer_too_small, /* 10. if a buffer is too small */ + /* the expected response did not occur within the expected time */ + Tfa98xx_Error_RpcBase = 100, + Tfa98xx_Error_RpcBusy = 101, + Tfa98xx_Error_RpcModId = 102, + Tfa98xx_Error_RpcParamId = 103, + Tfa98xx_Error_RpcInvalidCC = 104, + Tfa98xx_Error_RpcInvalidSeq = 105, + Tfa98xx_Error_RpcInvalidParam = 106, + Tfa98xx_Error_RpcBufferOverflow = 107, + Tfa98xx_Error_RpcCalibBusy = 108, + Tfa98xx_Error_RpcCalibFailed = 109, + Tfa98xx_Error_Not_Implemented, + Tfa98xx_Error_Not_Supported, + Tfa98xx_Error_I2C_Fatal, /* Fatal I2C error occurred */ + /* Nonfatal I2C error, and retry count reached */ + Tfa98xx_Error_I2C_NonFatal, + Tfa98xx_Error_Other = 1000 +}; + +/* + * Type containing all the possible msg returns DSP can give + * //TODO move to tfa_dsp_fw.h + */ +enum Tfa98xx_Status_ID { + Tfa98xx_DSP_Not_Running = -1, /* No response from DSP */ + Tfa98xx_I2C_Req_Done = 0, /* Request executed correctly and result, if any, is available for download */ + Tfa98xx_I2C_Req_Busy = 1, /* Request is being processed, just wait for result */ + Tfa98xx_I2C_Req_Invalid_M_ID = 2, /* Provided M-ID does not fit in valid rang [0..2] */ + Tfa98xx_I2C_Req_Invalid_P_ID = 3, /* Provided P-ID isn�t valid in the given M-ID context */ + Tfa98xx_I2C_Req_Invalid_CC = 4, /* Invalid channel configuration bits (SC|DS|DP|DC) combination */ + Tfa98xx_I2C_Req_Invalid_Seq = 5, /* Invalid sequence of commands, in case the DSP expects some commands in a specific order */ + Tfa98xx_I2C_Req_Invalid_Param = 6, /* Generic error */ + Tfa98xx_I2C_Req_Buffer_Overflow = 7, /* I2C buffer has overflowed: host has sent too many parameters, memory integrity is not guaranteed */ + Tfa98xx_I2C_Req_Calib_Busy = 8, /* Calibration not finished */ + Tfa98xx_I2C_Req_Calib_Failed = 9 /* Calibration failed */ +}; + +/* + * speaker as microphone + */ +enum Tfa98xx_saam { + Tfa98xx_saam_none, /*< SAAM feature not available */ + Tfa98xx_saam /*< SAAM feature available */ +}; + +/* + * config file subtypes + */ +enum Tfa98xx_config_type { + Tfa98xx_config_generic, + Tfa98xx_config_sub1, + Tfa98xx_config_sub2, + Tfa98xx_config_sub3, +}; + +enum Tfa98xx_AmpInputSel { + Tfa98xx_AmpInputSel_I2SLeft, + Tfa98xx_AmpInputSel_I2SRight, + Tfa98xx_AmpInputSel_DSP +}; + +enum Tfa98xx_OutputSel { + Tfa98xx_I2SOutputSel_CurrentSense, + Tfa98xx_I2SOutputSel_DSP_Gain, + Tfa98xx_I2SOutputSel_DSP_AEC, + Tfa98xx_I2SOutputSel_Amp, + Tfa98xx_I2SOutputSel_DataI3R, + Tfa98xx_I2SOutputSel_DataI3L, + Tfa98xx_I2SOutputSel_DcdcFFwdCur, +}; + +enum Tfa98xx_StereoGainSel { + Tfa98xx_StereoGainSel_Left, + Tfa98xx_StereoGainSel_Right +}; + +#define TFA98XX_MAXPATCH_LENGTH (3*1024) + +/* the number of biquads supported */ +#define TFA98XX_BIQUAD_NUM 10 + +enum Tfa98xx_Channel { + Tfa98xx_Channel_L, + Tfa98xx_Channel_R, + Tfa98xx_Channel_L_R, + Tfa98xx_Channel_Stereo +}; + +enum Tfa98xx_Mode { + Tfa98xx_Mode_Normal = 0, + Tfa98xx_Mode_RCV +}; + +enum Tfa98xx_Mute { + Tfa98xx_Mute_Off, + Tfa98xx_Mute_Digital, + Tfa98xx_Mute_Amplifier +}; + +enum Tfa98xx_SpeakerBoostStatusFlags { + Tfa98xx_SpeakerBoost_Activity = 0, /* Input signal activity. */ + Tfa98xx_SpeakerBoost_S_Ctrl, /* S Control triggers the limiter */ + Tfa98xx_SpeakerBoost_Muted, /* 1 when signal is muted */ + Tfa98xx_SpeakerBoost_X_Ctrl, /* X Control triggers the limiter */ + Tfa98xx_SpeakerBoost_T_Ctrl, /* T Control triggers the limiter */ + Tfa98xx_SpeakerBoost_NewModel, /* New model is available */ + Tfa98xx_SpeakerBoost_VolumeRdy, /* 0:stable vol, 1:still smoothing */ + Tfa98xx_SpeakerBoost_Damaged, /* Speaker Damage detected */ + Tfa98xx_SpeakerBoost_SignalClipping /* input clipping detected */ +}; + +struct Tfa98xx_DrcStateInfo { + float GRhighDrc1[2]; + float GRhighDrc2[2]; + float GRmidDrc1[2]; + float GRmidDrc2[2]; + float GRlowDrc1[2]; + float GRlowDrc2[2]; + float GRpostDrc1[2]; + float GRpostDrc2[2]; + float GRblDrc[2]; +}; +struct Tfa98xx_StateInfo { + /* SpeakerBoost State */ + float agcGain; /* Current AGC Gain value */ + float limGain; /* Current Limiter Gain value */ + float sMax; /* Current Clip/Lim threshold */ + int T; /* Current Speaker Temperature value */ + int statusFlag; /* Masked bit word */ + float X1; /* estimated excursion caused by Spkrboost gain ctrl */ + float X2; /* estimated excursion caused by manual gain setting */ + float Re; /* Loudspeaker blocked resistance */ + /* Framework state */ + /* increments each time a MIPS problem is detected on the DSP */ + int shortOnMips; + struct Tfa98xx_DrcStateInfo drcState; /* DRC state, when enabled */ +}; + +typedef struct nxpTfaMsg { + uint8_t msg_size; + unsigned char cmdId[3]; + int data[9]; +} nxpTfaMsg_t; + +typedef struct nxp_vstep_msg { + int fw_version; + uint8_t no_of_vsteps; + uint16_t reg_no; + uint8_t *msg_reg; + uint8_t msg_no; + uint32_t algo_param_length; + uint8_t *msg_algo_param; + uint32_t filter_coef_length; + uint8_t *msg_filter_coef; + uint32_t mbdrc_length; + uint8_t *msg_mbdrc; +} nxp_vstep_msg_t; + +typedef struct nxpTfaGroup { + uint8_t msg_size; + uint8_t profileId[64]; +} nxpTfaGroup_t; + + +struct nxpTfa98xx_Memtrack_data { + int length; + float mValues[MEMTRACK_MAX_WORDS]; + int mAdresses[MEMTRACK_MAX_WORDS]; + int trackers[MEMTRACK_MAX_WORDS]; + int scalingFactor[MEMTRACK_MAX_WORDS]; +}; + +/* possible memory values for DMEM in CF_CONTROLs */ +enum Tfa98xx_DMEM { + Tfa98xx_DMEM_ERR = -1, + Tfa98xx_DMEM_PMEM = 0, + Tfa98xx_DMEM_XMEM = 1, + Tfa98xx_DMEM_YMEM = 2, + Tfa98xx_DMEM_IOMEM = 3, +}; + +/** + * lookup the device type and return the family type + */ +int tfa98xx_dev2family(int dev_type); + +/** + * register definition structure + */ +struct regdef { + unsigned char offset; /**< subaddress offset */ + unsigned short pwronDefault; /**< register contents after poweron */ + unsigned short pwronTestmask; /**< mask of bits not test */ + char *name; /**< short register name */ +}; + +enum Tfa98xx_DMEM tfa98xx_filter_mem(struct tfa_device *tfa, int filter_index, unsigned short *address, int channel); + +/** + * Load the default HW settings in the device + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfa98xx_init(struct tfa_device *tfa); + +/** + * If needed, this function can be used to get a text version of the status ID code + * @param status the given status ID code + * @return the I2C status ID string + */ +const char *tfa98xx_get_i2c_status_id_string(int status); + +/* control the powerdown bit + * @param tfa the device struct pointer + * @param powerdown must be 1 or 0 + */ +enum Tfa98xx_Error tfa98xx_powerdown(struct tfa_device *tfa, int powerdown); + +/* indicates on which channel of DATAI2 the gain from the IC is set + * @param tfa the device struct pointer + * @param gain_sel, see Tfa98xx_StereoGainSel_t + */ +enum Tfa98xx_Error tfa98xx_select_stereo_gain_channel(struct tfa_device *tfa, + enum Tfa98xx_StereoGainSel gain_sel); + +/** + * set the mtp with user controllable values + * @param tfa the device struct pointer + * @param value to be written + * @param mask to be applied toi the bits affected + */ +enum Tfa98xx_Error tfa98xx_set_mtp(struct tfa_device *tfa, uint16_t value, uint16_t mask); +enum Tfa98xx_Error tfa98xx_get_mtp(struct tfa_device *tfa, uint16_t *value); + +/** + * lock or unlock KEY2 + * lock = 1 will lock + * lock = 0 will unlock + * note that on return all the hidden key will be off + */ +void tfa98xx_key2(struct tfa_device *tfa, int lock); + +int tfa_calibrate(struct tfa_device *tfa) ; +void tfa98xx_set_exttemp(struct tfa_device *tfa, short ext_temp); +short tfa98xx_get_exttemp(struct tfa_device *tfa); + +/* control the volume of the DSP + * @param vol volume in bit field. It must be between 0 and 255 + */ +enum Tfa98xx_Error tfa98xx_set_volume_level(struct tfa_device *tfa, + unsigned short vol); + +/* set the input channel to use + * @param channel see Tfa98xx_Channel_t enumeration + */ +enum Tfa98xx_Error tfa98xx_select_channel(struct tfa_device *tfa, + enum Tfa98xx_Channel channel); + +/* set the mode for normal or receiver mode + * @param mode see Tfa98xx_Mode enumeration + */ +enum Tfa98xx_Error tfa98xx_select_mode(struct tfa_device *tfa, enum Tfa98xx_Mode mode); + +/* mute/unmute the audio + * @param mute see Tfa98xx_Mute_t enumeration + */ +enum Tfa98xx_Error tfa98xx_set_mute(struct tfa_device *tfa, + enum Tfa98xx_Mute mute); + +/* + * tfa_supported_speakers - required for SmartStudio initialization + * returns the number of the supported speaker count + */ +enum Tfa98xx_Error tfa_supported_speakers(struct tfa_device *tfa, int *spkr_count); + +/** +* Return the tfa revision +*/ +void tfa98xx_rev(int *major, int *minor, int *revision); + +/* + * Return the feature bits from MTP and cnt file for comparison + */ +enum Tfa98xx_Error +tfa98xx_compare_features(struct tfa_device *tfa, int features_from_MTP[3], int features_from_cnt[3]); + +/* + * return feature bits + */ +enum Tfa98xx_Error +tfa98xx_dsp_get_sw_feature_bits(struct tfa_device *tfa, int features[2]); +enum Tfa98xx_Error +tfa98xx_dsp_get_hw_feature_bits(struct tfa_device *tfa, int *features); + +/* + * tfa98xx_supported_saam + * returns the speaker as microphone feature + * @param saam enum pointer + * @return error code + */ +enum Tfa98xx_Error tfa98xx_supported_saam(struct tfa_device *tfa, enum Tfa98xx_saam *saam); + +/* load the tables to the DSP + * called after patch load is done + * @return error code + */ +enum Tfa98xx_Error tfa98xx_dsp_write_tables(struct tfa_device *tfa, int sample_rate); + + +/* set or clear DSP reset signal + * @param new state + * @return error code + */ +enum Tfa98xx_Error tfa98xx_dsp_reset(struct tfa_device *tfa, int state); + +/* check the state of the DSP subsystem + * return ready = 1 when clocks are stable to allow safe DSP subsystem access + * @param tfa the device struct pointer + * @param ready pointer to state flag, non-zero if clocks are not stable + * @return error code + */ +enum Tfa98xx_Error tfa98xx_dsp_system_stable(struct tfa_device *tfa, int *ready); + +enum Tfa98xx_Error tfa98xx_auto_copy_mtp_to_iic(struct tfa_device *tfa); + +/** + * check the state of the DSP coolflux + * @param tfa the device struct pointer + * @return the value of CFE + */ +int tfa_cf_enabled(struct tfa_device *tfa); + +/* The following functions can only be called when the DSP is running + * - I2S clock must be active, + * - IC must be in operating mode + */ + +/** + * patch the ROM code of the DSP + * @param tfa the device struct pointer + * @param patchLength the number of bytes of patchBytes + * @param patchBytes pointer to the bytes to patch + */ +enum Tfa98xx_Error tfa_dsp_patch(struct tfa_device *tfa, + int patchLength, + const unsigned char *patchBytes); + +/** + * load explicitly the speaker parameters in case of free speaker, + * or when using a saved speaker model + */ +enum Tfa98xx_Error tfa98xx_dsp_write_speaker_parameters( + struct tfa_device *tfa, + int length, + const unsigned char *pSpeakerBytes); + +/** + * read the speaker parameters as used by the SpeakerBoost processing + */ +enum Tfa98xx_Error tfa98xx_dsp_read_speaker_parameters( + struct tfa_device *tfa, + int length, + unsigned char *pSpeakerBytes); + +/** + * read the current status of the DSP, typically used for development, + * not essential to be used in a product + */ +enum Tfa98xx_Error tfa98xx_dsp_get_state_info( + struct tfa_device *tfa, + unsigned char bytes[], + unsigned int *statesize); + +/** + * Check whether the DSP supports DRC + * pbSupportDrc=1 when DSP supports DRC, + * pbSupportDrc=0 when DSP doesn't support it + */ +enum Tfa98xx_Error tfa98xx_dsp_support_drc(struct tfa_device *tfa, + int *pbSupportDrc); + +enum Tfa98xx_Error +tfa98xx_dsp_support_framework(struct tfa_device *tfa, int *pbSupportFramework); + +/** + * read the speaker excursion model as used by SpeakerBoost processing + */ +enum Tfa98xx_Error tfa98xx_dsp_read_excursion_model( + struct tfa_device *tfa, + int length, + unsigned char *pSpeakerBytes); + +/** + * load all the parameters for a preset from a file + */ +enum Tfa98xx_Error tfa98xx_dsp_write_preset(struct tfa_device *tfa, + int length, const unsigned char + *pPresetBytes); + +/** + * wrapper for dsp_msg that adds opcode and only writes + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + const unsigned char data[]); + +/** + * wrapper for dsp_msg that writes opcode and reads back the data + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write_read(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]); + +/** + * wrapper for dsp_msg that adds opcode and 3 bytes required for coefs + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_coefs(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]); + +/** + * wrapper for dsp_msg that adds opcode and 3 bytes required for MBDrcDynamics + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_MBDrc_dynamics(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int index_subband, + int num_bytes, unsigned char data[]); + +/** + * Disable a certain biquad. + * @param tfa the device struct pointer + * @param biquad_index: 1-10 of the biquad that needs to be adressed +*/ +enum Tfa98xx_Error Tfa98xx_DspBiquad_Disable(struct tfa_device *tfa, + int biquad_index); + +/** + * fill the calibration value as milli ohms in the struct + * assume that the device has been calibrated + */ +enum Tfa98xx_Error +tfa_dsp_get_calibration_impedance(struct tfa_device *tfa); + +/* + * return the mohm value + */ +int tfa_get_calibration_info(struct tfa_device *tfa, int channel); + +/* + * return sign extended tap pattern + */ +int tfa_get_tap_pattern(struct tfa_device *tfa); + +/** + * Reads a number of words from dsp memory + * @param tfa the device struct pointer + * @param subaddress write address to set in address register + * @param pValue pointer to read data +*/ +enum Tfa98xx_Error tfa98xx_read_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short *pValue); + +/** + * Reads a number of words from dsp memory + * @param tfa the device struct pointer + * @param subaddress write address to set in address register + * @param value value to write int the memory +*/ +enum Tfa98xx_Error tfa98xx_write_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short value); + +/** + * Intialise the dsp + * @param tfa the device struct pointer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_init_dsp(struct tfa_device *tfa); + +/** + * Get the status of the external DSP + * @param tfa the device struct pointer + * @return status +*/ +int tfa98xx_get_dsp_status(struct tfa_device *tfa); + +/** + * Write a command message (RPC) to the dsp + * @param tfa the device struct pointer + * @param num_bytes command buffer size in bytes + * @param command_buffer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_write_dsp(struct tfa_device *tfa, int num_bytes, const char *command_buffer); + +/** + * Read the result from the last message from the dsp + * @param tfa the device struct pointer + * @param num_bytes result buffer size in bytes + * @param result_buffer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_read_dsp(struct tfa_device *tfa, int num_bytes, unsigned char *result_buffer); + +/** + * Write a command message (RPC) to the dsp and return the result + * @param tfa the device struct pointer + * @param command_length command buffer size in bytes + * @param command_buffer command buffer + * @param result_length result buffer size in bytes + * @param result_buffer result buffer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_writeread_dsp(struct tfa_device *tfa, int command_length, void *command_buffer, + int result_length, void *result_buffer); + +/** + * Reads a number of words from dsp memory + * @param tfa the device struct pointer + * @param start_offset offset from where to start reading + * @param num_words number of words to read + * @param pValues pointer to read data +*/ +enum Tfa98xx_Error tfa98xx_dsp_read_mem(struct tfa_device *tfa, + unsigned int start_offset, + int num_words, int *pValues); +/** + * Write a value to dsp memory + * @param tfa the device struct pointer + * @param address write address to set in address register + * @param value value to write int the memory + * @param memtype type of memory to write to +*/ +enum Tfa98xx_Error tfa98xx_dsp_write_mem_word(struct tfa_device *tfa, + unsigned short address, int value, int memtype); + +/** + * Read data from dsp memory + * @param tfa the device struct pointer + * @param subaddress write address to set in address register + * @param num_bytes number of bytes to read from dsp + * @param data the unsigned char buffer to read data into +*/ +enum Tfa98xx_Error tfa98xx_read_data(struct tfa_device *tfa, + unsigned char subaddress, + int num_bytes, unsigned char data[]); + +/** + * Write all the bytes specified by num_bytes and data to dsp memory + * @param tfa the device struct pointer + * @param subaddress the subaddress to write to + * @param num_bytes number of bytes to write + * @param data actual data to write +*/ +enum Tfa98xx_Error tfa98xx_write_data(struct tfa_device *tfa, + unsigned char subaddress, + int num_bytes, + const unsigned char data[]); + +enum Tfa98xx_Error tfa98xx_write_raw(struct tfa_device *tfa, + int num_bytes, + const unsigned char data[]); + +/* support for converting error codes into text */ +const char *tfa98xx_get_error_string(enum Tfa98xx_Error error); + +/** + * convert signed 24 bit integers to 32bit aligned bytes + * input: data contains "num_bytes/3" int24 elements + * output: bytes contains "num_bytes" byte elements + * @param num_data length of the input data array + * @param data input data as integer array + * @param bytes output data as unsigned char array +*/ +void tfa98xx_convert_data2bytes(int num_data, const int data[], + unsigned char bytes[]); + +/** + * convert memory bytes to signed 24 bit integers + * input: bytes contains "num_bytes" byte elements + * output: data contains "num_bytes/3" int24 elements + * @param num_bytes length of the input data array + * @param bytes input data as unsigned char array + * @param data output data as integer array +*/ +void tfa98xx_convert_bytes2data(int num_bytes, const unsigned char bytes[], + int data[]); + +/** + * Read a part of the dsp memory + * @param tfa the device struct pointer + * @param memoryType indicator to the memory type + * @param offset from where to start reading + * @param length the number of bytes to read + * @param bytes output data as unsigned char array +*/ +enum Tfa98xx_Error tfa98xx_dsp_get_memory(struct tfa_device *tfa, + int memoryType, int offset, int length, + unsigned char bytes[]); + +/** + * Write a value to the dsp memory + * @param tfa the device struct pointer + * @param memoryType indicator to the memory type + * @param offset from where to start writing + * @param length the number of bytes to write + * @param value the value to write to the dsp +*/ +enum Tfa98xx_Error tfa98xx_dsp_set_memory(struct tfa_device *tfa, + int memoryType, int offset, + int length, int value); + +enum Tfa98xx_Error tfa98xx_dsp_write_config(struct tfa_device *tfa, int length, + const unsigned char *p_config_bytes); +enum Tfa98xx_Error tfa98xx_dsp_write_drc(struct tfa_device *tfa, int length, + const unsigned char *p_drc_bytes); + +/** + * write/read raw msg functions : + * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes + * The functions will return immediately and do not not wait for DSP response + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buf character buffer to write +*/ +enum Tfa98xx_Error tfa_dsp_msg(struct tfa_device *tfa, int length, const char *buf); + + +/** + * The wrapper functions to call the dsp msg, register and memory function for tfa or probus + */ +enum Tfa98xx_Error dsp_msg(struct tfa_device *tfa, int length, const char *buf); +enum Tfa98xx_Error dsp_msg_read(struct tfa_device *tfa, int length, unsigned char *bytes); +enum Tfa98xx_Error reg_write(struct tfa_device *tfa, unsigned char subaddress, unsigned short value); +enum Tfa98xx_Error reg_read(struct tfa_device *tfa, unsigned char subaddress, unsigned short *value); +enum Tfa98xx_Error mem_write(struct tfa_device *tfa, unsigned short address, int value, int memtype); +enum Tfa98xx_Error mem_read(struct tfa_device *tfa, unsigned int start_offset, int num_words, int *pValues); + +enum Tfa98xx_Error dsp_partial_coefficients(struct tfa_device *tfa, uint8_t *prev, uint8_t *next); +int is_94_N2_device(struct tfa_device *tfa); +/** + * write/read raw msg functions: + * the buffer is provided in little endian format, each word occupying 3 bytes, + * length is in bytes The functions will return immediately and do not not wait + * for DSP response. An ID is added to modify the command-ID + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buf character buffer to write + * @param cmdid command identifier +*/ +enum Tfa98xx_Error tfa_dsp_msg_id(struct tfa_device *tfa, int length, + const char *buf, uint8_t cmdid[3]); + +/** + * write raw dsp msg functions + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buffer character buffer to write +*/ +enum Tfa98xx_Error tfa_dsp_msg_write(struct tfa_device *tfa, int length, + const char *buffer); + +/** + * write raw dsp msg functions + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buffer character buffer to write + * @param cmdid command identifier +*/ +enum Tfa98xx_Error tfa_dsp_msg_write_id(struct tfa_device *tfa, int length, + const char *buffer, uint8_t cmdid[3]); + +/** + * status function used by tfa_dsp_msg() to retrieve command/msg status: + * return a <0 status of the DSP did not ACK. + * @param tfa the device struct pointer + * @param pRpcStatus status for remote processor communication +*/ +enum Tfa98xx_Error tfa_dsp_msg_status(struct tfa_device *tfa, int *pRpcStatus); + +/** + * Read a message from dsp + * @param tfa the device struct pointer + * @param length number of bytes of the message + * @param bytes pointer to unsigned char buffer +*/ +enum Tfa98xx_Error tfa_dsp_msg_read(struct tfa_device *tfa, int length, + unsigned char *bytes); + +int tfa_set_bf(struct tfa_device *tfa, const uint16_t bf, const uint16_t value); +int tfa_set_bf_volatile(struct tfa_device *tfa, const uint16_t bf, + const uint16_t value); + +/** + * Get the value of a given bitfield + * @param tfa the device struct pointer + * @param bf the value indicating which bitfield + */ +int tfa_get_bf(struct tfa_device *tfa, const uint16_t bf); + +/** + * Set the value of a given bitfield + * @param bf the value indicating which bitfield + * @param bf_value the value of the bitfield + * @param p_reg_value a pointer to the register where to write the bitfield + * value + */ +int tfa_set_bf_value(const uint16_t bf, const uint16_t bf_value, + uint16_t *p_reg_value); + +uint16_t tfa_get_bf_value(const uint16_t bf, const uint16_t reg_value); +int tfa_write_reg(struct tfa_device *tfa, const uint16_t bf, + const uint16_t reg_value); +int tfa_read_reg(struct tfa_device *tfa, const uint16_t bf); + +/* bitfield */ +/** + * get the datasheet or bitfield name corresponding to the bitfield number + * @param num is the number for which to get the bitfield name + * @param rev is the device type + */ +char *tfaContBfName(uint16_t num, unsigned short rev); + +/** + * get the datasheet name corresponding to the bitfield number + * @param num is the number for which to get the bitfield name + * @param rev is the device type + */ +char *tfaContDsName(uint16_t num, unsigned short rev); + +/** + * get the bitfield name corresponding to the bitfield number + * @param num is the number for which to get the bitfield name + * @param rev is the device type + */ +char *tfaContBitName(uint16_t num, unsigned short rev); + +/** + * get the bitfield number corresponding to the bitfield name + * @param name is the bitfield name for which to get the bitfield number + * @param rev is the device type + */ +uint16_t tfaContBfEnum(const char *name, unsigned short rev); + +/** +* get the bitfield number corresponding to the bitfield name, checks for all devices +* @param name is the bitfield name for which to get the bitfield number + */ +uint16_t tfaContBfEnumAny(const char *name); + +#define TFA_FAM(tfa, fieldname) ((tfa->tfa_family == 1) ? TFA1_BF_##fieldname : TFA2_BF_##fieldname) +#define TFA_FAM_FW(tfa, fwname) ((tfa->tfa_family == 1) ? TFA1_FW_##fwname : TFA2_FW_##fwname) + +/* set/get bit fields to HW register*/ +#define TFA_SET_BF(tfa, fieldname, value) tfa_set_bf(tfa, TFA_FAM(tfa, fieldname), value) +#define TFA_SET_BF_VOLATILE(tfa, fieldname, value) tfa_set_bf_volatile(tfa, TFA_FAM(tfa, fieldname), value) +#define TFA_GET_BF(tfa, fieldname) tfa_get_bf(tfa, TFA_FAM(tfa, fieldname)) + +/* set/get bit field in variable */ +#define TFA_SET_BF_VALUE(tfa, fieldname, bf_value, p_reg_value) tfa_set_bf_value(TFA_FAM(tfa, fieldname), bf_value, p_reg_value) +#define TFA_GET_BF_VALUE(tfa, fieldname, reg_value) tfa_get_bf_value(TFA_FAM(tfa, fieldname), reg_value) + +/* write/read registers using a bit field name to determine the register address */ +#define TFA_WRITE_REG(tfa, fieldname, value) tfa_write_reg(tfa, TFA_FAM(tfa, fieldname), value) +#define TFA_READ_REG(tfa, fieldname) tfa_read_reg(tfa, TFA_FAM(tfa, fieldname)) + +/* FOR CALIBRATION RETRIES */ +#define TFA98XX_API_WAITRESULT_NTRIES 3000 // defined in API + +/** + * run the startup/init sequence and set ACS bit + * @param tfa the device struct pointer + * @param state the cold start state that is requested + */ +enum Tfa98xx_Error tfaRunColdboot(struct tfa_device *tfa, int state); +enum Tfa98xx_Error tfaRunMute(struct tfa_device *tfa); +enum Tfa98xx_Error tfaRunUnmute(struct tfa_device *tfa); + +/** + * wait for calibrateDone + * @param tfa the device struct pointer + * @param calibrateDone pointer to status of calibration + */ +enum Tfa98xx_Error tfaRunWaitCalibration(struct tfa_device *tfa, int *calibrateDone); + +/** + * run the startup/init sequence and set ACS bit + * @param tfa the device struct pointer + * @param profile the profile that should be loaded + */ +enum Tfa98xx_Error tfaRunColdStartup(struct tfa_device *tfa, int profile); + +/** + * this will load the patch witch will implicitly start the DSP + * if no patch is available the DPS is started immediately + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfaRunStartDSP(struct tfa_device *tfa); + +/** + * start the clocks and wait until the AMP is switching + * on return the DSP sub system will be ready for loading + * @param tfa the device struct pointer + * @param profile the profile that should be loaded on startup + */ +enum Tfa98xx_Error tfaRunStartup(struct tfa_device *tfa, int profile); + +/** + * start the maximus speakerboost algorithm + * this implies a full system startup when the system was not already started + * @param tfa the device struct pointer + * @param force indicates whether a full system startup should be allowed + * @param profile the profile that should be loaded + */ +enum Tfa98xx_Error tfaRunSpeakerBoost(struct tfa_device *tfa, + int force, int profile); + +/** + * Startup the device and write all files from device and profile section + * @param tfa the device struct pointer + * @param force indicates whether a full system startup should be allowed + * @param profile the profile that should be loaded on speaker startup + */ +enum Tfa98xx_Error tfaRunSpeakerStartup(struct tfa_device *tfa, int force, + int profile); + +/** + * Run calibration + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfaRunSpeakerCalibration(struct tfa_device *tfa); + +/** + * startup all devices. all step until patch loading is handled + * @param tfa the device struct pointer + */ +int tfaRunStartupAll(struct tfa_device *tfa); + +/** + * powerup the coolflux subsystem and wait for it + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfa_cf_powerup(struct tfa_device *tfa); + +/* + * print the current device manager state + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error show_current_state(struct tfa_device *tfa); + +/** + * Init registers and coldboot dsp + * @param tfa the device struct pointer + */ +int tfa_reset(struct tfa_device *tfa); + +/** + * Get profile from a register + * @param tfa the device struct pointer + */ +int tfa_dev_get_swprof(struct tfa_device *tfa); + +/** + * Save profile in a register + */ +int tfa_dev_set_swprof(struct tfa_device *tfa, unsigned short new_value); + +int tfa_dev_get_swvstep(struct tfa_device *tfa); + +int tfa_dev_set_swvstep(struct tfa_device *tfa, unsigned short new_value); + +int tfa_needs_reset(struct tfa_device *tfa); + +int tfa_is_cold(struct tfa_device *tfa); + +void tfa_set_query_info(struct tfa_device *tfa); + +int tfa_get_pga_gain(struct tfa_device *tfa); +int tfa_set_pga_gain(struct tfa_device *tfa, uint16_t value); +int tfa_get_noclk(struct tfa_device *tfa); + +/** + * Status of used for monitoring + * @param tfa the device struct pointer + * @return tfa error enum + */ + +enum Tfa98xx_Error tfa_status(struct tfa_device *tfa); + +/* + * function overload for flag_mtp_busy + */ +int tfa_dev_get_mtpb(struct tfa_device *tfa); + +enum Tfa98xx_Error tfaGetFwApiVersion(struct tfa_device *tfa, unsigned char *pFirmwareVersion); +#ifdef __cplusplus +} +#endif +#endif /* TFA_SERVICE_H */ diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index f0cb1c4afe3cec6429038af5eaee5e892c478917..c5a8d758f58b8a122c8d44583df9174770fd24a4 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -170,7 +170,7 @@ SOC_DOUBLE("Polarity Invert Switch", WM8737_ADC_CONTROL, 5, 6, 1, 0), SOC_SINGLE("3D Switch", WM8737_3D_ENHANCE, 0, 1, 0), SOC_SINGLE("3D Depth", WM8737_3D_ENHANCE, 1, 15, 0), SOC_ENUM("3D Low Cut-off", low_3d), -SOC_ENUM("3D High Cut-off", low_3d), +SOC_ENUM("3D High Cut-off", high_3d), SOC_SINGLE_TLV("3D ADC Volume", WM8737_3D_ENHANCE, 7, 1, 1, adc_tlv), SOC_SINGLE("Noise Gate Switch", WM8737_NOISE_GATE, 0, 1, 0), diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index fd2731d171dd02511ecb85d67a1189b509db4c71..0e8008d38161905e06bdd6a40fb96c84f3212ace 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2791,7 +2791,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, if (target % Fref == 0) { fll_div->theta = 0; - fll_div->lambda = 0; + fll_div->lambda = 1; } else { gcd_fll = gcd(target, fratio * Fref); @@ -2861,7 +2861,7 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return -EINVAL; } - if (fll_div.theta || fll_div.lambda) + if (fll_div.theta) fll1 |= WM8962_FLL_FRAC; /* Stop the FLL while we reconfigure */ diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 07bac9ea65c41a3e003711a21c28aa8ff7bc014d..e10e03800cce52d76ca7c6f6ca4b83e73835b2f1 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -882,14 +882,13 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream, active_slots = hweight32(mcasp->tdm_mask[stream]); active_serializers = (channels + active_slots - 1) / active_slots; - if (active_serializers == 1) { + if (active_serializers == 1) active_slots = channels; - for (i = 0; i < total_slots; i++) { - if ((1 << i) & mcasp->tdm_mask[stream]) { - mask |= (1 << i); - if (--active_slots <= 0) - break; - } + for (i = 0; i < total_slots; i++) { + if ((1 << i) & mcasp->tdm_mask[stream]) { + mask |= (1 << i); + if (--active_slots <= 0) + break; } } } else { diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 8e525f7ac08d1e859ffbb76d1f73f441abef0e92..3d99a8579c99f8f75a092c72448e87e4820a65bf 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -119,7 +119,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) codec_dev = of_find_i2c_device_by_node(codec_np); if (!codec_dev) { dev_err(&pdev->dev, "failed to find codec platform device\n"); - return -EPROBE_DEFER; + ret = -EPROBE_DEFER; + goto fail; } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index d49adc822a110ed2a9b61f1916570ed70065a3fd..8e6b88d68ca6ca981cc4d5bd5cd818f33a614b16 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -163,41 +163,52 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) if (!cpu || !codec) { dev_err(dev, "Can't find cpu/codec DT node\n"); - return ERR_PTR(-EINVAL); + ret = -EINVAL; + goto error; } link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0); if (!link->cpu_of_node) { dev_err(card->dev, "error getting cpu phandle\n"); - return ERR_PTR(-EINVAL); + ret = -EINVAL; + goto error; } ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name); if (ret) { dev_err(card->dev, "error getting cpu dai name\n"); - return ERR_PTR(ret); + goto error; } ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); if (ret < 0) { dev_err(card->dev, "error getting codec dai name\n"); - return ERR_PTR(ret); + goto error; } link->platform_of_node = link->cpu_of_node; ret = of_property_read_string(np, "link-name", &link->name); if (ret) { dev_err(card->dev, "error getting codec dai_link name\n"); - return ERR_PTR(ret); + goto error; } link->stream_name = link->name; link->init = apq8016_sbc_dai_init; link++; + + of_node_put(cpu); + of_node_put(codec); } return data; + + error: + of_node_put(np); + of_node_put(cpu); + of_node_put(codec); + return ERR_PTR(ret); } static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index f9fbcbccb57f1abfc96f0fbc3652c68041de0f22..6d15b430a4f2a716518d8d767aa1f9e0336f8ca0 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -73,8 +73,8 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) else codec_stream = &dai->driver->capture; - /* If the codec specifies any rate at all, it supports the stream. */ - return codec_stream->rates; + /* If the codec specifies any channels at all, it supports the stream */ + return codec_stream->channels_min; } /** diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 2d5cf263515b7eec76ed7774ccc18607425b5dae..72301bcad3bddde53465a7b29f06e5ca0ba60813 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1921,6 +1921,7 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, int count = hdr->count; int i; bool abi_match; + int ret; if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) return 0; @@ -1957,7 +1958,12 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, } /* create the FE DAIs and DAI links */ - soc_tplg_pcm_create(tplg, _pcm); + ret = soc_tplg_pcm_create(tplg, _pcm); + if (ret < 0) { + if (!abi_match) + kfree(_pcm); + return ret; + } /* offset by version-specific struct size and * real priv data size diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index d8b6936e544e3c9e42444130f9087dc31be73357..908f13623f8cdfb8cbed69e47f745d29467a1419 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -226,7 +226,6 @@ static void uni_player_set_channel_status(struct uniperif *player, * sampling frequency. If no sample rate is already specified, then * set one. */ - mutex_lock(&player->ctrl_lock); if (runtime) { switch (runtime->rate) { case 22050: @@ -303,7 +302,6 @@ static void uni_player_set_channel_status(struct uniperif *player, player->stream_settings.iec958.status[3 + (n * 4)] << 24; SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status); } - mutex_unlock(&player->ctrl_lock); /* Update the channel status */ if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) @@ -365,8 +363,10 @@ static int uni_player_prepare_iec958(struct uniperif *player, SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player); + mutex_lock(&player->ctrl_lock); /* Update the channel status */ uni_player_set_channel_status(player, runtime); + mutex_unlock(&player->ctrl_lock); /* Clear the user validity user bits */ SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); @@ -598,7 +598,6 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, iec958->status[1] = ucontrol->value.iec958.status[1]; iec958->status[2] = ucontrol->value.iec958.status[2]; iec958->status[3] = ucontrol->value.iec958.status[3]; - mutex_unlock(&player->ctrl_lock); spin_lock_irqsave(&player->irq_lock, flags); if (player->substream && player->substream->runtime) @@ -608,6 +607,8 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, uni_player_set_channel_status(player, NULL); spin_unlock_irqrestore(&player->irq_lock, flags); + mutex_unlock(&player->ctrl_lock); + return 0; } diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 84cc5678beba5e9367e981c765cad3045aabe32f..7bc57651e1866eda637764d71aedbf8289a34739 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -213,6 +213,7 @@ * @slave_config: dma slave channel runtime config pointer * @phys_addr: SPDIFRX registers physical base address * @lock: synchronization enabling lock + * @irq_lock: prevent race condition with IRQ on stream state * @cs: channel status buffer * @ub: user data buffer * @irq: SPDIFRX interrupt line @@ -233,6 +234,7 @@ struct stm32_spdifrx_data { struct dma_slave_config slave_config; dma_addr_t phys_addr; spinlock_t lock; /* Sync enabling lock */ + spinlock_t irq_lock; /* Prevent race condition on stream state */ unsigned char cs[SPDIFRX_CS_BYTES_NB]; unsigned char ub[SPDIFRX_UB_BYTES_NB]; int irq; @@ -313,6 +315,7 @@ static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) { int cr, cr_mask, imr, ret; + unsigned long flags; /* Enable IRQs */ imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; @@ -320,7 +323,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) if (ret) return ret; - spin_lock(&spdifrx->lock); + spin_lock_irqsave(&spdifrx->lock, flags); spdifrx->refcount++; @@ -353,7 +356,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) "Failed to start synchronization\n"); } - spin_unlock(&spdifrx->lock); + spin_unlock_irqrestore(&spdifrx->lock, flags); return ret; } @@ -361,11 +364,12 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) { int cr, cr_mask, reg; + unsigned long flags; - spin_lock(&spdifrx->lock); + spin_lock_irqsave(&spdifrx->lock, flags); if (--spdifrx->refcount) { - spin_unlock(&spdifrx->lock); + spin_unlock_irqrestore(&spdifrx->lock, flags); return; } @@ -384,7 +388,7 @@ static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, ®); regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, ®); - spin_unlock(&spdifrx->lock); + spin_unlock_irqrestore(&spdifrx->lock, flags); } static int stm32_spdifrx_dma_ctrl_register(struct device *dev, @@ -644,7 +648,6 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) { struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid; - struct snd_pcm_substream *substream = spdifrx->substream; struct platform_device *pdev = spdifrx->pdev; unsigned int cr, mask, sr, imr; unsigned int flags; @@ -712,14 +715,19 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, SPDIFRX_CR_SPDIFEN_MASK, cr); - if (substream) - snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + spin_lock(&spdifrx->irq_lock); + if (spdifrx->substream) + snd_pcm_stop(spdifrx->substream, + SNDRV_PCM_STATE_DISCONNECTED); + spin_unlock(&spdifrx->irq_lock); return IRQ_HANDLED; } - if (err_xrun && substream) - snd_pcm_stop_xrun(substream); + spin_lock(&spdifrx->irq_lock); + if (err_xrun && spdifrx->substream) + snd_pcm_stop_xrun(spdifrx->substream); + spin_unlock(&spdifrx->irq_lock); return IRQ_HANDLED; } @@ -728,9 +736,12 @@ static int stm32_spdifrx_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; int ret; + spin_lock_irqsave(&spdifrx->irq_lock, flags); spdifrx->substream = substream; + spin_unlock_irqrestore(&spdifrx->irq_lock, flags); ret = clk_prepare_enable(spdifrx->kclk); if (ret) @@ -802,8 +813,12 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + spin_lock_irqsave(&spdifrx->irq_lock, flags); spdifrx->substream = NULL; + spin_unlock_irqrestore(&spdifrx->irq_lock, flags); + clk_disable_unprepare(spdifrx->kclk); } @@ -908,6 +923,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) spdifrx->pdev = pdev; init_completion(&spdifrx->cs_completion); spin_lock_init(&spdifrx->lock); + spin_lock_init(&spdifrx->irq_lock); platform_set_drvdata(pdev, spdifrx); diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index da0a2083e12af2fc257616ab4f2ceae07eb8068d..d2802fd8c1dd76d8a9b7f33203768ca0a56d15e5 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -80,8 +80,8 @@ #define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0) #define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0) -#define SUN4I_I2S_RX_CNT_REG 0x28 -#define SUN4I_I2S_TX_CNT_REG 0x2c +#define SUN4I_I2S_TX_CNT_REG 0x28 +#define SUN4I_I2S_RX_CNT_REG 0x2c #define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 #define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index d27264a274bb626a50ddcd6e4a15db904c861249..14f953679f9fca1981361ad62151610203dcb23a 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2982,7 +2982,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, (err = snd_usb_mixer_status_create(mixer)) < 0) goto _error; - snd_usb_mixer_apply_create_quirk(mixer); + err = snd_usb_mixer_apply_create_quirk(mixer); + if (err < 0) + goto _error; err = snd_device_new(chip->card, SNDRV_DEV_CODEC, mixer, &dev_ops); if (err < 0) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index d32727c74a168779fc31f91302d408ab7d0f52e5..c892b4d1e733f7b061f7a983fd11025209eb944e 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3293,19 +3293,14 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), .ifnum = 0, .type = QUIRK_AUDIO_STANDARD_MIXER, }, - /* Capture */ - { - .ifnum = 1, - .type = QUIRK_IGNORE_INTERFACE, - }, /* Playback */ { - .ifnum = 2, + .ifnum = 1, .type = QUIRK_AUDIO_FIXED_ENDPOINT, .data = &(const struct audioformat) { .formats = SNDRV_PCM_FMTBIT_S16_LE, .channels = 2, - .iface = 2, + .iface = 1, .altsetting = 1, .altset_idx = 1, .attributes = UAC_EP_CS_ATTR_FILL_MAX | diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index ad14d6b78bdcfc6f8ee19d3c4202d7787fd2d7b5..51ee7910e98cf141f4299bedc44142e02c79759b 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1143,6 +1143,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */ case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */ + case USB_ID(0x05a7, 0x1020): /* Bose Companion 5 */ case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */ case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */ diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h index 6c3e2cc274c5546ce64709e444701bdec582390b..0ec646f127dc6b63686920b880e5ea2eda6b077c 100644 --- a/tools/include/linux/string.h +++ b/tools/include/linux/string.h @@ -14,7 +14,15 @@ int strtobool(const char *s, bool *res); * However uClibc headers also define __GLIBC__ hence the hack below */ #if defined(__GLIBC__) && !defined(__UCLIBC__) +// pragma diagnostic was introduced in gcc 4.6 +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif extern size_t strlcpy(char *dest, const char *src, size_t size); +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic pop +#endif #endif char *str_error_r(int errnum, char *buf, size_t buflen); diff --git a/tools/lib/string.c b/tools/lib/string.c index 93b3d4b6feac378d81c2f189310399518efc611f..ee0afcbdd696279bd228b77c4dcb56a3a5c2f9f1 100644 --- a/tools/lib/string.c +++ b/tools/lib/string.c @@ -95,6 +95,10 @@ int strtobool(const char *s, bool *res) * If libc has strlcpy() then that version will override this * implementation: */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wignored-attributes" +#endif size_t __weak strlcpy(char *dest, const char *src, size_t size) { size_t ret = strlen(src); @@ -106,3 +110,6 @@ size_t __weak strlcpy(char *dest, const char *src, size_t size) } return ret; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 8107f060fa849263cb84a8b2dce774af2e14462f..a0ac01c647f5349f11a794499b50da898c2d2115 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -115,6 +115,7 @@ EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) LIB_TARGET = libtraceevent.a libtraceevent.so.$(EVENT_PARSE_VERSION) LIB_INSTALL = libtraceevent.a libtraceevent.so* +LIB_INSTALL := $(addprefix $(OUTPUT),$(LIB_INSTALL)) INCLUDES = -I. -I $(srctree)/tools/include $(CONFIG_INCLUDES) diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index bec7a2f1fb4dc34d6e87d954b72b078133746b7f..264d458bfe2ae644a861265052770fc183353042 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -528,8 +528,8 @@ tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused, { struct c2c_hist_entry *c2c_left; struct c2c_hist_entry *c2c_right; - unsigned int tot_hitm_left; - unsigned int tot_hitm_right; + uint64_t tot_hitm_left; + uint64_t tot_hitm_right; c2c_left = container_of(left, struct c2c_hist_entry, he); c2c_right = container_of(right, struct c2c_hist_entry, he); @@ -562,7 +562,8 @@ __f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \ \ c2c_left = container_of(left, struct c2c_hist_entry, he); \ c2c_right = container_of(right, struct c2c_hist_entry, he); \ - return c2c_left->stats.__f - c2c_right->stats.__f; \ + return (uint64_t) c2c_left->stats.__f - \ + (uint64_t) c2c_right->stats.__f; \ } #define STAT_FN(__f) \ @@ -615,7 +616,8 @@ ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused, c2c_left = container_of(left, struct c2c_hist_entry, he); c2c_right = container_of(right, struct c2c_hist_entry, he); - return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats); + return (uint64_t) llc_miss(&c2c_left->stats) - + (uint64_t) llc_miss(&c2c_right->stats); } static uint64_t total_records(struct c2c_stats *stats) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index fd4dd12b8f9d62c90c6a395f2f22c04b3b0d75c2..429c3e140dc32190bd82146ea7bbd78eb98ded8e 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -342,10 +342,10 @@ static int report__setup_sample_type(struct report *rep) PERF_SAMPLE_BRANCH_ANY)) rep->nonany_branch_mode = true; -#ifndef HAVE_LIBUNWIND_SUPPORT +#if !defined(HAVE_LIBUNWIND_SUPPORT) && !defined(HAVE_DWARF_SUPPORT) if (dwarf_callchain_users) { - ui__warning("Please install libunwind development packages " - "during the perf build.\n"); + ui__warning("Please install libunwind or libdw " + "development packages during the perf build.\n"); } #endif @@ -742,6 +742,7 @@ int cmd_report(int argc, const char **argv) struct stat st; bool has_br_stack = false; int branch_mode = -1; + int last_key = 0; bool branch_call_mode = false; char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; const char * const report_usage[] = { @@ -1048,7 +1049,8 @@ int cmd_report(int argc, const char **argv) else use_browser = 0; - if (setup_sorting(session->evlist) < 0) { + if ((last_key != K_SWITCH_INPUT_DATA) && + (setup_sorting(session->evlist) < 0)) { if (sort_order) parse_options_usage(report_usage, options, "s", 1); if (field_order) @@ -1108,6 +1110,7 @@ int cmd_report(int argc, const char **argv) ret = __cmd_report(&report); if (ret == K_SWITCH_INPUT_DATA) { perf_session__delete(session); + last_key = K_SWITCH_INPUT_DATA; goto repeat; } else ret = 0; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index b99d68943f252808acc827551f3d92aed373ab53..595f91f46811f7c6a2fa9efd95e679d9403405b6 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -317,10 +317,10 @@ static inline void perf_hpp__prepend_sort_field(struct perf_hpp_fmt *format) list_for_each_entry_safe(format, tmp, &(_list)->sorts, sort_list) #define hists__for_each_format(hists, format) \ - perf_hpp_list__for_each_format((hists)->hpp_list, fmt) + perf_hpp_list__for_each_format((hists)->hpp_list, format) #define hists__for_each_sort_list(hists, format) \ - perf_hpp_list__for_each_sort_list((hists)->hpp_list, fmt) + perf_hpp_list__for_each_sort_list((hists)->hpp_list, format) extern struct perf_hpp_fmt perf_hpp__format[]; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 30a5e92b67bd35fd792fa5cfbdcdcccfdd9d0158..893193bd28c1788c8b41bb6cdd7010a3b2751e44 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -615,38 +615,26 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, const char *function, struct probe_trace_point *tp) { - Dwarf_Addr eaddr, highaddr; + Dwarf_Addr eaddr; GElf_Sym sym; const char *symbol; /* Verify the address is correct */ - if (dwarf_entrypc(sp_die, &eaddr) != 0) { - pr_warning("Failed to get entry address of %s\n", - dwarf_diename(sp_die)); - return -ENOENT; - } - if (dwarf_highpc(sp_die, &highaddr) != 0) { - pr_warning("Failed to get end address of %s\n", - dwarf_diename(sp_die)); - return -ENOENT; - } - if (paddr > highaddr) { - pr_warning("Offset specified is greater than size of %s\n", + if (!dwarf_haspc(sp_die, paddr)) { + pr_warning("Specified offset is out of %s\n", dwarf_diename(sp_die)); return -EINVAL; } - symbol = dwarf_diename(sp_die); + /* Try to get actual symbol name from symtab */ + symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); if (!symbol) { - /* Try to get the symbol name from symtab */ - symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); - if (!symbol) { - pr_warning("Failed to find symbol at 0x%lx\n", - (unsigned long)paddr); - return -ENOENT; - } - eaddr = sym.st_value; + pr_warning("Failed to find symbol at 0x%lx\n", + (unsigned long)paddr); + return -ENOENT; } + eaddr = sym.st_value; + tp->offset = (unsigned long)(paddr - eaddr); tp->address = (unsigned long)paddr; tp->symbol = strdup(symbol); diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 913539aea645040e087602e6103031f4b90e7700..9babb3fef8e2e16b8e5e6beb5157a877f027e5a6 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -7281,7 +7281,7 @@ static struct bpf_test tests[] = { offsetof(struct __sk_buff, mark)), BPF_EXIT_INSN(), }, - .errstr = "dereference of modified ctx ptr R1 off=68+8, ctx+const is allowed, ctx+const+const is not", + .errstr = "dereference of modified ctx ptr", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -7944,6 +7944,62 @@ static struct bpf_test tests[] = { .errstr = "BPF_XADD stores into R2 packet", .prog_type = BPF_PROG_TYPE_XDP, }, + { + "pass unmodified ctx pointer to helper", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_csum_update), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "pass modified ctx pointer to helper, 1", + .insns = { + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -612), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_csum_update), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = REJECT, + .errstr = "dereference of modified ctx ptr", + }, + { + "pass modified ctx pointer to helper, 2", + .insns = { + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -612), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_socket_cookie), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result_unpriv = REJECT, + .result = REJECT, + .errstr_unpriv = "dereference of modified ctx ptr", + .errstr = "dereference of modified ctx ptr", + }, + { + "pass modified ctx pointer to helper, 3", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, 0), + BPF_ALU64_IMM(BPF_AND, BPF_REG_3, 4), + BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_csum_update), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = REJECT, + .errstr = "variable ctx access var_off=(0x0; 0x4)", + }, }; static int probe_filter_length(const struct bpf_insn *fp) diff --git a/tools/testing/selftests/filesystems/incfs/.gitignore b/tools/testing/selftests/filesystems/incfs/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..4cba9c219a92b6a5eec6ecc56e4f82e35d1c1542 --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/.gitignore @@ -0,0 +1 @@ +incfs_test \ No newline at end of file diff --git a/tools/testing/selftests/filesystems/incfs/Makefile b/tools/testing/selftests/filesystems/incfs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1f13573d36179148e00b20a1e7aa1f8ec3d0263d --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +CFLAGS += -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -lssl -lcrypto -llz4 +CFLAGS += -I../../../../../usr/include/ +CFLAGS += -I../../../../include/uapi/ +CFLAGS += -I../../../../lib + +EXTRA_SOURCES := utils.c +CFLAGS += $(EXTRA_SOURCES) + +TEST_GEN_PROGS := incfs_test + +include ../../lib.mk + +$(OUTPUT)incfs_test: incfs_test.c $(EXTRA_SOURCES) +all: $(OUTPUT)incfs_test + +clean: + rm -rf $(OUTPUT)incfs_test *.o diff --git a/tools/testing/selftests/filesystems/incfs/config b/tools/testing/selftests/filesystems/incfs/config new file mode 100644 index 0000000000000000000000000000000000000000..b6749837a31878434de0f4a44e09ae34c55563f6 --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/config @@ -0,0 +1 @@ +CONFIG_INCREMENTAL_FS=y \ No newline at end of file diff --git a/tools/testing/selftests/filesystems/incfs/incfs_test.c b/tools/testing/selftests/filesystems/incfs/incfs_test.c new file mode 100644 index 0000000000000000000000000000000000000000..dd70e019dc4ce7182ec0f267bf3ef95fd21d50e3 --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/incfs_test.c @@ -0,0 +1,2422 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../kselftest.h" + +#include "lz4.h" +#include "utils.h" + +#define __packed __attribute__((__packed__)) + +#define TEST_FAILURE 1 +#define TEST_SUCCESS 0 +#define INCFS_MAX_MTREE_LEVELS 8 + +#define INCFS_ROOT_INODE 0 + +struct hash_block { + char data[INCFS_DATA_FILE_BLOCK_SIZE]; +}; + +struct test_signature { + void *data; + size_t size; + + char add_data[100]; + size_t add_data_size; +}; + +struct test_file { + int index; + incfs_uuid_t id; + char *name; + off_t size; + char root_hash[INCFS_MAX_HASH_SIZE]; + struct hash_block *mtree; + int mtree_block_count; + struct test_signature sig; +}; + +struct test_files_set { + struct test_file *files; + int files_count; +}; + +struct linux_dirent64 { + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[0]; +} __packed; + +/* + * The certificate below and the private key were created by calling: + * openssl req -x509 -newkey rsa:4096 -keyout private.key -out cert.crt + * -days 1000 -sha256 -nodes -outform PEM -subj + * "/C=US/ST=WA/L=Kirkland/O=Example/OU=Org/CN=www.example.com" + */ +char x509_cert[] = +"-----BEGIN CERTIFICATE-----\n" +"MIIFvzCCA6egAwIBAgIUXpwqelEljm6BBllRQGHLrls2MYgwDQYJKoZIhvcNAQEL\n" +"BQAwbzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcM\n" +"CEtpcmtsYW5kMRAwDgYDVQQKDAdFeGFtcGxlMQwwCgYDVQQLDANPcmcxGDAWBgNV\n" +"BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xOTA4MDgyMzA3MDZaFw0yMjA1MDQyMzA3\n" +"MDZaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMREwDwYDVQQH\n" +"DAhLaXJrbGFuZDEQMA4GA1UECgwHRXhhbXBsZTEMMAoGA1UECwwDT3JnMRgwFgYD\n" +"VQQDDA93d3cuZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" +"AoICAQC1LuFW/lDV/GflqFMz7RDvFFgWld982ZuDJRaK55JNj+MI4RZNL61PDw43\n" +"NeeJtqUoVxSLS9wHURjSjD/CV5GudUOnzGfbwFlLko+jhYRT4HNFS+5ys1FEJLtA\n" +"uYcY4P9GHQEXYUX+ue82A2kJ91oY6G3vCQYJFiGteb6TRDICmug31x4pBfB8rOdt\n" +"4/NXS/Dn+S0/mJlxw34IKfqrlFjzUziRZtAWWqDcfxFDUizSggkdXIUq4GY38RAD\n" +"qGewNNCab3ClJDP7/M32BhSNgsIKhgtSTM2+ocfvBhwup+BjV6UbL21DPAshlolV\n" +"gSL1HM2jin5bi4bpFMreY0LXwFih87/6AVSfQHY9TZrombVZnMxvB7NG1NCSwDBT\n" +"qjjFb3oiSMugJzY+MhISM754m46fwUyHZ1ylWCLJEU8kQ5A1q9vvqMcaDa4uTGP3\n" +"UgC6SyVmZxG2o+AO6m8TRTCtqHN41mPTM9HK4T1UyuzVpykSc2LlYkKE517SyEiV\n" +"XDmotNb2myXNYHHTjRYNxkq75Lbii2I4Q4z8XtDngaIrhZqACKSqIt2CocGjx61S\n" +"oxKWi+LGa7B4NaCMjz1LnaOIsXn1rJDRnUWL49T42g4kOi/5QaC2JDygfefw1hAb\n" +"uxkq9EYUDg+w9broltiBf4rKAnw8JMySARnyPZbj0lhZK3va5wIDAQABo1MwUTAd\n" +"BgNVHQ4EFgQUo6JN3gY2yGbzOTNj8Al7hNB3rw0wHwYDVR0jBBgwFoAUo6JN3gY2\n" +"yGbzOTNj8Al7hNB3rw0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n" +"AgEAQb3pJqOzM4whfNVdpEOswd1EApcWNM1ps9iTlEEjDoRv9F7F1PW0uXCIpk3B\n" +"j5JgCmIxAcPnzj42rduRSx421hHMZhbAIWI/JL4ZSF64qlG0YrmJDXlJgSMoyst5\n" +"biUqeWgO7Js5udPt3zhkeA62z3hGM6dE5B3k7gHTaKKtK17+UeR9imZKsOK8GBnM\n" +"rxMPI6XghxxAK2OQ/r09DHDiyf/GxgOE46oknfXfMPx3HaSvDKrZUTZ+UvVbM5c2\n" +"5eXOgH5UO/e4llLknJK7CoP/R6G7pV44iT4t4t9FMnvCYvavAHwfR+6z5vTF3o8a\n" +"wd80fC8z1vfLsIPLROdzBl9rGCvv536fPiEA677CM1AZkjfT0a9DVzrE1NDvuCUF\n" +"0KgEdiNwux+hO6dbTyiS38yPT6TbpoWJptJmFhFkC4hGvUgoX/TI0covSyf74VRH\n" +"k3BHojOBMYiX1K66xoN7fhlGK8cith3L0XXPB8CgSEUPWURvm8RCaGuX2T3FZomF\n" +"BCnNpN+WNnN3Yf4OkjtuvtxxktUU7pfVLsUxrdpo/ph4rWm6U83VT/Zlq92aF4vW\n" +"QJ+7uraQFip7e+Gy9g3UJINm3B7b1C4ch/Z/upCZESOI/23sVGzkfTgOrS+23i6/\n" +"Vi9YW75zySC2FCa1AWMS1NmS5qfDSycJUgD6YvOUg0C54ZI=\n" +"-----END CERTIFICATE-----"; + +char private_key[] = +"-----BEGIN PRIVATE KEY-----\n" +"MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC1LuFW/lDV/Gfl\n" +"qFMz7RDvFFgWld982ZuDJRaK55JNj+MI4RZNL61PDw43NeeJtqUoVxSLS9wHURjS\n" +"jD/CV5GudUOnzGfbwFlLko+jhYRT4HNFS+5ys1FEJLtAuYcY4P9GHQEXYUX+ue82\n" +"A2kJ91oY6G3vCQYJFiGteb6TRDICmug31x4pBfB8rOdt4/NXS/Dn+S0/mJlxw34I\n" +"KfqrlFjzUziRZtAWWqDcfxFDUizSggkdXIUq4GY38RADqGewNNCab3ClJDP7/M32\n" +"BhSNgsIKhgtSTM2+ocfvBhwup+BjV6UbL21DPAshlolVgSL1HM2jin5bi4bpFMre\n" +"Y0LXwFih87/6AVSfQHY9TZrombVZnMxvB7NG1NCSwDBTqjjFb3oiSMugJzY+MhIS\n" +"M754m46fwUyHZ1ylWCLJEU8kQ5A1q9vvqMcaDa4uTGP3UgC6SyVmZxG2o+AO6m8T\n" +"RTCtqHN41mPTM9HK4T1UyuzVpykSc2LlYkKE517SyEiVXDmotNb2myXNYHHTjRYN\n" +"xkq75Lbii2I4Q4z8XtDngaIrhZqACKSqIt2CocGjx61SoxKWi+LGa7B4NaCMjz1L\n" +"naOIsXn1rJDRnUWL49T42g4kOi/5QaC2JDygfefw1hAbuxkq9EYUDg+w9broltiB\n" +"f4rKAnw8JMySARnyPZbj0lhZK3va5wIDAQABAoICAQCMKul/0J2e/ncub6t2t4dr\n" +"PnTrfCT6xKqPqciny4Ee6hr9So1jR2gvink380bd/mQFMmEdZqGhM3cdpAzLf82f\n" +"hu7BSNxsYIF0er0PB4MZFMJ4sMaXC+zp5/TJnP5MG/zBND0c5k8tQpEyWy8O28Jj\n" +"FKW/0F5P90Q0ncP20EJUS50tXgniOMsU2Prtw/UE6yZDgD0mPxsurMu66ycXSFwM\n" +"WqyfqEeBk7lw/AjR6Sft71W31lTbl+DclG0MN2OIKUPcxiwCRmDFKI36MDgERk1x\n" +"sMPfdrWRLj2ryDFTUuLAWBTOVEGWS0RdRsWWVaJCuHbKd6FLl0TW2xQbOfWDTjYC\n" +"Ps31ejh163qdbk7OGOZIbd83fP3jsyL+4eNzhUpeXMKhfG58mFIv4yhdZIUOpuL6\n" +"aqnoU9z9wEsJKj/SrKr3nw6tuTnmbXgNjun9LfTFmqqDRBYd0Okiprw6jHNM1jgA\n" +"GG0kC/K7r89jKymVDABwGMFCS33ynR1Tb6zG+cqgNMPw19Fy3uQuW21CjqSzCOyP\n" +"aEVCEUZeP+ofql5+7ZKi6Dj+EdTfeKt2ihgheHZZoaYSINb8tsnKbdJhwBfW9PFT\n" +"aT/hu3bnO2FPC8H2NGOqxOEeel9ALU4SFu1pOknEhiL3/mNfOQ+KgrSRDtNRlcL0\n" +"cto05J90u0cmqwWKlshfaQKCAQEA5dcklxs4ezyzt28NcsiyS02oZ+9TkQp6pCXV\n" +"kx7AwhivAmVTlJ+c6BegA5EPd7A1gknM3+EKzGpoBOqmlF45G57phVIAphAp4oCH\n" +"UOVtIQgM8p4EU2gtX+uNOopdYlpBQnWimXaHA2sOD9/yTbZ03j/McRH6D15+iCld\n" +"3880GHdZaYYbQmHoSDg39LRRO1bdS3WC0oKBD2gPi3K0b9RaZSwKzuVrmlvrLURj\n" +"WMZfmkGl4BsITfuoTxbWFVncG3Kb9eYkYUFZy4M2G/s849PS/HjrN7BvgpanjtVp\n" +"1/39APQfAYfUuBPbKYnb6F8dE0pb5cVd4uMZklAeTb3bXjOO9QKCAQEAyc4CxWXr\n" +"bG6Do5dGpWudQ7ucq00MR0T3MHQIu5XTn6BsPHAJ9ZgrQw9C24PXm2VEjjsrMs5T\n" +"rHNF9oeO39s25Za1iyJ+893icqA3h3ivCUOOoVE54BkuJK6REhkXPD5G1ubmxeBz\n" +"MKNehlpd/eSbJJArkzKFZ8sBtLt8i9VFhRnXSpDAbiMpCbjW+bem9MWdLmkenSnu\n" +"OUbnqYcJhFBCvOT7ZCHFCDNUNPfHcaReSY2EYjw0ZqtqAZD0Q+DL+RkLz7l1+/bF\n" +"eEwNjmjFTcwRyawqf38D4miU0H6ca16FkeSlbmM5p3HdwZK2HVYYz3FSwhox6Ebd\n" +"n6in42qfL4Ug6wKCAQAh9IDRWhIkErmyNdPUy1WbzmM8x5ye5t9rdLNywq5TfnYM\n" +"co/AezwhBax8GmgglIWzM9fykzqXLHklkMz/SlRBgl6ZdZ3m6qhlb/uNtfdDU/8l\n" +"sLaO4+sgKpp4tYxKRW8ytFJLPbmAhcZUDg+r73KgiuhXJAK/VoR29TWLJP9bRfaN\n" +"omRQkEpSsQuDOUhu7cxPo5KqKuGKNyNkxJNnmgWowLLwEfCtozrBO0M6EER7c4tf\n" +"6l51tuIMnSEPknD0FSB5WYCyZYcwi7fotlsuhVK8PdjyJzyyHDOw5FJ4uGsyQt55\n" +"yWlhsH1GS7mTQMn42Zlt/pR6OnbCqNdxQMUxy4gpAoIBAFvMbs5E0pb8nr0n72cI\n" +"UP2itl3mKpOw95D+94n9WcrfOt0zShSCKAvVQWCB1O5HXqwklj4CRWXI+iZu+7sx\n" +"CQPfTq3//ygH4x6paxkg+N6J8LPJMz6Rtb/R+QP2je9FlQvk9U1GEKArcLBFI0R/\n" +"XWOAgZHwBWd1nU0NjFY/qeQmIR02Q5LWQ7C8eG4X8MafriSShO6RSGCdtHwVhWq+\n" +"59ztfL3L7skQMFn37K3xS0LCMVpOcLfTeeFEgxjthVvG3OydPOJlGubiEbiaSEZf\n" +"cif/PUXKDYZMdIVzUsw0ryXykJ5qXKuizHFlv5oQtDCJKFBLgjBbLC2YluaIdekz\n" +"8gkCggEBAJWxS7EuB/qL7fOz0o3HRy0plR3qbwZ0pLoCz0Ii7WxraBS1yQwmxif1\n" +"Rgv89GyFqg1yQl3CSrMiw7oC9WxxxuiEZDO18c4KO3NTv9K4itN9OPQVBTHmEhod\n" +"KWcyP4/W/Sfuae77PyclSqUsAARRrKYn2fpLTS5ibaU0QZgHmdPgYDUrPr+6PHKK\n" +"ZfQKU2uBfuo6zoMbMmFi3UYG49j9rv4d6v+44vS1MPHV9JK/LD8YfBhgx8Pg/u6D\n" +"nUgipS48pkGjJr2u2Vu7Mx70vqz0Yf2neyyDbdLtkYauC4w7YKPTD0yzDJyGuAeB\n" +"GyPbW1yZa5vE302a1Cr0Cd7RC4AFAAw=\n" +"-----END PRIVATE KEY-----"; + +struct test_files_set get_test_files_set(void) +{ + static struct test_file files[] = { + { .index = 0, .name = "file_one_byte", .size = 1 }, + { .index = 1, + .name = "file_one_block", + .size = INCFS_DATA_FILE_BLOCK_SIZE }, + { .index = 2, + .name = "file_one_and_a_half_blocks", + .size = INCFS_DATA_FILE_BLOCK_SIZE + + INCFS_DATA_FILE_BLOCK_SIZE / 2 }, + { .index = 3, + .name = "file_three", + .size = 300 * INCFS_DATA_FILE_BLOCK_SIZE + 3 }, + { .index = 4, + .name = "file_four", + .size = 400 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 5, + .name = "file_five", + .size = 500 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 6, + .name = "file_six", + .size = 600 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 7, + .name = "file_seven", + .size = 700 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 8, + .name = "file_eight", + .size = 800 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 9, + .name = "file_nine", + .size = 900 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 10, .name = "file_big", .size = 500 * 1024 * 1024 } + }; + return (struct test_files_set){ .files = files, + .files_count = ARRAY_SIZE(files) }; +} + +struct test_files_set get_small_test_files_set(void) +{ + static struct test_file files[] = { + { .index = 0, .name = "file_one_byte", .size = 1 }, + { .index = 1, + .name = "file_one_block", + .size = INCFS_DATA_FILE_BLOCK_SIZE }, + { .index = 2, + .name = "file_one_and_a_half_blocks", + .size = INCFS_DATA_FILE_BLOCK_SIZE + + INCFS_DATA_FILE_BLOCK_SIZE / 2 }, + { .index = 3, + .name = "file_three", + .size = 300 * INCFS_DATA_FILE_BLOCK_SIZE + 3 }, + { .index = 4, + .name = "file_four", + .size = 400 * INCFS_DATA_FILE_BLOCK_SIZE + 7 } + }; + return (struct test_files_set){ .files = files, + .files_count = ARRAY_SIZE(files) }; +} + +static int get_file_block_seed(int file, int block) +{ + return 7919 * file + block; +} + +static loff_t min(loff_t a, loff_t b) +{ + return a < b ? a : b; +} + +static pid_t flush_and_fork(void) +{ + fflush(stdout); + return fork(); +} + +static void print_error(char *msg) +{ + ksft_print_msg("%s: %s\n", msg, strerror(errno)); +} + +static int wait_for_process(pid_t pid) +{ + int status; + int wait_res; + + wait_res = waitpid(pid, &status, 0); + if (wait_res <= 0) { + print_error("Can't wait for the child"); + return -EINVAL; + } + if (!WIFEXITED(status)) { + ksft_print_msg("Unexpected child status pid=%d\n", pid); + return -EINVAL; + } + status = WEXITSTATUS(status); + if (status != 0) + return status; + return 0; +} + +static void rnd_buf(uint8_t *data, size_t len, unsigned int seed) +{ + int i; + + for (i = 0; i < len; i++) { + seed = 1103515245 * seed + 12345; + data[i] = (uint8_t)(seed >> (i % 13)); + } +} + +char *bin2hex(char *dst, const void *src, size_t count) +{ + const unsigned char *_src = src; + static const char hex_asc[] = "0123456789abcdef"; + + while (count--) { + unsigned char x = *_src++; + + *dst++ = hex_asc[(x & 0xf0) >> 4]; + *dst++ = hex_asc[(x & 0x0f)]; + } + *dst = 0; + return dst; +} + +static char *get_index_filename(char *mnt_dir, incfs_uuid_t id) +{ + char path[FILENAME_MAX]; + char str_id[1 + 2 * sizeof(id)]; + + bin2hex(str_id, id.bytes, sizeof(id.bytes)); + snprintf(path, ARRAY_SIZE(path), "%s/.index/%s", mnt_dir, str_id); + + return strdup(path); +} + +int open_file_by_id(char *mnt_dir, incfs_uuid_t id) +{ + char *path = get_index_filename(mnt_dir, id); + int fd = open(path, O_RDWR); + + free(path); + if (fd < 0) { + print_error("Can't open file by id."); + return -errno; + } + + return fd; +} + +int get_file_attr(char *mnt_dir, incfs_uuid_t id, char *value, int size) +{ + char *path = get_index_filename(mnt_dir, id); + int res; + + res = getxattr(path, INCFS_XATTR_METADATA_NAME, value, size); + if (res < 0) + res = -errno; + + free(path); + return res; +} + +static bool same_id(incfs_uuid_t *id1, incfs_uuid_t *id2) +{ + return !memcmp(id1->bytes, id2->bytes, sizeof(id1->bytes)); +} + +static int emit_test_blocks(char *mnt_dir, struct test_file *file, + int blocks[], int count) +{ + uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; + uint8_t comp_data[2 * INCFS_DATA_FILE_BLOCK_SIZE]; + int block_count = (count > 32) ? 32 : count; + int data_buf_size = 2 * INCFS_DATA_FILE_BLOCK_SIZE * block_count; + uint8_t *data_buf = malloc(data_buf_size); + uint8_t *current_data = data_buf; + uint8_t *data_end = data_buf + data_buf_size; + struct incfs_new_data_block *block_buf = + calloc(block_count, sizeof(*block_buf)); + ssize_t write_res = 0; + int fd; + int error = 0; + int i = 0; + int blocks_written = 0; + + fd = open_file_by_id(mnt_dir, file->id); + if (fd <= 0) { + error = -errno; + goto out; + } + + for (i = 0; i < block_count; i++) { + int block_index = blocks[i]; + bool compress = (file->index + block_index) % 2 == 0; + int seed = get_file_block_seed(file->index, block_index); + off_t block_offset = + ((off_t)block_index) * INCFS_DATA_FILE_BLOCK_SIZE; + size_t block_size = 0; + + if (block_offset > file->size) { + error = -EINVAL; + break; + } + if (file->size - block_offset > + INCFS_DATA_FILE_BLOCK_SIZE) + block_size = INCFS_DATA_FILE_BLOCK_SIZE; + else + block_size = file->size - block_offset; + + rnd_buf(data, block_size, seed); + if (compress) { + size_t comp_size = LZ4_compress_default( + (char *)data, (char *)comp_data, block_size, + ARRAY_SIZE(comp_data)); + + if (comp_size <= 0) { + error = -EBADMSG; + break; + } + if (current_data + comp_size > data_end) { + error = -ENOMEM; + break; + } + memcpy(current_data, comp_data, comp_size); + block_size = comp_size; + block_buf[i].compression = COMPRESSION_LZ4; + } else { + if (current_data + block_size > data_end) { + error = -ENOMEM; + break; + } + memcpy(current_data, data, block_size); + block_buf[i].compression = COMPRESSION_NONE; + } + + block_buf[i].block_index = block_index; + block_buf[i].data_len = block_size; + block_buf[i].data = ptr_to_u64(current_data); + block_buf[i].compression = + compress ? COMPRESSION_LZ4 : COMPRESSION_NONE; + current_data += block_size; + } + + if (!error) { + write_res = write(fd, block_buf, sizeof(*block_buf) * i); + if (write_res < 0) + error = -errno; + else + blocks_written = write_res / sizeof(*block_buf); + } + if (error) { + ksft_print_msg( + "Writing data block error. Write returned: %d. Error:%s\n", + write_res, strerror(-error)); + } + +out: + free(block_buf); + free(data_buf); + close(fd); + return (error < 0) ? error : blocks_written; +} + +static int emit_test_block(char *mnt_dir, struct test_file *file, + int block_index) +{ + int res = emit_test_blocks(mnt_dir, file, &block_index, 1); + + if (res == 0) + return -EINVAL; + if (res == 1) + return 0; + return res; +} + +static void shuffle(int array[], int count, unsigned int seed) +{ + int i; + + for (i = 0; i < count - 1; i++) { + int items_left = count - i; + int shuffle_index; + int v; + + seed = 1103515245 * seed + 12345; + shuffle_index = i + seed % items_left; + + v = array[shuffle_index]; + array[shuffle_index] = array[i]; + array[i] = v; + } +} + +static int emit_test_file_data(char *mount_dir, struct test_file *file) +{ + int i; + int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + int *block_indexes = NULL; + int result = 0; + int blocks_written = 0; + + if (file->size == 0) + return 0; + + block_indexes = calloc(block_cnt, sizeof(*block_indexes)); + for (i = 0; i < block_cnt; i++) + block_indexes[i] = i; + shuffle(block_indexes, block_cnt, file->index); + + for (i = 0; i < block_cnt; i += blocks_written) { + blocks_written = emit_test_blocks(mount_dir, file, + block_indexes + i, block_cnt - i); + if (blocks_written < 0) { + result = blocks_written; + goto out; + } + if (blocks_written == 0) { + result = -EIO; + goto out; + } + } +out: + free(block_indexes); + return result; +} + +static loff_t read_whole_file(char *filename) +{ + int fd = -1; + loff_t result; + loff_t bytes_read = 0; + uint8_t buff[16 * 1024]; + + fd = open(filename, O_RDONLY); + if (fd <= 0) + return fd; + + while (1) { + int read_result = read(fd, buff, ARRAY_SIZE(buff)); + + if (read_result < 0) { + print_error("Error during reading from a file."); + result = -errno; + goto cleanup; + } else if (read_result == 0) + break; + + bytes_read += read_result; + } + result = bytes_read; + +cleanup: + close(fd); + return result; +} + +static int read_test_file(uint8_t *buf, size_t len, char *filename, + int block_idx) +{ + int fd = -1; + int result; + int bytes_read = 0; + size_t bytes_to_read = len; + off_t offset = ((off_t)block_idx) * INCFS_DATA_FILE_BLOCK_SIZE; + + fd = open(filename, O_RDONLY); + if (fd <= 0) + return fd; + + if (lseek(fd, offset, SEEK_SET) != offset) { + print_error("Seek error"); + return -errno; + } + + while (bytes_read < bytes_to_read) { + int read_result = + read(fd, buf + bytes_read, bytes_to_read - bytes_read); + if (read_result < 0) { + result = -errno; + goto cleanup; + } else if (read_result == 0) + break; + + bytes_read += read_result; + } + result = bytes_read; + +cleanup: + close(fd); + return result; +} + +static char *create_backing_dir(char *mount_dir) +{ + struct stat st; + char backing_dir_name[255]; + + snprintf(backing_dir_name, ARRAY_SIZE(backing_dir_name), "%s-src", + mount_dir); + + if (stat(backing_dir_name, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + int error = delete_dir_tree(backing_dir_name); + + if (error) { + ksft_print_msg( + "Can't delete existing backing dir. %d\n", + error); + return NULL; + } + } else { + if (unlink(backing_dir_name)) { + print_error("Can't clear backing dir"); + return NULL; + } + } + } + + if (mkdir(backing_dir_name, 0777)) { + if (errno != EEXIST) { + print_error("Can't open/create backing dir"); + return NULL; + } + } + + return strdup(backing_dir_name); +} + +static int validate_test_file_content_with_seed(char *mount_dir, + struct test_file *file, + unsigned int shuffle_seed) +{ + int error = -1; + char *filename = concat_file_name(mount_dir, file->name); + off_t size = file->size; + loff_t actual_size = get_file_size(filename); + int block_cnt = 1 + (size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + int *block_indexes = NULL; + int i; + + block_indexes = alloca(sizeof(int) * block_cnt); + for (i = 0; i < block_cnt; i++) + block_indexes[i] = i; + + if (shuffle_seed != 0) + shuffle(block_indexes, block_cnt, shuffle_seed); + + if (actual_size != size) { + ksft_print_msg( + "File size doesn't match. name: %s expected size:%ld actual size:%ld\n", + filename, size, actual_size); + error = -1; + goto failure; + } + + for (i = 0; i < block_cnt; i++) { + int block_idx = block_indexes[i]; + uint8_t expected_block[INCFS_DATA_FILE_BLOCK_SIZE]; + uint8_t actual_block[INCFS_DATA_FILE_BLOCK_SIZE]; + int seed = get_file_block_seed(file->index, block_idx); + size_t bytes_to_compare = min( + (off_t)INCFS_DATA_FILE_BLOCK_SIZE, + size - ((off_t)block_idx) * INCFS_DATA_FILE_BLOCK_SIZE); + int read_result = + read_test_file(actual_block, INCFS_DATA_FILE_BLOCK_SIZE, + filename, block_idx); + if (read_result < 0) { + ksft_print_msg( + "Error reading block %d from file %s. Error: %s\n", + block_idx, filename, strerror(-read_result)); + error = read_result; + goto failure; + } + rnd_buf(expected_block, INCFS_DATA_FILE_BLOCK_SIZE, seed); + if (memcmp(expected_block, actual_block, bytes_to_compare)) { + ksft_print_msg( + "File contents don't match. name: %s block:%d\n", + file->name, block_idx); + error = -2; + goto failure; + } + } + free(filename); + return 0; + +failure: + free(filename); + return error; +} + +static int validate_test_file_content(char *mount_dir, struct test_file *file) +{ + return validate_test_file_content_with_seed(mount_dir, file, 0); +} + +static int data_producer(char *mount_dir, struct test_files_set *test_set) +{ + int ret = 0; + int timeout_ms = 1000; + struct incfs_pending_read_info prs[100] = {}; + int prs_size = ARRAY_SIZE(prs); + int fd = open_commands_file(mount_dir); + + if (fd < 0) + return -errno; + + while ((ret = wait_for_pending_reads(fd, timeout_ms, prs, prs_size)) > + 0) { + int read_count = ret; + int i; + + for (i = 0; i < read_count; i++) { + int j = 0; + struct test_file *file = NULL; + + for (j = 0; j < test_set->files_count; j++) { + bool same = same_id(&(test_set->files[j].id), + &(prs[i].file_id)); + + if (same) { + file = &test_set->files[j]; + break; + } + } + if (!file) { + ksft_print_msg( + "Unknown file in pending reads.\n"); + break; + } + + ret = emit_test_block(mount_dir, file, + prs[i].block_index); + if (ret < 0) { + ksft_print_msg("Emitting test data error: %s\n", + strerror(-ret)); + break; + } + } + } + close(fd); + return ret; +} + +static int build_mtree(struct test_file *file) +{ + char data[INCFS_DATA_FILE_BLOCK_SIZE] = {}; + const int digest_size = SHA256_DIGEST_SIZE; + const int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size; + int block_count = 0; + int hash_block_count = 0; + int total_tree_block_count = 0; + int tree_lvl_index[INCFS_MAX_MTREE_LEVELS] = {}; + int tree_lvl_count[INCFS_MAX_MTREE_LEVELS] = {}; + int levels_count = 0; + char data_to_sign[256] = {}; + int sig_data_size; + int i, level; + + if (file->size == 0) + return 0; + + block_count = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + hash_block_count = block_count; + for (i = 0; hash_block_count > 1; i++) { + hash_block_count = (hash_block_count + hash_per_block - 1) + / hash_per_block; + tree_lvl_count[i] = hash_block_count; + total_tree_block_count += hash_block_count; + } + levels_count = i; + + for (i = 0; i < levels_count; i++) { + int prev_lvl_base = (i == 0) ? total_tree_block_count : + tree_lvl_index[i - 1]; + + tree_lvl_index[i] = prev_lvl_base - tree_lvl_count[i]; + } + + file->mtree_block_count = total_tree_block_count; + if (block_count == 1) { + int seed = get_file_block_seed(file->index, 0); + + rnd_buf((uint8_t *)data, file->size, seed); + sha256(data, file->size, file->root_hash); + return 0; + } + + file->mtree = calloc(total_tree_block_count, sizeof(*file->mtree)); + /* Build level 0 hashes. */ + for (i = 0; i < block_count; i++) { + off_t offset = i * INCFS_DATA_FILE_BLOCK_SIZE; + size_t block_size = INCFS_DATA_FILE_BLOCK_SIZE; + int block_index = tree_lvl_index[0] + + i / hash_per_block; + int block_off = (i % hash_per_block) * digest_size; + int seed = get_file_block_seed(file->index, i); + char *hash_ptr = file->mtree[block_index].data + block_off; + + if (file->size - offset < block_size) + block_size = file->size - offset; + + rnd_buf((uint8_t *)data, block_size, seed); + sha256(data, block_size, hash_ptr); + } + + /* Build higher levels of hash tree. */ + for (level = 1; level < levels_count; level++) { + int prev_lvl_base = tree_lvl_index[level - 1]; + int prev_lvl_count = tree_lvl_count[level - 1]; + + for (i = 0; i < prev_lvl_count; i++) { + int block_index = + i / hash_per_block + tree_lvl_index[level]; + int block_off = (i % hash_per_block) * digest_size; + char *hash_ptr = + file->mtree[block_index].data + block_off; + + sha256(file->mtree[i + prev_lvl_base].data, + INCFS_DATA_FILE_BLOCK_SIZE, hash_ptr); + } + } + + /* Calculate root hash from the top block */ + sha256(file->mtree[0].data, + INCFS_DATA_FILE_BLOCK_SIZE, file->root_hash); + + /* Calculating digital signature */ + snprintf(file->sig.add_data, sizeof(file->sig.add_data), "%ld", + file->size); + memcpy(data_to_sign, file->root_hash, SHA256_DIGEST_SIZE); + memcpy(data_to_sign + SHA256_DIGEST_SIZE, file->sig.add_data, + strlen(file->sig.add_data)); + sig_data_size = SHA256_DIGEST_SIZE + strlen(file->sig.add_data); + if (!sign_pkcs7(data_to_sign, sig_data_size, private_key, x509_cert, + &file->sig.data, &file->sig.size)) { + ksft_print_msg("Signing failed.\n"); + return -EINVAL; + } + + return 0; +} + +static int load_hash_tree(const char *mount_dir, struct test_file *file) +{ + int err; + int i; + int fd; + + size_t blocks_size = + file->mtree_block_count * sizeof(struct incfs_new_data_block); + struct incfs_new_data_block *blocks = NULL; + char *file_path; + + if (blocks_size == 0) + return 0; + + blocks = malloc(blocks_size); + if (!blocks) + return -ENOMEM; + + for (i = 0; i < file->mtree_block_count; i++) { + blocks[i] = (struct incfs_new_data_block){ + .block_index = i, + .data_len = INCFS_DATA_FILE_BLOCK_SIZE, + .data = ptr_to_u64(file->mtree[i].data), + .flags = INCFS_BLOCK_FLAGS_HASH + }; + } + + file_path = concat_file_name(mount_dir, file->name); + fd = open(file_path, O_RDWR); + free(file_path); + if (fd < 0) { + err = errno; + goto failure; + } + + err = write(fd, blocks, blocks_size); + close(fd); + + if (err < blocks_size) + err = errno; + else { + err = 0; + free(file->mtree); + } + +failure: + free(blocks); + return err; +} + +static int cant_touch_index_test(char *mount_dir) +{ + char *file_name = "test_file"; + int file_size = 123; + incfs_uuid_t file_id; + char *index_path = concat_file_name(mount_dir, ".index"); + char *subdir = concat_file_name(index_path, "subdir"); + char *dst_name = concat_file_name(mount_dir, "something"); + char *filename_in_index = NULL; + char *file_path = concat_file_name(mount_dir, file_name); + char *backing_dir; + int cmd_fd = -1; + int err; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + free(backing_dir); + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + + err = mkdir(subdir, 0777); + if (err == 0 || errno != EBUSY) { + print_error("Shouldn't be able to crate subdir in index\n"); + goto failure; + } + + err = emit_file(cmd_fd, ".index", file_name, &file_id, + file_size, NULL); + if (err != -EBUSY) { + print_error("Shouldn't be able to crate a file in index\n"); + goto failure; + } + + err = emit_file(cmd_fd, NULL, file_name, &file_id, + file_size, NULL); + if (err < 0) + goto failure; + filename_in_index = get_index_filename(mount_dir, file_id); + + err = unlink(filename_in_index); + if (err == 0 || errno != EBUSY) { + print_error("Shouldn't be delete from index\n"); + goto failure; + } + + + err = rename(filename_in_index, dst_name); + if (err == 0 || errno != EBUSY) { + print_error("Shouldn't be able to move from index\n"); + goto failure; + } + + free(filename_in_index); + filename_in_index = concat_file_name(index_path, "abc"); + err = link(file_path, filename_in_index); + if (err == 0 || errno != EBUSY) { + print_error("Shouldn't be able to link inside index\n"); + goto failure; + } + + close(cmd_fd); + free(subdir); + free(index_path); + free(dst_name); + free(filename_in_index); + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + free(subdir); + free(dst_name); + free(index_path); + free(filename_in_index); + close(cmd_fd); + umount(mount_dir); + return TEST_FAILURE; +} + +static bool iterate_directory(char *dir_to_iterate, bool root, int file_count) +{ + struct expected_name { + const char *name; + bool root_only; + bool found; + } names[] = { + {INCFS_LOG_FILENAME, true, false}, + {INCFS_PENDING_READS_FILENAME, true, false}, + {".index", true, false}, + {"..", false, false}, + {".", false, false}, + }; + + bool pass = true, found; + int i; + + /* Test directory iteration */ + int fd = open(dir_to_iterate, O_RDONLY | O_DIRECTORY); + + if (fd < 0) { + print_error("Can't open directory\n"); + return false; + } + + for (;;) { + /* Enough space for one dirent - no name over 30 */ + char buf[sizeof(struct linux_dirent64) + NAME_MAX]; + struct linux_dirent64 *dirent = (struct linux_dirent64 *) buf; + int nread; + int i; + + for (i = 0; i < NAME_MAX; ++i) { + nread = syscall(__NR_getdents64, fd, buf, + sizeof(struct linux_dirent64) + i); + + if (nread >= 0) + break; + if (errno != EINVAL) + break; + } + + if (nread == 0) + break; + if (nread < 0) { + print_error("Error iterating directory\n"); + pass = false; + goto failure; + } + + /* Expected size is rounded up to 8 byte boundary. Not sure if + * this is universal truth or just happenstance, but useful test + * for the moment + */ + if (nread != (((sizeof(struct linux_dirent64) + + strlen(dirent->d_name) + 1) + 7) & ~7)) { + print_error("Wrong dirent size"); + pass = false; + goto failure; + } + + found = false; + for (i = 0; i < sizeof(names) / sizeof(*names); ++i) + if (!strcmp(dirent->d_name, names[i].name)) { + if (names[i].root_only && !root) { + print_error("Root file error"); + pass = false; + goto failure; + } + + if (names[i].found) { + print_error("File appears twice"); + pass = false; + goto failure; + } + + names[i].found = true; + found = true; + break; + } + + if (!found) + --file_count; + } + + for (i = 0; i < sizeof(names) / sizeof(*names); ++i) { + if (!names[i].found) + if (root || !names[i].root_only) { + print_error("Expected file not present"); + pass = false; + goto failure; + } + } + + if (file_count) { + print_error("Wrong number of files\n"); + pass = false; + goto failure; + } + +failure: + close(fd); + return pass; +} + +static int basic_file_ops_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + char *subdir1 = concat_file_name(mount_dir, "subdir1"); + char *subdir2 = concat_file_name(mount_dir, "subdir2"); + char *backing_dir; + int cmd_fd = -1; + int i, err; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + free(backing_dir); + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + err = mkdir(subdir1, 0777); + if (err < 0 && errno != EEXIST) { + print_error("Can't create subdir1\n"); + goto failure; + } + + err = mkdir(subdir2, 0777); + if (err < 0 && errno != EEXIST) { + print_error("Can't create subdir2\n"); + goto failure; + } + + /* Create all test files in subdir1 directory */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + loff_t size; + char *file_path = concat_file_name(subdir1, file->name); + + err = emit_file(cmd_fd, "subdir1", file->name, &file->id, + file->size, NULL); + if (err < 0) + goto failure; + + size = get_file_size(file_path); + free(file_path); + if (size != file->size) { + ksft_print_msg("Wrong size %lld of %s.\n", + size, file->name); + goto failure; + } + } + + if (!iterate_directory(subdir1, false, file_num)) + goto failure; + + /* Link the files to subdir2 */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *src_name = concat_file_name(subdir1, file->name); + char *dst_name = concat_file_name(subdir2, file->name); + loff_t size; + + err = link(src_name, dst_name); + if (err < 0) { + print_error("Can't move file\n"); + goto failure; + } + + size = get_file_size(dst_name); + if (size != file->size) { + ksft_print_msg("Wrong size %lld of %s.\n", + size, file->name); + goto failure; + } + free(src_name); + free(dst_name); + } + + /* Move the files from subdir2 to the mount dir */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *src_name = concat_file_name(subdir2, file->name); + char *dst_name = concat_file_name(mount_dir, file->name); + loff_t size; + + err = rename(src_name, dst_name); + if (err < 0) { + print_error("Can't move file\n"); + goto failure; + } + + size = get_file_size(dst_name); + if (size != file->size) { + ksft_print_msg("Wrong size %lld of %s.\n", + size, file->name); + goto failure; + } + free(src_name); + free(dst_name); + } + + /* +2 because there are 2 subdirs */ + if (!iterate_directory(mount_dir, true, file_num + 2)) + goto failure; + + /* Open and close all files from the mount dir */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *path = concat_file_name(mount_dir, file->name); + int fd; + + fd = open(path, O_RDWR); + free(path); + if (fd <= 0) { + print_error("Can't open file"); + goto failure; + } + if (close(fd)) { + print_error("Can't close file"); + goto failure; + } + } + + /* Delete all files from the mount dir */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *path = concat_file_name(mount_dir, file->name); + + err = unlink(path); + free(path); + if (err < 0) { + print_error("Can't unlink file"); + goto failure; + } + } + + err = delete_dir_tree(subdir1); + if (err) { + ksft_print_msg("Error deleting subdir1 %d", err); + goto failure; + } + + err = rmdir(subdir2); + if (err) { + print_error("Error deleting subdir2"); + goto failure; + } + + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + umount(mount_dir); + return TEST_FAILURE; +} + +static int dynamic_files_and_data_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + const int missing_file_idx = 5; + int cmd_fd = -1; + char *backing_dir; + int i; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + free(backing_dir); + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Check that test files don't exist in the filesystem. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *filename = concat_file_name(mount_dir, file->name); + + if (access(filename, F_OK) != -1) { + ksft_print_msg( + "File %s somehow already exists in a clean FS.\n", + filename); + goto failure; + } + free(filename); + } + + /* Write test data into the command file. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int res; + + build_mtree(file); + res = emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL); + if (res < 0) { + ksft_print_msg("Error %s emiting file %s.\n", + strerror(-res), file->name); + goto failure; + } + + /* Skip writing data to one file so we can check */ + /* that it's missing later. */ + if (i == missing_file_idx) + continue; + + res = load_hash_tree(mount_dir, file); + if (res) { + ksft_print_msg("Can't load hashes for %s. error: %s\n", + file->name, strerror(-res)); + goto failure; + } + + res = emit_test_file_data(mount_dir, file); + if (res) { + ksft_print_msg("Error %s emiting data for %s.\n", + strerror(-res), file->name); + goto failure; + } + } + + /* Validate contents of the FS */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (i == missing_file_idx) { + /* No data has been written to this file. */ + /* Check for read error; */ + uint8_t buf; + char *filename = + concat_file_name(mount_dir, file->name); + int res = read_test_file(&buf, 1, filename, 0); + + free(filename); + if (res > 0) { + ksft_print_msg( + "Data present, even though never writtern.\n"); + goto failure; + } + if (res != -ETIME) { + ksft_print_msg("Wrong error code: %d.\n", res); + goto failure; + } + } else { + if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + } + } + + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + umount(mount_dir); + return TEST_FAILURE; +} + +static int concurrent_reads_and_writes_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + /* Validate each file from that many child processes. */ + const int child_multiplier = 3; + int cmd_fd = -1; + char *backing_dir; + int status; + int i; + pid_t producer_pid; + pid_t *child_pids = alloca(child_multiplier * file_num * sizeof(pid_t)); + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + free(backing_dir); + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Tell FS about the files, without actually providing the data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int res; + + res = emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL); + if (res) + goto failure; + } + + /* Start child processes acessing data in the files */ + for (i = 0; i < file_num * child_multiplier; i++) { + struct test_file *file = &test.files[i / child_multiplier]; + pid_t child_pid = flush_and_fork(); + + if (child_pid == 0) { + /* This is a child process, do the data validation. */ + int ret = validate_test_file_content_with_seed( + mount_dir, file, i); + if (ret >= 0) { + /* Zero exit status if data is valid. */ + exit(0); + } + + /* Positive status if validation error found. */ + exit(-ret); + } else if (child_pid > 0) { + child_pids[i] = child_pid; + } else { + print_error("Fork error"); + goto failure; + } + } + + producer_pid = flush_and_fork(); + if (producer_pid == 0) { + int ret; + /* + * This is a child that should provide data to + * pending reads. + */ + + ret = data_producer(mount_dir, &test); + exit(-ret); + } else { + status = wait_for_process(producer_pid); + if (status != 0) { + ksft_print_msg("Data produces failed. %d(%s) ", status, + strerror(status)); + goto failure; + } + } + + /* Check that all children has finished with 0 exit status */ + for (i = 0; i < file_num * child_multiplier; i++) { + struct test_file *file = &test.files[i / child_multiplier]; + + status = wait_for_process(child_pids[i]); + if (status != 0) { + ksft_print_msg( + "Validation for the file %s failed with code %d (%s)\n", + file->name, status, strerror(status)); + goto failure; + } + } + + /* Check that there are no pending reads left */ + { + struct incfs_pending_read_info prs[1] = {}; + int timeout = 0; + int read_count = wait_for_pending_reads(cmd_fd, timeout, prs, + ARRAY_SIZE(prs)); + + if (read_count) { + ksft_print_msg( + "Pending reads pending when all data written\n"); + goto failure; + } + } + + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + umount(mount_dir); + return TEST_FAILURE; +} + +static int work_after_remount_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + const int file_num_stage1 = file_num / 2; + const int file_num_stage2 = file_num; + char *backing_dir = NULL; + int i = 0; + int cmd_fd = -1; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Write first half of the data into the command file. (stage 1) */ + for (i = 0; i < file_num_stage1; i++) { + struct test_file *file = &test.files[i]; + int res; + + build_mtree(file); + if (emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL)) + goto failure; + + if (emit_test_file_data(mount_dir, file)) + goto failure; + + res = load_hash_tree(mount_dir, file); + if (res) { + ksft_print_msg("Can't load hashes for %s. error: %s\n", + file->name, strerror(-res)); + goto failure; + } +} + + /* Unmount and mount again, to see that data is persistent. */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Write the second half of the data into the command file. (stage 2) */ + for (; i < file_num_stage2; i++) { + struct test_file *file = &test.files[i]; + int res = emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL); + + if (res) + goto failure; + + if (emit_test_file_data(mount_dir, file)) + goto failure; + } + + /* Validate contents of the FS */ + for (i = 0; i < file_num_stage2; i++) { + struct test_file *file = &test.files[i]; + + if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + } + + /* Delete all files */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *filename = concat_file_name(mount_dir, file->name); + char *filename_in_index = get_index_filename(mount_dir, + file->id); + + if (access(filename, F_OK) != 0) { + ksft_print_msg("File %s is not visible.\n", filename); + goto failure; + } + + if (access(filename_in_index, F_OK) != 0) { + ksft_print_msg("File %s is not visible.\n", + filename_in_index); + goto failure; + } + + unlink(filename); + + if (access(filename, F_OK) != -1) { + ksft_print_msg("File %s is still present.\n", filename); + goto failure; + } + + if (access(filename_in_index, F_OK) != 0) { + ksft_print_msg("File %s is still present.\n", + filename_in_index); + goto failure; + } + free(filename); + free(filename_in_index); + } + + /* Unmount and mount again, to see that deleted files stay deleted. */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Validate all deleted files are still deleted. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *filename = concat_file_name(mount_dir, file->name); + + if (access(filename, F_OK) != -1) { + ksft_print_msg("File %s is still visible.\n", filename); + goto failure; + } + free(filename); + } + + /* Final unmount */ + close(cmd_fd); + free(backing_dir); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int attribute_test(char *mount_dir) +{ + char file_attr[] = "metadata123123"; + char attr_buf[INCFS_MAX_FILE_ATTR_SIZE] = {}; + int cmd_fd = -1; + incfs_uuid_t file_id; + int attr_res = 0; + char *backing_dir; + + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + if (emit_file(cmd_fd, NULL, "file", &file_id, 12, file_attr)) + goto failure; + + /* Test attribute values */ + attr_res = get_file_attr(mount_dir, file_id, attr_buf, + ARRAY_SIZE(attr_buf)); + if (attr_res != strlen(file_attr)) { + ksft_print_msg("Get file attr error: %d\n", attr_res); + goto failure; + } + if (strcmp(attr_buf, file_attr) != 0) { + ksft_print_msg("Incorrect file attr value: '%s'", attr_buf); + goto failure; + } + + /* Unmount and mount again, to see that attributes are persistent. */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Test attribute values again after remount*/ + attr_res = get_file_attr(mount_dir, file_id, attr_buf, + ARRAY_SIZE(attr_buf)); + if (attr_res != strlen(file_attr)) { + ksft_print_msg("Get dir attr error: %d\n", attr_res); + goto failure; + } + if (strcmp(attr_buf, file_attr) != 0) { + ksft_print_msg("Incorrect file attr value: '%s'", attr_buf); + goto failure; + } + + /* Final unmount */ + close(cmd_fd); + free(backing_dir); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int child_procs_waiting_for_data_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + int cmd_fd = -1; + int i; + pid_t *child_pids = alloca(file_num * sizeof(pid_t)); + char *backing_dir; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. (10s wait time) */ + if (mount_fs(mount_dir, backing_dir, 10000) != 0) + goto failure; + + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Tell FS about the files, without actually providing the data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL); + } + + /* Start child processes acessing data in the files */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + pid_t child_pid = flush_and_fork(); + + if (child_pid == 0) { + /* This is a child process, do the data validation. */ + int ret = validate_test_file_content(mount_dir, file); + + if (ret >= 0) { + /* Zero exit status if data is valid. */ + exit(0); + } + + /* Positive status if validation error found. */ + exit(-ret); + } else if (child_pid > 0) { + child_pids[i] = child_pid; + } else { + print_error("Fork error"); + goto failure; + } + } + + /* Write test data into the command file. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (emit_test_file_data(mount_dir, file)) + goto failure; + } + + /* Check that all children has finished with 0 exit status */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int status = wait_for_process(child_pids[i]); + + if (status != 0) { + ksft_print_msg( + "Validation for the file %s failed with code %d (%s)\n", + file->name, status, strerror(status)); + goto failure; + } + } + + close(cmd_fd); + free(backing_dir); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int multiple_providers_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + const int producer_count = 5; + int cmd_fd = -1; + int status; + int i; + pid_t *producer_pids = alloca(producer_count * sizeof(pid_t)); + char *backing_dir; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. (10s wait time) */ + if (mount_fs(mount_dir, backing_dir, 10000) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Tell FS about the files, without actually providing the data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL) < 0) + goto failure; + } + + /* Start producer processes */ + for (i = 0; i < producer_count; i++) { + pid_t producer_pid = flush_and_fork(); + + if (producer_pid == 0) { + int ret; + /* + * This is a child that should provide data to + * pending reads. + */ + + ret = data_producer(mount_dir, &test); + exit(-ret); + } else if (producer_pid > 0) { + producer_pids[i] = producer_pid; + } else { + print_error("Fork error"); + goto failure; + } + } + + /* Validate FS content */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *filename = concat_file_name(mount_dir, file->name); + loff_t read_result = read_whole_file(filename); + + free(filename); + if (read_result != file->size) { + ksft_print_msg( + "Error validating file %s. Result: %ld\n", + file->name, read_result); + goto failure; + } + } + + /* Check that all producers has finished with 0 exit status */ + for (i = 0; i < producer_count; i++) { + status = wait_for_process(producer_pids[i]); + if (status != 0) { + ksft_print_msg("Producer %d failed with code (%s)\n", i, + strerror(status)); + goto failure; + } + } + + close(cmd_fd); + free(backing_dir); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int signature_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + int i = 0; + unsigned char sig_buf[INCFS_MAX_SIGNATURE_SIZE]; + char *backing_dir; + int cmd_fd = -1; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. (10s wait time) */ + if (mount_fs(mount_dir, backing_dir, 10000) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Write hashes and data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int res; + + build_mtree(file); + + res = crypto_emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, file->root_hash, + file->sig.data, file->sig.size, file->sig.add_data); + + if (res) { + ksft_print_msg("Emit failed for %s. error: %s\n", + file->name, strerror(-res)); + goto failure; + } + + if (emit_test_file_data(mount_dir, file)) + goto failure; + + res = load_hash_tree(mount_dir, file); + if (res) { + ksft_print_msg("Can't load hashes for %s. error: %s\n", + file->name, strerror(-res)); + goto failure; + } + } + + /* Validate data */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int sig_len; + char *path; + int fd; + + if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + + path = concat_file_name(mount_dir, file->name); + fd = open(path, O_RDWR); + free(path); + if (fd < 0) { + print_error("Can't open file"); + goto failure; + } + + sig_len = get_file_signature(fd, sig_buf, ARRAY_SIZE(sig_buf)); + + if (close(fd)) { + print_error("Can't close file"); + goto failure; + } + + if (sig_len < 0) { + ksft_print_msg("Can't load signature %s. error: %s\n", + file->name, strerror(-sig_len)); + goto failure; + } + + if (sig_len != file->sig.size || + memcmp(sig_buf, file->sig.data, sig_len)) { + ksft_print_msg("Signature mismatch %s.\n", + file->name); + goto failure; + } + } + + /* Unmount and mount again, to make sure the signature is persistent. */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Validate data again */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int sig_len; + char *path; + int fd; + + if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + + path = concat_file_name(mount_dir, file->name); + fd = open(path, O_RDWR); + free(path); + if (fd < 0) { + print_error("Can't open file"); + goto failure; + } + + sig_len = get_file_signature(fd, sig_buf, ARRAY_SIZE(sig_buf)); + + if (close(fd)) { + print_error("Can't close file"); + goto failure; + } + + if (sig_len < 0) { + ksft_print_msg("Can't load signature %s. error: %s\n", + file->name, strerror(-sig_len)); + goto failure; + } + if (sig_len != file->sig.size || + memcmp(sig_buf, file->sig.data, sig_len)) { + ksft_print_msg("Signature mismatch %s.\n", + file->name); + goto failure; + } + } + + /* Final unmount */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int hash_tree_test(char *mount_dir) +{ + char *backing_dir; + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + const int corrupted_file_idx = 5; + int i = 0; + int cmd_fd = -1; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Write hashes and data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int res; + + build_mtree(file); + res = crypto_emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, file->root_hash, + file->sig.data, file->sig.size, file->sig.add_data); + + if (i == corrupted_file_idx) { + /* Corrupt third blocks hash */ + file->mtree[0].data[2 * SHA256_DIGEST_SIZE] ^= 0xff; + } + if (emit_test_file_data(mount_dir, file)) + goto failure; + + res = load_hash_tree(mount_dir, file); + if (res) { + ksft_print_msg("Can't load hashes for %s. error: %s\n", + file->name, strerror(-res)); + goto failure; + } + } + + /* Validate data */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (i == corrupted_file_idx) { + uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; + char *filename = + concat_file_name(mount_dir, file->name); + int res; + + res = read_test_file(data, INCFS_DATA_FILE_BLOCK_SIZE, + filename, 2); + free(filename); + if (res != -EBADMSG) { + ksft_print_msg("Hash violation missed1. %d\n", + res); + goto failure; + } + } else if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + } + + /* Unmount and mount again, to that hashes are persistent. */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Validate data again */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (i == corrupted_file_idx) { + uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; + char *filename = + concat_file_name(mount_dir, file->name); + int res; + + res = read_test_file(data, INCFS_DATA_FILE_BLOCK_SIZE, + filename, 2); + free(filename); + if (res != -EBADMSG) { + ksft_print_msg("Hash violation missed2. %d\n", + res); + goto failure; + } + } else if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + } + + /* Final unmount */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int validate_logs(char *mount_dir, int log_fd, struct test_file *file) +{ + uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; + struct incfs_pending_read_info prs[100] = {}; + int prs_size = ARRAY_SIZE(prs); + int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + int res; + int read_count; + int i; + char *filename = concat_file_name(mount_dir, file->name); + int fd; + + fd = open(filename, O_RDONLY); + free(filename); + if (fd <= 0) + return TEST_FAILURE; + + if (block_cnt > prs_size) + block_cnt = prs_size; + + for (i = 0; i < block_cnt; i++) { + res = pread(fd, data, sizeof(data), + INCFS_DATA_FILE_BLOCK_SIZE * i); + if (res <= 0) + goto failure; + } + + read_count = wait_for_pending_reads(log_fd, 0, prs, prs_size); + if (read_count < 0) { + ksft_print_msg("Error reading logged reads %s.\n", + strerror(-read_count)); + goto failure; + } + + if (read_count != block_cnt) { + ksft_print_msg("Bad log read count %s %d %d.\n", file->name, + read_count, block_cnt); + goto failure; + } + + for (i = 0; i < read_count; i++) { + struct incfs_pending_read_info *read = &prs[i]; + + if (!same_id(&read->file_id, &file->id)) { + ksft_print_msg("Bad log read ino %s\n", file->name); + goto failure; + } + + if (read->block_index != i) { + ksft_print_msg("Bad log read ino %s %d %d.\n", + file->name, read->block_index, i); + goto failure; + } + + if (i != 0) { + unsigned long psn = prs[i - 1].serial_number; + + if (read->serial_number != psn + 1) { + ksft_print_msg("Bad log read sn %s %d %d.\n", + file->name, read->serial_number, + psn); + goto failure; + } + } + + if (read->timestamp_us == 0) { + ksft_print_msg("Bad log read timestamp %s.\n", + file->name); + goto failure; + } + } + close(fd); + return TEST_SUCCESS; + +failure: + close(fd); + return TEST_FAILURE; +} + +static int read_log_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + int i = 0; + int cmd_fd = -1, log_fd = -1; + char *backing_dir; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0") != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + log_fd = open_log_file(mount_dir); + if (cmd_fd < 0) + ksft_print_msg("Can't open log file.\n"); + + /* Write data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL)) + goto failure; + + if (emit_test_file_data(mount_dir, file)) + goto failure; + } + + /* Validate data */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (validate_logs(mount_dir, log_fd, file)) + goto failure; + } + + /* Unmount and mount again, to see that logs work after remount. */ + close(cmd_fd); + close(log_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0") != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + log_fd = open_log_file(mount_dir); + if (cmd_fd < 0) + ksft_print_msg("Can't open log file.\n"); + + /* Validate data again */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (validate_logs(mount_dir, log_fd, file)) + goto failure; + } + + /* Final unmount */ + close(cmd_fd); + close(log_fd); + free(backing_dir); + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + close(log_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static char *setup_mount_dir() +{ + struct stat st; + char *current_dir = getcwd(NULL, 0); + char *mount_dir = concat_file_name(current_dir, "incfs-mount-dir"); + + free(current_dir); + if (stat(mount_dir, &st) == 0) { + if (S_ISDIR(st.st_mode)) + return mount_dir; + + ksft_print_msg("%s is a file, not a dir.\n", mount_dir); + return NULL; + } + + if (mkdir(mount_dir, 0777)) { + print_error("Can't create mount dir."); + return NULL; + } + + return mount_dir; +} + +int main(int argc, char *argv[]) +{ + char *mount_dir = NULL; + int fails = 0; + int i; + int fd, count; + + // Seed randomness pool for testing on QEMU + // NOTE - this abuses the concept of randomness - do *not* ever do this + // on a machine for production use - the device will think it has good + // randomness when it does not. + fd = open("/dev/urandom", O_WRONLY); + count = 4096; + for (int i = 0; i < 128; ++i) + ioctl(fd, RNDADDTOENTCNT, &count); + close(fd); + + ksft_print_header(); + + if (geteuid() != 0) + ksft_print_msg("Not a root, might fail to mount.\n"); + + mount_dir = setup_mount_dir(); + if (mount_dir == NULL) + ksft_exit_fail_msg("Can't create a mount dir\n"); + +#define MAKE_TEST(test) \ + { \ + test, #test \ + } + struct { + int (*pfunc)(char *dir); + const char *name; + } cases[] = { + MAKE_TEST(basic_file_ops_test), + MAKE_TEST(cant_touch_index_test), + MAKE_TEST(dynamic_files_and_data_test), + MAKE_TEST(concurrent_reads_and_writes_test), + MAKE_TEST(attribute_test), + MAKE_TEST(work_after_remount_test), + MAKE_TEST(child_procs_waiting_for_data_test), + MAKE_TEST(multiple_providers_test), + MAKE_TEST(signature_test), + MAKE_TEST(hash_tree_test), + MAKE_TEST(read_log_test), + }; +#undef MAKE_TEST + + /* Bring back for kernel 5.x */ + /* ksft_set_plan(ARRAY_SIZE(cases)); */ + + for (i = 0; i < ARRAY_SIZE(cases); ++i) { + ksft_print_msg("Running %s\n", cases[i].name); + if (cases[i].pfunc(mount_dir) == TEST_SUCCESS) + ksft_test_result_pass("%s\n", cases[i].name); + else { + ksft_test_result_fail("%s\n", cases[i].name); + fails++; + } + } + + umount2(mount_dir, MNT_FORCE); + rmdir(mount_dir); + + if (fails > 0) + ksft_exit_pass(); + else + ksft_exit_pass(); + return 0; +} diff --git a/tools/testing/selftests/filesystems/incfs/utils.c b/tools/testing/selftests/filesystems/incfs/utils.c new file mode 100644 index 0000000000000000000000000000000000000000..08b8452ad0bcdbbe5982d1780b6f1dd71ef68396 --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/utils.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int mount_fs(char *mount_dir, char *backing_dir, int read_timeout_ms) +{ + static const char fs_name[] = INCFS_NAME; + char mount_options[512]; + int result; + + snprintf(mount_options, ARRAY_SIZE(mount_options), + "read_timeout_ms=%u", + read_timeout_ms); + + result = mount(backing_dir, mount_dir, fs_name, 0, mount_options); + if (result != 0) + perror("Error mounting fs."); + return result; +} + +int mount_fs_opt(char *mount_dir, char *backing_dir, char *opt) +{ + static const char fs_name[] = INCFS_NAME; + int result; + + result = mount(backing_dir, mount_dir, fs_name, 0, opt); + if (result != 0) + perror("Error mounting fs."); + return result; +} + +int unlink_node(int fd, int parent_ino, char *filename) +{ + return 0; +} + + +static EVP_PKEY *deserialize_private_key(const char *pem_key) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + int len = strlen(pem_key); + + bio = BIO_new_mem_buf(pem_key, len); + if (!bio) + return NULL; + + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + BIO_free(bio); + return pkey; +} + +static X509 *deserialize_cert(const char *pem_cert) +{ + BIO *bio = NULL; + X509 *cert = NULL; + int len = strlen(pem_cert); + + bio = BIO_new_mem_buf(pem_cert, len); + if (!bio) + return NULL; + + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + return cert; +} + +bool sign_pkcs7(const void *data_to_sign, size_t data_size, + char *pkey_pem, char *cert_pem, + void **sig_ret, size_t *sig_size_ret) +{ + /* + * PKCS#7 signing flags: + * + * - PKCS7_BINARY signing binary data, so skip MIME translation + * + * - PKCS7_NOATTR omit extra authenticated attributes, such as + * SMIMECapabilities + * + * - PKCS7_PARTIAL PKCS7_sign() creates a handle only, then + * PKCS7_sign_add_signer() can add a signer later. + * This is necessary to change the message digest + * algorithm from the default of SHA-1. Requires + * OpenSSL 1.0.0 or later. + */ + int pkcs7_flags = PKCS7_BINARY | PKCS7_NOATTR | PKCS7_PARTIAL; + void *sig; + size_t sig_size; + BIO *bio = NULL; + PKCS7 *p7 = NULL; + EVP_PKEY *pkey = NULL; + X509 *cert = NULL; + bool ok = false; + + const EVP_MD *md = EVP_sha256(); + + pkey = deserialize_private_key(pkey_pem); + if (!pkey) { + printf("deserialize_private_key failed\n"); + goto out; + } + + cert = deserialize_cert(cert_pem); + if (!cert) { + printf("deserialize_cert failed\n"); + goto out; + } + + bio = BIO_new_mem_buf(data_to_sign, data_size); + if (!bio) + goto out; + + p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags); + if (!p7) { + printf("failed to initialize PKCS#7 signature object\n"); + goto out; + } + + if (!PKCS7_sign_add_signer(p7, cert, pkey, md, pkcs7_flags)) { + printf("failed to add signer to PKCS#7 signature object\n"); + goto out; + } + + if (PKCS7_final(p7, bio, pkcs7_flags) != 1) { + printf("failed to finalize PKCS#7 signature\n"); + goto out; + } + + BIO_free(bio); + bio = BIO_new(BIO_s_mem()); + if (!bio) { + printf("out of memory\n"); + goto out; + } + + if (i2d_PKCS7_bio(bio, p7) != 1) { + printf("failed to DER-encode PKCS#7 signature object\n"); + goto out; + } + + sig_size = BIO_get_mem_data(bio, &sig); + *sig_ret = malloc(sig_size); + memcpy(*sig_ret, sig, sig_size); + *sig_size_ret = sig_size; + ok = true; +out: + PKCS7_free(p7); + BIO_free(bio); + return ok; +} + +int crypto_emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, + size_t size, const char *root_hash, char *sig, size_t sig_size, + char *add_data) +{ + int mode = __S_IFREG | 0555; + struct incfs_file_signature_info sig_info = { + .hash_tree_alg = root_hash + ? INCFS_HASH_TREE_SHA256 + : 0, + .root_hash = ptr_to_u64(root_hash), + .additional_data = ptr_to_u64(add_data), + .additional_data_size = strlen(add_data), + .signature = ptr_to_u64(sig), + .signature_size = sig_size, + }; + + struct incfs_new_file_args args = { + .size = size, + .mode = mode, + .file_name = ptr_to_u64(filename), + .directory_path = ptr_to_u64(dir), + .signature_info = ptr_to_u64(&sig_info), + .file_attr = 0, + .file_attr_len = 0 + }; + + md5(filename, strlen(filename), (char *)args.file_id.bytes); + + if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0) + return -errno; + + *id_out = args.file_id; + return 0; +} + + +int emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, + size_t size, char *attr) +{ + int mode = __S_IFREG | 0555; + struct incfs_file_signature_info sig_info = { + .hash_tree_alg = 0, + .root_hash = ptr_to_u64(NULL) + }; + struct incfs_new_file_args args = { + .size = size, + .mode = mode, + .file_name = ptr_to_u64(filename), + .directory_path = ptr_to_u64(dir), + .signature_info = ptr_to_u64(&sig_info), + .file_attr = ptr_to_u64(attr), + .file_attr_len = attr ? strlen(attr) : 0 + }; + + md5(filename, strlen(filename), (char *)args.file_id.bytes); + + if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0) + return -errno; + + *id_out = args.file_id; + return 0; +} + +int get_file_bmap(int cmd_fd, int ino, unsigned char *buf, int buf_size) +{ + return 0; +} + +int get_file_signature(int fd, unsigned char *buf, int buf_size) +{ + struct incfs_get_file_sig_args args = { + .file_signature = ptr_to_u64(buf), + .file_signature_buf_size = buf_size + }; + + if (ioctl(fd, INCFS_IOC_READ_FILE_SIGNATURE, &args) == 0) + return args.file_signature_len_out; + return -errno; +} + +loff_t get_file_size(char *name) +{ + struct stat st; + + if (stat(name, &st) == 0) + return st.st_size; + return -ENOENT; +} + +int open_commands_file(char *mount_dir) +{ + char cmd_file[255]; + int cmd_fd; + + snprintf(cmd_file, ARRAY_SIZE(cmd_file), + "%s/%s", mount_dir, INCFS_PENDING_READS_FILENAME); + cmd_fd = open(cmd_file, O_RDONLY); + + if (cmd_fd < 0) + perror("Can't open commands file"); + return cmd_fd; +} + +int open_log_file(char *mount_dir) +{ + char cmd_file[255]; + int cmd_fd; + + snprintf(cmd_file, ARRAY_SIZE(cmd_file), "%s/.log", mount_dir); + cmd_fd = open(cmd_file, O_RDWR); + if (cmd_fd < 0) + perror("Can't open log file"); + return cmd_fd; +} + +int wait_for_pending_reads(int fd, int timeout_ms, + struct incfs_pending_read_info *prs, int prs_count) +{ + ssize_t read_res = 0; + + if (timeout_ms > 0) { + int poll_res = 0; + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN + }; + + poll_res = poll(&pollfd, 1, timeout_ms); + if (poll_res < 0) + return -errno; + if (poll_res == 0) + return 0; + if (!(pollfd.revents | POLLIN)) + return 0; + } + + read_res = read(fd, prs, prs_count * sizeof(*prs)); + if (read_res < 0) + return -errno; + + return read_res / sizeof(*prs); +} + +char *concat_file_name(const char *dir, char *file) +{ + char full_name[FILENAME_MAX] = ""; + + if (snprintf(full_name, ARRAY_SIZE(full_name), "%s/%s", dir, file) < 0) + return NULL; + return strdup(full_name); +} + +int delete_dir_tree(const char *dir_path) +{ + DIR *dir = NULL; + struct dirent *dp; + int result = 0; + + dir = opendir(dir_path); + if (!dir) { + result = -errno; + goto out; + } + + while ((dp = readdir(dir))) { + char *full_path; + + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; + + full_path = concat_file_name(dir_path, dp->d_name); + if (dp->d_type == DT_DIR) + result = delete_dir_tree(full_path); + else + result = unlink(full_path); + free(full_path); + if (result) + goto out; + } + +out: + if (dir) + closedir(dir); + if (!result) + rmdir(dir_path); + return result; +} + +void sha256(char *data, size_t dsize, char *hash) +{ + SHA256_CTX ctx; + + SHA256_Init(&ctx); + SHA256_Update(&ctx, data, dsize); + SHA256_Final((unsigned char *)hash, &ctx); +} + +void md5(char *data, size_t dsize, char *hash) +{ + MD5_CTX ctx; + + MD5_Init(&ctx); + MD5_Update(&ctx, data, dsize); + MD5_Final((unsigned char *)hash, &ctx); +} diff --git a/tools/testing/selftests/filesystems/incfs/utils.h b/tools/testing/selftests/filesystems/incfs/utils.h new file mode 100644 index 0000000000000000000000000000000000000000..9c9ba3c5f70a54b69cfffebba7692d34395e9d1f --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/utils.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ +#include +#include + +#include "../../include/uapi/linux/incrementalfs.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +#ifdef __LP64__ +#define ptr_to_u64(p) ((__u64)p) +#else +#define ptr_to_u64(p) ((__u64)(__u32)p) +#endif + +#define SHA256_DIGEST_SIZE 32 + +int mount_fs(char *mount_dir, char *backing_dir, int read_timeout_ms); + +int mount_fs_opt(char *mount_dir, char *backing_dir, char *opt); + +int get_file_bmap(int cmd_fd, int ino, unsigned char *buf, int buf_size); + +int get_file_signature(int fd, unsigned char *buf, int buf_size); + +int emit_node(int fd, char *filename, int *ino_out, int parent_ino, + size_t size, mode_t mode, char *attr); + +int emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, + size_t size, char *attr); + +int crypto_emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, + size_t size, const char *root_hash, char *sig, size_t sig_size, + char *add_data); + +int unlink_node(int fd, int parent_ino, char *filename); + +loff_t get_file_size(char *name); + +int open_commands_file(char *mount_dir); + +int open_log_file(char *mount_dir); + +int wait_for_pending_reads(int fd, int timeout_ms, + struct incfs_pending_read_info *prs, int prs_count); + +char *concat_file_name(const char *dir, char *file); + +void sha256(char *data, size_t dsize, char *hash); + +void md5(char *data, size_t dsize, char *hash); + +bool sign_pkcs7(const void *data_to_sign, size_t data_size, + char *pkey_pem, char *cert_pem, + void **sig_ret, size_t *sig_size_ret); + +int delete_dir_tree(const char *path); diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c index ee9382bdfadc8755b17f87c9e37437a28688e376..c5587844fbb8c6e2e5254ea050f6167c834186ad 100644 --- a/tools/testing/selftests/ipc/msgque.c +++ b/tools/testing/selftests/ipc/msgque.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE #include #include #include #include -#include +#include #include #include "../kselftest.h" @@ -73,7 +74,7 @@ int restore_queue(struct msgque_data *msgque) return 0; destroy: - if (msgctl(id, IPC_RMID, 0)) + if (msgctl(id, IPC_RMID, NULL)) printf("Failed to destroy queue: %d\n", -errno); return ret; } @@ -120,7 +121,7 @@ int check_and_destroy_queue(struct msgque_data *msgque) ret = 0; err: - if (msgctl(msgque->msq_id, IPC_RMID, 0)) { + if (msgctl(msgque->msq_id, IPC_RMID, NULL)) { printf("Failed to destroy queue: %d\n", -errno); return -errno; } @@ -129,7 +130,7 @@ int check_and_destroy_queue(struct msgque_data *msgque) int dump_queue(struct msgque_data *msgque) { - struct msqid64_ds ds; + struct msqid_ds ds; int kern_id; int i, ret; @@ -246,7 +247,7 @@ int main(int argc, char **argv) return ksft_exit_pass(); err_destroy: - if (msgctl(msgque.msq_id, IPC_RMID, 0)) { + if (msgctl(msgque.msq_id, IPC_RMID, NULL)) { printf("Failed to destroy queue: %d\n", -errno); return ksft_exit_fail(); } diff --git a/tools/testing/selftests/rseq/settings b/tools/testing/selftests/rseq/settings new file mode 100644 index 0000000000000000000000000000000000000000..e7b9417537fbc4626153b72e8f295ab4594c844b --- /dev/null +++ b/tools/testing/selftests/rseq/settings @@ -0,0 +1 @@ +timeout=0